A sample book produced from the generator

The TWOW πŸ“• gen (commonly referred to as the booksona generator) is a tool made by Cary's brother, Michael, that produces book images colored based on an inputted name.

Its existence was first revealed in HTwins Central by Michael on June 1, 2016, whereas its first mention in the show fell on TWOW 14A two days later.


The TWOW πŸ“• gen lets users input a name and will generate colors corresponding to the first two characters of that name. Each letter produces its own hue, cycling through the rainbow such that β€œA” is a shade of red, β€œN” is cyan, and β€œZ” is rose. A slightly different cycle exists for numerals so that, instead, β€œ0” is red, β€œ5” is cyan, and β€œ9” is rose.

The generator will then produce a book image by tinting the separated parts of a book asset with the produced colors and then layering them over one another.

The tool utilizes a total of six images, each an isolated part of the book, to generate the final images. The first three are for books with a face and limbs, and the other three are for blank books. Users can select whether the produced book should have a face and limbs or not.

Color generation


The on-site JavaScript implementation of the process

The calculations used to generate the color for each letter are as follows:

JavaScript English
function makeLetterTint(char) {
Let char be the character to be processed.
    char = char.toUpperCase();
Capitalize the character. (e.g. β€œa” to β€œA”, β€œΓ©β€ to β€œΓ‰β€, do nothing with characters that don’t have a distinguishable capital)
    const charCode = char.charCodeAt();
Take the Unicode codepoint of this capital character.
    let hue1 = 0;
(Initialize the variable hue1. This step is used for variable scoping in the JavaScript implementation and does not affect the calculation.)
    if (char >= "0" && char <= "9") {
        hue1 = (charCode - "0".charCodeAt()) / 10;
  • If the character is an Arabic digit (β€œ0β€β€“β€œ9”), subtract 48 (the code for β€œ0”) from its codepoint and divide the resulting value by 10. Let hue1 be this result.
    else {
        hue1 = (charCode - "A".charCodeAt()) / 26 % 1;
  • Otherwise, subtract 65 (the code for β€œA”) from its code point and divide the resulting value by 26. Take the decimal portion of the resulting quotient. Let hue1 be this result.
    const sat1 = .7 - Math.max(0, .3 - Math.abs(hue1 - 2/3) * 2);
Subtract two thirds from hue1 and take the absolute value of this difference. Then, multiply this absolute value by 2. Subtract this product from 0.3. Compare this difference with 0 and take whichever is higher, and then subtract it from 0.7. Let this third difference be sat1.
    const hue360 = hue1 * 360;
    const sat100 = sat1 * 100;
Let hue360 be hue1 multiplied by 360. Let sat100 be sat1 multiplied by 100.
    return `hsl(${hue360}, ${sat100}%, 60%)`;
The character’s color, in terms of HSL, has a hue of hue360 degrees, a saturation of sat100%, and a lightness of 60%.

This process is the same used by Cary when generating default book sprites[1].

This information can be found by inspecting the JavaScript of the page, specifically the makeLetterTint function.

The ranges of both cycles intersect at hues of 0 degrees (β€œA” and β€œ0”) and 180 degrees (β€œN” and β€œ5”). As such, there are 34 (26 + 10 βˆ’ 2) unique tints that the tool can generate, leading to a total count of 1156 possible books.


  • During an older version, Meester Tweester noted that the generator could not create books from a single character input. When Michael resolved this bug, he placed a comment, reading,Β 
    // This is dedicated to Meester Tweester
    within the updateBookΒ function beside the code used to fix it[2].
  • When putting the textures with the sides of the book together, there is a distinct line running through the center.
  • Characters with a hexadecimal value of 10000 (decimal value of 65,536) or higher will start to produce two different colors. This is due to astral characters' composition of two characters.
  • After selecting "Blank", the user cannot revert until the page is reloaded.
    • This occurs because the code erroneously tries to use:
      faceEnabled = checks[0].getAttribute('checked');
      which returns an empty string, unlike:
      faceEnabled = checks[0].checked;
      in the checkChanged function.
  • Depending on the browser, the generated image may have miscolored limbs and no outline, caused by a lack of support for compositing operations.
  • The book’s legs end up in front of the cover, though the first imported image shows that they should be behind. This happens because the second image has the legs uncovered and is placed over the first.



  1. ↑
  2. ↑