@arraypress/covers 1.4.0 → 1.5.1

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 CHANGED
@@ -5,6 +5,27 @@ All notable changes to `@arraypress/covers` are documented here.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [1.5.1] — 2026-11-06
9
+
10
+ ### Changed
11
+
12
+ - **`fluted-poster`** keeps the name readable: with `subject: 'name'` (or no mark) and no `preset`, the glass is gentler (12 convex ribs at refraction 0.15, little defocus, chroma 0.2), so the word steps at the rib edges but never doubles. A `preset` given is used as it is; the mark keeps the `fluted` preset. `preset` now defaults to `''` (the subject's default).
13
+
14
+ ## [1.5.0] — 2026-11-06
15
+
16
+ Three more posters on the 400-wide grid, and the layers they stand on. Every published recipe renders as before (157 SVGs, flyers at 4:5 and as release covers, the release styles and the built-ins, byte-identical to 1.4.0).
17
+
18
+ ### Added
19
+
20
+ - **Three posters**, drawn on a 400-wide grid as tall as the canvas, so they set at 4:5, 1:1, 9:16 and A-series portrait alike: `construction` (a construction sheet: the mark large over its own construction, read from its paths, a dashed grid, its box, a centre cross, the inscribed and circumscribed circles, the circles its curves are drawn on and the lines its straight edges lie on, in one thin accent; meta in the corners; dark or light by `ground` and `ink`), `fluted-poster` (the mark, or the name set huge, in white on black behind fluted glass, a soft light in one accent behind it, and vector Swiss type over it: the year stacked, the series, a two-line title with a glitched `||` of bars, credits and an edition line; `preset` picks the glass) and `series-card` (a numbered card for a run of posts: a flat soft colour, a two-line title, a large number and the mark solid or as contour lines).
21
+ - **`construction` layer**: a mark over its construction guides (`markGuides`: circles fitted to its arcs and Béziers, lines along its straight edges, added up where several lie on one); `grid`, `size`, `circles`, `lines`, `color`, `gridColor`, `gridOpacity`, `markColor`, `over` (the guides shown faintly over the mark), `stroke`.
22
+ - **`outline` layer**: a mark fitted by its real bounds and drawn as contour lines, its outline and `lines − 1` more `gap` apart (isolines of its signed distance field, from `@logomarks/core`'s raster fill and distance transform, measured exactly to its edges where the lines run, so parts merge as contours do and cusps stay sharp), out or `in`; `lines: 0` draws it solid.
23
+ - The image effects of `@logomarks/image-effects` 0.2–0.3 on any layer, and in the schema: `fluted` (reeded glass; presets `fluted`, `reeded-deep`, `reeded-prism`, `reeded-soft`) and `print` (letterpress, riso and stamp finishes).
24
+
25
+ ### Changed
26
+
27
+ - Depends on `@logomarks/image-effects` `^0.3.2`.
28
+
8
29
  ## [1.4.0] — 2026-11-06
9
30
 
10
31
  Three flyers that set on any canvas, and the layers they stand on. Every published recipe renders as before (185 SVGs, flyers at 4:5 and as release covers plus the built-ins, byte-identical to 1.3.1).
package/README.md CHANGED
@@ -36,7 +36,7 @@ await writeFile('public/covers/introducing-covers.webp', webp);
36
36
  - [API](https://github.com/arraypress/covers/blob/main/docs/api.md): every export and cover option
37
37
  - [Layers](https://github.com/arraypress/covers/blob/main/docs/layers.md): mesh, grain, text, diagrams, riso inks, dithers, poster type and more
38
38
  - [Effects](https://github.com/arraypress/covers/blob/main/docs/effects.md): filters and pixel effects on any layer, masks, paints
39
- - [Recipes](https://github.com/arraypress/covers/blob/main/docs/recipes.md): seventeen built-ins, 87 flyers and release covers, your own
39
+ - [Recipes](https://github.com/arraypress/covers/blob/main/docs/recipes.md): seventeen built-ins, 90 flyers and release covers, your own
40
40
  - [JSON recipes](https://github.com/arraypress/covers/blob/main/docs/json-recipes.md): a cover style as data, with no JavaScript
41
41
  - [Palettes](https://github.com/arraypress/covers/blob/main/docs/palettes.md): presets, one accent, a theme's tokens
42
42
  - [Formats, print and brand kits](https://github.com/arraypress/covers/blob/main/docs/formats.md): social sizes with safe zones, print with bleed, `kit`, `lint`
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@arraypress/covers",
3
- "version": "1.4.0",
3
+ "version": "1.5.1",
4
4
  "description": "Covers, flyers, posters, release art, social formats and print stationery from one seed and a stack of layers: mesh gradients, grain, riso inks and halftones, knockout and justified type, torn paper, barcodes, safe zones and bleed, as SVG or WebP/PNG/AVIF/JPEG. Recipes are JSON. Runs in Node, browsers and Cloudflare Workers.",
5
5
  "type": "module",
6
6
  "main": "src/index.js",
@@ -86,7 +86,7 @@
86
86
  "dependencies": {
87
87
  "@arraypress/color-utils": "^1.3.0",
88
88
  "@logomarks/core": "^0.1.5",
89
- "@logomarks/image-effects": "^0.1.1",
89
+ "@logomarks/image-effects": "^0.3.2",
90
90
  "harfbuzzjs": "^1.6.3"
91
91
  },
92
92
  "peerDependencies": {
@@ -0,0 +1,36 @@
1
+ {
2
+ "$schema": "../../schema/recipe.schema.json",
3
+ "name": "construction",
4
+ "description": "Construction sheet: the mark large and centred over its own construction, read from its paths: a light dashed square grid behind (cells an eighth of the mark by default, centred on it), its bounding box, a centre cross, the circles inscribed in its box and round its outline, the circles its curves are drawn on (each centre marked) and the lines its straight edges lie on, run across the sheet, all in one thin accent (blue by default) and showing faintly over the mark. Small meta in the corners: a label and the name across the top, the grid's size and a ® (or any caption) along the foot. A dark ground by default; set ground and ink for a light one. Drawn on a 400-wide grid as tall as the canvas, so it sets at 4:5, 1:1, 9:16 and A-series portrait alike.",
5
+ "requires": ["mark"],
6
+ "params": {
7
+ "name": "Kestrel",
8
+ "meta": "Construction · v1.0",
9
+ "gridLabel": "",
10
+ "caption": "®",
11
+ "grid": 8,
12
+ "size": 0.58,
13
+ "ground": "#0b0b0c",
14
+ "ink": "#f2f1ec",
15
+ "accent": "#3b82f6"
16
+ },
17
+ "vars": {
18
+ "h": { "mul": [400, { "div": ["@height", "@width"] }] }
19
+ },
20
+ "layers": [
21
+ { "id": "ground", "type": "solid", "color": "{ground}" },
22
+ {
23
+ "id": "sheet",
24
+ "type": "group",
25
+ "viewBox": [0, 0, 400, "$h"],
26
+ "fit": "contain",
27
+ "layers": [
28
+ { "id": "construction", "type": "construction", "markup": "{mark}", "x": 16, "y": 40, "width": 368, "height": { "sub": ["$h", 80] }, "size": "{size}", "grid": "{grid}", "color": "{accent}", "markColor": "{ink}", "stroke": 0.55 },
29
+ { "id": "meta", "type": "text", "content": "{meta}", "when": "meta", "font": "Inter Tight", "weight": 500, "size": 7, "letterSpacing": 0, "x": 16, "y": 24, "maxWidth": 200, "maxLines": 1, "color": "{ink}" },
30
+ { "id": "name", "type": "text", "content": "{name}", "when": "name", "font": "Inter Tight", "weight": 600, "size": 7, "letterSpacing": 0, "x": 384, "y": 24, "align": "right", "maxWidth": 160, "maxLines": 1, "color": "{ink}" },
31
+ { "id": "gridLabel", "type": "text", "content": { "if": "gridLabel", "then": "{gridLabel}", "else": { "join": [["Grid ", "{grid}", " × ", "{grid}"], ""] } }, "when": { "any": ["gridLabel", "grid"] }, "font": "Inter Tight", "weight": 500, "size": 7, "letterSpacing": 0, "x": 16, "y": { "sub": ["$h", 18] }, "maxWidth": 200, "maxLines": 1, "color": "{ink}", "opacity": 0.6 },
32
+ { "id": "caption", "type": "text", "content": "{caption}", "when": "caption", "font": "Inter Tight", "weight": 500, "size": 9, "letterSpacing": 0, "x": 384, "y": { "sub": ["$h", 17] }, "align": "right", "maxWidth": 160, "maxLines": 1, "color": "{ink}" }
33
+ ]
34
+ }
35
+ ]
36
+ }
@@ -0,0 +1,95 @@
1
+ {
2
+ "$schema": "../../schema/recipe.schema.json",
3
+ "name": "fluted-poster",
4
+ "description": "Fluted glass poster: the mark (or the name, set huge) in white on black, seen through reeded glass (@logomarks/image-effects' fluted effect: by default its fluted preset for a mark, and gentler glass for the name, 12 wide convex ribs at light refraction (0.15) and little defocus, so the word steps at the rib edges but never doubles; a preset given, fluted, reeded-deep, reeded-prism or reeded-soft, is used as it is), with a soft light in one accent colour behind it (none with accent \"\"). Over the glass, small Swiss type stays vector: the year stacked large top-left, the series top-right, a two-line title bottom-left with a glitched || ornament of plain bars right of it in the accent, credits and an edition line along the foot. The glass is rastered at the output size and embedded; the type is outlines. Drawn on a 400-wide grid as tall as the canvas, so it sets at 4:5, 1:1, 9:16 and A-series portrait alike; the ornament's glitch follows the seed.",
5
+ "params": {
6
+ "name": "Kestrel",
7
+ "subject": "mark",
8
+ "preset": "",
9
+ "title": ["Through", "the glass"],
10
+ "year": "2026",
11
+ "series": "",
12
+ "credits": "",
13
+ "edition": "Posters / Series 03",
14
+ "accent": "#ff4d1a",
15
+ "ground": "#000000",
16
+ "ink": "#ffffff"
17
+ },
18
+ "vars": {
19
+ "h": { "mul": [400, { "div": ["@height", "@width"] }] },
20
+ "bar": { "if": "accent", "then": "{accent}", "else": "{ink}" },
21
+ "tall": { "min": [2, { "max": [1, { "div": ["$h", 380] }] }] },
22
+ "s1": { "range": [-3, 3] },
23
+ "s2": { "range": [-3, 3] },
24
+ "s3": { "range": [-3, 3] },
25
+ "cut": { "range": [0.3, 0.6] }
26
+ },
27
+ "layers": [
28
+ { "id": "ground", "type": "solid", "color": "{ground}" },
29
+ {
30
+ "id": "glass",
31
+ "type": "group",
32
+ "viewBox": [0, 0, 400, "$h"],
33
+ "fit": "contain",
34
+ "effects": [{ "kind": "fluted", "preset": { "if": "preset", "then": "{preset}", "else": "fluted" }, "profile": { "if": { "all": [{ "any": [{ "subject": "name" }, { "not": "mark" }] }, { "not": "preset" }] }, "then": "convex" }, "ribs": { "if": { "all": [{ "any": [{ "subject": "name" }, { "not": "mark" }] }, { "not": "preset" }] }, "then": 12 }, "refraction": { "if": { "all": [{ "any": [{ "subject": "name" }, { "not": "mark" }] }, { "not": "preset" }] }, "then": 0.15 }, "stretch": { "if": { "all": [{ "any": [{ "subject": "name" }, { "not": "mark" }] }, { "not": "preset" }] }, "then": "0.4vmin" }, "chroma": { "if": { "all": [{ "any": [{ "subject": "name" }, { "not": "mark" }] }, { "not": "preset" }] }, "then": 0.2 } }],
35
+ "layers": [
36
+ { "id": "light", "type": "radial", "when": "accent", "x": 0.5, "y": 0.47, "colors": ["{accent}", "{ground}"], "radius": "52vmin", "opacity": 0.75 },
37
+ { "id": "mark", "type": "outline", "when": { "all": ["mark", { "not": { "subject": "name" } }] }, "markup": "{mark}", "lines": 0, "x": 70, "y": { "sub": [{ "mul": ["$h", 0.47] }, 130] }, "width": 260, "height": 260, "color": "{ink}" },
38
+ {
39
+ "id": "word",
40
+ "type": "group",
41
+ "when": { "any": [{ "subject": "name" }, { "not": "mark" }] },
42
+ "transform": { "scale": [1, "$tall"], "origin": [200, { "mul": ["$h", 0.47] }] },
43
+ "layers": [
44
+ { "id": "name", "type": "text", "content": "{name}", "transform": "uppercase", "font": "Inter Tight", "weight": 800, "size": 120, "lineHeight": 0.9, "letterSpacing": -0.05, "fit": "width", "maxWidth": 360, "maxHeight": { "div": [{ "mul": ["$h", 0.42] }, "$tall"] }, "anchor": "center", "margin": 0, "offset": { "x": 0, "y": { "mul": ["$h", -0.03] } }, "color": "{ink}" }
45
+ ]
46
+ }
47
+ ]
48
+ },
49
+ {
50
+ "id": "type",
51
+ "type": "group",
52
+ "viewBox": [0, 0, 400, "$h"],
53
+ "fit": "contain",
54
+ "layers": [
55
+ { "id": "year", "type": "text", "when": "year", "content": [{ "slice": ["{year}", 0, 2] }, { "slice": ["{year}", 2] }], "font": "Inter Tight", "weight": 700, "size": 26, "lineHeight": 0.86, "letterSpacing": -0.04, "x": 15, "y": 36, "color": "{ink}" },
56
+ { "id": "series", "type": "text", "content": { "if": "series", "then": "{series}", "else": "{name}\nGlass series" }, "font": "Inter Tight", "weight": 500, "size": 7, "lineHeight": 1.25, "letterSpacing": 0, "x": 384, "y": 24, "align": "right", "maxWidth": 140, "maxLines": 3, "color": "{ink}" },
57
+ {
58
+ "id": "title",
59
+ "type": "text",
60
+ "content": "{title}",
61
+ "when": "title",
62
+ "transform": "uppercase",
63
+ "font": "Inter Tight",
64
+ "weight": 700,
65
+ "size": 24,
66
+ "lineHeight": 0.92,
67
+ "letterSpacing": -0.035,
68
+ "fit": "shrink",
69
+ "maxWidth": 300,
70
+ "maxLines": 2,
71
+ "anchor": "bottom-left",
72
+ "margin": 0,
73
+ "offset": { "x": 15, "y": -46 },
74
+ "color": "{ink}"
75
+ },
76
+ {
77
+ "id": "ornament",
78
+ "type": "shape",
79
+ "fill": "$bar",
80
+ "items": [
81
+ { "kind": "rect", "x": 362, "y": { "sub": ["$h", 90] }, "width": 5, "height": { "mul": [44, "$cut"] } },
82
+ { "kind": "rect", "x": { "add": [362, "$s1"] }, "y": { "add": [{ "sub": ["$h", 90] }, { "mul": [44, "$cut"] }, 1.5] }, "width": 5, "height": 5 },
83
+ { "kind": "rect", "x": 362, "y": { "add": [{ "sub": ["$h", 90] }, { "mul": [44, "$cut"] }, 8] }, "width": 5, "height": { "sub": [36, { "mul": [44, "$cut"] }] } },
84
+ { "kind": "rect", "x": 375, "y": { "sub": ["$h", 90] }, "width": 5, "height": { "sub": [36, { "mul": [44, "$cut"] }] } },
85
+ { "kind": "rect", "x": { "add": [375, "$s2"] }, "y": { "add": [{ "sub": ["$h", 90] }, { "sub": [36, { "mul": [44, "$cut"] }] }, 1.5] }, "width": 5, "height": 5 },
86
+ { "kind": "rect", "x": { "add": [375, { "mul": ["$s3", 0.5] }] }, "y": { "add": [{ "sub": ["$h", 90] }, { "sub": [36, { "mul": [44, "$cut"] }] }, 8] }, "width": 5, "height": { "mul": [44, "$cut"] } }
87
+ ]
88
+ },
89
+ { "id": "credits", "type": "text", "content": { "if": "credits", "then": "{credits}", "else": "Design — {name}\nSet in Inter Tight" }, "font": "Inter Tight", "weight": 500, "size": 6.5, "lineHeight": 1.3, "letterSpacing": 0, "x": 16, "y": { "sub": ["$h", 27] }, "maxWidth": 180, "maxLines": 2, "color": "{ink}", "opacity": 0.72 },
90
+ { "id": "edition", "type": "text", "content": "{edition}", "when": "edition", "font": "Inter Tight", "weight": 500, "size": 6.5, "letterSpacing": 0, "x": 384, "y": { "sub": ["$h", 18.5] }, "align": "right", "maxWidth": 180, "maxLines": 1, "color": "{ink}", "opacity": 0.72 }
91
+ ]
92
+ },
93
+ { "id": "print", "type": "grain", "amount": 0.035, "size": 1.5 }
94
+ ]
95
+ }
@@ -0,0 +1,81 @@
1
+ {
2
+ "$schema": "../../schema/recipe.schema.json",
3
+ "name": "series-card",
4
+ "description": "Numbered series card, for a run of posts: one flat soft colour, a two-line uppercase title top-left, a large number bottom-left (\"01\"), and the mark large in the space left, solid or as contour lines (its outline and three to five more drawn round it, gap apart, merging where its parts meet). Set number and ground per post and keep the rest, and ten of them read as one series across a palette. An optional label top-right. Drawn on a 400-wide grid as tall as the canvas, so it sets at 1:1, 4:5, 9:16 and A-series portrait alike.",
5
+ "params": {
6
+ "title": ["Everything", "is connected"],
7
+ "number": "01",
8
+ "label": "",
9
+ "style": "contour",
10
+ "lines": 4,
11
+ "gap": 0.055,
12
+ "ground": "#f3c9b8",
13
+ "ink": "#1c1b19"
14
+ },
15
+ "vars": {
16
+ "h": { "mul": [400, { "div": ["@height", "@width"] }] }
17
+ },
18
+ "layers": [
19
+ { "id": "ground", "type": "solid", "color": "{ground}" },
20
+ {
21
+ "id": "card",
22
+ "type": "group",
23
+ "viewBox": [0, 0, 400, "$h"],
24
+ "fit": "contain",
25
+ "layers": [
26
+ {
27
+ "id": "mark",
28
+ "type": "outline",
29
+ "when": "mark",
30
+ "markup": "{mark}",
31
+ "lines": { "if": { "style": "solid" }, "then": 0, "else": "{lines}" },
32
+ "gap": "{gap}",
33
+ "stroke": 1.15,
34
+ "x": 124,
35
+ "y": 84,
36
+ "width": 260,
37
+ "height": { "sub": ["$h", 100] },
38
+ "color": "{ink}"
39
+ },
40
+ {
41
+ "id": "title",
42
+ "type": "text",
43
+ "content": "{title}",
44
+ "when": "title",
45
+ "transform": "uppercase",
46
+ "font": "Inter Tight",
47
+ "weight": 700,
48
+ "size": 21,
49
+ "lineHeight": 0.95,
50
+ "letterSpacing": -0.025,
51
+ "fit": "shrink",
52
+ "maxWidth": 250,
53
+ "maxLines": 2,
54
+ "anchor": "top-left",
55
+ "margin": 0,
56
+ "offset": { "x": 18, "y": 20 },
57
+ "color": "{ink}"
58
+ },
59
+ { "id": "label", "type": "text", "content": "{label}", "when": "label", "font": "Inter Tight", "weight": 500, "size": 7, "letterSpacing": 0, "x": 382, "y": 27, "align": "right", "maxWidth": 110, "maxLines": 2, "color": "{ink}" },
60
+ {
61
+ "id": "number",
62
+ "type": "text",
63
+ "content": "{number}",
64
+ "when": "number",
65
+ "font": "Inter Tight",
66
+ "weight": 600,
67
+ "size": 92,
68
+ "lineHeight": 0.8,
69
+ "letterSpacing": -0.06,
70
+ "fit": "shrink",
71
+ "maxWidth": 104,
72
+ "maxLines": 1,
73
+ "anchor": "bottom-left",
74
+ "margin": 0,
75
+ "offset": { "x": 14, "y": -16 },
76
+ "color": "{ink}"
77
+ }
78
+ ]
79
+ }
80
+ ]
81
+ }