@arraypress/covers 1.0.0 → 1.1.0
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/CHANGELOG.md +76 -0
- package/README.md +296 -11
- package/package.json +33 -5
- package/recipes/brand.json +1143 -0
- package/schema/recipe.schema.json +7300 -770
- package/src/animate/index.d.ts +19 -0
- package/src/animate/index.js +116 -0
- package/src/builtins.js +4 -0
- package/src/effects/ascii.d.ts +7 -0
- package/src/effects/ascii.js +93 -0
- package/src/effects/buffer.d.ts +60 -0
- package/src/effects/buffer.js +472 -0
- package/src/effects/detail.d.ts +12 -0
- package/src/effects/detail.js +124 -0
- package/src/effects/digital.d.ts +14 -0
- package/src/effects/digital.js +216 -0
- package/src/effects/distort.d.ts +20 -0
- package/src/effects/distort.js +314 -0
- package/src/effects/dither.d.ts +8 -0
- package/src/effects/dither.js +147 -0
- package/src/effects/drop-shadow.d.ts +4 -0
- package/src/effects/drop-shadow.js +45 -0
- package/src/effects/extrude.d.ts +5 -0
- package/src/effects/extrude.js +55 -0
- package/src/effects/film.d.ts +11 -0
- package/src/effects/film.js +204 -0
- package/src/effects/glow.d.ts +8 -0
- package/src/effects/glow.js +56 -0
- package/src/effects/grade.d.ts +30 -0
- package/src/effects/grade.js +274 -0
- package/src/effects/halftone.d.ts +8 -0
- package/src/effects/halftone.js +95 -0
- package/src/effects/index.d.ts +125 -0
- package/src/effects/index.js +277 -0
- package/src/effects/ink.d.ts +12 -0
- package/src/effects/ink.js +70 -0
- package/src/effects/lens.d.ts +14 -0
- package/src/effects/lens.js +277 -0
- package/src/effects/light.d.ts +10 -0
- package/src/effects/light.js +59 -0
- package/src/effects/looks.d.ts +9 -0
- package/src/effects/looks.js +74 -0
- package/src/effects/mask.d.ts +52 -0
- package/src/effects/mask.js +314 -0
- package/src/effects/motion.d.ts +6 -0
- package/src/effects/motion.js +60 -0
- package/src/effects/newsprint.d.ts +6 -0
- package/src/effects/newsprint.js +89 -0
- package/src/effects/optics.d.ts +10 -0
- package/src/effects/optics.js +213 -0
- package/src/effects/options.d.ts +6 -0
- package/src/effects/options.js +106 -0
- package/src/effects/paint-presets.d.ts +10 -0
- package/src/effects/paint-presets.js +47 -0
- package/src/effects/paint.d.ts +49 -0
- package/src/effects/paint.js +66 -0
- package/src/effects/pixels.d.ts +24 -0
- package/src/effects/pixels.js +138 -0
- package/src/effects/polar.d.ts +10 -0
- package/src/effects/polar.js +265 -0
- package/src/effects/region.d.ts +8 -0
- package/src/effects/region.js +136 -0
- package/src/effects/round-border.d.ts +5 -0
- package/src/effects/round-border.js +62 -0
- package/src/effects/screen.d.ts +14 -0
- package/src/effects/screen.js +212 -0
- package/src/effects/sort.d.ts +8 -0
- package/src/effects/sort.js +125 -0
- package/src/effects/symmetry.d.ts +6 -0
- package/src/effects/symmetry.js +74 -0
- package/src/effects/tile.d.ts +7 -0
- package/src/effects/tile.js +55 -0
- package/src/effects/tone.d.ts +16 -0
- package/src/effects/tone.js +117 -0
- package/src/effects/transform.d.ts +35 -0
- package/src/effects/transform.js +127 -0
- package/src/effects/util.d.ts +16 -0
- package/src/effects/util.js +85 -0
- package/src/extract.js +4 -3
- package/src/fonts.d.ts +55 -0
- package/src/fonts.js +246 -53
- package/src/formats/cut.d.ts +10 -0
- package/src/formats/cut.js +77 -0
- package/src/formats/index.d.ts +6 -0
- package/src/formats/index.js +9 -0
- package/src/formats/presets.d.ts +41 -0
- package/src/formats/presets.js +89 -0
- package/src/formats/print.d.ts +25 -0
- package/src/formats/print.js +117 -0
- package/src/formats/zones.d.ts +10 -0
- package/src/formats/zones.js +64 -0
- package/src/geometry.js +1 -1
- package/src/icons.js +43 -9
- package/src/index.d.ts +205 -19
- package/src/index.js +12 -4
- package/src/inter-data.js +27 -0
- package/src/json-recipe.js +181 -23
- package/src/kit/index.d.ts +20 -0
- package/src/kit/index.js +58 -0
- package/src/layer-options.js +23 -4
- package/src/layers/barcode.d.ts +19 -0
- package/src/layers/barcode.js +63 -0
- package/src/layers/code128.d.ts +4 -0
- package/src/layers/code128.js +28 -0
- package/src/layers/expr.d.ts +6 -0
- package/src/layers/expr.js +121 -0
- package/src/layers/geometry.d.ts +6 -0
- package/src/layers/geometry.js +238 -0
- package/src/layers/index.d.ts +18 -0
- package/src/layers/index.js +15 -0
- package/src/layers/perforation.d.ts +14 -0
- package/src/layers/perforation.js +47 -0
- package/src/layers/repeat.d.ts +29 -0
- package/src/layers/repeat.js +90 -0
- package/src/layers/shape.d.ts +46 -0
- package/src/layers/shape.js +115 -0
- package/src/layers/soft.d.ts +5 -0
- package/src/layers/soft.js +43 -0
- package/src/layers/svg.d.ts +23 -0
- package/src/layers/svg.js +109 -0
- package/src/layers/table.d.ts +25 -0
- package/src/layers/table.js +80 -0
- package/src/layers/tear.d.ts +21 -0
- package/src/layers/tear.js +74 -0
- package/src/layers/texture.d.ts +17 -0
- package/src/layers/texture.js +106 -0
- package/src/layers/util.d.ts +8 -0
- package/src/layers/util.js +48 -0
- package/src/layers.js +125 -41
- package/src/lint/image-size.d.ts +4 -0
- package/src/lint/image-size.js +34 -0
- package/src/lint/index.d.ts +16 -0
- package/src/lint/index.js +127 -0
- package/src/lint/rules.d.ts +5 -0
- package/src/lint/rules.js +19 -0
- package/src/node.d.ts +2 -0
- package/src/node.js +20 -0
- package/src/platform/bytes.d.ts +22 -0
- package/src/platform/bytes.js +103 -0
- package/src/platform/compress.d.ts +12 -0
- package/src/platform/compress.js +81 -0
- package/src/platform/harfbuzz.d.ts +9 -0
- package/src/platform/harfbuzz.js +80 -0
- package/src/platform/index.d.ts +8 -0
- package/src/platform/index.js +13 -0
- package/src/platform/load.d.ts +6 -0
- package/src/platform/load.js +72 -0
- package/src/platform/no-harfbuzz.d.ts +2 -0
- package/src/platform/no-harfbuzz.js +11 -0
- package/src/platform/node.d.ts +26 -0
- package/src/platform/node.js +86 -0
- package/src/platform/settings.d.ts +28 -0
- package/src/platform/settings.js +51 -0
- package/src/png.js +77 -28
- package/src/print.js +8 -7
- package/src/raster/index.d.ts +24 -0
- package/src/raster/index.js +171 -0
- package/src/recipes.js +4 -3
- package/src/render/backdrop.d.ts +6 -0
- package/src/render/backdrop.js +55 -0
- package/src/render/content.d.ts +5 -0
- package/src/render/content.js +58 -0
- package/src/render/context.d.ts +82 -0
- package/src/render/grain.d.ts +7 -0
- package/src/render/grain.js +113 -0
- package/src/render/group.d.ts +23 -0
- package/src/render/group.js +67 -0
- package/src/render/key.d.ts +5 -0
- package/src/render/key.js +91 -0
- package/src/render/report.d.ts +5 -0
- package/src/render/report.js +19 -0
- package/src/render/tiles.d.ts +6 -0
- package/src/render/tiles.js +77 -0
- package/src/render/use.d.ts +27 -0
- package/src/render/use.js +73 -0
- package/src/render/wrap.d.ts +14 -0
- package/src/render/wrap.js +199 -0
- package/src/render.js +303 -212
- package/src/text.d.ts +29 -0
- package/src/text.js +22 -15
- package/src/type/auto-color.d.ts +9 -0
- package/src/type/auto-color.js +44 -0
- package/src/type/fallback.d.ts +11 -0
- package/src/type/fallback.js +92 -0
- package/src/type/glyphs.d.ts +24 -0
- package/src/type/glyphs.js +87 -0
- package/src/type/index.d.ts +5 -0
- package/src/type/index.js +10 -0
- package/src/type/kern.d.ts +4 -0
- package/src/type/kern.js +144 -0
- package/src/type/layout-ref.d.ts +10 -0
- package/src/type/layout-ref.js +74 -0
- package/src/type/line.d.ts +11 -0
- package/src/type/line.js +105 -0
- package/src/type/live.d.ts +6 -0
- package/src/type/live.js +39 -0
- package/src/type/name.d.ts +4 -0
- package/src/type/name.js +32 -0
- package/src/type/path.d.ts +18 -0
- package/src/type/path.js +89 -0
- package/src/type/pixel.d.ts +9 -0
- package/src/type/pixel.js +115 -0
- package/src/type/sfnt.d.ts +20 -0
- package/src/type/sfnt.js +258 -0
- package/src/type/spans.d.ts +33 -0
- package/src/type/spans.js +138 -0
- package/src/type/symbols.d.ts +7 -0
- package/src/type/symbols.js +89 -0
- package/src/type/typeset.d.ts +10 -0
- package/src/type/typeset.js +352 -0
- package/src/type/woff2.d.ts +6 -0
- package/src/type/woff2.js +301 -0
- package/src/version.js +4 -0
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
// Print set-up: sizes at a dpi, bleed, safe margin, crop marks, die lines.
|
|
2
|
+
import type { Zones, FormatName, Format } from './presets.js';
|
|
3
|
+
|
|
4
|
+
/** Print set-up, px. */
|
|
5
|
+
export interface PrintInfo {
|
|
6
|
+
dpi: number;
|
|
7
|
+
unit: 'mm' | 'in';
|
|
8
|
+
trimWidth: number;
|
|
9
|
+
trimHeight: number;
|
|
10
|
+
bleed: number;
|
|
11
|
+
safe: number;
|
|
12
|
+
slug: number;
|
|
13
|
+
cropMarks: boolean;
|
|
14
|
+
cut?: import('./cut.js').Cut;
|
|
15
|
+
cutLine: boolean;
|
|
16
|
+
mm: number;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
/** A length in a unit as px at a dpi. */
|
|
21
|
+
export function toPx(v: number, unit: string, dpi: number): number;
|
|
22
|
+
/** A cover's `format` as its canvas, print set-up and zones (undefined without one). */
|
|
23
|
+
export function resolveFormat(o: { format?: FormatName | (Partial<Format> & { width: number; height: number }); width?: number; height?: number; dpi?: number; bleed?: number | false; safe?: number; cropMarks?: boolean; cutLine?: boolean; cut?: import('./cut.js').Cut }): { width: number; height: number; format?: string; zones?: Zones; print?: PrintInfo } | undefined;
|
|
24
|
+
/** Crop marks (slug coordinates) and the die line (bleed-box coordinates). */
|
|
25
|
+
export function printMarks(p: PrintInfo, w: number, h: number): { marks: string; cut: string };
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Named formats: release covers, social posts, flyers and print stationery,
|
|
3
|
+
* alongside `aspect`.
|
|
4
|
+
*
|
|
5
|
+
* Screen formats are pixel sizes. Print formats are a trim size in
|
|
6
|
+
* millimetres or inches, rendered at `dpi` (300 by default) with a bleed
|
|
7
|
+
* (3 mm by default) and a safe area inside the trim; `cropMarks: true`
|
|
8
|
+
* adds a slug with crop marks round the bleed. The layers are drawn on the
|
|
9
|
+
* bleed box (trim plus bleed on every side), so backgrounds run off the
|
|
10
|
+
* edge, and text and icons keep their default margins inside the safe area.
|
|
11
|
+
*
|
|
12
|
+
* @module formats/print
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
import { FORMATS } from './presets.js';
|
|
16
|
+
import { scaleZones } from './zones.js';
|
|
17
|
+
import { cutPath } from './cut.js';
|
|
18
|
+
|
|
19
|
+
/** @param {number} v @param {string} unit @param {number} dpi @returns {number} px */
|
|
20
|
+
export function toPx(v, unit, dpi) {
|
|
21
|
+
return unit === 'mm' ? (v / 25.4) * dpi : unit === 'in' ? v * dpi : v;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* The print set-up of a cover, in px.
|
|
26
|
+
*
|
|
27
|
+
* @typedef {object} PrintInfo
|
|
28
|
+
* @property {number} dpi
|
|
29
|
+
* @property {'mm' | 'in'} unit - The format's unit.
|
|
30
|
+
* @property {number} trimWidth - px.
|
|
31
|
+
* @property {number} trimHeight - px.
|
|
32
|
+
* @property {number} bleed - px on each side.
|
|
33
|
+
* @property {number} safe - px inside the trim on each side.
|
|
34
|
+
* @property {number} slug - px of slug outside the bleed (crop marks), 0 without.
|
|
35
|
+
* @property {boolean} cropMarks
|
|
36
|
+
* @property {import('./cut.js').Cut} [cut] - Die-cut shape.
|
|
37
|
+
* @property {boolean} cutLine - Draw the die line.
|
|
38
|
+
* @property {number} mm - px per millimetre.
|
|
39
|
+
*/
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Resolve a cover's `format` (a name or a custom `{ width, height, unit }`)
|
|
43
|
+
* to its canvas and print set-up.
|
|
44
|
+
*
|
|
45
|
+
* @param {any} o - Cover options: `format`, `dpi`, `bleed` (mm, or `false`), `safe` (mm), `cropMarks`, `cutLine`.
|
|
46
|
+
* @returns {{ width: number, height: number, print?: PrintInfo, format?: string, zones?: import('./index.js').Zones } | undefined}
|
|
47
|
+
*/
|
|
48
|
+
export function resolveFormat(o) {
|
|
49
|
+
if (o.format == null) return undefined;
|
|
50
|
+
const f = typeof o.format === 'string' ? FORMATS[o.format] : { unit: 'px', ...o.format };
|
|
51
|
+
if (!f) throw new RangeError(`Unknown format "${o.format}". Formats: ${Object.keys(FORMATS).join(', ')}`);
|
|
52
|
+
const name = typeof o.format === 'string' ? o.format : undefined;
|
|
53
|
+
if (f.unit === 'px') {
|
|
54
|
+
// A screen format: one side given scales the zones and the other side.
|
|
55
|
+
const k = o.width && !o.height ? o.width / f.width : 1;
|
|
56
|
+
const zones = f.zones ? scaleZones(f.zones, k) : undefined;
|
|
57
|
+
return { width: Math.round(f.width * k), height: Math.round(f.height * k), format: name, zones };
|
|
58
|
+
}
|
|
59
|
+
const dpi = o.dpi ?? 300;
|
|
60
|
+
const mm = dpi / 25.4;
|
|
61
|
+
const trimWidth = Math.round(toPx(f.width, f.unit, dpi));
|
|
62
|
+
const trimHeight = Math.round(toPx(f.height, f.unit, dpi));
|
|
63
|
+
const bleed = o.bleed === false ? 0 : Math.round((o.bleed ?? f.bleed ?? 3) * mm);
|
|
64
|
+
const safe = Math.round((o.safe ?? f.safe ?? 3) * mm);
|
|
65
|
+
const cropMarks = Boolean(o.cropMarks);
|
|
66
|
+
const slug = cropMarks ? Math.round(Math.max(6, (o.bleed === false ? 0 : o.bleed ?? f.bleed ?? 3) + 3) * mm) : 0;
|
|
67
|
+
return {
|
|
68
|
+
width: trimWidth + 2 * bleed,
|
|
69
|
+
height: trimHeight + 2 * bleed,
|
|
70
|
+
format: name,
|
|
71
|
+
print: { dpi, unit: /** @type {'mm' | 'in'} */ (f.unit), trimWidth, trimHeight, bleed, safe, slug, cropMarks, cut: o.cut ?? f.cut, cutLine: Boolean(o.cutLine), mm },
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Crop marks in the slug, a die line, and the document's outer size.
|
|
77
|
+
*
|
|
78
|
+
* @param {PrintInfo} p
|
|
79
|
+
* @param {number} w - Bleed-box width, px.
|
|
80
|
+
* @param {number} h - Bleed-box height, px.
|
|
81
|
+
* @returns {{ marks: string, cut: string }} Markup: marks in slug coordinates (the bleed box starts at `slug`), and the die line in bleed-box coordinates.
|
|
82
|
+
*/
|
|
83
|
+
export function printMarks(p, w, h) {
|
|
84
|
+
const n = (/** @type {number} */ v) => Math.round(v * 100) / 100;
|
|
85
|
+
let marks = '';
|
|
86
|
+
if (p.cropMarks) {
|
|
87
|
+
const s = p.slug;
|
|
88
|
+
const b = p.bleed;
|
|
89
|
+
const len = s - b - p.mm;
|
|
90
|
+
const gap = b + p.mm;
|
|
91
|
+
const stroke = Math.max(0.5, 0.25 * p.mm);
|
|
92
|
+
const xs = [s + b, s + w - b];
|
|
93
|
+
const ys = [s + b, s + h - b];
|
|
94
|
+
let d = '';
|
|
95
|
+
for (const x of xs) for (const y of ys) {
|
|
96
|
+
const dx = x < s + w / 2 ? -1 : 1;
|
|
97
|
+
const dy = y < s + h / 2 ? -1 : 1;
|
|
98
|
+
d += `M${n(x + dx * gap)} ${n(y)}h${n(dx * len)}M${n(x)} ${n(y + dy * gap)}v${n(dy * len)}`;
|
|
99
|
+
}
|
|
100
|
+
marks = `<path d="${d}" fill="none" stroke="#000" stroke-width="${n(stroke)}"/>`;
|
|
101
|
+
}
|
|
102
|
+
let cut = '';
|
|
103
|
+
if (p.cutLine) {
|
|
104
|
+
const x = p.bleed;
|
|
105
|
+
const y = p.bleed;
|
|
106
|
+
const cw = p.trimWidth;
|
|
107
|
+
const ch = p.trimHeight;
|
|
108
|
+
const custom = p.cut && typeof p.cut === 'object';
|
|
109
|
+
const shape = custom
|
|
110
|
+
? `<path d="${cutPath(p.cut, { x, y, width: cw, height: ch }, p.mm).map((g) => g.cmd + g.pts.map(n).join(' ')).join('')}"`
|
|
111
|
+
: p.cut === 'circle'
|
|
112
|
+
? `<ellipse cx="${n(x + cw / 2)}" cy="${n(y + ch / 2)}" rx="${n(cw / 2)}" ry="${n(ch / 2)}"`
|
|
113
|
+
: `<rect x="${n(x)}" y="${n(y)}" width="${n(cw)}" height="${n(ch)}"${p.cut === 'rounded' ? ` rx="${n(3 * p.mm)}"` : ''}`;
|
|
114
|
+
cut = `${shape} fill="none" stroke="#ec008c" stroke-width="${n(Math.max(0.5, 0.25 * p.mm))}" id="CutContour"/>`;
|
|
115
|
+
}
|
|
116
|
+
return { marks, cut };
|
|
117
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
// Safe zones.
|
|
2
|
+
import type { Zones } from './presets.js';
|
|
3
|
+
import type { PrintInfo } from './print.js';
|
|
4
|
+
|
|
5
|
+
/** A preview overlay of the zones: safe area dashed green, covered areas red, crops blue. */
|
|
6
|
+
export function zonesOverlay(z: Zones, w: number, h: number): string;
|
|
7
|
+
/** Zones scaled by `k`. */
|
|
8
|
+
export function scaleZones(z: Zones, k: number): Zones;
|
|
9
|
+
/** A cover's safe box, px. */
|
|
10
|
+
export function safeBox(c: { width: number; height: number; print?: PrintInfo; zones?: Zones }): { x: number; y: number; width: number; height: number } | undefined;
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Safe zones: the box layouts fit into, scaling, and a preview overlay.
|
|
3
|
+
*
|
|
4
|
+
* @module formats/zones
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* A preview overlay of a format's zones: the safe area dashed, covered
|
|
9
|
+
* areas tinted red, device crops outlined.
|
|
10
|
+
*
|
|
11
|
+
* @param {import('./index.js').Zones} z
|
|
12
|
+
* @param {number} w @param {number} h
|
|
13
|
+
* @returns {string} Markup.
|
|
14
|
+
*/
|
|
15
|
+
export function zonesOverlay(z, w, h) {
|
|
16
|
+
const n = (/** @type {number} */ v) => Math.round(v * 100) / 100;
|
|
17
|
+
const sw = n(Math.max(1, Math.min(w, h) / 360));
|
|
18
|
+
let out = '';
|
|
19
|
+
for (const c of z.crops ?? []) {
|
|
20
|
+
const [x, y, cw, ch] = c.rect;
|
|
21
|
+
if (c.name === 'circle') {
|
|
22
|
+
out += `<path d="M0 0H${n(w)}V${n(h)}H0ZM${n(x)} ${n(y + ch / 2)}a${n(cw / 2)} ${n(ch / 2)} 0 1 0 ${n(cw)} 0a${n(cw / 2)} ${n(ch / 2)} 0 1 0 ${n(-cw)} 0Z" fill="#000" fill-opacity="0.45" fill-rule="evenodd"/>`;
|
|
23
|
+
} else {
|
|
24
|
+
out += `<rect x="${n(x)}" y="${n(y)}" width="${n(cw)}" height="${n(ch)}" fill="none" stroke="#00b3ff" stroke-width="${sw}" stroke-dasharray="${n(sw * 2)} ${n(sw * 3)}"/>`;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
for (const a of z.avoid ?? []) {
|
|
28
|
+
if (a.circle) out += `<circle cx="${n(a.circle[0])}" cy="${n(a.circle[1])}" r="${n(a.circle[2])}" fill="#ff2d55" fill-opacity="0.35" stroke="#ff2d55" stroke-width="${sw}"/>`;
|
|
29
|
+
if (a.rect) out += `<rect x="${n(a.rect[0])}" y="${n(a.rect[1])}" width="${n(a.rect[2])}" height="${n(a.rect[3])}" fill="#ff2d55" fill-opacity="0.3"/>`;
|
|
30
|
+
}
|
|
31
|
+
const [x, y, sw2, sh] = z.safe;
|
|
32
|
+
out += `<rect x="${n(x)}" y="${n(y)}" width="${n(sw2)}" height="${n(sh)}" fill="none" stroke="#18e05a" stroke-width="${n(sw * 2)}" stroke-dasharray="${n(sw * 8)} ${n(sw * 5)}"/>`;
|
|
33
|
+
return `<g pointer-events="none">${out}</g>`;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* @param {import('./index.js').Zones} z @param {number} k
|
|
38
|
+
* @returns {import('./index.js').Zones}
|
|
39
|
+
*/
|
|
40
|
+
export function scaleZones(z, k) {
|
|
41
|
+
if (k === 1) return z;
|
|
42
|
+
const r = (/** @type {number[]} */ a) => /** @type {any} */ (a.map((v) => Math.round(v * k)));
|
|
43
|
+
return { ...z, safe: r(z.safe), avoid: z.avoid?.map((a) => ({ ...a, rect: a.rect && r(a.rect), circle: a.circle && r(a.circle) })), crops: z.crops?.map((c) => ({ ...c, rect: r(c.rect) })) };
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* The safe box of a cover, px: a format's safe zone, or a print piece's
|
|
49
|
+
* trim less its safe margin. Undefined for a plain canvas.
|
|
50
|
+
*
|
|
51
|
+
* @param {{ width: number, height: number, print?: import('./index.js').PrintInfo, zones?: import('./index.js').Zones }} c
|
|
52
|
+
* @returns {{ x: number, y: number, width: number, height: number } | undefined}
|
|
53
|
+
*/
|
|
54
|
+
export function safeBox(c) {
|
|
55
|
+
if (c.zones) {
|
|
56
|
+
const [x, y, width, height] = c.zones.safe;
|
|
57
|
+
return { x, y, width, height };
|
|
58
|
+
}
|
|
59
|
+
if (c.print) {
|
|
60
|
+
const i = c.print.bleed + c.print.safe;
|
|
61
|
+
return { x: i, y: i, width: c.width - 2 * i, height: c.height - 2 * i };
|
|
62
|
+
}
|
|
63
|
+
return undefined;
|
|
64
|
+
}
|
package/src/geometry.js
CHANGED
|
@@ -106,7 +106,7 @@ export function len(value, canvas, fallback = 0) {
|
|
|
106
106
|
}
|
|
107
107
|
|
|
108
108
|
/** The nine anchors, as fractions of the free space along x and y. */
|
|
109
|
-
const ANCHORS = Object.freeze({
|
|
109
|
+
export const ANCHORS = Object.freeze({
|
|
110
110
|
'top-left': [0, 0], top: [0.5, 0], 'top-right': [1, 0],
|
|
111
111
|
left: [0, 0.5], center: [0.5, 0.5], right: [1, 0.5],
|
|
112
112
|
'bottom-left': [0, 1], bottom: [0.5, 1], 'bottom-right': [1, 1],
|
package/src/icons.js
CHANGED
|
@@ -14,12 +14,8 @@
|
|
|
14
14
|
* @module icons
|
|
15
15
|
*/
|
|
16
16
|
|
|
17
|
-
import {
|
|
18
|
-
import {
|
|
19
|
-
import { join } from 'node:path';
|
|
20
|
-
import { fileURLToPath } from 'node:url';
|
|
21
|
-
|
|
22
|
-
const require = createRequire(import.meta.url);
|
|
17
|
+
import { node, settings, loadBytes } from './platform/index.js';
|
|
18
|
+
import { utf8 } from './platform/bytes.js';
|
|
23
19
|
|
|
24
20
|
/** @type {Map<string, IconSet>} */
|
|
25
21
|
const sets = new Map();
|
|
@@ -72,17 +68,53 @@ function loadSet(prefix) {
|
|
|
72
68
|
let set = sets.get(prefix);
|
|
73
69
|
if (set) return set;
|
|
74
70
|
const pkg = `@iconify-json/${prefix}`;
|
|
71
|
+
const mod = node('module');
|
|
72
|
+
const fs = node('fs');
|
|
73
|
+
const path = node('path');
|
|
74
|
+
const url = node('url');
|
|
75
75
|
let file;
|
|
76
76
|
try {
|
|
77
|
-
|
|
77
|
+
if (!mod || !fs) throw new Error('no node');
|
|
78
|
+
const require = mod.createRequire(import.meta.url);
|
|
79
|
+
const here = String(import.meta.url).startsWith('file:') ? [url.fileURLToPath(new URL('.', import.meta.url))] : [];
|
|
80
|
+
file = path.join(require.resolve(`${pkg}/package.json`, { paths: [/** @type {any} */ (globalThis).process.cwd(), ...here] }), '..', 'icons.json');
|
|
78
81
|
} catch {
|
|
79
|
-
throw new Error(`Icon set "${prefix}" is not available. Install ${pkg}, or pass the set to registerIcons().`);
|
|
82
|
+
throw new Error(`Icon set "${prefix}" is not available. Install ${pkg}, or pass the set to registerIcons()${mod ? '' : ' (or configure({ icons }) with a URL to load sets from)'}.`);
|
|
80
83
|
}
|
|
81
|
-
set = /** @type {IconSet} */ (JSON.parse(readFileSync(file, 'utf8')));
|
|
84
|
+
set = /** @type {IconSet} */ (JSON.parse(fs.readFileSync(file, 'utf8')));
|
|
82
85
|
sets.set(prefix, set);
|
|
83
86
|
return set;
|
|
84
87
|
}
|
|
85
88
|
|
|
89
|
+
/**
|
|
90
|
+
* Make sure the icon sets these names need are loaded: from Node's
|
|
91
|
+
* `node_modules`, or (in a browser or Worker) from `configure({ icons })`,
|
|
92
|
+
* a URL template like `'https://cdn.jsdelivr.net/npm/@iconify-json/{prefix}/icons.json'`
|
|
93
|
+
* or a function of the prefix. Names whose set can't be found are left for
|
|
94
|
+
* {@link resolveIcon} to report.
|
|
95
|
+
*
|
|
96
|
+
* @param {Iterable<string>} names - Candidate icon names (`prefix:name`).
|
|
97
|
+
* @returns {Promise<void>}
|
|
98
|
+
*/
|
|
99
|
+
export async function preloadIcons(names) {
|
|
100
|
+
const prefixes = new Set();
|
|
101
|
+
for (const n of names) {
|
|
102
|
+
const m = /^([a-z0-9-]+):([a-z0-9-]+)$/i.exec(n);
|
|
103
|
+
if (m && !sets.has(m[1])) prefixes.add(m[1]);
|
|
104
|
+
}
|
|
105
|
+
for (const prefix of prefixes) {
|
|
106
|
+
if (node('module')) {
|
|
107
|
+
try { loadSet(prefix); } catch { /* reported when drawn */ }
|
|
108
|
+
continue;
|
|
109
|
+
}
|
|
110
|
+
const where = typeof settings.icons === 'function' ? settings.icons(prefix) : settings.icons?.replace('{prefix}', prefix);
|
|
111
|
+
if (!where) continue;
|
|
112
|
+
try {
|
|
113
|
+
registerIcons(JSON.parse(utf8(await loadBytes(where, 'icons'))));
|
|
114
|
+
} catch { /* reported when drawn */ }
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
86
118
|
/**
|
|
87
119
|
* Resolve an Iconify name (`'prefix:name'`) to its markup and viewBox.
|
|
88
120
|
*
|
|
@@ -128,6 +160,8 @@ export function resolveIcon(name) {
|
|
|
128
160
|
*/
|
|
129
161
|
export function parseSvgIcon(svg) {
|
|
130
162
|
const open = svg.match(/<svg\b[^>]*>/i);
|
|
163
|
+
// Bare markup (a mark's paths on a 512 grid): wrap it.
|
|
164
|
+
if (!open && /^\s*<(path|g|circle|rect|polygon|ellipse|line|polyline)\b/i.test(svg)) return parseSvgIcon(`<svg viewBox="0 0 512 512">${svg}</svg>`);
|
|
131
165
|
if (!open) throw new Error('Icon SVG must contain an <svg> element');
|
|
132
166
|
const tag = open[0];
|
|
133
167
|
const vb = tag.match(/viewBox\s*=\s*["']([^"']+)["']/i);
|
package/src/index.d.ts
CHANGED
|
@@ -5,6 +5,36 @@
|
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
7
|
/** A CSS colour: hex (3/4/6/8 digits), `rgb()`/`rgba()` or `hsl()`/`hsla()`. Alpha is ignored. */
|
|
8
|
+
import type { LayerTransform, Effect, EffectKind, EffectMask } from './effects/index.js';
|
|
9
|
+
import type { Paint } from './effects/paint.js';
|
|
10
|
+
import type { TextPath } from './type/path.js';
|
|
11
|
+
import type { GroupLayer } from './render/group.js';
|
|
12
|
+
import type { DefsLayer, UseLayer } from './render/use.js';
|
|
13
|
+
import type { RepeatLayer } from './layers/repeat.js';
|
|
14
|
+
import type { TextSpan } from './type/spans.js';
|
|
15
|
+
import type { GlyphControl } from './type/glyphs.js';
|
|
16
|
+
import type { Cut } from './formats/cut.js';
|
|
17
|
+
import type { ShapeLayer, SvgLayer, TableLayer, BarcodeLayer, PerforationLayer, TearLayer, TextureLayer } from './layers/index.js';
|
|
18
|
+
import type { Zones, PrintInfo, FormatName } from './formats/index.js';
|
|
19
|
+
|
|
20
|
+
export type { RepeatLayer, DefsLayer, UseLayer, TextSpan, GlyphControl, Cut };
|
|
21
|
+
export type { LayerTransform, Effect, EffectKind, EffectMask, Paint, TextPath, GroupLayer, ShapeLayer, SvgLayer, TableLayer, BarcodeLayer, PerforationLayer, TearLayer, TextureLayer, Zones, PrintInfo, FormatName };
|
|
22
|
+
export type { ShapeSpec, TableCell } from './layers/index.js';
|
|
23
|
+
export type { Format } from './formats/index.js';
|
|
24
|
+
export type { LintIssue } from './lint/index.js';
|
|
25
|
+
export type { Settings } from './platform/index.js';
|
|
26
|
+
|
|
27
|
+
export { safeBox } from './formats/index.js';
|
|
28
|
+
export { rasterize } from './raster/index.js';
|
|
29
|
+
import type { RasterizeOptions } from './raster/index.js';
|
|
30
|
+
export type { RasterizeOptions };
|
|
31
|
+
export { lint } from './lint/index.js';
|
|
32
|
+
export { kit, KIT_FORMATS } from './kit/index.js';
|
|
33
|
+
export { FORMATS } from './formats/index.js';
|
|
34
|
+
export { configure } from './platform/index.js';
|
|
35
|
+
export { EFFECTS, EFFECT_OPTIONS } from './effects/index.js';
|
|
36
|
+
export { valueAt } from './animate/index.js';
|
|
37
|
+
|
|
8
38
|
export type Color = string;
|
|
9
39
|
|
|
10
40
|
/** Pixels, or a viewport unit of the canvas: `'6vmin'`, `'4vw'`, `'4vh'`, `'5vmax'`. */
|
|
@@ -67,15 +97,22 @@ export type PaletteInput =
|
|
|
67
97
|
onAccent?: Color;
|
|
68
98
|
};
|
|
69
99
|
|
|
70
|
-
/** A font the text layers can use. TrueType, OpenType or WOFF (
|
|
100
|
+
/** A font the text layers can use. TrueType, OpenType or WOFF (WOFF2 only for live text). */
|
|
71
101
|
export interface FontSource {
|
|
72
102
|
/** Family name, as text layers ask for it (`font: 'Inter'`). */
|
|
73
103
|
name: string;
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
104
|
+
/** The font's bytes; or give `src`. */
|
|
105
|
+
data?: Uint8Array | ArrayBuffer;
|
|
106
|
+
/** Where to load it from: a path (Node), a URL, or anything a `configure({ load })` hook reads. */
|
|
107
|
+
src?: string | URL;
|
|
108
|
+
/** Default 400. A variable font's range (`[100, 900]`) matches any weight in it and sets `wght`. */
|
|
109
|
+
weight?: number | [number, number];
|
|
77
110
|
/** Default `'normal'`. */
|
|
78
111
|
style?: 'normal' | 'italic';
|
|
112
|
+
/** Variable-font axes applied whenever this face is used. */
|
|
113
|
+
axes?: Record<string, number>;
|
|
114
|
+
/** Use this face for characters other fonts lack (glyph fallback). */
|
|
115
|
+
fallback?: boolean;
|
|
79
116
|
}
|
|
80
117
|
|
|
81
118
|
/** Options every layer takes. */
|
|
@@ -87,6 +124,18 @@ export interface BaseLayer {
|
|
|
87
124
|
/** 0–1. */
|
|
88
125
|
opacity?: number;
|
|
89
126
|
blend?: BlendMode;
|
|
127
|
+
/** Move, turn, scale, skew or mirror the layer. (On a text layer, a case keyword is still its case.) */
|
|
128
|
+
transform?: LayerTransform | string;
|
|
129
|
+
/** Effects (filters, pixel effects, copies), applied in order; a kind alone takes its defaults. */
|
|
130
|
+
effects?: Effect | EffectKind | (Effect | EffectKind)[];
|
|
131
|
+
/** Layers whose luminance masks this one (white shows). */
|
|
132
|
+
mask?: Layer[];
|
|
133
|
+
/** Layers cut out of this one (knockout type and marks, punched holes). */
|
|
134
|
+
knockout?: Layer[];
|
|
135
|
+
/** Layers this one shows only inside. */
|
|
136
|
+
clip?: Layer[];
|
|
137
|
+
/** Draw the layer in a box: the print `'trim'` or `'safe'` area, or fractions of the canvas. */
|
|
138
|
+
area?: 'bleed' | 'trim' | 'safe' | Region;
|
|
90
139
|
}
|
|
91
140
|
|
|
92
141
|
export interface SolidLayer extends BaseLayer {
|
|
@@ -196,10 +245,15 @@ export interface StripesLayer extends BaseLayer {
|
|
|
196
245
|
|
|
197
246
|
export interface ImageLayer extends BaseLayer {
|
|
198
247
|
type: 'image';
|
|
199
|
-
/** A local file path, a `data:` URI, or
|
|
200
|
-
src: string | Uint8Array;
|
|
248
|
+
/** A local file path, a `data:` URI, bytes, or a URL (fetched in browsers and Workers; in Node only with `configure({ network: true })` or a loader). */
|
|
249
|
+
src: string | URL | Uint8Array | ArrayBuffer;
|
|
201
250
|
/** Default `'cover'`. */
|
|
202
|
-
fit?: 'cover' | 'contain';
|
|
251
|
+
fit?: 'cover' | 'contain' | 'stretch';
|
|
252
|
+
/** An explicit box in px or `'%'` (instead of `region`). */
|
|
253
|
+
x?: Length | `${number}%`;
|
|
254
|
+
y?: Length | `${number}%`;
|
|
255
|
+
width?: Length | `${number}%`;
|
|
256
|
+
height?: Length | `${number}%`;
|
|
203
257
|
/** Crop focus: an anchor, or (with sharp) `'attention'` / `'entropy'`. Default `'center'`. */
|
|
204
258
|
focus?: Anchor | 'attention' | 'entropy';
|
|
205
259
|
/** Default the whole canvas. */
|
|
@@ -311,12 +365,19 @@ export interface IconLayer extends BaseLayer {
|
|
|
311
365
|
svg?: string;
|
|
312
366
|
/** A bare path `d` (filled with the colour). */
|
|
313
367
|
path?: string;
|
|
314
|
-
/** For `path`. Default `[0, 0, 24, 24]
|
|
368
|
+
/** For `path`. Default `[0, 0, 24, 24]` (`[0, 0, 512, 512]` for `markup`). */
|
|
315
369
|
viewBox?: [number, number, number, number];
|
|
370
|
+
/** Inner SVG markup (a mark's `<path>`s on a 512 grid), filled with `color`. */
|
|
371
|
+
markup?: string;
|
|
372
|
+
/** Top-left corner in px (a mark at `translate(x y) scale(size / 512)`), instead of anchoring. */
|
|
373
|
+
x?: Length | `${number}%`;
|
|
374
|
+
y?: Length | `${number}%`;
|
|
316
375
|
/** Default `'24vmin'` (`'15vmin'` on a tile). */
|
|
317
376
|
size?: Length;
|
|
318
377
|
/** Default the accent on a tile, else `palette.text`. */
|
|
319
378
|
color?: Color;
|
|
379
|
+
/** A paint instead of `color`: a gradient, tile or preset laid over the icon's grid. */
|
|
380
|
+
fill?: Paint;
|
|
320
381
|
/** Override stroke icons' `stroke-width` (in icon units). */
|
|
321
382
|
strokeWidth?: number;
|
|
322
383
|
/** Default `'center'`. */
|
|
@@ -347,10 +408,60 @@ export interface TextLabel {
|
|
|
347
408
|
gap?: Length;
|
|
348
409
|
}
|
|
349
410
|
|
|
350
|
-
export interface TextLayer extends BaseLayer {
|
|
411
|
+
export interface TextLayer extends Omit<BaseLayer, 'transform'> {
|
|
351
412
|
type: 'text';
|
|
352
|
-
|
|
353
|
-
|
|
413
|
+
/** The text; an array is one line per item. (Optional with `spans`.) */
|
|
414
|
+
content?: string | string[];
|
|
415
|
+
/** First baseline x (px or `'%'`): places the text like SVG `<text x y>`, `align` acting as the anchor. */
|
|
416
|
+
x?: Length | `${number}%`;
|
|
417
|
+
y?: Length | `${number}%`;
|
|
418
|
+
/** Justify every line to this width (`textLength`). */
|
|
419
|
+
width?: Length;
|
|
420
|
+
/** Justify every line to `maxWidth`. */
|
|
421
|
+
justify?: boolean;
|
|
422
|
+
/** Default `'spacingAndGlyphs'` (scale the glyphs); `'spacing'` opens the letter-spacing. */
|
|
423
|
+
lengthAdjust?: 'spacingAndGlyphs' | 'spacing';
|
|
424
|
+
/** `'width'`: the block fills the width; `'lines'`: each line does; `'words'`: a word a line, the widest filling the width; `'wrap'`: wrap at the width, then fill it; `'shrink'`: shrink before wrapping. */
|
|
425
|
+
fit?: 'width' | 'lines' | 'words' | 'wrap' | 'shrink';
|
|
426
|
+
/** `'words'`: a word a line. */
|
|
427
|
+
split?: 'words';
|
|
428
|
+
/** Shrink the block to this height. */
|
|
429
|
+
maxHeight?: Length;
|
|
430
|
+
/** Mixed runs on the same lines, each with its own font, weight, size, colour (instead of `content`). */
|
|
431
|
+
spans?: (TextSpan | string)[];
|
|
432
|
+
/** Per-glyph scale, shift, turn and colour (arrays cycle). */
|
|
433
|
+
glyphs?: GlyphControl;
|
|
434
|
+
/** A family (or list) for characters the font lacks; then fonts registered with `fallback: true`, then built-in symbols. */
|
|
435
|
+
fallback?: string | string[];
|
|
436
|
+
/** Dashes on the stroke (`stroke`): `[on, off]` lengths, `'dashed'` or `'dotted'`. */
|
|
437
|
+
dash?: 'dashed' | 'dotted' | Length[];
|
|
438
|
+
/** Block extrusion: a depth, or its options. */
|
|
439
|
+
extrude?: Length | { depth?: Length; angle?: number; offset?: [Length, Length]; steps?: number; color?: Color; to?: Color };
|
|
440
|
+
/** `color: 'auto'` takes the dark colour above this backdrop luma (0–1). Default 0.72. */
|
|
441
|
+
autoThreshold?: number;
|
|
442
|
+
/** Stretch about the first baseline: `[sx, sy]`, or `sy`. */
|
|
443
|
+
stretch?: number | [number, number];
|
|
444
|
+
/** Variable-font axes: `{ wdth: 50, SOFT: 100, WONK: 1, opsz: 144 }`. */
|
|
445
|
+
axes?: Record<string, number>;
|
|
446
|
+
/** Outline colour (with `fill: 'none'` for outline type). */
|
|
447
|
+
stroke?: Color;
|
|
448
|
+
strokeWidth?: Length;
|
|
449
|
+
/** Keylines under the fill, widest first (a preset paint brings its own). */
|
|
450
|
+
strokes?: { color: Color; width: Length; fill?: Color; dash?: 'dashed' | 'dotted' | Length[] }[];
|
|
451
|
+
fill?: Paint;
|
|
452
|
+
/** Set the text along a path. */
|
|
453
|
+
path?: TextPath;
|
|
454
|
+
/** Along the path: 0–1, or px. Default 0.5 (centred). */
|
|
455
|
+
startOffset?: number | Length;
|
|
456
|
+
/** Space the text to fill the path (a ring); a length leaves that gap. */
|
|
457
|
+
fitPath?: boolean | Length;
|
|
458
|
+
/** Shift off the path. */
|
|
459
|
+
dy?: Length;
|
|
460
|
+
/** `'live'`: `<text>` with the font embedded by `@font-face` (or linked by URL). Default `'outline'`. */
|
|
461
|
+
render?: 'outline' | 'live';
|
|
462
|
+
/** For `color: 'auto'`. Default `['#ffffff', '#0b0b0b']`. */
|
|
463
|
+
autoColors?: [Color, Color];
|
|
464
|
+
/** Family. Default `'Inter'` (bundled). `'pixel'`: the built-in 5×7 face. */
|
|
354
465
|
font?: string;
|
|
355
466
|
/** Default 600. */
|
|
356
467
|
weight?: number;
|
|
@@ -363,8 +474,8 @@ export interface TextLayer extends BaseLayer {
|
|
|
363
474
|
lineHeight?: number;
|
|
364
475
|
/** Em. Default -0.02. */
|
|
365
476
|
letterSpacing?: number;
|
|
366
|
-
/** Default `palette.text`. */
|
|
367
|
-
color?: Color;
|
|
477
|
+
/** Default `palette.text`. `'auto'`: white or near-black, whichever reads better on what's drawn underneath. */
|
|
478
|
+
color?: Color | 'auto';
|
|
368
479
|
/** Default from the anchor. */
|
|
369
480
|
align?: 'left' | 'center' | 'right';
|
|
370
481
|
/** Default `'bottom-left'`. */
|
|
@@ -381,7 +492,8 @@ export interface TextLayer extends BaseLayer {
|
|
|
381
492
|
ellipsis?: string;
|
|
382
493
|
/** Even out line lengths. Default true. */
|
|
383
494
|
balance?: boolean;
|
|
384
|
-
|
|
495
|
+
/** The case (`'uppercase'`, `'lowercase'`), or a geometric transform. */
|
|
496
|
+
transform?: 'none' | 'uppercase' | 'lowercase' | LayerTransform;
|
|
385
497
|
/** A small line above (a string, or its options). */
|
|
386
498
|
label?: string | TextLabel;
|
|
387
499
|
/** A pill or box behind the block. */
|
|
@@ -601,13 +713,15 @@ export interface RuleLayer extends BaseLayer {
|
|
|
601
713
|
}
|
|
602
714
|
|
|
603
715
|
export type Layer =
|
|
716
|
+
| GroupLayer | ShapeLayer | SvgLayer | TableLayer | BarcodeLayer | PerforationLayer | TearLayer | TextureLayer
|
|
604
717
|
| InkLayer | DitherLayer | ContourLayer | WaveformLayer | TilesLayer | RuleLayer
|
|
605
718
|
| DiagramLayer | PaperLayer | ScribbleLayer
|
|
606
719
|
| SolidLayer | LinearLayer | RadialLayer | MeshLayer | StripesLayer | ImageLayer
|
|
607
|
-
| GrainLayer | PatternLayer | ShapesLayer | IconLayer | TextLayer | FrameLayer
|
|
720
|
+
| GrainLayer | PatternLayer | ShapesLayer | IconLayer | TextLayer | FrameLayer
|
|
721
|
+
| RepeatLayer | DefsLayer | UseLayer;
|
|
608
722
|
|
|
609
723
|
/** Built-in recipe names. */
|
|
610
|
-
export type RecipeName = 'aurora' | 'gridTitle' | 'iconTile' | 'bigType' | 'stripes' | 'duotone' | 'mark' | 'diagram' | 'cutout' | 'riso' | 'dither' | 'contour' | 'waveform' | 'bauhaus' | 'issue' | 'photo';
|
|
724
|
+
export type RecipeName = 'aurora' | 'gridTitle' | 'iconTile' | 'bigType' | 'stripes' | 'duotone' | 'mark' | 'diagram' | 'cutout' | 'riso' | 'dither' | 'contour' | 'waveform' | 'bauhaus' | 'issue' | 'photo' | 'brand';
|
|
611
725
|
|
|
612
726
|
/** What a recipe function receives besides the options. */
|
|
613
727
|
export interface RecipeContext {
|
|
@@ -619,6 +733,12 @@ export interface RecipeContext {
|
|
|
619
733
|
u: number;
|
|
620
734
|
/** The cover's seed. */
|
|
621
735
|
seed?: string;
|
|
736
|
+
/** The safe box (a format's safe zone, a print piece's trim less its safe margin, else the canvas). */
|
|
737
|
+
safeX?: number; safeY?: number; safeWidth?: number; safeHeight?: number;
|
|
738
|
+
/** Print: bleed and safe margin in px, the trim size, px per mm, dpi. */
|
|
739
|
+
bleed?: number; safe?: number; trimWidth?: number; trimHeight?: number; mm?: number; dpi?: number;
|
|
740
|
+
/** The format's name, when one was given. */
|
|
741
|
+
format?: string;
|
|
622
742
|
}
|
|
623
743
|
|
|
624
744
|
/** A custom recipe. JSON recipes defined with {@link defineRecipe} also carry `recipeName` and `json`. */
|
|
@@ -645,6 +765,9 @@ export type RecipeValue =
|
|
|
645
765
|
| { ramp: RecipeValue[] }
|
|
646
766
|
| { taper: [RecipeValue, RecipeValue] }
|
|
647
767
|
| { reverse: RecipeValue }
|
|
768
|
+
| { join: [RecipeValue] | [RecipeValue, RecipeValue] } | { upper: RecipeValue } | { lower: RecipeValue }
|
|
769
|
+
| { slice: [RecipeValue, RecipeValue] | [RecipeValue, RecipeValue, RecipeValue] }
|
|
770
|
+
| { keyframes: [number, RecipeValue][]; ease?: 'linear' | 'in' | 'out' | 'inOut' | 'step'; loop?: boolean | 'pingpong' }
|
|
648
771
|
| { [key: string]: RecipeValue };
|
|
649
772
|
|
|
650
773
|
/** A condition: an option name (set?), `{ name: value }` (equals; `mode` is the palette's), `not`, `all`, `any`. */
|
|
@@ -677,6 +800,10 @@ export interface RecipeJson {
|
|
|
677
800
|
output?: { lossless?: boolean };
|
|
678
801
|
/** Named values, resolved in order; referenced as `"$name"`. */
|
|
679
802
|
vars?: Record<string, RecipeValue>;
|
|
803
|
+
/** The pages of a two-sided piece; layers pick theirs with `when: { page: 'back' }`. */
|
|
804
|
+
pages?: string[];
|
|
805
|
+
/** Fonts the recipe uses: a path beside the recipe file, or a URL. */
|
|
806
|
+
fonts?: { name: string; src: string; weight?: number | [number, number]; style?: 'normal' | 'italic'; axes?: Record<string, number>; fallback?: boolean }[];
|
|
680
807
|
layers: RecipeJsonLayer[];
|
|
681
808
|
}
|
|
682
809
|
|
|
@@ -742,6 +869,23 @@ export interface RecipeOptions {
|
|
|
742
869
|
show?: 'blur';
|
|
743
870
|
/** `mark` icon colour. `'auto'` (default): white whenever it clears 3:1 against everything under the icon, else near-black. */
|
|
744
871
|
iconColor?: 'auto' | 'white' | 'black' | Color;
|
|
872
|
+
/** Brand and event data, for recipes that read them (`{name}`, `{lineup.0}`). */
|
|
873
|
+
name?: string;
|
|
874
|
+
tagline?: string;
|
|
875
|
+
/** A mark: `<path>` markup on a 512 grid. */
|
|
876
|
+
mark?: string;
|
|
877
|
+
photo?: string | Uint8Array | URL;
|
|
878
|
+
/** The photo's subject cut out (transparent, in the same frame). */
|
|
879
|
+
cutout?: string | Uint8Array | URL;
|
|
880
|
+
lines?: string[];
|
|
881
|
+
lineup?: string[];
|
|
882
|
+
dates?: string[];
|
|
883
|
+
tracklist?: (string | string[] | Record<string, string>)[];
|
|
884
|
+
venue?: string;
|
|
885
|
+
address?: string;
|
|
886
|
+
time?: string;
|
|
887
|
+
price?: string;
|
|
888
|
+
meta?: unknown;
|
|
745
889
|
/** Any recipe layer by id: `mesh`, `grid`, `grain`, `bg`, `glow`, `rings`, `wash`, `stripes`, `spot`, `scrim`… */
|
|
746
890
|
[layerId: string]: unknown;
|
|
747
891
|
}
|
|
@@ -768,6 +912,28 @@ export interface CoverOptions extends RecipeOptions {
|
|
|
768
912
|
radius?: Length;
|
|
769
913
|
/** Preferred encoding, overriding the recipe's. */
|
|
770
914
|
output?: { lossless?: boolean };
|
|
915
|
+
/** A named format (`'release'`, `'instagram-story'`, `'business-card'`, …; see `FORMATS`) or a custom size with a unit. */
|
|
916
|
+
format?: FormatName | { width: number; height: number; unit?: 'px' | 'mm' | 'in'; bleed?: number; safe?: number; zones?: Zones };
|
|
917
|
+
/** Print: dots per inch. Default 300. */
|
|
918
|
+
dpi?: number;
|
|
919
|
+
/** Print: bleed in mm (default the format's, usually 3), or `false`. */
|
|
920
|
+
bleed?: number | false;
|
|
921
|
+
/** Print: safe margin inside the trim, mm. */
|
|
922
|
+
safe?: number;
|
|
923
|
+
/** Print: crop marks in a slug round the bleed. */
|
|
924
|
+
cropMarks?: boolean;
|
|
925
|
+
/** Print: draw the die line (`CutContour`). */
|
|
926
|
+
cutLine?: boolean;
|
|
927
|
+
/** Print: the die-cut shape. */
|
|
928
|
+
cut?: Cut;
|
|
929
|
+
/** Draw the format's safe zones over the art (for previews). */
|
|
930
|
+
overlay?: boolean;
|
|
931
|
+
/** Which page of a two-sided piece to draw. Default `'front'`. */
|
|
932
|
+
page?: string;
|
|
933
|
+
/** `'live'`: every text layer as `<text>` with `@font-face`. */
|
|
934
|
+
textRender?: 'outline' | 'live';
|
|
935
|
+
/** Seconds: the length of an animated cover's loop (keyframes with `loop` wrap at it). */
|
|
936
|
+
loop?: number;
|
|
771
937
|
}
|
|
772
938
|
|
|
773
939
|
/** A resolved cover (from {@link cover}). */
|
|
@@ -782,6 +948,17 @@ export interface Cover {
|
|
|
782
948
|
radius?: Length;
|
|
783
949
|
/** Preferred encoding (from the recipe, or set here). */
|
|
784
950
|
output?: { lossless?: boolean };
|
|
951
|
+
/** Print set-up, when the format is a print size. */
|
|
952
|
+
print?: PrintInfo;
|
|
953
|
+
/** The format's name. */
|
|
954
|
+
format?: string;
|
|
955
|
+
/** The format's safe zones, px. */
|
|
956
|
+
zones?: Zones;
|
|
957
|
+
page?: string;
|
|
958
|
+
pages?: string[];
|
|
959
|
+
overlay?: boolean;
|
|
960
|
+
loop?: number;
|
|
961
|
+
textRender?: 'outline' | 'live';
|
|
785
962
|
}
|
|
786
963
|
|
|
787
964
|
export interface RenderImageOptions {
|
|
@@ -821,10 +998,19 @@ export interface IconSet {
|
|
|
821
998
|
/** Resolve a cover's size and palette and expand its recipe. Pure and synchronous. */
|
|
822
999
|
export function cover(options: CoverOptions | Cover): Cover;
|
|
823
1000
|
|
|
824
|
-
/** Render to an SVG string (text and icons as outlines; byte-identical for the same input). */
|
|
825
|
-
export function renderSvg(input: CoverOptions | Cover): Promise<string>;
|
|
1001
|
+
/** Render to an SVG string (text and icons as outlines; byte-identical for the same input). `t`: the time to draw, in seconds, for keyframed layers. */
|
|
1002
|
+
export function renderSvg(input: CoverOptions | Cover, options?: { t?: number }): Promise<string>;
|
|
1003
|
+
|
|
1004
|
+
/** Render each page of a two-sided piece: `{ front, back }`. */
|
|
1005
|
+
export function renderPages(input: CoverOptions, options?: { pages?: string[] }): Promise<Record<string, string>>;
|
|
1006
|
+
|
|
1007
|
+
/** Render to an image in the browser (a canvas; no sharp). */
|
|
1008
|
+
export function renderBlob(input: CoverOptions | Cover, options?: RasterizeOptions): Promise<Blob>;
|
|
1009
|
+
|
|
1010
|
+
/** Register a font for every cover. */
|
|
1011
|
+
export function registerFont(font: FontSource): void;
|
|
826
1012
|
|
|
827
|
-
/** Render to image bytes with sharp (a peer dependency). */
|
|
1013
|
+
/** Render to image bytes with sharp (a peer dependency; Node). */
|
|
828
1014
|
export function renderImage(input: CoverOptions | Cover, options?: RenderImageOptions): Promise<Buffer>;
|
|
829
1015
|
|
|
830
1016
|
/** The content-hash cache key for a cover and output options (40 hex chars). */
|