Book Cover Generator

io.github.otsirh由 GitHub 账号 otsirh 发布v1.13.0更新于 Nov 14, 2026

Book covers from a title and an author: 39 styles, 28 palettes, mockups, SVG and PNG.

已验证Streamable HTTP可网页运行开发者工具媒体与设计

概览

AI 生成的概览

根据书名和作者生成书籍封面,提供样式、配色、样机和印刷用图,并返回图片链接与编辑器链接。

可以做什么
  • 用书名、作者、副标题、系列行、署名或徽章生成封面,并可指定样式、配色、随机种子、字体和尺寸
  • 列出可用样式及其适用类型和可固定选项,以及明暗配色及其颜色
  • 把封面做成 3D 书、平铺图、电子阅读器或带一行文字社交卡片的样机
  • 返回图片链接(SVG 与 PNG)以及可在网页编辑器中修改和下载的设计链接
适用场景
适合为书稿、系列或自出版作品快速起草封面方案,或在不打开设计软件的情况下为书籍准备占位图和社交卡片图。
运行要求
可作为远程端点使用,也可作为本地 npm 包通过 npx 运行;未声明需要账号、API 密钥或环境变量。编辑器和 PNG/JPEG 下载在 covers.otsirh.dev 网页应用中进行。
安装前请注意
生成的设计会成为第三方网站上的公开链接,标题或简介中不要放机密内容。封面会缓存一天且服务有速率限制;服务端渲染只支持拉丁、希腊和西里尔文字,其他文字需改用 SVG 输出。

安装

在 SourceWeft 中

  1. 打开 控制台中的 Book Cover Generator,将其添加到工作区。
  2. 为需要使用其工具的对话启用该服务。

Web executable,通过 Streamable HTTP。 远程服务在工作区中配置后即可从网页运行时运行。

交给智能体安装

把这段提示词粘贴到 Claude Code、Codex、Cursor 等智能体,或 SourceWeft 对话中。智能体会读取该服务器的安装指南,先向你展示发布者、端点和登录方式,经你同意后再把它添加到你的客户端。密钥不会写进任何命令。

阅读 https://sourceweft.com/mcp/io.github.otsirh%2Fbook-cover-generator/install.md,并按其中说明把这个 MCP 服务器接入我的客户端。修改任何配置之前,先告诉我它的发布者、端点和登录方式,等我确认。不要把 API 密钥写进命令或我会提交的文件;问我密钥应从哪里获取。

查看智能体所依据的安装指南

其他 MCP 客户端

把它添加到你客户端的 mcpServers 配置中。

{
  "mcpServers": {
    "book-cover-generator": {
      "type": "http",
      "url": "https://covers.otsirh.dev/mcp"
    }
  }
}

README

Book Cover Generator

[CI] [npm] [Website] [Dependencies] [Types] [OpenSSF Scorecard] [OpenSSF Best Practices] [License: MIT]

Generate book covers from a title and an author. 39 styles, 28 palettes or your own colours, a seeded randomizer, any size, and export to SVG, PNG, JPEG or WebP. The library has no dependencies and ships TypeScript types. It's written as plain ES modules, so it runs in the browser, Node, Deno and Bun.

▶ Open the generator · See every style

[Sample covers]

Features

  • 39 styles in six families.
    • Typographic: Big Type, Minimal, Big Letter, Swiss.
    • Genre: Thriller, Botanical, Noir, Blueprint, Hollow (horror), Ribbon (romance), Crest (fantasy), Storybook (children's), Big Idea (non-fiction).
    • Vintage: Art Deco, Classic Paperback, Engraved, Sunburst, Typewriter.
    • Scenic: Landscape, Retro Sun, Silhouette, Constellation, Orbit, Waves, Aurora, Bookshelf.
    • Geometric: Bauhaus, Split, Blocks, Concentric, Stripes.
    • Pattern: Paper Cut, Halftone, Topographic, Flow Field, Low Poly, Mosaic, Memphis, Pixel.
  • 28 palettes (15 light, 13 dark), or pass your own. Every style adapts to light and dark palettes.
  • Typography that responds to the title. Short titles are set large, a leading "The" (or another article of three letters or more) becomes a small line above the title, and some styles stack the words edge to edge. Long titles wrap with balanced lines and shrink to fit. Author names stay readable at thumbnail size. Accents, emoji, Chinese, Japanese and Thai are handled.
  • Subtitle or tagline, and an optional paper texture.
  • Randomizer. Every random choice comes from a seed, so the same seed always gives the same cover. If you don't pass a seed, it is derived from the title and author.
  • Any size. 2:3 paperback, 5:8 eBook, 1:1 audiobook, or any width × height from 50 to 10,000 px with an aspect ratio between 1:3 and 3:1, such as Kindle's 1600 × 2560 or a print trim size at 300 dpi.
  • Export. Download SVG, PNG, JPEG or WebP. PNG and JPEG files record 300 dpi, so print software sizes them right. Copy the image or the SVG, or share it from a phone.
  • A paperback for print. The whole cover of a printed book, back, spine and front, as the PDF Amazon KDP takes: sized from the trim and the page count, with bleed, the back cover's text, and room for the barcode.

The web app

On covers.otsirh.dev you type a title and author (press Enter in the title to break its line where you want), and if you like a subtitle, a series line ("Book Two of the Ember Cycle"), a credit ("Translated by…") and a badge ("Winner of the Hugo Award", set as a seal in a corner clear of the text). Then you choose:

  • a style, from a rail that previews your book in all 39 styles (its Genre menu shows only those that suit a genre, and Randomize then stays in it). Fifteen styles let you pin a choice the variation otherwise makes, such as Silhouette's city or forest, or where Aurora puts the title;
  • title type: any of the nine fonts instead of the style's, and the title in capitals or as typed. It stays when you change style, so the rail shows every style in your type;
  • a palette, from swatches that show the background, text colour and accents, or Custom for your own five colours (it starts from the palette on the cover and shows the text contrast);
  • a variation, the seed behind the artwork: the strip under the preview shows six others to click;
  • a format: paperback, eBook, square, or Custom for any size in pixels, typed in or picked from common sizes (Kindle, print trim sizes at 300 dpi, audiobook, social posts).

Store size shrinks the preview to the size a store lists covers at, to check the title still reads. Randomize reshuffles everything, except what you've locked. Undo and redo (Z, or Ctrl/Cmd+Z) step back and forth through your designs, and survive a reload; the browser's Back button leaves the site. Copy link shares the exact design, because the URL holds every setting, and Copy embed link gives the HTTP API URL that draws it, to put in any page. The main download is a PNG (a JPEG for an eBook, as KDP takes), and the export panel tells you which size suits Kindle, print or audiobook covers.

Mockup shows and downloads the cover as a 3D book, a flat shot, on an e-reader, or on a social card (a 1200 × 630 link preview, a square post or a story, with a line such as "Out now").

Many covers takes a list of books (one per line as Title | Author | Subtitle, or a CSV with a title column) and makes them all with the design you have, as PNG or SVG in one ZIP. With a fixed variation they share one look, as a series does; switch on "A different palette for each" for a set in several colours.

Paperback for print makes the whole cover of a printed paperback from the design: the back with your headline, back cover text and imprint (and the barcode's box left clear), the spine with the title and author, and the front. Choose the trim size, the page count and the paper, and it sizes everything as Amazon KDP asks: an eighth of an inch of bleed, a spine as wide as the pages are thick (and blank under 80 pages, as KDP requires), the front's art carried into the bleed. Download print PDF saves the file to upload: one page at 300 dpi, its trim marked. The back and spine take any colour of the palette; the settings stay in your browser for next time.

Keep, the star on the preview (or K), saves a design to a tray under the preview, together with the cover as it was drawn, so a later version of the app can't change it. Download all saves every kept design as a PNG in one ZIP file. Export saves the kept designs to a file, and Import adds them in another browser.

The app works offline once it has loaded.

Keyboard shortcuts:

  • R randomizes.
  • ← and → step through styles.
  • [ and ] step through palettes.
  • Z undoes and Shift+Z redoes.

The single-key shortcuts can be turned off under the controls (for example with speech input).

HTTP API

The site draws covers from a URL too, so a page can show one with nothing installed:

html
<img src="https://covers.otsirh.dev/api/cover.svg?title=Dune&author=Frank+Herbert&style=retro" alt="Dune" />
  • GET /api/cover.svg answers with the cover as SVG.
  • GET /api/mockup.svg answers with a mockup of it. Add kind (book, flat, ereader, card, square, story), text for the line on a card, square or story, and background.
  • GET /api/cover.json says what a query draws: the style, palette, colours, seed, size and pins it came to (so a random style or palette can be kept), its link with every choice written out, and its SVG, PNG, edit and share URLs.
  • GET /api/catalog.json lists every style (with its genres and the choices it lets you pin), palette, genre, font, format and mockup; GET /api/openapi.json describes the API as OpenAPI 3.1.
  • GET /api/cover.png and GET /api/mockup.png answer with the same as PNG, for places that don't take SVG (email, chat, social posts): a cover up to 600,000 pixels (600 × 900), a mockup up to 2.1 million (a 1080 × 1920 story; a flat or e-reader shot, whose shadow costs more, 1.3 million). A larger one is drawn smaller to fit; scale (above 0, up to 4) asks for a size, refused if it won't fit. Larger PNGs come from the app, which draws them in your browser. The server draws them with open fonts and lays the text out in their widths; they have Latin, Greek and Cyrillic letters, so a cover in another script (Chinese, Japanese, Arabic…) gets a 422: ask for its SVG.

The query takes the options' own names (title, author, subtitle, series, credit, badge, style, palette, seed, genre, font, lang, width, height) and the app's link parameters, so the part of an app link after # draws the same design (the server measures text with the widths of the fonts as macOS draws them, so on another system a line can break a little differently from the app's preview):

parametervalue
formatpaperback, ebook, square, or a size in px such as 1600x2560
casethe title upper, or normal (as typed)
texture1 (on) or 0 (off)
variantpinned choices as name.value, joined by -: field.pale-emblem.sun
palettea palette id, or your own colours as custom-0b132b-f8f9fa-ff6b6b (background, text, accents)
bg, ink, accentyour own colours, as hex (the # is optional; accents separated by commas)

A title breaks its line at %0A. A design's link from the app (Copy link: https://covers.otsirh.dev/?title=…) shows that design in link previews, as a social card drawn by /api/mockup.png. Anyone may embed the answers (CORS and Cross-Origin-Resource-Policy allow it), and the headers X-Cover-Style, X-Cover-Palette and X-Cover-Version say what was drawn. The same URL always draws the same cover in a version of the library, so answers are cached for a day. Options the library rejects get a 400 with the reason as plain text. Add download=1 to any image to get it as a file named after the title (or download=my-cover to name it).

The API is free to use. PNGs not yet cached are limited to 240 a minute for each client, and MCP requests to 600 (429 with Retry-After beyond that); SVGs aren't limited. If you need more, draw the covers in your own code with the library, or run your own copy: fork the repository, set your account_id and routes (or "workers_dev": true) in wrangler.jsonc, and run npx wrangler deploy.

On any page: <book-cover>

One script, then a cover wherever you write the element:

html
<script type="module" src="https://covers.otsirh.dev/element.js"></script>
<book-cover cover-title="Dune" author="Frank Herbert" cover-style="retro" seed="1"></book-cover>

(/element.js is the same as one minified file; /src/element.js loads the library's modules as they are.)

Its attributes are the app's link parameters, except the title and the style, which are cover-title and cover-style (title and style are HTML's own): cover-title, author, subtitle, series, credit, badge, cover-style, genre, palette, seed, format, font, case, variant, texture (present: on) and lang (the language of the text, such as zh-Hant). Styles, palettes and fonts may be named as the app's menus name them. With loading="lazy", as on an image, a cover draws only once it comes near the viewport (a page of many covers loads faster); until then it holds the cover's shape and is named for screen readers, and attributes changed meanwhile apply when it draws. The cover is 240 px wide unless you style the element's width; it draws again when an attribute changes, and fires cover (with the cover) or cover-error (with what's wrong). It is drawn in the page, measuring the text with the fonts installed there, and shown as an image, so a page with Trusted Types can show it (its CSP must allow data: images). An image can't use the page's web fonts: if the page loads one that a cover's font stack names (such as EB Garamond or Oswald), the text is measured in it but drawn in the system's font, and may fit less well. From npm: import 'book-cover-generator/element'.

From an AI assistant (MCP)

Book Cover Generator is a Model Context Protocol server, so an assistant such as Claude can make covers for you: "a cover for my horror novel The Hollow Night, in red". It answers with a link to the image and one that opens the cover in the app to change and download.

Add it to Claude Code:

sh
claude mcp add book-covers -- npx -y book-cover-generator --mcp# or, with nothing installed, the hosted server:claude mcp add --transport http book-covers https://covers.otsirh.dev/mcp

Or to any client that takes a JSON configuration (Claude Desktop, Cursor and others):

json
{  "mcpServers": {    "book-covers": { "command": "npx", "args": ["-y", "book-cover-generator", "--mcp"] }  }}

The tools: create_cover (a title, and any of author, subtitle, style, genre, palette or your own colours, seed, format, font, pins), create_mockup (the same, as a 3D book, on an e-reader or on a social card), list_styles and list_palettes. Each cover comes with links to its SVG, its PNG and the app; the hosted server also answers with the picture itself, so the assistant can see what it made and your client can show it. Run locally, create_cover can also save the SVG to a file (output, a path ending in .svg).

Library usage

Browser (no install)

html
<script type="module">  import { generateCover } from 'https://cdn.jsdelivr.net/npm/book-cover-generator@1/src/index.js';
  document.body.innerHTML = generateCover({    title: 'The Lighthouse Keeper',    author: 'Mara Ellison',    style: 'artdeco',    palette: 'midnight',  });</script>

@1 gives you the latest 1.x release. Pin an exact version (such as @1.1.0) if you need the artwork to never change.

Node, Deno, Bun and bundlers

sh
npm install book-cover-generator
js
import { createCover } from 'book-cover-generator';import { writeFileSync } from 'node:fs';
const { svg, style, palette, seed } = createCover({  title: 'Neon Tide',  author: 'Kai Moreno',  style: 'random', // or a style id, see `styles`  seed: 42, // same seed, same cover  width: 1600,  height: 2560,});writeFileSync('cover.svg', svg);

In Deno, import npm:book-cover-generator; in Bun, bun add book-cover-generator. CI checks that Node, Deno and Bun draw the same covers byte for byte.

CLI

sh
npx book-cover-generator "The Lighthouse Keeper" "Mara Ellison" --style artdeco -o cover.svgnpx book-cover-generator --list   # all styles and palettes
sh
# your own colours (the # is optional), as an eBook 1600 px widenpx book-cover-generator "Bright Machines" --bg 0b132b --ink f8f9fa --accent ff6b6b,4ecdc4 --format ebook --width 1600 -o cover.svg# any size, and the choices as JSON (with the SVG, when there is no -o)npx book-cover-generator "Neon Tide" --size 1800x2700 --json# a cover for every book in a list (CSV with a header row, JSON lines, or "Title | Author" lines), one look for allnpx book-cover-generator --batch books.csv --style minimal --seed series --out-dir covers# twelve variations to choose from: ideas/cover-1.svg … ideas/cover-12.svg (seeds 1 to 12)npx book-cover-generator "Salt and Static" --count 12 -o ideas/cover.svg# a paperback's whole cover for print (back, spine and front), 6 × 9 in with 320 pages on cream papernpx book-cover-generator "The Lighthouse Keeper" "Mara Ellison" -s artdeco --print 6x9 --pages 320 --paper cream \  --hook "Some lights are kept burning." --blurb-file blurb.txt -o paperback.svg

Options: -s/--style, -p/--palette, --bg, --ink, --accent, --subtitle, --texture, --seed, --format (paperback, ebook or square), --width, --height, --size, --genre, --lang, --series, --credit, --badge, --font, --case upper|normal, --variant name=value (--list shows each style's), -o/--out, --count, --batch <file|->, --out-dir, --print <trim> with --pages, --paper, --hook, --blurb, --blurb-file and --imprint, --json, --list, --help. A print cover is an SVG at 96 px to the inch: the app makes the PDF, or any SVG converter does (rsvg-convert -f pdf).

API

generateCover(options) → string

Returns the SVG markup.

createCover(options) → { svg, body, style, palette, colors, seed, width, height, lang, variants, title, author }

Same as generateCover, but also tells you which style and palette were chosen. This is useful when either one was random. body is the markup inside the outer <svg>, for nesting the cover in a larger SVG (its ids are unique to the cover, so several can share a document).

optiontypedefaultnotes
titlestring'Untitled'a line break (\n) breaks the title's line there
authorstring''optional
subtitlestring''optional subtitle or tagline
seriesstring''a series line above the title
creditstring''a credit under the subtitle ("Translated by…")
badgestring''a seal in a corner clear of the text
texturebooleanfalseadds a fine film grain (any truthy value)
stylestring'random'a style id, see styles
palettestring | object'random'a palette id, or { bg, ink, accents: [...] } (or a link's custom-rrggbb-…)
seedstring | numberthe title and authorcontrols every random choice
widthnumber600 (a height alone: height ÷ 1.5)px, 50–10000; aspect ratio 1:3 to 3:1
heightnumberwidth × 1.5px, 50–10000
langstringinferredlanguage of the text, such as 'ja'
variantsobject{}pin a style's choices: { scene: 'forest' }
genrestringwith a random style, one that suits this genre
fontstringthe style'sthe title's font, one of FONTS
titleCasestringthe style's'upper' (capitals) or 'normal' (as typed)

An ink that reads badly on its bg (under 3:1 contrast) is replaced with black or white, so the text is always readable; the cover's colors say which.

Styles, palettes, genres and fonts may be given by id or by name, in any case: 'artdeco', 'Art Deco' and 'ART DECO' are the same style, and a book list or a link can name them as the app's menus do.

lang is set on the cover so Chinese characters get the right glyphs for the language. Without it, text with kana is marked Japanese and text with Hangul Korean; pass 'zh-Hans', 'zh-Hant' or 'ja' for text in Chinese characters only.

Titles and subtitles longer than 300 characters (authors: 200) are cut. With 'random', the style and palette are picked from the seed, so you get the same result every time for the same seed. Some styles prefer dark or light palettes when they pick one themselves. Invalid options throw an error that says what's wrong.

Other exports

  • styles: array of style ids
  • genres: [{ id, name }], the genres styles suit: literary, thriller, horror, romance, fantasy, children, nonfiction
  • listStyles(): [{ id, name, description, group, variants, genres }]. variants lists the choices a style lets you pin, as [{ name, label, values: [{ value, label }] }]; pin them with createCover({ variants: { scene: 'forest' } }), and createCover reports the ones it used in variants. Names a style lacks are ignored. A value no style offers throws; with a style you name, so does a value that style lacks (a style picked at random takes only the pins it can)
  • palettes: [{ id, name, bg, ink, accents, dark? }]
  • randomSeed(): a short random seed string
  • pickStyle(options): the style id createCover would use for these options (resolving 'random' from the seed), without drawing the cover
  • registerStyle({ id, name, description, group, prefer, render(ctx) }): add your own style (see below). Replacing a built-in style takes registerStyle(style, { replace: true }); unregisterStyle(id) removes a style or brings the built-in back
  • registerPalette({ id, name, bg, ink, accents }): add a palette to use by id, as palette: 'brand' ({ replace: true } for a built-in id); unregisterPalette(id) removes it. Registered styles and palettes can also be picked by 'random', so registering one changes what a seed gives
  • parseBookList(text): a list of books (CSV with commas, semicolons or tabs and a header row naming a title column, JSON lines, or one "Title | Author | Subtitle" per line) as cover options, one per book
  • styleIdFor(name): the id of the style a name or id names, in any case ('Art Deco' → 'artdeco'), or undefined
  • optionsForBook(book, defaults): the options for one of those books over the options every book shares (its own values win; a genre the shared style doesn't suit picks a style that does)
  • noteText(x0, y0, x1, y1) and recordText(draw): note where a custom style writes its own text (so a badge stays clear of it), and collect what draw notes
  • version: the library's version (artwork for a seed can change between minor versions)
  • sizeLimits ({ min: 50, max: 10000, ratio: 3 }) and formats (paperback, ebook and square as [width, height] at 600 px wide): the sizes covers can have, and the app's shapes
  • titleBlock, authorFit: the typography the built-in styles use (a title with its lead line and subtitle, and the author line)
  • fitText, drawText, fitStack, drawStack, splitLead, measureText, setTextMeasurer, FONTS: lower-level text helpers (fitText can hyphenate one long word with hyphenate: px), and baselineOf, textBottom, textGroupAttrs, markExtent for styles that draw text themselves
  • strongAccents, textColor, tintText, fitTitleWith, textPanel, TEXT_CONTRAST: the colour and layout helpers the built-in styles use (accents that stand out, text colours that stay readable, giving up art for a longer title, a panel for title and author)
  • svgUtils: the SVG, colour and noise helpers the built-in styles use

TypeScript

Types are included. CoverOptions, Cover, StyleId, PaletteId, StyleGroup, StyleContext, CoverStyle, TitleBlock and the rest are exported from the main entry point, and style and palette ids autocomplete.

Mockups

js
import { createCover, createMockup } from 'book-cover-generator';
const cover = createCover({ title: 'Neon Tide', author: 'Kai Moreno' });const { svg, width, height } = createMockup(cover, { kind: 'book' }); // or 'flat', 'ereader'const card = createMockup(cover, { kind: 'card', text: 'Out now' }); // 1200 × 630; also 'square', 'story'

Product shots (flat, book, ereader) follow the cover's size on a light backdrop (background to change it); social cards have fixed sizes and take the cover's colours. mockupKinds lists them.

Print: a paperback's whole cover

js
import { createPrintCover } from 'book-cover-generator';import { svgToPdf, downloadBlob } from 'book-cover-generator/browser';
const print = createPrintCover(  { title: 'The Lighthouse Keeper', author: 'Mara Ellison', style: 'artdeco' },  { trim: '6x9', pages: 320, paper: 'cream', hook: 'Some lights are kept burning.', blurb: 'When the lamp…' },);print.inches; // { width: 13.05, height: 9.25, trim: [6, 9], spine: 0.8, bleed: 0.125 }const pdf = await svgToPdf(print.svg, { bleed: print.inches.bleed, title: 'The Lighthouse Keeper' });downloadBlob(pdf, 'paperback.pdf'); // one page at 300 dpi, the file to upload to KDP

createPrintCover(cover, print) lays out the back (the hook, the blurb's paragraphs at the largest size from 12 to 8 pt that fits, an imprint, and the barcode's 2 × 1.2 in box kept clear), the spine (the title and author, from 80 pages and when they'd be readable) and the front (the cover these options draw at the trim's shape, its edges mirrored into the bleed). Sizes follow Amazon KDP: trim by name (trimSizes) or [width, height] in inches, paper (paperTypes: white, cream, color, premium-color), bleed (0.125 in) and pageThickness for another printer's figures, backColor and spineColor (the cover's background and ink by default), and guides to dash the trim, the folds and the barcode's box for a preview. spineWidth(pages, paper) gives the spine alone, pageRange(trim, paper) the page counts a trim takes on a paper, and printLimits what KDP takes. svgToPdf draws a page too large for one canvas in strips.

Export helpers (browser)

js
import { downloadCover, rasterize, copyText, copyImage, zipFiles } from 'book-cover-generator/browser';
await copyText(svg); // copy SVG markupawait copyImage(svg, { scale: 2 }); // copy a PNG (where canCopyImage() is true)await downloadCover(svg, 'svg', 'my-cover'); // my-cover.svgawait downloadCover(svg, 'png', 'my-cover', { scale: 3, dpi: 300 }); // 1800×2700 PNG that prints at 6 × 9 inawait downloadCover(svg, 'jpeg', 'my-cover', { width: 1600, quality: 0.9 }); // exactly 1600 px wideconst name = await downloadCover(svg, 'webp', 'my-cover'); // 'my-cover.png' where WebP can't be madeconst blob = await rasterize(svg, { type: 'image/webp', width: 1600, height: 2560 });const zip = await zipFiles([  { name: 'cover.png', data: blob },  { name: 'cover.svg', data: svg },]);

setDpi(blob, dpi) records the pixel density in a PNG or JPEG you made yourself. It and zipFiles also work in Node.

Custom palette

js
generateCover({  title: 'Bright Machines',  palette: { bg: '#0b132b', ink: '#f8f9fa', accents: ['#ff6b6b', '#4ecdc4', '#ffe66d'] },});

Custom style

render(ctx) returns SVG markup without the outer <svg> element. ctx contains:

  • title, author, subtitle (may be empty; a credit follows the subtitle on a line of its own), series (set by titleBlock above the title)
  • W, H: the size of the cover
  • u: a scale unit (1 at a short side of 600px)
  • m: the suggested margin
  • S: the short side; base text sizes on it so wide covers work
  • rng: seeded random with next, float, int, bool, pick, shuffle
  • p: the palette, with bg, ink, accents, plus paper (lighter) and night (darker)
  • id(name): makes ids that are unique per cover, for gradients and filters
  • titleFont, titleCase: the cover's font and titleCase, or null; titleBlock follows them, so a style that sets its title with it gets them for free
  • Text drawn with drawText, drawStack or titleBlock is noted, so a badge stays clear of it; a style that writes its own text elements can call noteText(x0, y0, x1, y1)
  • choose(name, values): picks one of values as rng.pick would, unless the cover pins the variant name. Declare what can be pinned in the style's variants: { mood: { label: 'Mood', values: { calm: 'Calm', loud: 'Loud' } } }
js
import { registerStyle, titleBlock, authorFit, drawText, FONTS } from 'book-cover-generator';
registerStyle({  id: 'plain',  name: 'Plain',  group: 'Typographic',  render(c) {    const title = titleBlock(c, {      font: FONTS.serif,      maxWidth: c.W - c.m * 2,      maxHeight: c.H * 0.5,      maxSize: c.S * 0.2,    });    const author = authorFit(c);    return (      `<rect width="${c.W}" height="${c.H}" fill="${c.p.bg}"/>` +      title.draw({ x: c.m, y: c.m, fill: c.p.ink }) +      drawText(author, { x: c.m, y: c.H - c.m - author.height, fill: c.p.ink })    );  },});

Notes

  • Fonts. Covers only use system font stacks (Georgia, Helvetica, Futura, Didot, Impact, Courier and others), each with close matches on Windows, Android and Linux. This is because an SVG drawn into a canvas for PNG/JPEG export can't load web fonts. In the browser, text is measured with a canvas, so it fits exactly. In Node (and the CLI and HTTP API), the built-in fonts are measured from their characters' widths as macOS draws them, so text fits much as it does in the app; fonts of your own are estimated. Plug in a real font engine with setTextMeasurer if you need exact fits there.
  • Deterministic. The same options always give the same artwork. In Node the SVG is identical every time. In the browser, text is measured with the fonts installed on that computer, so line breaks can differ slightly between machines. Registering a custom style changes which style style: 'random' picks for a given seed.
  • Versioning. Artwork for a given seed can change in minor releases (a style gets better). Pin an exact version if you need byte-identical covers forever.
  • Browser support. Current Chrome, Edge, Firefox and Safari. Every release is tested in Chromium, Firefox and WebKit, including PNG and JPEG export.

Development

sh
npm ci                     # install dev tooling (the library itself has no dependencies)npx playwright install     # browsers for the end-to-end testsnpm run dev                # http://127.0.0.1:4173
scriptwhat it does
npm run checklint, format, type and package checks, unit tests and fuzzing
npm testunit tests (node --test)
npm run test:coverageunit tests with coverage thresholds
npm run test:fuzzproperty-based fuzzing (fast-check); FUZZ_RUNS=20 for more
npm run test:e2ebrowser tests in Chromium, Firefox, WebKit and mobile Chrome
npm run formatformat everything with Prettier
npm run assetsregenerate the app icons, the social preview and the README image
npm run deployrun every check, then build and deploy to Cloudflare (wrangler)

Open examples/contact-sheet.html?palettes=noir,mint&seeds=a,b on the dev server to see many covers at once (also styles, titles, subtitle, w, h, cols and texture=1).

Project layout

src/            the library (plain ES modules + .d.ts types)  styles/       the 39 styles, in a file per familybin/            the CLIsite/           the web app (index.html is at the root)public/         files served at the site root: headers, 404, icons, manifest, service workertest/           unit tests (node --test)test-d/         type tests (tsc)e2e/            browser tests (Playwright)scripts/        build, dev server and asset generationworker/         the HTTP API (the site's Worker)

The site is a Cloudflare Workers deployment configured in wrangler.jsonc: static assets, with security headers in public/_headers, and a Worker (worker/index.js) that answers /api/*, /mcp and a design's link (/?title=…). The dev server answers them the same way.

Contributing

Contributions are welcome. See CONTRIBUTING.md, and report security issues as described in SECURITY.md. Questions, ideas and covers you've made go in Discussions.

License

MIT

来源:README.md,提交 bd83a89

工具

4

create_cover

Create a book cover

Draw a book cover. Answers with the picture, links to the image (SVG and PNG) and to edit it in the app, and the style, palette and seed it used.

输入参数svgcasefontlangseedbadgegenrestyletitle必填authorcolorscredit另有 6 个

create_mockup

Create a mockup of a cover

Draw a cover as a product shot (a 3D book, flat, on an e-reader) or on a social card with a line of text. Answers with the picture and its links.

输入参数svgcasefontkindlangseedtextbadgegenrestyletitle必填author另有 8 个

list_styles

List the cover styles

The styles, with their genres and the choices each lets you pin.

输入参数genre

list_palettes

List the colour palettes

The palettes, light and dark, with their colours.

无需输入参数。

版本历史

1
  1. v1.13.0最新Nov 14, 2026

评分

已满足适用检查项的 100%

该评分衡量此收录条目的完整程度,依据注册中心条目、端点与公开来源计算得出。它不是对服务器本身的评价,也不表示服务器安全或当前可用:可连通性是带日期的检查结果,评分也不包含安装量或用户评价。

  • 近 30 天内可连通必需25 分
  • 已声明认证方式必需10 分
  • 已列出工具必需15 分
  • 描述必需15 分
  • 图标10 分
  • 文档15 分
  • 许可证10 分