Skip to content

Commit f457723

Browse files
seanhancaseanhancaclaude
authored
feat: RFC #9 decorative primitives + 4 new Life-in-Glyph pages (#81)
## Summary - **RFC #9** adds gradient/pattern defs, starfield, glow, silhouette-path, icon library (10 icons), ellipse, polygon, polyline, raw-svg escape hatch to the compose grammar. - **4 new Life-in-Glyph pages** — greenfield bio + engineering scenes using only RFC #9 features (no hand-authored SVG). Existing 8 heroes untouched. ## New pages | URL | What it draws | |---|---| | `draw-me-dna.html` | DNA double helix (gradients, silhouette-paths, polyline rungs, starfield, glow) | | `draw-me-jellyfish.html` | Aurelia aurita (radial gradients, scalloped bell, 7 tentacle sines, ellipse, star icons, plankton) | | `draw-me-hydraulic.html` | Pascal's press in pencil-on-parchment (pattern fluid, U-tube, 2 frames, annotation leaders) | | `draw-me-windmill.html` | Dutch tower mill with rotating blades (stone pattern, 4 polygons + rotate-loop, gradient sky/ground) | ## Test plan - [x] All 683 tests pass - [x] 4 new compose scenes locked via toMatchFileSnapshot - [x] Visual QA of each rendered SVG confirmed publication-quality - [ ] Once deployed: verify all 4 new pages render correctly on GitHub Pages - [ ] Verify gallery shows 12 cards (6 + 6) - [ ] Verify the 8 existing heroes are visually unchanged 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: seanhanca <infraservice@livepeer.org> Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent a620973 commit f457723

28 files changed

Lines changed: 7169 additions & 31 deletions

docs/superpowers/plans/2026-05-23-compose-visual-parity.md

Lines changed: 1110 additions & 0 deletions
Large diffs are not rendered by default.

packages/core/__fixtures__/compose/bio-dna.json

Lines changed: 801 additions & 0 deletions
Large diffs are not rendered by default.
Lines changed: 1 addition & 0 deletions
Loading
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
/**
2+
* Bio + Engineering showcases extending Life in Glyph (without touching
3+
* any of the existing 8 hand-authored heroes). Each fixture exercises
4+
* the RFC #9 decorative primitives (gradients, patterns, starfield,
5+
* glow, silhouette-path, icon, ellipse, polygon, polyline, raw-svg)
6+
* to test whether the compose grammar can match the quality bar the
7+
* hand-authored heroes set.
8+
*
9+
* Asserts byte-stability + key SVG constructs per scene. Snapshots are
10+
* locked in `.svg` siblings.
11+
*/
12+
import { readFileSync } from "node:fs";
13+
import { fileURLToPath } from "node:url";
14+
import { describe, expect, it } from "vitest";
15+
import { compileCompose } from "../../src/compiler/compose.js";
16+
import { renderSvg } from "../../src/render/svg.js";
17+
import { parseComposeSpec } from "../../src/spec/compose-schema.js";
18+
19+
interface Scene {
20+
label: string;
21+
file: string;
22+
expects: string[];
23+
}
24+
25+
const scenes: Scene[] = [
26+
{
27+
label: "bio · DNA helix",
28+
file: "./bio-dna.json",
29+
expects: [
30+
'id="g-strand-a"',
31+
'id="g-strand-b"',
32+
'stroke="url(#g-strand-a)"',
33+
'stroke="url(#g-strand-b)"',
34+
"<defs>",
35+
"<polyline",
36+
"Deoxyribonucleic",
37+
],
38+
},
39+
{
40+
label: "bio · jellyfish",
41+
file: "./bio-jellyfish.json",
42+
expects: [
43+
'id="g-bell"',
44+
'id="g-tentacle"',
45+
"<ellipse",
46+
"Aurelia aurita",
47+
"<circle ",
48+
],
49+
},
50+
{
51+
label: "eng · hydraulic press",
52+
file: "./eng-hydraulic.json",
53+
expects: [
54+
'id="p-fluid"',
55+
'id="p-piston"',
56+
"<pattern",
57+
'fill="url(#p-fluid)"',
58+
"A₁",
59+
"A₂",
60+
"Pressure equalizes",
61+
],
62+
},
63+
{
64+
label: "eng · windmill",
65+
file: "./eng-windmill.json",
66+
expects: [
67+
'id="p-stone"',
68+
'id="g-sky"',
69+
'id="g-sun"',
70+
"<polygon",
71+
"<ellipse",
72+
'<animateTransform attributeName="transform" type="rotate"',
73+
"Netherlands",
74+
],
75+
},
76+
];
77+
78+
describe("compose — bio + engineering RFC #9 showcases", () => {
79+
for (const scene of scenes) {
80+
it(`renders ${scene.label} deterministically`, async () => {
81+
const url = new URL(scene.file, import.meta.url);
82+
const raw = JSON.parse(readFileSync(fileURLToPath(url), "utf8"));
83+
const spec = parseComposeSpec(raw);
84+
const svg = renderSvg(compileCompose(spec));
85+
const svg2 = renderSvg(compileCompose(parseComposeSpec(raw)));
86+
expect(svg2).toBe(svg);
87+
for (const needle of scene.expects) {
88+
expect(svg, `expected to contain: ${needle}`).toContain(needle);
89+
}
90+
const snapshotPath = scene.file.replace(/\.json$/, ".svg");
91+
await expect(svg).toMatchFileSnapshot(snapshotPath);
92+
});
93+
}
94+
});

0 commit comments

Comments
 (0)