Book covers from a seed

Scriby is a quiet word processor for writing books. Its library is a bookshelf, and a shelf of grey rectangles with titles on them looks like a spreadsheet. So every book gets a cover the moment it exists, before you've written a word, with no image model and nothing to download. It's painted from a seed. (Later on Scriby can also paint one from the story itself, or you can choose your own image, but nobody has to.)

Type a title and an author. The art and the template come from the seed, so typing only re-sets the type. Shuffle rolls a new seed.

Same seed, same cover

A cover has to be the same every time you open the app, but I didn't want to store a picture for every book. So the seed is a string (the book's id), hashed with FNV-1a into 32 bits and fed to mulberry32, a tiny random number generator that gives the same sequence for the same seed, on every machine, forever.

function hash(str) {            // FNV-1a
  let h = 0x811c9dc5;
  for (const ch of str) h = Math.imul(h ^ ch.charCodeAt(0), 0x01000193) >>> 0;
  return h;
}
const r = rng(hash(book.id));  // mulberry32: r() is 0…1, always the same order

Every decision then pulls the next number. A base hue, then a scheme (analogous, split, mono or duotone), a saturation between 28% and 62%, and a coin flip weighted 70/30 towards a deep ground rather than a pale one. That gives five colours: a ground, a second ground, a mid tone, one accent and a pale. Then one of seven art styles: soft orbs, a horizon with a glow and sometimes a sun, a ring with a crossing line, Bauhaus bands, translucent shards, stacked waves, or a lone solitary shape in a lot of space. A pinch of grain goes on last, so they read as printed rather than rendered.

Because the title isn't part of the seed, renaming a book keeps its painting and only re-sets the type. Shuffle just makes a new seed.

The title is the design

The type is a separate layer of real text, which means it's always sharp and never misspelled. A second seed picks one of seven templates, each a face and a stance: tall Anton stacked to the top left, Bebas Neue centred, Playfair Display Black, Abril Fatface sitting at the bottom, Cinzel inside a thin frame, Josefin Sans on a solid band, and Oswald under a short rule.

The layout engine breaks the title into lines and sizes each line to run the full width of the cover, the way display type on a bestseller does. The small connecting words, the, of, and and friends, get their own line at about a third of the size, letterspaced or in Playfair italic, so "The Salt Road" becomes a whisper and two shouts. A lone leading connector on a two-word title stays big, because "The Road" with a tiny "the" looks like a typo. If the stack gets too tall, the whole block shrinks together.

Six made-up books, six seeds. Click one to open it above.

Picking the ink

White or black? Instead of guessing from the palette, Scriby measures the painting. It works out where the title block and the author line will land, then reads the pixels in exactly those rectangles (every fourth one is plenty) and takes the mean luminance and its spread. Under 0.56 the ink is white, otherwise near-black. If the mean sits in the murky middle (within 0.22 of 0.5) or the area is busy (spread over 0.2), it adds a scrim behind the type: a soft gradient that follows the template, from the top for Anton, from the bottom for Abril, a radial glow for the centred ones. The author's name is measured separately and gets its own little plate if it needs one.

The same plan draws the shelf tile in CSS and the full-size export on a canvas, so the cover on your shelf is the cover in your export. This page uses the canvas path for everything.

Credit

Scriby is a fork of NEO, the word processor for authors by Hugh Howey, released under the MIT licence. The editor, the library and shelves, the saving rules and the exports started as his work, and the fonts here still carry their NEO names for that reason. The covers on this page use latin subsets of seven SIL Open Font License faces, about 140 KB in all (licences).

Built
October 2026
Stack
Canvas 2D, seeded randomness, no libraries
Lives at
Scriby's bookshelf (macOS)
Source
tomxander/scriby, covers.js

Built with Claude Code. The demo runs Scriby's covers.js, trimmed to the parts that paint and set covers, with the connector list cut down to English.