Skip to content

Relive the Glory of Japanese Fighting Baseball With faker.js and Cloudinary

The year was 1994. South Africa held its first fully representative democratic election, Netscape Navigator became the first commercially successful web browser. Coconuts Japan re-released EA Sports’ MLBPA Baseball video game under the perhaps surprising title Fighting Baseball. Unlike MLBPA Baseball, which was licensed by the Major League Baseball (MLB), Fighting Baseball could not infringe on MLB trademarks, reference the National League or American League by name, or adopt actual team or player names.

To get around that limitation, the team invented an entire league’s worth of fake American names. That’s thanks to a simple procedure concocted by some clever internet sleuths: Take a player’s last name, change a letter or two, and pair that last name with another player’s first name, which was occasionally edited in a similar way.

The results were simply beautiful with long-lasting appeal. After all, who wouldn’t want to play baseball with Todd Bonzalez, Bobson Dugnutt, and Sleve McDichael?

That was then; this is now. In the last 25 years, the ability to generate an unending amount of randomness has taken off at top speed, and programmatically producing fake names in a like manner is achievable. Once a list is in hand, it’s a breeze to leverage Cloudinary to turn it into a graphic that fits right into the game.

Even better, we can do all the randomization on the front end and generate images with front-end calls to Cloudinary. The result is a Jamstack app that requires no server management. This post shines a light on the process.

First, generate template names with the faker.js JavaScript library, which offers many utilities for spawning fake data: names, dates, addresses, passwords, vehicles, bitcoin addresses. Here, we’ll take advantage of faker’s name-generating capabilities. See the steps below.

  1. initialize with a locale and a seed to ensure that the results are deterministic based on the URL:

    const faker = window.faker;
    faker.locale = "en_US";
    // getParameterByName is a utility function retrieving the seed from the URL.
    let seed = parseInt(getParameterByName("seed"));
    if (seed && !isNaN(seed)) {
      faker.seed(seed);
    }
    Code language: JavaScript (javascript)
  2. Generate names of 16 characters maximum so that the names would display properly in the image.

    do {
      firstName = faker.name.firstName(0);
      lastName = faker.name.lastName();
      name = `${firstName} ${lastName}`;
    } while (name.length > 16)
    Code language: JavaScript (javascript)
  3. Arbitrarily replace one or two characters of the last name with other characters for a touch of randomness. The scramble function picks the letters and passes them to the validMoves function to determine an appropriate replacement.

    function validMoves(letter) {
      if (letter.toUpperCase() == "Y") return; // Y is tricky, just don't mess with it.
      const hPreceders = ["c", "s", "t"];
      const consonants = "bdfghjklmnpqrvwxz".split("");
      const vowels = "aeiou".split("");
      let toReturn;
      if (hPreceders.includes(letter.toLowerCase())) {
        return hPreceders;
      } else if (consonants.includes(letter.toLowerCase())) {
        return consonants;
      } else {
        return vowels;
      }
    }
    Code language: JavaScript (javascript)

    We always return the same class of letter: H preceder, consonant, or vowel.

  4. Perform a similar replacement on the first name about 20% of the time, matching the apparent trend in Fighting Baseball.

That’s it. A new name is now available, and we’re ready to generate images.

Start with this image of a blue background and layer on names. Cloudinary’s transformation feature for text layers is the perfect tool for the job. We can specify position, font, size, color, and text transformations, along with, of course, the text itself.

Here’s the transformation for the first player, Gbant Nolav (originally Grant Nolan):

co_rgb:edeae5,l_text:Press Start 2P_16:GBANT%2520NOLAV/co_rgb:000000,e_shadow:5,x_2,y_2/fl_layer_apply,g_north_west,x_38,y_30

The font Press Start 2P, available on Google Fonts, looks reasonably similar to the original in the game, and Cloudinary supports text overlays with any Google font out of the box. Also added is a black shadow with the e_shadow effect.

Finally, place the text with a northwest gravity, as well as specific x and y coordinates to offset from the corner. Here is the result:

Loading code examples Board with one name

To add another name, Troy Orl (originally Troy Orn), with a similar transformation:

co_rgb:edeae5,l_text:Press Start 2P_16:TROY%2520ORL/co_rgb:000000,e_shadow:5,x_2,y_2/fl_layer_apply,g_north_west,x_38,y_50

The result:

Loading code examples Board with two names

That’s a tedious task, involving a load of manual work to calculate the text positions. A much more efficient way would be to describe each position as a row and a column, and have Cloudinary do the math. Here’s what to do:

  1. Create a named transformation, bobson_name, with three arguments (col, row, and player) to store the calculation.

    co_rgb:edeae5,l_text:Press Start 2P_16:$(player)/co_rgb:000000,e_shadow:5,x_2,y_2/fl_layer_apply,g_north_west,x_$col_mul_294_sub_256,y_10_add_$row_mul_20
    

    A simple substitution takes care of the player name. For col, multiply it by the column width (294 pixels) and then subtract an offset of 256 pixels. For row, multiply it by the row height (20 pixels) and add a 10-pixel further offset.

    The result is a replacement of the two transformations above with the following:

    $player_!GBANT%20NOLAV!,$col_1,$row_1/t_bobson_name/$player_!TROY%20ORL!,$col_1,$row_2/t_bobson_name/
    

    {note} First specify the variables and then invoke the transformation, once per text overlay. Strings are surrounded by instances of !; integers have no special surrounding characters. {/note}

  2. Now effortlessly add the remaining players:

    $player_!GBANT%20NOLAV!,$col_1,$row_1/t_bobson_name/$player_!TROY%20ORL!,$col_1,$row_2/t_bobson_name/$player_!SCOTT%20JIRVEY!,$col_1,$row_3/t_bobson_name/$player_!TIM%20OBSHIRE!,$col_1,$row_4/t_bobson_name/$player_!JIMMIE%20QEITZON!,$col_1,$row_5/t_bobson_name/$player_!TATH%20PELLICH!,$col_1,$row_6/t_bobson_name/$player_!RANDALL%20KIIKN!,$col_1,$row_7/t_bobson_name/$player_!RAYLOND%20WOKJ!,$col_1,$row_8/t_bobson_name/$player_!PHILIP%20FERQY!,$col_1,$row_9/t_bobson_name/$player_!SIDNEY%20KUVALAS!,$col_1,$row_10/t_bobson_name/$player_!WILBUR%20WISUZK!,$col_1,$row_11/t_bobson_name/$player_!ROMAN%20SHIOLDS!,$col_2,$row_1/t_bobson_name/$player_!GEORGE%20DICKINSUN!,$col_2,$row_2/t_bobson_name/$player_!LOUIS%20STHAEFER!,$col_2,$row_3/t_bobson_name/$player_!DOYLE%20CIRKERY!,$col_2,$row_4/t_bobson_name/$player_!FELIPE%20ZAST!,$col_2,$row_5/t_bobson_name/$player_!BRUCE%20WOYLE!,$col_2,$row_6/t_bobson_name/$player_!CONRAD%20FEHE!,$col_2,$row_7/t_bobson_name/$player_!DARRYL%20KOORE!,$col_2,$row_8/t_bobson_name/$player_!MIGUEL%20SHAMPLIN!,$col_2,$row_9/t_bobson_name/$player_!TIM%20MKANT!,$col_2,$row_10/t_bobson_name/$player_!DANNY%20TANFORD!,$col_2,$row_11/t_bobson_name
    

The image then looks like this:

Loading code examples Final image

Our very own Fighting Baseball team is now for real, complete with Scott Jirvey, Louis Sthaefer, and Bruce Woyle. See the live image, which was generated from seed 66219.

To add context, cite a random team name, assisted by faker.js and the pluralize library:

function headerText() {
  return `Meet Your Amazing ${1950 + rand(71)} ${faker.address.city()} ${pluralize(faker.commerce.productName())}!`;
}
Code language: JavaScript (javascript)

Feel free to build your own teams and rosters by clicking Redraft the team! and inspect the source code. Have a blast.

Back to top

Featured Post