book-cover-generator 1.9.0 → 1.9.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +19 -19
- package/package.json +1 -1
- package/src/browser.d.ts +21 -0
- package/src/core.d.ts +69 -0
- package/src/element-types.d.ts +41 -0
- package/src/element.d.ts +4 -15
- package/src/element.js +1 -1
- package/src/index.d.ts +73 -3
- package/src/index.js +2 -2
- package/src/palettes.d.ts +5 -0
- package/src/text.d.ts +48 -2
- package/src/type.d.ts +37 -1
package/README.md
CHANGED
|
@@ -191,25 +191,25 @@ Returns the SVG markup.
|
|
|
191
191
|
|
|
192
192
|
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).
|
|
193
193
|
|
|
194
|
-
| option | type | default
|
|
195
|
-
| ----------- | ------------------ |
|
|
196
|
-
| `title` | `string` | `'Untitled'`
|
|
197
|
-
| `author` | `string` | `''`
|
|
198
|
-
| `subtitle` | `string` | `''`
|
|
199
|
-
| `series` | `string` | `''`
|
|
200
|
-
| `credit` | `string` | `''`
|
|
201
|
-
| `badge` | `string` | `''`
|
|
202
|
-
| `texture` | `boolean` | `false`
|
|
203
|
-
| `style` | `string` | `'random'`
|
|
204
|
-
| `palette` | `string \| object` | `'random'`
|
|
205
|
-
| `seed` | `string \| number` |
|
|
206
|
-
| `width` | `number` | `600`
|
|
207
|
-
| `height` | `number` | `width × 1.5`
|
|
208
|
-
| `lang` | `string` | inferred
|
|
209
|
-
| `variants` | `object` | `{}`
|
|
210
|
-
| `genre` | `string` |
|
|
211
|
-
| `font` | `string` | the style's
|
|
212
|
-
| `titleCase` | `string` | the style's
|
|
194
|
+
| option | type | default | notes |
|
|
195
|
+
| ----------- | ------------------ | -------------------- | ------------------------------------------------- |
|
|
196
|
+
| `title` | `string` | `'Untitled'` | a line break (`\n`) breaks the title's line there |
|
|
197
|
+
| `author` | `string` | `''` | optional |
|
|
198
|
+
| `subtitle` | `string` | `''` | optional subtitle or tagline |
|
|
199
|
+
| `series` | `string` | `''` | a series line above the title |
|
|
200
|
+
| `credit` | `string` | `''` | a credit under the subtitle ("Translated by…") |
|
|
201
|
+
| `badge` | `string` | `''` | a seal in a corner clear of the text |
|
|
202
|
+
| `texture` | `boolean` | `false` | adds a fine film grain (any truthy value) |
|
|
203
|
+
| `style` | `string` | `'random'` | a style id, see `styles` |
|
|
204
|
+
| `palette` | `string \| object` | `'random'` | a palette id, or `{ bg, ink, accents: [...] }` |
|
|
205
|
+
| `seed` | `string \| number` | the title and author | controls every random choice |
|
|
206
|
+
| `width` | `number` | `600` | px, 50–10000; aspect ratio 1:3 to 3:1 |
|
|
207
|
+
| `height` | `number` | `width × 1.5` | px, 50–10000 |
|
|
208
|
+
| `lang` | `string` | inferred | language of the text, such as `'ja'` |
|
|
209
|
+
| `variants` | `object` | `{}` | pin a style's choices: `{ scene: 'forest' }` |
|
|
210
|
+
| `genre` | `string` | | with a random style, one that suits this genre |
|
|
211
|
+
| `font` | `string` | the style's | the title's font, one of `FONTS` |
|
|
212
|
+
| `titleCase` | `string` | the style's | `'upper'` (capitals) or `'normal'` (as typed) |
|
|
213
213
|
|
|
214
214
|
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.
|
|
215
215
|
|
package/package.json
CHANGED
package/src/browser.d.ts
CHANGED
|
@@ -1,7 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Browser helpers to export a cover: rasterise it to PNG, JPEG or WebP, download it, copy it to the
|
|
3
|
+
* clipboard, or zip several files. `setDpi` and `zipFiles` also work in Node.
|
|
4
|
+
*
|
|
5
|
+
* ```js
|
|
6
|
+
* import { createCover } from '@otsirh/book-cover-generator';
|
|
7
|
+
* import { downloadCover, rasterize } from '@otsirh/book-cover-generator/browser';
|
|
8
|
+
*
|
|
9
|
+
* const { svg } = createCover({ title: 'Dune', author: 'Frank Herbert' });
|
|
10
|
+
* await downloadCover(svg, 'png', 'dune', { scale: 3, dpi: 300 }); // dune.png, 1800 × 2700 px
|
|
11
|
+
* const blob = await rasterize(svg, { type: 'image/webp', width: 1600 }); // 1600 × 2400 px
|
|
12
|
+
* ```
|
|
13
|
+
*
|
|
14
|
+
* @module
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
/** SVG markup as a `data:` URL, for an `<img>`'s `src`. */
|
|
1
18
|
export declare function svgToDataUrl(svg: string): string;
|
|
19
|
+
/** SVG markup as a Blob of type `image/svg+xml;charset=utf-8`. */
|
|
2
20
|
export declare function svgToBlob(svg: string): Blob;
|
|
3
21
|
|
|
22
|
+
/** Options for `rasterize`. */
|
|
4
23
|
export interface RasterizeOptions {
|
|
24
|
+
/** The image's type. Default `'image/png'`; a browser that can't encode it makes a PNG. */
|
|
5
25
|
type?: 'image/png' | 'image/jpeg' | 'image/webp';
|
|
6
26
|
/** Multiplier applied to the SVG's width and height. Default 1. Ignored when `width` or `height` is given. */
|
|
7
27
|
scale?: number;
|
|
@@ -22,6 +42,7 @@ export declare function rasterize(svg: string, opts?: RasterizeOptions): Promise
|
|
|
22
42
|
/** Trigger a file download for a Blob. */
|
|
23
43
|
export declare function downloadBlob(blob: Blob, filename: string): void;
|
|
24
44
|
|
|
45
|
+
/** The formats `downloadCover` makes: the SVG itself, or a PNG, JPEG (`'jpeg'` or `'jpg'`) or WebP image. */
|
|
25
46
|
export type ExportFormat = 'svg' | 'png' | 'jpeg' | 'jpg' | 'webp';
|
|
26
47
|
/**
|
|
27
48
|
* Download a cover; `basename` gets the right extension appended. Resolves to the file name,
|
package/src/core.d.ts
CHANGED
|
@@ -1,3 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The SVG, colour and noise helpers the built-in styles use, exported as `svgUtils`.
|
|
3
|
+
*
|
|
4
|
+
* @module
|
|
5
|
+
*/
|
|
6
|
+
|
|
1
7
|
/** Seeded pseudo-random number generator. */
|
|
2
8
|
export interface Rng {
|
|
3
9
|
/** Next float in `[0, 1)`. */
|
|
@@ -8,20 +14,32 @@ export interface Rng {
|
|
|
8
14
|
int(min: number, max: number): number;
|
|
9
15
|
/** `true` with probability `p`. */
|
|
10
16
|
bool(p?: number): boolean;
|
|
17
|
+
/** One of `arr`'s items, at random (undefined for an empty array). */
|
|
11
18
|
pick<T>(arr: readonly T[]): T;
|
|
12
19
|
/** A shuffled copy. */
|
|
13
20
|
shuffle<T>(arr: readonly T[]): T[];
|
|
14
21
|
}
|
|
15
22
|
|
|
23
|
+
/** A 32-bit hash of `String(input)` (cyrb53, folded to 32 bits), as an unsigned integer. */
|
|
16
24
|
export declare function hashString(input: unknown): number;
|
|
25
|
+
/**
|
|
26
|
+
* A seeded random number generator (mulberry32). The seed is hashed as a string, so the same seed
|
|
27
|
+
* (42 or '42') always gives the same numbers.
|
|
28
|
+
*/
|
|
17
29
|
export declare function createRng(seed: unknown): Rng;
|
|
18
30
|
|
|
31
|
+
/** `v` kept within `lo`–`hi`. */
|
|
19
32
|
export declare function clamp(v: number, lo: number, hi: number): number;
|
|
33
|
+
/** Linear interpolation: `a` at `t = 0`, `b` at `t = 1` (`t` isn't clamped). */
|
|
20
34
|
export declare function lerp(a: number, b: number, t: number): number;
|
|
35
|
+
/** 0 at `e0` and below, 1 at `e1` and above, and a smooth S-curve in between. */
|
|
21
36
|
export declare function smoothstep(e0: number, e1: number, x: number): number;
|
|
22
37
|
|
|
38
|
+
/** Whether `v` is a hex colour string, `#rgb` or `#rrggbb` in any case (spaces at either end allowed). */
|
|
23
39
|
export declare function isHex(v: unknown): boolean;
|
|
40
|
+
/** A hex colour (`#rgb` or `#rrggbb`) as `[r, g, b]`, each 0–255. It isn't checked: see `isHex`. */
|
|
24
41
|
export declare function hexToRgb(hex: string): [number, number, number];
|
|
42
|
+
/** `[r, g, b]` as `#rrggbb`; each channel is rounded and clamped to 0–255. */
|
|
25
43
|
export declare function rgbToHex(rgb: readonly number[]): string;
|
|
26
44
|
/** Linear blend of two hex colours; `t = 0` is `a`, `t = 1` is `b`. */
|
|
27
45
|
export declare function mix(a: string, b: string, t: number): string;
|
|
@@ -36,19 +54,42 @@ export declare function inkCandidates(p: { readonly ink: string; readonly bg: st
|
|
|
36
54
|
/** Best text colour on `bg`: the palette's ink or background, or white / near-black. */
|
|
37
55
|
export declare function inkOn(bg: string, p: { readonly ink: string; readonly bg: string }): string;
|
|
38
56
|
|
|
57
|
+
/** A 2D noise function: a value between -1 and 1 for each point. */
|
|
39
58
|
export type Noise2D = (x: number, y: number) => number;
|
|
59
|
+
/** Smooth 2D value noise from `rng`: values between -1 and 1, changing over about one unit. */
|
|
40
60
|
export declare function makeNoise2D(rng: Rng): Noise2D;
|
|
61
|
+
/**
|
|
62
|
+
* Fractal noise at (x, y): `octaves` layers of `noise` (default 4), each at twice the frequency and
|
|
63
|
+
* half the weight of the one before, averaged by weight so it stays in the range of `noise`.
|
|
64
|
+
*/
|
|
41
65
|
export declare function fbm(noise: Noise2D, x: number, y: number, octaves?: number): number;
|
|
42
66
|
/** Midpoint-displacement ridge line with values in `[-1, 1]`. */
|
|
43
67
|
export declare function ridge(rng: Rng, segments?: number, roughness?: number): number[];
|
|
44
68
|
|
|
45
69
|
/** Round to one decimal place. */
|
|
46
70
|
export declare function n(v: number): number;
|
|
71
|
+
/**
|
|
72
|
+
* `String(str)` without the characters XML 1.0 forbids: control characters other than tab, LF and
|
|
73
|
+
* CR, U+FFFE, U+FFFF and lone surrogates.
|
|
74
|
+
*/
|
|
47
75
|
export declare function stripInvalidXml(str: unknown): string;
|
|
76
|
+
/**
|
|
77
|
+
* `String(str)` made safe for SVG text and attribute values: the characters XML forbids dropped, and
|
|
78
|
+
* `& < > " '` escaped.
|
|
79
|
+
*/
|
|
48
80
|
export declare function escapeXml(str: unknown): string;
|
|
49
81
|
|
|
82
|
+
/** A `<rect>`. Numbers are rounded to one decimal; `fill` and `extra` (raw attributes) are written as given. */
|
|
50
83
|
export declare function rect(x: number, y: number, w: number, h: number, fill: string, extra?: string): string;
|
|
84
|
+
/**
|
|
85
|
+
* A `<circle>` (a negative radius is drawn as 0). Numbers are rounded to one decimal; `fill` and
|
|
86
|
+
* `extra` are written as given.
|
|
87
|
+
*/
|
|
51
88
|
export declare function circle(cx: number, cy: number, r: number, fill: string, extra?: string): string;
|
|
89
|
+
/**
|
|
90
|
+
* A `<line>` with a stroke `width` px wide. Numbers are rounded to one decimal; `stroke` and
|
|
91
|
+
* `extra` are written as given.
|
|
92
|
+
*/
|
|
52
93
|
export declare function line(
|
|
53
94
|
x1: number,
|
|
54
95
|
y1: number,
|
|
@@ -60,39 +101,67 @@ export declare function line(
|
|
|
60
101
|
): string;
|
|
61
102
|
/** `[[x, y], ...]` to a path `d` string. */
|
|
62
103
|
export declare function pathD(points: ReadonlyArray<readonly number[]>, close?: boolean): string;
|
|
104
|
+
/** A `<path>`; `d`, `fill` and `extra` (raw attributes) are written as given. */
|
|
63
105
|
export declare function path(d: string, fill: string, extra?: string): string;
|
|
64
106
|
/** Path for a quarter disc filling the square (x, y, size), centred on its bottom-left corner. */
|
|
65
107
|
export declare function quarterDisc(x: number, y: number, size: number): string;
|
|
66
108
|
/** Path for a half disc standing on the bottom edge of the square (x, y, size). */
|
|
67
109
|
export declare function halfDisc(x: number, y: number, size: number): string;
|
|
68
110
|
|
|
111
|
+
/** Options for `grain`. */
|
|
69
112
|
export interface GrainOptions {
|
|
113
|
+
/** The layer's opacity, 0–1. Default 0.12. */
|
|
70
114
|
opacity?: number;
|
|
115
|
+
/** White specks instead of black. Default `false`. */
|
|
71
116
|
light?: boolean;
|
|
117
|
+
/**
|
|
118
|
+
* The noise's base frequency for a short side of 600 px (it is divided by `u`, so the grain
|
|
119
|
+
* scales with the cover). Default 0.75.
|
|
120
|
+
*/
|
|
72
121
|
freq?: number;
|
|
73
122
|
/** Filter id suffix, when a cover needs more than one grain filter. Default `'grain'`. */
|
|
74
123
|
id?: string;
|
|
75
124
|
/** Noise seed, so two grain layers don't line up. Default 0. */
|
|
76
125
|
seed?: number;
|
|
77
126
|
}
|
|
127
|
+
/**
|
|
128
|
+
* A film-grain overlay: a `<filter>` for the cover's `<defs>` (`defs`), and a rectangle the size
|
|
129
|
+
* of the cover drawn with it (`layer`). `c` is the style's context.
|
|
130
|
+
*/
|
|
78
131
|
export declare function grain(
|
|
79
132
|
c: { id(name: string): string; readonly u: number; readonly W: number; readonly H: number },
|
|
80
133
|
opts?: GrainOptions,
|
|
81
134
|
): { defs: string; layer: string };
|
|
135
|
+
/**
|
|
136
|
+
* A soft drop-shadow `<filter>` with this id: the shape over its shadow, blurred by `blur` (a
|
|
137
|
+
* standard deviation) and moved down by `dy`, both times `u`, at `opacity` (defaults 4, 2 and 0.35).
|
|
138
|
+
*/
|
|
82
139
|
export declare function shadowFilter(
|
|
83
140
|
id: string,
|
|
84
141
|
u: number,
|
|
85
142
|
opts?: { blur?: number; dy?: number; opacity?: number },
|
|
86
143
|
): string;
|
|
144
|
+
/**
|
|
145
|
+
* A Gaussian-blur `<filter>` with this id and standard deviation `std` (px), with room around the
|
|
146
|
+
* shape for the blur.
|
|
147
|
+
*/
|
|
87
148
|
export declare function blurFilter(id: string, std: number): string;
|
|
88
149
|
|
|
89
150
|
/** `[offset 0–1, colour, opacity?]` */
|
|
90
151
|
export type GradientStop = readonly [offset: number, color: string, opacity?: number];
|
|
152
|
+
/**
|
|
153
|
+
* A `<linearGradient>` with this id. The vector is in fractions of the shape's box: top to bottom
|
|
154
|
+
* by default (`x1` 0, `y1` 0, `x2` 0, `y2` 1).
|
|
155
|
+
*/
|
|
91
156
|
export declare function linearGradient(
|
|
92
157
|
id: string,
|
|
93
158
|
stops: readonly GradientStop[],
|
|
94
159
|
vector?: { x1?: number; y1?: number; x2?: number; y2?: number },
|
|
95
160
|
): string;
|
|
161
|
+
/**
|
|
162
|
+
* A `<radialGradient>` with this id: centre (`cx`, `cy`) and radius `r` in fractions of the
|
|
163
|
+
* shape's box (0.5 each by default), and the focal point (`fx`, `fy`) if given.
|
|
164
|
+
*/
|
|
96
165
|
export declare function radialGradient(
|
|
97
166
|
id: string,
|
|
98
167
|
stops: readonly GradientStop[],
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `<book-cover>`: a cover on any page, drawn from the element's attributes. Importing this module
|
|
3
|
+
* defines the element (outside a browser, such as in Node, it loads and defines nothing). See
|
|
4
|
+
* `BookCover` for its attributes and events.
|
|
5
|
+
*
|
|
6
|
+
* ```html
|
|
7
|
+
* <script type="module" src="https://covers.otsirh.dev/src/element.js"></script>
|
|
8
|
+
*
|
|
9
|
+
* <book-cover cover-title="Dune" author="Frank Herbert" cover-style="retro"></book-cover>
|
|
10
|
+
* <!-- drawn once it comes near the viewport, as a lazy image is -->
|
|
11
|
+
* <book-cover cover-title="Emma" author="Jane Austen" loading="lazy"></book-cover>
|
|
12
|
+
* ```
|
|
13
|
+
*
|
|
14
|
+
* ```js
|
|
15
|
+
* // Or from a module (Deno, or a bundler):
|
|
16
|
+
* import '@otsirh/book-cover-generator/element';
|
|
17
|
+
* ```
|
|
18
|
+
*
|
|
19
|
+
* @module
|
|
20
|
+
*/
|
|
21
|
+
|
|
22
|
+
import type { CoverOptions, createCover } from './index.js';
|
|
23
|
+
|
|
24
|
+
// (The class alone: Deno and JSR use these types, as a package there may not declare global ones.
|
|
25
|
+
// element.d.ts adds the tag to `document.createElement`'s types for TypeScript from npm.)
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* `<book-cover>`: a cover on any page, from its attributes (cover-title, author, subtitle, series,
|
|
29
|
+
* credit, badge, cover-style, genre, palette, seed, format, font, case, texture, variant, lang). It
|
|
30
|
+
* fires `cover` (detail: the cover) when it draws, and `cover-error` (detail: the error) when the
|
|
31
|
+
* attributes can't make one. With `loading="lazy"` it draws once it comes near the viewport, as an
|
|
32
|
+
* image does; until then it holds the cover's shape and is named for screen readers.
|
|
33
|
+
*/
|
|
34
|
+
export declare class BookCover extends HTMLElement {
|
|
35
|
+
/** The attributes it watches: those that make the cover, and `loading`. */
|
|
36
|
+
static observedAttributes: string[];
|
|
37
|
+
/** The cover drawn last, or null (before the first, or after an error). */
|
|
38
|
+
cover: ReturnType<typeof createCover> | null;
|
|
39
|
+
/** The cover's options, read from the attributes as the HTTP API reads a link. */
|
|
40
|
+
options(): CoverOptions;
|
|
41
|
+
}
|
package/src/element.d.ts
CHANGED
|
@@ -1,19 +1,8 @@
|
|
|
1
|
-
|
|
1
|
+
// The types of book-cover-generator/element from npm: the class, and the tag in
|
|
2
|
+
// `document.createElement('book-cover')`'s types.
|
|
3
|
+
import { BookCover } from './element-types.js';
|
|
2
4
|
|
|
3
|
-
|
|
4
|
-
* `<book-cover>`: a cover on any page, from its attributes (cover-title, author, subtitle, series,
|
|
5
|
-
* credit, badge, cover-style, genre, palette, seed, format, font, case, texture, variant, lang). It
|
|
6
|
-
* fires `cover` (detail: the cover) when it draws, and `cover-error` (detail: the error) when the
|
|
7
|
-
* attributes can't make one. With `loading="lazy"` it draws once it comes near the viewport, as an
|
|
8
|
-
* image does; until then it holds the cover's shape and is named for screen readers.
|
|
9
|
-
*/
|
|
10
|
-
export declare class BookCover extends HTMLElement {
|
|
11
|
-
static observedAttributes: string[];
|
|
12
|
-
/** The cover drawn last, or null (before the first, or after an error). */
|
|
13
|
-
cover: ReturnType<typeof createCover> | null;
|
|
14
|
-
/** The cover's options, read from the attributes as the HTTP API reads a link. */
|
|
15
|
-
options(): CoverOptions;
|
|
16
|
-
}
|
|
5
|
+
export { BookCover };
|
|
17
6
|
|
|
18
7
|
declare global {
|
|
19
8
|
interface HTMLElementTagNameMap {
|
package/src/element.js
CHANGED
package/src/index.d.ts
CHANGED
|
@@ -1,3 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Draw book covers as SVG from a title and an author. Every random choice (the style, the palette,
|
|
3
|
+
* the artwork) comes from a seed, by default the title and author, so the same options give the
|
|
4
|
+
* same cover.
|
|
5
|
+
*
|
|
6
|
+
* ```js
|
|
7
|
+
* import { createCover } from '@otsirh/book-cover-generator';
|
|
8
|
+
*
|
|
9
|
+
* const { svg, style, palette } = createCover({
|
|
10
|
+
* title: 'Dune',
|
|
11
|
+
* author: 'Frank Herbert',
|
|
12
|
+
* style: 'retro', // or 'random' (the default): picked from the seed
|
|
13
|
+
* seed: 42,
|
|
14
|
+
* });
|
|
15
|
+
* ```
|
|
16
|
+
*
|
|
17
|
+
* `generateCover` returns the SVG alone, and `createMockup` shows a cover as a book or on a social
|
|
18
|
+
* card. To make a PNG, JPEG or WebP in a browser, see the `./browser` entry point; for a cover from
|
|
19
|
+
* an HTML element, `./element`. `registerStyle` adds a style of your own, drawn with the same text and
|
|
20
|
+
* colour helpers the built-in styles use.
|
|
21
|
+
*
|
|
22
|
+
* (On npm the package is `book-cover-generator`: `import { createCover } from 'book-cover-generator'`.)
|
|
23
|
+
*
|
|
24
|
+
* @module
|
|
25
|
+
*/
|
|
26
|
+
|
|
1
27
|
import type { Rng } from './core.js';
|
|
2
28
|
import type { Palette, PaletteId } from './palettes.js';
|
|
3
29
|
import type { FontSpec, FONTS } from './text.js';
|
|
@@ -22,11 +48,14 @@ export {
|
|
|
22
48
|
} from './text.js';
|
|
23
49
|
export { titleBlock, authorFit, fitStack, drawStack, splitLead } from './type.js';
|
|
24
50
|
export { strongAccents, textColor, tintText, fitTitleWith, textPanel, TEXT_CONTRAST } from './styles/util.js';
|
|
51
|
+
/** The SVG, colour and noise helpers the built-in styles use. */
|
|
25
52
|
export * as svgUtils from './core.js';
|
|
26
53
|
|
|
54
|
+
/** A kind of mockup: a product shot (`flat`, `book`, `ereader`) or a social card (`card`, `square`, `story`). */
|
|
27
55
|
export type MockupKind = 'flat' | 'book' | 'ereader' | 'card' | 'square' | 'story';
|
|
28
56
|
/** The kinds of mockup `createMockup` makes. */
|
|
29
57
|
export declare const mockupKinds: readonly MockupKind[];
|
|
58
|
+
/** Options for `createMockup`. */
|
|
30
59
|
export interface MockupOptions {
|
|
31
60
|
/** Default `'book'`. `card` is 1200 × 630, `square` 1080 × 1080, `story` 1080 × 1920; the others follow the cover's size. */
|
|
32
61
|
kind?: MockupKind;
|
|
@@ -68,6 +97,7 @@ export declare const formats: Readonly<{
|
|
|
68
97
|
square: readonly [number, number];
|
|
69
98
|
}>;
|
|
70
99
|
|
|
100
|
+
/** The ids of the built-in styles. */
|
|
71
101
|
export type StyleId =
|
|
72
102
|
| 'minimal'
|
|
73
103
|
| 'swiss'
|
|
@@ -109,18 +139,29 @@ export type StyleId =
|
|
|
109
139
|
| 'storybook'
|
|
110
140
|
| 'idea';
|
|
111
141
|
|
|
142
|
+
/** The families the built-in styles belong to. */
|
|
112
143
|
export type StyleGroup = 'Typographic' | 'Geometric' | 'Pattern' | 'Scenic' | 'Vintage' | 'Genre';
|
|
113
144
|
|
|
114
145
|
/** A palette you define yourself. All colours must be hex (`#rgb` or `#rrggbb`). */
|
|
115
146
|
export interface CustomPalette {
|
|
147
|
+
/** The background. */
|
|
116
148
|
bg: string;
|
|
149
|
+
/** The text colour. */
|
|
117
150
|
ink: string;
|
|
151
|
+
/** One or more accents; a cover repeats them to make three if there are fewer. */
|
|
118
152
|
accents: readonly string[];
|
|
153
|
+
/** Its id: what the cover reports as its `palette` (default `'custom'`). `registerPalette` needs one. */
|
|
119
154
|
id?: string;
|
|
155
|
+
/** Its name as people read it. Default `'Custom'`, or for `registerPalette` its id. */
|
|
120
156
|
name?: string;
|
|
157
|
+
/** Whether the background is dark. Default: whether `bg` is darker than `ink`. */
|
|
121
158
|
dark?: boolean;
|
|
122
159
|
}
|
|
123
160
|
|
|
161
|
+
/**
|
|
162
|
+
* Options for `createCover` and `generateCover`, all optional. An option that isn't valid throws
|
|
163
|
+
* an error that says why (`texture` excepted: any truthy value turns it on).
|
|
164
|
+
*/
|
|
124
165
|
export interface CoverOptions {
|
|
125
166
|
/** Defaults to `'Untitled'`. Up to 300 characters are used. */
|
|
126
167
|
title?: string;
|
|
@@ -134,7 +175,7 @@ export interface CoverOptions {
|
|
|
134
175
|
credit?: string;
|
|
135
176
|
/** A seal set in a corner clear of the text, such as `'Winner of the Hugo Award'`. Up to 60 characters. */
|
|
136
177
|
badge?: string;
|
|
137
|
-
/** Add a fine film-grain texture over the cover. Default `false
|
|
178
|
+
/** Add a fine film-grain texture over the cover. Default `false`; any truthy value (even `'false'`) turns it on. */
|
|
138
179
|
texture?: boolean;
|
|
139
180
|
/** A style id, a registered custom style, or `'random'` (default; picked from the seed). */
|
|
140
181
|
style?: StyleId | 'random' | (string & {});
|
|
@@ -142,7 +183,7 @@ export interface CoverOptions {
|
|
|
142
183
|
genre?: GenreId | (string & {});
|
|
143
184
|
/** A palette id, a custom palette, or `'random'` / `'auto'` (default; picked from the seed). */
|
|
144
185
|
palette?: PaletteId | 'random' | 'auto' | CustomPalette | (string & {});
|
|
145
|
-
/** Controls every random choice. Defaults to
|
|
186
|
+
/** Controls every random choice. Defaults to the title and author (`Cover.seed` says which seed was used). */
|
|
146
187
|
seed?: string | number;
|
|
147
188
|
/** Width in px, 50–10000. Default 600. */
|
|
148
189
|
width?: number;
|
|
@@ -169,7 +210,9 @@ export interface CoverOptions {
|
|
|
169
210
|
titleCase?: 'upper' | 'normal';
|
|
170
211
|
}
|
|
171
212
|
|
|
213
|
+
/** A cover made by `createCover`: its SVG, and the choices it was made with. */
|
|
172
214
|
export interface Cover {
|
|
215
|
+
/** The SVG document, `width` × `height` px, named for screen readers by its title, author and other text. */
|
|
173
216
|
svg: string;
|
|
174
217
|
/** The markup inside the outer `<svg>`, to nest the cover in another SVG (its ids are unique to the cover). */
|
|
175
218
|
body: string;
|
|
@@ -179,28 +222,42 @@ export interface Cover {
|
|
|
179
222
|
palette: string;
|
|
180
223
|
/** The palette's colours, as the cover used them. */
|
|
181
224
|
colors: { bg: string; ink: string; accents: string[]; dark: boolean };
|
|
225
|
+
/**
|
|
226
|
+
* The seed the cover was drawn from: the `seed` option as a string, else one made from the title
|
|
227
|
+
* and author. The same options with this seed give the same cover.
|
|
228
|
+
*/
|
|
182
229
|
seed: string;
|
|
230
|
+
/** Width in px. */
|
|
183
231
|
width: number;
|
|
232
|
+
/** Height in px. */
|
|
184
233
|
height: number;
|
|
185
234
|
/** The language set on the cover (given or inferred), or `''`. */
|
|
186
235
|
lang: string;
|
|
187
236
|
/** The value of each of the style's variants this cover has, pinned or picked by the seed. */
|
|
188
237
|
variants: Record<string, string>;
|
|
189
|
-
/** The title as set (line breaks as "\n"
|
|
238
|
+
/** The title as set, after cleaning (line breaks as "\n"; `'Untitled'` when there is none). */
|
|
190
239
|
title: string;
|
|
240
|
+
/** The author after cleaning, or `''`. */
|
|
191
241
|
author: string;
|
|
192
242
|
}
|
|
193
243
|
|
|
194
244
|
/** A choice a style lets you pin, such as Silhouette's scene. */
|
|
195
245
|
export interface StyleVariant {
|
|
246
|
+
/** The name to pin it by, such as `'scene'`. */
|
|
196
247
|
name: string;
|
|
248
|
+
/** The name as people read it, such as `'Scene'`. */
|
|
197
249
|
label: string;
|
|
250
|
+
/** The values it can take, each with a label as people read it. */
|
|
198
251
|
values: { value: string; label: string }[];
|
|
199
252
|
}
|
|
200
253
|
|
|
254
|
+
/** A style as `listStyles()` describes it. */
|
|
201
255
|
export interface StyleInfo {
|
|
256
|
+
/** Its id, as `createCover({ style })` takes it. */
|
|
202
257
|
id: string;
|
|
258
|
+
/** Its name as people read it, such as `'Art Deco'`; for a registered style without one, its id. */
|
|
203
259
|
name: string;
|
|
260
|
+
/** What it looks like, in a sentence; empty for a registered style without one. */
|
|
204
261
|
description: string;
|
|
205
262
|
/** The family the style belongs to; `'Custom'` for registered styles without one. */
|
|
206
263
|
group: StyleGroup | (string & {});
|
|
@@ -210,13 +267,16 @@ export interface StyleInfo {
|
|
|
210
267
|
genres: string[];
|
|
211
268
|
}
|
|
212
269
|
|
|
270
|
+
/** The ids of the genres in `genres`. */
|
|
213
271
|
export type GenreId = 'literary' | 'thriller' | 'horror' | 'romance' | 'fantasy' | 'children' | 'nonfiction';
|
|
214
272
|
/** The genres styles can suit, as `createCover({ genre })` and `listStyles()` name them. */
|
|
215
273
|
export declare const genres: readonly { readonly id: GenreId; readonly name: string }[];
|
|
216
274
|
|
|
217
275
|
/** A palette as seen by styles, with derived light/dark colours. */
|
|
218
276
|
export interface ResolvedPalette extends Palette {
|
|
277
|
+
/** At least three accents: a palette with fewer has them repeated. */
|
|
219
278
|
readonly accents: readonly string[];
|
|
279
|
+
/** Whether the background is dark: the palette's `dark`, else whether `bg` is darker than `ink`. */
|
|
220
280
|
readonly dark: boolean;
|
|
221
281
|
/** The lighter of `bg` and `ink`. */
|
|
222
282
|
readonly paper: string;
|
|
@@ -226,7 +286,9 @@ export interface ResolvedPalette extends Palette {
|
|
|
226
286
|
|
|
227
287
|
/** Everything a style's `render` function receives. */
|
|
228
288
|
export interface StyleContext {
|
|
289
|
+
/** The title after cleaning (`'Untitled'` if there is none), with any line breaks it was typed with as "\n". */
|
|
229
290
|
readonly title: string;
|
|
291
|
+
/** The author after cleaning, or empty. */
|
|
230
292
|
readonly author: string;
|
|
231
293
|
/**
|
|
232
294
|
* The subtitle, then the credit ("Translated by …"), if any, on a line of its own (after "\n"):
|
|
@@ -247,6 +309,7 @@ export interface StyleContext {
|
|
|
247
309
|
readonly m: number;
|
|
248
310
|
/** Seeded random numbers, unique to this cover and style. */
|
|
249
311
|
readonly rng: Rng;
|
|
312
|
+
/** The palette, with its lighter and darker colours as `paper` and `night`. */
|
|
250
313
|
readonly p: ResolvedPalette;
|
|
251
314
|
/** Make an id that is unique to this cover, for gradients, filters, masks… */
|
|
252
315
|
id(name: string): string;
|
|
@@ -261,10 +324,15 @@ export interface StyleContext {
|
|
|
261
324
|
readonly titleCase: 'upper' | 'normal' | null;
|
|
262
325
|
}
|
|
263
326
|
|
|
327
|
+
/** A style to add with `registerStyle`. */
|
|
264
328
|
export interface CoverStyle {
|
|
329
|
+
/** Its id: a non-empty string without spaces at either end, and not `'random'` (in any case). */
|
|
265
330
|
id: string;
|
|
331
|
+
/** Its name as people read it. Default: the id. */
|
|
266
332
|
name?: string;
|
|
333
|
+
/** What it looks like, in a sentence. Default empty. */
|
|
267
334
|
description?: string;
|
|
335
|
+
/** The family it belongs to, as `listStyles()` reports it. Default `'Custom'`. */
|
|
268
336
|
group?: StyleGroup | (string & {});
|
|
269
337
|
/** Background preference when the palette is picked automatically. */
|
|
270
338
|
prefer?: 'light' | 'dark';
|
|
@@ -284,7 +352,9 @@ export interface CoverStyle {
|
|
|
284
352
|
|
|
285
353
|
/** Ids of every available style (including registered custom styles). */
|
|
286
354
|
export declare const styles: string[];
|
|
355
|
+
/** Every available style, built-in and registered, as copies: changing them changes no style. */
|
|
287
356
|
export declare function listStyles(): StyleInfo[];
|
|
357
|
+
/** Options for `registerStyle` and `registerPalette`. */
|
|
288
358
|
export interface RegisterOptions {
|
|
289
359
|
/** Allow replacing the built-in style (or palette) with the same id. */
|
|
290
360
|
replace?: boolean;
|
package/src/index.js
CHANGED
|
@@ -32,7 +32,7 @@ export { createMockup, mockupKinds } from './mockups.js';
|
|
|
32
32
|
export { parseBookList } from './books.js';
|
|
33
33
|
|
|
34
34
|
/** This version of the library (artwork for a seed can change between minor versions). */
|
|
35
|
-
export const version = '1.9.
|
|
35
|
+
export const version = '1.9.2';
|
|
36
36
|
|
|
37
37
|
/** The sizes a cover can have: each side `min` to `max` px, and neither more than `ratio` times the other. */
|
|
38
38
|
export const sizeLimits = Object.freeze({ min: 50, max: 10000, ratio: 3 });
|
|
@@ -200,7 +200,7 @@ export function styleIdFor(name) {
|
|
|
200
200
|
return idFor(name, registry.values());
|
|
201
201
|
}
|
|
202
202
|
|
|
203
|
-
/**
|
|
203
|
+
/** Every available style: its id, name, description and group, the genres it suits, and its variants. */
|
|
204
204
|
export function listStyles() {
|
|
205
205
|
return [...registry.values()].map(({ id, name, description, group, variants, genres: suits }) => ({
|
|
206
206
|
id,
|
package/src/palettes.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
/** The ids of the built-in palettes. */
|
|
1
2
|
export type PaletteId =
|
|
2
3
|
| 'parchment'
|
|
3
4
|
| 'bauhaus'
|
|
@@ -28,13 +29,17 @@ export type PaletteId =
|
|
|
28
29
|
| 'thriller'
|
|
29
30
|
| 'dusk';
|
|
30
31
|
|
|
32
|
+
/** A palette: a background, an ink colour for text, and accents. */
|
|
31
33
|
export interface Palette {
|
|
34
|
+
/** Its id, as `createCover({ palette })` takes it. */
|
|
32
35
|
readonly id: string;
|
|
36
|
+
/** Its name as people read it, such as `'Midnight'`. */
|
|
33
37
|
readonly name: string;
|
|
34
38
|
/** Background, as hex. */
|
|
35
39
|
readonly bg: string;
|
|
36
40
|
/** Text colour with strong contrast against `bg`. */
|
|
37
41
|
readonly ink: string;
|
|
42
|
+
/** Accent colours, as hex (three in each built-in palette). */
|
|
38
43
|
readonly accents: readonly string[];
|
|
39
44
|
/** `true` for dark backgrounds. */
|
|
40
45
|
readonly dark?: boolean;
|
package/src/text.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
/** A font to set text in: a CSS font-family stack, and what fitting text in it needs to know. */
|
|
1
2
|
export interface FontSpec {
|
|
2
3
|
/** Its name as the app's menu shows it (the built-in fonts). */
|
|
3
4
|
name?: string;
|
|
@@ -11,6 +12,10 @@ export interface FontSpec {
|
|
|
11
12
|
mono?: boolean;
|
|
12
13
|
}
|
|
13
14
|
|
|
15
|
+
/**
|
|
16
|
+
* The built-in fonts. Each is a stack of system fonts, as an SVG drawn into a canvas (for PNG or
|
|
17
|
+
* JPEG export) can't load web fonts.
|
|
18
|
+
*/
|
|
14
19
|
export declare const FONTS: Readonly<{
|
|
15
20
|
serif: FontSpec;
|
|
16
21
|
didone: FontSpec;
|
|
@@ -23,9 +28,13 @@ export declare const FONTS: Readonly<{
|
|
|
23
28
|
mono: FontSpec;
|
|
24
29
|
}>;
|
|
25
30
|
|
|
31
|
+
/** The type `measureText` measures with: a font, its weight and style, and letter-spacing. */
|
|
26
32
|
export interface TextSpec {
|
|
33
|
+
/** The font. */
|
|
27
34
|
font: FontSpec;
|
|
35
|
+
/** Font weight. Default 400. */
|
|
28
36
|
weight?: number;
|
|
37
|
+
/** Italic. Default `false`. */
|
|
29
38
|
italic?: boolean;
|
|
30
39
|
/** In em. */
|
|
31
40
|
letterSpacing?: number;
|
|
@@ -43,6 +52,12 @@ export type TextMeasurer = (
|
|
|
43
52
|
* string and font at a reference size of 100 px, and other sizes are scaled from it. Pass `null` to restore the default.
|
|
44
53
|
*/
|
|
45
54
|
export declare function setTextMeasurer(fn: TextMeasurer | null): void;
|
|
55
|
+
/**
|
|
56
|
+
* The width in px of `text` at `size` px, letter-spacing included: measured with the function set
|
|
57
|
+
* by `setTextMeasurer`, else with a canvas, else from the built-in fonts' character widths (other
|
|
58
|
+
* fonts are estimated). Throws a TypeError if that function returns anything but a finite width of
|
|
59
|
+
* 0 or more.
|
|
60
|
+
*/
|
|
46
61
|
export declare function measureText(text: string, size: number, spec: TextSpec): number;
|
|
47
62
|
/** Throw a TypeError if `maxWidth` is missing or `maxHeight` is NaN. */
|
|
48
63
|
export declare function checkBox(fn: string, o: { maxWidth: number; maxHeight?: number }): void;
|
|
@@ -60,9 +75,13 @@ export declare const LINE_BREAK: RegExp;
|
|
|
60
75
|
export declare function typedLines(text: string): number;
|
|
61
76
|
/** Where some text was drawn. */
|
|
62
77
|
export interface TextBox {
|
|
78
|
+
/** Left edge, in px. */
|
|
63
79
|
x0: number;
|
|
80
|
+
/** Top edge, in px. */
|
|
64
81
|
y0: number;
|
|
82
|
+
/** Right edge, in px. */
|
|
65
83
|
x1: number;
|
|
84
|
+
/** Bottom edge, in px. */
|
|
66
85
|
y1: number;
|
|
67
86
|
}
|
|
68
87
|
/** Note that text was drawn in this box (drawText and drawStack do it), so a badge can be placed clear of it. */
|
|
@@ -74,23 +93,32 @@ export declare function clipGraphemes(str: string, max: number, options?: { unit
|
|
|
74
93
|
/** Split a string into user-perceived characters. */
|
|
75
94
|
export declare function graphemes(str: string): string[];
|
|
76
95
|
|
|
96
|
+
/** Options for `fitText`: the box to fit, and how to set the text. */
|
|
77
97
|
export interface FitOptions {
|
|
78
98
|
/** Box width in px. */
|
|
79
99
|
maxWidth: number;
|
|
80
100
|
/** Largest font size in px. */
|
|
81
101
|
maxSize: number;
|
|
82
|
-
/**
|
|
102
|
+
/**
|
|
103
|
+
* Box height in px: from the top of the first line (its cap height, or its marks when it has
|
|
104
|
+
* accents or marks above, such as É, Thai or Devanagari) to the last baseline.
|
|
105
|
+
*/
|
|
83
106
|
maxHeight?: number;
|
|
84
107
|
/** Smallest font size in px before words are broken and truncated. */
|
|
85
108
|
minSize?: number;
|
|
109
|
+
/** The font. Default `FONTS.sans`. */
|
|
86
110
|
font?: FontSpec;
|
|
111
|
+
/** Font weight. Default 400. */
|
|
87
112
|
weight?: number;
|
|
113
|
+
/** Italic. Default `false`. */
|
|
88
114
|
italic?: boolean;
|
|
89
115
|
/** In em. Ignored for scripts whose letters join (Arabic…), which browsers don't letter-space. */
|
|
90
116
|
letterSpacing?: number;
|
|
91
117
|
/** Multiple of the font size. */
|
|
92
118
|
lineHeight?: number;
|
|
119
|
+
/** The most lines to wrap to. Default 5. */
|
|
93
120
|
maxLines?: number;
|
|
121
|
+
/** Set the text in capitals. Default `false`. */
|
|
94
122
|
upper?: boolean;
|
|
95
123
|
/** Even out line lengths (default `true`). */
|
|
96
124
|
balance?: boolean;
|
|
@@ -100,18 +128,27 @@ export interface FitOptions {
|
|
|
100
128
|
hyphenate?: number;
|
|
101
129
|
}
|
|
102
130
|
|
|
131
|
+
/** Text fitted to a box by `fitText`, ready for `drawText`. */
|
|
103
132
|
export interface TextFit {
|
|
133
|
+
/** The lines, as set (in capitals with `upper`); empty for empty text. */
|
|
104
134
|
lines: string[];
|
|
135
|
+
/** Font size in px (0 for empty text). */
|
|
105
136
|
size: number;
|
|
137
|
+
/** The widest line's width in px. */
|
|
106
138
|
width: number;
|
|
107
139
|
/** From the top of the first line (its cap height, or its accents and marks where they reach higher) to the baseline of the last. */
|
|
108
140
|
height: number;
|
|
141
|
+
/** The font. */
|
|
109
142
|
font: FontSpec;
|
|
143
|
+
/** Font weight. */
|
|
110
144
|
weight: number;
|
|
145
|
+
/** Whether it is italic. */
|
|
111
146
|
italic: boolean;
|
|
147
|
+
/** Letter-spacing in em (0 for scripts whose letters join). */
|
|
112
148
|
letterSpacing: number;
|
|
113
149
|
/** The pitch between baselines, as a multiple of the size: the requested line height, or more where a line's accents or marks would reach the line above. */
|
|
114
150
|
lineHeight: number;
|
|
151
|
+
/** Cap height as a fraction of the size: the font's `cap`, else 0.72. */
|
|
115
152
|
cap: number;
|
|
116
153
|
/** Room above the first line's cap height for its accents and marks, as a fraction of the size. */
|
|
117
154
|
above?: number;
|
|
@@ -121,12 +158,17 @@ export interface TextFit {
|
|
|
121
158
|
truncated: boolean;
|
|
122
159
|
}
|
|
123
160
|
|
|
161
|
+
/** Where and how `drawText` sets a fit. */
|
|
124
162
|
export interface DrawOptions {
|
|
163
|
+
/** The x of the anchor point, in px. */
|
|
125
164
|
x: number;
|
|
126
165
|
/** Top of the text block: the cap height of the first line, or its accents and marks where they reach higher. */
|
|
127
166
|
y: number;
|
|
167
|
+
/** How the lines align on `x`, as SVG's `text-anchor`. Default `'start'`. */
|
|
128
168
|
anchor?: 'start' | 'middle' | 'end';
|
|
169
|
+
/** Text colour. Default `'#000'`. */
|
|
129
170
|
fill?: string;
|
|
171
|
+
/** Opacity, 0–1. Default 1. */
|
|
130
172
|
opacity?: number;
|
|
131
173
|
/** Extra raw SVG attributes for the wrapping `<g>`. */
|
|
132
174
|
attrs?: string;
|
|
@@ -142,7 +184,11 @@ export declare function baselineOf(fit: TextFit, y: number, i: number): number;
|
|
|
142
184
|
export declare function markExtent(text: string): { above: number; below: number };
|
|
143
185
|
/** Room below a line for descenders and marks, in em. */
|
|
144
186
|
export declare function descentOf(line: string): number;
|
|
145
|
-
/**
|
|
187
|
+
/**
|
|
188
|
+
* Attributes shared by every line of a text block, for its wrapping `<g>`: the font family and fill
|
|
189
|
+
* are escaped, `attrs` is written as given (raw SVG). Unlike the fitting options, `size` and
|
|
190
|
+
* `letterSpacing` are in px here (`drawText` passes a fit's letter-spacing × its size).
|
|
191
|
+
*/
|
|
146
192
|
export declare function textGroupAttrs(o: {
|
|
147
193
|
font: FontSpec;
|
|
148
194
|
fill: string;
|
package/src/type.d.ts
CHANGED
|
@@ -3,6 +3,7 @@ import type { StyleContext } from './index.js';
|
|
|
3
3
|
|
|
4
4
|
/** A justified stack: every line spans the full width at its own size. */
|
|
5
5
|
export interface StackFit {
|
|
6
|
+
/** Tells a stack from a `TextFit`. */
|
|
6
7
|
kind: 'stack';
|
|
7
8
|
/**
|
|
8
9
|
* `descent` is the room below each line for descenders and marks, and `above` the room above
|
|
@@ -13,30 +14,50 @@ export interface StackFit {
|
|
|
13
14
|
height: number;
|
|
14
15
|
/** Room needed below the last baseline, in px. */
|
|
15
16
|
descent: number;
|
|
17
|
+
/** The widest line's width in px. */
|
|
16
18
|
width: number;
|
|
17
19
|
/** The largest line size. */
|
|
18
20
|
size: number;
|
|
21
|
+
/** The font. */
|
|
19
22
|
font: FontSpec;
|
|
23
|
+
/** Font weight (`fitStack` defaults to 700). */
|
|
20
24
|
weight: number;
|
|
25
|
+
/** Whether it is italic. */
|
|
21
26
|
italic: boolean;
|
|
27
|
+
/** Letter-spacing in em (0 for scripts whose letters join). */
|
|
22
28
|
letterSpacing: number;
|
|
23
29
|
/** Space between lines, as a fraction of the lower line's size. */
|
|
24
30
|
gap: number;
|
|
31
|
+
/** Cap height as a fraction of each line's size: the font's `cap`, else 0.72. */
|
|
25
32
|
cap: number;
|
|
26
33
|
}
|
|
27
34
|
|
|
35
|
+
/** Options for `titleBlock`. */
|
|
28
36
|
export interface TitleBlockOptions {
|
|
37
|
+
/** Box width in px. */
|
|
29
38
|
maxWidth: number;
|
|
39
|
+
/** Box height in px, for all of it: the series line, the lead, the title and the subtitle. */
|
|
30
40
|
maxHeight: number;
|
|
31
|
-
/** Largest title size in px. */
|
|
41
|
+
/** Largest title size in px (a short one-word title, such as "Dune", may grow to 1.6 times this). */
|
|
32
42
|
maxSize: number;
|
|
43
|
+
/**
|
|
44
|
+
* Smallest title size in px (default as for `fitText`). Rather than set the title smaller or cut
|
|
45
|
+
* it, the leading article rejoins the title, then the subtitle and then the series line are left out.
|
|
46
|
+
*/
|
|
33
47
|
minSize?: number;
|
|
48
|
+
/** The title's font. Default `FONTS.serif`; the cover's `font` option wins. */
|
|
34
49
|
font?: FontSpec;
|
|
50
|
+
/** The title's weight. Default 400 (at most 700 when the cover's `font` option swaps in a serif). */
|
|
35
51
|
weight?: number;
|
|
52
|
+
/** Set the title in italics. Default `false`. */
|
|
36
53
|
italic?: boolean;
|
|
54
|
+
/** Set the title in capitals. Default `false`; the cover's `titleCase` option wins. */
|
|
37
55
|
upper?: boolean;
|
|
56
|
+
/** The title's letter-spacing in em. Default 0. */
|
|
38
57
|
letterSpacing?: number;
|
|
58
|
+
/** The title's line height, as a multiple of its size. Default 1.05. */
|
|
39
59
|
lineHeight?: number;
|
|
60
|
+
/** The most title lines. Default 5 (or as many as the title was typed on, if more). */
|
|
40
61
|
maxLines?: number;
|
|
41
62
|
/**
|
|
42
63
|
* Set a leading article of three letters or more ("The", "Les", "Der") as a small line above the
|
|
@@ -47,19 +68,25 @@ export interface TitleBlockOptions {
|
|
|
47
68
|
stack?: boolean;
|
|
48
69
|
/** Include the subtitle under the title. Default `true`. */
|
|
49
70
|
subtitle?: boolean;
|
|
71
|
+
/** The font of the subtitle and the series line. Default: the title's. */
|
|
50
72
|
subtitleFont?: FontSpec;
|
|
51
73
|
/** `false` to leave out the cover's series line (for a style that sets it itself). */
|
|
52
74
|
series?: false;
|
|
75
|
+
/** Set the subtitle in italics. Default `true`, except in `FONTS.mono`. */
|
|
53
76
|
subtitleItalic?: boolean;
|
|
77
|
+
/** Set the subtitle in spaced capitals. Default `false`. */
|
|
54
78
|
subtitleUpper?: boolean;
|
|
79
|
+
/** Largest subtitle size in px. Default 3.6% of the cover's short side. */
|
|
55
80
|
subtitleSize?: number;
|
|
56
81
|
/** Use this text instead of the cover's title. */
|
|
57
82
|
text?: string;
|
|
58
83
|
}
|
|
59
84
|
|
|
85
|
+
/** A title laid out by `titleBlock`, ready to draw. */
|
|
60
86
|
export interface TitleBlock {
|
|
61
87
|
/** From the top of the first line to the bottom of the block. */
|
|
62
88
|
height: number;
|
|
89
|
+
/** The widest line's width in px (the title's, the lead's, the subtitle's or the series line's). */
|
|
63
90
|
width: number;
|
|
64
91
|
/** The main title size (the largest line, for stacks). */
|
|
65
92
|
size: number;
|
|
@@ -71,6 +98,11 @@ export interface TitleBlock {
|
|
|
71
98
|
lines: number;
|
|
72
99
|
/** The title was cut with an ellipsis because it didn't fit. */
|
|
73
100
|
truncated: boolean;
|
|
101
|
+
/**
|
|
102
|
+
* The block as SVG, its top at `y`. `fill` colours the title, `leadFill` the lead and the series
|
|
103
|
+
* line, and `subtitleFill` the subtitle (both default to `fill`); `attrs` (raw SVG attributes)
|
|
104
|
+
* go on every part.
|
|
105
|
+
*/
|
|
74
106
|
draw(o: {
|
|
75
107
|
x: number;
|
|
76
108
|
y: number;
|
|
@@ -90,6 +122,10 @@ export declare function splitLead(title: string): { lead: string; main: string }
|
|
|
90
122
|
export declare function stackLines(text: string): string[];
|
|
91
123
|
/** Fit a justified stack, or `null` when the text doesn't suit one. */
|
|
92
124
|
export declare function fitStack(text: string, opts: FitOptions & { gap?: number }): StackFit | null;
|
|
125
|
+
/**
|
|
126
|
+
* Render a stack as SVG `<text>` elements, its top at `y` (as for `drawText`); `lineFills` colours
|
|
127
|
+
* lines one by one.
|
|
128
|
+
*/
|
|
93
129
|
export declare function drawStack(fit: StackFit, opts: DrawOptions & { lineFills?: (string | undefined)[] }): string;
|
|
94
130
|
/** Fit the title (with a demoted leading article and the subtitle) into a box. */
|
|
95
131
|
export declare function titleBlock(c: StyleContext, opts: TitleBlockOptions): TitleBlock;
|