@skyf0xx/hedgehog 2.0.4 → 2.0.6
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/package.json +1 -1
- package/src/agents/landing-builder.md +10 -8
- package/src/agents/landing-copywriter.md +22 -1
- package/src/agents/landing-strategist.md +39 -7
- package/src/agents/landing-systems.md +23 -17
- package/src/golden-cores/landing-page/package.json +2 -1
- package/src/golden-cores/landing-page/pnpm-lock.yaml +118 -7
- package/src/skills/hedgehog-bootstrap-landing-page-core/SKILL.md +10 -18
- package/src/skills/hedgehog-landing-loop/SKILL.md +0 -3
- package/src/skills/motif-authoring/SKILL.md +127 -0
- package/src/templates/CLAUDE.core.landing-page.md +31 -19
- package/src/skills/svg-motif-authoring/SKILL.md +0 -88
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: landing-builder
|
|
3
|
-
description: Use for the build phase of the Chain Method (landing-page core) — implementing the audited spec exactly in Astro, Tailwind, GSAP/ScrollTrigger/Lenis, SplitType, and
|
|
3
|
+
description: Use for the build phase of the Chain Method (landing-page core) — implementing the audited spec exactly in Astro, Tailwind, GSAP/ScrollTrigger/Lenis, SplitType, and the p5.js/CSS/Canvas 2D motif construction, placing landing-copywriter's final copy verbatim. Runs last, only after landing-critic returns a pass. Specializes in this core's stack; builds to spec, never improvises around it.
|
|
4
4
|
model: sonnet
|
|
5
5
|
color: green
|
|
6
6
|
tools: Read, Glob, Grep, Edit, Write, Bash
|
|
@@ -28,18 +28,20 @@ never silently improvised around.
|
|
|
28
28
|
gap in the token system, flagged back to `landing-systems`, not
|
|
29
29
|
invented locally.
|
|
30
30
|
- **GSAP + ScrollTrigger** — implement `landing-sequencer`'s pacing spec:
|
|
31
|
-
section transitions, timing.
|
|
32
|
-
|
|
33
|
-
|
|
31
|
+
section transitions, timing. Scoped to CSS/transform targets only, no
|
|
32
|
+
plugins — a `border-radius` string tween replaces shape-morphing, for
|
|
33
|
+
example.
|
|
34
34
|
- **Lenis** — wire smooth-scroll globally, matching the beat structure
|
|
35
35
|
`landing-sequencer` specified.
|
|
36
36
|
- **SplitType** — implement copy-reveal splitting exactly where
|
|
37
37
|
`landing-sequencer`'s beat structure calls for it, not on every section
|
|
38
38
|
by default.
|
|
39
|
-
- **
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
39
|
+
- **p5.js / CSS / Canvas 2D** — implement the motif from `src/motifs/`
|
|
40
|
+
exactly as `landing-systems` specified (source, persistence,
|
|
41
|
+
continuity, scale range, literalness), using whichever construction
|
|
42
|
+
technique the spec calls for (p5.js for organic/generative, CSS for
|
|
43
|
+
static geometric, Canvas 2D for measured/connective) — don't simplify
|
|
44
|
+
or embellish it during implementation.
|
|
43
45
|
- **React Three Fiber** — only if the subject is genuinely spatial and
|
|
44
46
|
`landing-systems`/`landing-sequencer` specified it; otherwise never
|
|
45
47
|
reach for it.
|
|
@@ -93,7 +93,18 @@ directly while writing, not as a pass after:
|
|
|
93
93
|
`landing-systems`'s voice spec and token system, `landing-sequencer`'s
|
|
94
94
|
section list and beat structure — not a summary of any of them.
|
|
95
95
|
2. Write the headline plus 2 backups, each usable against the subject
|
|
96
|
-
statement's single job.
|
|
96
|
+
statement's single job. **The reader wants an outcome, not the
|
|
97
|
+
mechanism that produces it** — the headline's grammatical subject must
|
|
98
|
+
be what the reader gets (what changes for them, what they now have or
|
|
99
|
+
no longer have to worry about), not the product, feature, or mechanism
|
|
100
|
+
that delivers it. A headline built from the subject statement's own
|
|
101
|
+
phrasing ("ZenBin is one cryptographic trust primitive...") tends to
|
|
102
|
+
smuggle the mechanism into the subject position by default — naming it
|
|
103
|
+
is not the same as leading with it. Demote the mechanism one level: it
|
|
104
|
+
belongs in the subhead or the sentence right after, earning its
|
|
105
|
+
specificity once the outcome has already landed. If a backup headline
|
|
106
|
+
only works because the reader already knows what the mechanism is
|
|
107
|
+
for, it's failing this test, not passing it narrowly.
|
|
97
108
|
3. Write each section's copy in `landing-sequencer`'s order, to its
|
|
98
109
|
assigned beat.
|
|
99
110
|
4. Write CTA text, checked against the token system's CTA styling intent
|
|
@@ -119,6 +130,16 @@ directly while writing, not as a pass after:
|
|
|
119
130
|
- The headline and every section trace to a named adjective or the
|
|
120
131
|
subject statement — a line that could run on a competitor's page
|
|
121
132
|
unchanged (the swap test, applied to copy specifically) gets rewritten.
|
|
133
|
+
- **The headline's subject is the reader's outcome, not the mechanism.**
|
|
134
|
+
Read only the headline, with no subhead for context: does it state
|
|
135
|
+
what the reader gets, or does it name the thing that gets it to them?
|
|
136
|
+
"One signature. Three uses." fails this (the signature is the
|
|
137
|
+
subject); "Your agent's work outlives the session that made it."
|
|
138
|
+
passes (the outcome is the subject, and "signature" doesn't need to
|
|
139
|
+
appear at all). If the headline's first noun phrase is the product,
|
|
140
|
+
the feature, or the underlying mechanism rather than the change in the
|
|
141
|
+
reader's situation, rewrite it before presenting — don't let it pass
|
|
142
|
+
because it's otherwise on-voice and traceable.
|
|
122
143
|
|
|
123
144
|
## Constraints
|
|
124
145
|
|
|
@@ -27,7 +27,8 @@ literally.
|
|
|
27
27
|
|
|
28
28
|
**In:** raw brief (from `planner`'s planning intake,
|
|
29
29
|
`.hedgehog/chain/00-brief.md`)
|
|
30
|
-
**Out:** one-paragraph subject/audience/job statement
|
|
30
|
+
**Out:** one-paragraph subject/audience/job statement, confirmed by the
|
|
31
|
+
user before Step 2 starts
|
|
31
32
|
|
|
32
33
|
Name the concrete subject, its audience, and the page's single job. If
|
|
33
34
|
the brief doesn't pin this down, state the assumption explicitly rather
|
|
@@ -35,6 +36,28 @@ than proceeding on vagueness — an unstated assumption here is the single
|
|
|
35
36
|
most expensive thing to get wrong, since every later phase inherits it
|
|
36
37
|
silently.
|
|
37
38
|
|
|
39
|
+
**Plain-verb check (run before presenting the statement):** restate the
|
|
40
|
+
subject in one sentence using only the concrete verb a builder would use
|
|
41
|
+
describing it out loud — no abstraction noun ("primitive," "mechanism,"
|
|
42
|
+
"infrastructure layer") standing in for the verb. If that plain-verb
|
|
43
|
+
sentence doesn't foreground the same verb as the formal subject
|
|
44
|
+
statement, the statement has already been abstracted past what the user
|
|
45
|
+
actually said — tighten it, or if there's a genuine choice between
|
|
46
|
+
leading with the action versus the mechanism behind it, that's not yours
|
|
47
|
+
to resolve silently.
|
|
48
|
+
|
|
49
|
+
**Confirm the statement before Step 2.** Show the user the subject/
|
|
50
|
+
audience/job statement in plain language — not the finished prose, the
|
|
51
|
+
one-line "here's the big idea" version — and get explicit go-ahead before
|
|
52
|
+
any adjective work is built on it. This is a hard stop, the same weight
|
|
53
|
+
as planning intake's own Confirm & Lock: every phase from here through
|
|
54
|
+
`landing-copywriter` inherits this framing silently, and by the time
|
|
55
|
+
copy is reviewed at phase 9, correcting the framing means unwinding
|
|
56
|
+
multiple committed phases via the Correction Protocol instead of one
|
|
57
|
+
quick revision now. A revision at this point is just another pass at
|
|
58
|
+
Step 1, not a Correction Protocol entry, since nothing downstream exists
|
|
59
|
+
yet.
|
|
60
|
+
|
|
38
61
|
### Step 2 — Brand Anthropologist
|
|
39
62
|
|
|
40
63
|
**In:** subject statement
|
|
@@ -84,15 +107,24 @@ adjective is meant to fade rather than hold constant throughout the page.
|
|
|
84
107
|
1. Read `.hedgehog/chain/00-brief.md` (written by `planner` at planning
|
|
85
108
|
intake). If it's missing or thin, stop and flag it back — you don't
|
|
86
109
|
re-run planning intake yourself.
|
|
87
|
-
2. Run step 1 (subject/audience/job).
|
|
88
|
-
3.
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
110
|
+
2. Run step 1 (subject/audience/job), including its plain-verb check.
|
|
111
|
+
3. **Confirm step 1's statement with the user. Wait for explicit
|
|
112
|
+
go-ahead before proceeding to step 2** — this is a hard stop, not a
|
|
113
|
+
formality; nothing downstream exists yet, so a revision here is free.
|
|
114
|
+
4. Run steps 2–3 (Brand Anthropologist, Psychologist), informed by the
|
|
115
|
+
confirmed subject statement.
|
|
116
|
+
5. Run step 4c (Perfumer) against the completed sort from step 3.
|
|
117
|
+
6. Self-test (below) before presenting the combined artifact.
|
|
118
|
+
7. Commit the combined artifact as `feat(landing): strategy`.
|
|
93
119
|
|
|
94
120
|
## Self-test
|
|
95
121
|
|
|
122
|
+
- The subject statement was confirmed by the user before step 2 started
|
|
123
|
+
— not drafted and assumed. If it wasn't, stop now and go back for
|
|
124
|
+
confirmation rather than letting adjective work compound on an
|
|
125
|
+
unconfirmed framing.
|
|
126
|
+
- The plain-verb check was run and passed (or the framing choice — action
|
|
127
|
+
vs. mechanism — was put to the user explicitly, not resolved silently).
|
|
96
128
|
- Every adjective has a named opposite. An adjective without one isn't
|
|
97
129
|
falsifiable — send it back through step 2.
|
|
98
130
|
- Every adjective is sorted into exactly one of visceral/behavioral/
|
|
@@ -21,14 +21,19 @@ values and the signature motif.
|
|
|
21
21
|
block in `src/styles/global.css` (Tailwind v4, CSS-first — no
|
|
22
22
|
`tailwind.config.js`). No component classes, no plugin beyond the
|
|
23
23
|
base.
|
|
24
|
-
- **
|
|
25
|
-
|
|
26
|
-
- **
|
|
27
|
-
|
|
28
|
-
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
24
|
+
- **Motif construction** is picked per motif type, never hand-typed
|
|
25
|
+
coordinates:
|
|
26
|
+
- **p5.js** for an organic/generative motif — described as a rule
|
|
27
|
+
(noise, jitter, growth) rather than freehand path data.
|
|
28
|
+
- **CSS** (`clip-path` / gradients / `border-radius`) for a static
|
|
29
|
+
geometric motif — spines, chevrons, blobs — directly GSAP-animatable.
|
|
30
|
+
- **Canvas 2D with computed coordinates** for a measured/connective
|
|
31
|
+
motif — threads/lines that align to real DOM positions, drawn from
|
|
32
|
+
measured values, not imagined ones.
|
|
33
|
+
- This core has no design-handoff tool. Every token, dial, and motif
|
|
34
|
+
choice is derived directly from `landing-strategist`'s emotional
|
|
35
|
+
target and your own reconciliation at step 5 — never imported from an
|
|
36
|
+
external design file.
|
|
32
37
|
|
|
33
38
|
## Core Responsibilities
|
|
34
39
|
|
|
@@ -153,13 +158,16 @@ Borrowed technique:
|
|
|
153
158
|
retrograde) for exactly how the motif is allowed to evolve as it
|
|
154
159
|
recurs, rather than repeating identically or mutating arbitrarily
|
|
155
160
|
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
`
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
161
|
+
Pick the construction technique from what the motif actually is, not by
|
|
162
|
+
default: a p5.js sketch (driven by a formula — noise, jitter, growth) for
|
|
163
|
+
an organic motif that needs to evolve programmatically across sections; a
|
|
164
|
+
CSS-only treatment (`clip-path`, gradients, `border-radius`) for a static
|
|
165
|
+
geometric shape; Canvas 2D driven by measured DOM coordinates for a motif
|
|
166
|
+
that threads/connects across real element positions. Output the result
|
|
167
|
+
into `src/motifs/`. Use the `motif-authoring` skill for the actual
|
|
168
|
+
construction: build from a formula, a measurement, or a small set of
|
|
169
|
+
deliberate CSS primitives — never a hand-typed freehand coordinate — that's
|
|
170
|
+
the difference between a sourced motif and generic clip-art geometry.
|
|
163
171
|
|
|
164
172
|
## Workflow
|
|
165
173
|
|
|
@@ -200,8 +208,6 @@ generic clip-art geometry.
|
|
|
200
208
|
decorative asset to fill a gap — that gap is a signal to go back to the
|
|
201
209
|
Ingredient Vocabulary and derive the right choice, not to default to
|
|
202
210
|
something off-the-shelf.
|
|
203
|
-
- Figma/Stitch MCP output, if used, is never copied through as final
|
|
204
|
-
token values — always re-derived through step 5's reconciliation.
|
|
205
211
|
- Don't write section layout, pacing, or transitions — that's
|
|
206
212
|
`landing-sequencer`'s step 7, working from your token system.
|
|
207
213
|
- Don't touch `src/pages/`, `src/sections/` beyond what's needed to
|
|
@@ -20,9 +20,12 @@ importers:
|
|
|
20
20
|
lenis:
|
|
21
21
|
specifier: ^1.3.25
|
|
22
22
|
version: 1.3.25
|
|
23
|
-
|
|
24
|
-
specifier: ^0.
|
|
25
|
-
version: 0.
|
|
23
|
+
ogl:
|
|
24
|
+
specifier: ^1.0.11
|
|
25
|
+
version: 1.0.11
|
|
26
|
+
p5:
|
|
27
|
+
specifier: ^2.3.1
|
|
28
|
+
version: 2.3.1
|
|
26
29
|
split-type:
|
|
27
30
|
specifier: ^0.3.4
|
|
28
31
|
version: 0.3.4
|
|
@@ -175,6 +178,10 @@ packages:
|
|
|
175
178
|
engines: {node: '>=6.0.0'}
|
|
176
179
|
hasBin: true
|
|
177
180
|
|
|
181
|
+
'@babel/runtime@7.29.7':
|
|
182
|
+
resolution: {integrity: sha512-Nq8OhGWiZIZGV6hLHoyAKLLcJihP/xFeBMGJoUrxTX2psI8dCifzLhZISFb+VWS3wFMRDmCGw5R+dOySCqPLhw==}
|
|
183
|
+
engines: {node: '>=6.9.0'}
|
|
184
|
+
|
|
178
185
|
'@babel/types@7.29.7':
|
|
179
186
|
resolution: {integrity: sha512-4zBIxpPzowiZpusoFkyGVwakdRJUyuH5PxQ/PrqghfdFWWasvnCdPfQXHrenDai+gyLARulZjZowCOj6fjT4pA==}
|
|
180
187
|
engines: {node: '>=6.9.0'}
|
|
@@ -236,6 +243,9 @@ packages:
|
|
|
236
243
|
resolution: {integrity: sha512-y7/yvZ2TPAnR9+jnc00klvNNLkJiXFFrQA/hlLCcxA9a2A4zQIOimyFQ9XfwYKiGD1fb5GY8vbKIIgO8d5Tb2A==}
|
|
237
244
|
engines: {node: '>= 20.12.0'}
|
|
238
245
|
|
|
246
|
+
'@davepagurek/bezier-path@0.0.7':
|
|
247
|
+
resolution: {integrity: sha512-CVlnCOrV1iy4Z12T756i9l4G6kF7r8uhlnb+xqDemAMmWQB+8Q0b+8VEqIiUfywgZDSiDr18Rm7pZlnA69rE8Q==}
|
|
248
|
+
|
|
239
249
|
'@emmetio/abbreviation@2.3.3':
|
|
240
250
|
resolution: {integrity: sha512-mgv58UrU3rh4YgbE/TzgLQwJ3pFsHHhCLqY20aJq+9comytTXUDNGG/SMtSeMJdkpxgXSXunBGLD8Boka3JyVA==}
|
|
241
251
|
|
|
@@ -621,6 +631,9 @@ packages:
|
|
|
621
631
|
cpu: [x64]
|
|
622
632
|
os: [win32]
|
|
623
633
|
|
|
634
|
+
'@japont/unicode-range@1.0.0':
|
|
635
|
+
resolution: {integrity: sha512-BckHvA2XdjRBVAWe2uceNuRf78lBeI28kyWEbfr/Q2pE17POkwuZ6WWY/UMv8FL9iBxhW4xfDoNLM9UVZaTeUQ==}
|
|
636
|
+
|
|
624
637
|
'@jridgewell/gen-mapping@0.3.13':
|
|
625
638
|
resolution: {integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==}
|
|
626
639
|
|
|
@@ -991,6 +1004,10 @@ packages:
|
|
|
991
1004
|
peerDependencies:
|
|
992
1005
|
acorn: ^6.0.0 || ^7.0.0 || ^8.0.0
|
|
993
1006
|
|
|
1007
|
+
acorn-walk@8.3.5:
|
|
1008
|
+
resolution: {integrity: sha512-HEHNfbars9v4pgpW6SO1KSPkfoS0xVOM/9UzkJltjlsHZmJasxg8aXkuZa7SMf8vKGIBhpUsPluQSqhJFCqebw==}
|
|
1009
|
+
engines: {node: '>=0.4.0'}
|
|
1010
|
+
|
|
994
1011
|
acorn@8.17.0:
|
|
995
1012
|
resolution: {integrity: sha512-xRQbDb9BnwDafYNn6Vwl839DYVjqXYb1XVGtWAZ1kcDc6iwAL4hg3B1dZlRiuENFeO2H53gFG3in621AdERVAg==}
|
|
996
1013
|
engines: {node: '>=0.4.0'}
|
|
@@ -1106,6 +1123,9 @@ packages:
|
|
|
1106
1123
|
color-name@1.1.4:
|
|
1107
1124
|
resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==}
|
|
1108
1125
|
|
|
1126
|
+
colorjs.io@0.6.1:
|
|
1127
|
+
resolution: {integrity: sha512-8lyR2wHzuIykCpqHKgluGsqQi5iDm3/a2IgP2GBZrasn2sBRkE4NOGsglZxWLs/jZQoNkmA/KM/8NV16rLUdBg==}
|
|
1128
|
+
|
|
1109
1129
|
comma-separated-tokens@2.0.3:
|
|
1110
1130
|
resolution: {integrity: sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg==}
|
|
1111
1131
|
|
|
@@ -1242,6 +1262,11 @@ packages:
|
|
|
1242
1262
|
resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==}
|
|
1243
1263
|
engines: {node: '>=10'}
|
|
1244
1264
|
|
|
1265
|
+
escodegen@2.1.0:
|
|
1266
|
+
resolution: {integrity: sha512-2NlIDTwUWJN0mRPQOdtQBzbUHvdGY2P1VXSyU83Q3xKxM7WHX2Ql8dKq782Q9TgQUNOLEzEYu9bzLNj1q88I5w==}
|
|
1267
|
+
engines: {node: '>=6.0'}
|
|
1268
|
+
hasBin: true
|
|
1269
|
+
|
|
1245
1270
|
eslint-plugin-astro@3.0.1:
|
|
1246
1271
|
resolution: {integrity: sha512-skys0KV/5m/rQ6a4BDAGOGtrGoBlWNYiWtoDjx25bghDwTiKXng63s4Yv823iX3ht/tH/kHtoUM2poxESGsv3w==}
|
|
1247
1272
|
engines: {node: ^22.22.3 || ^24.16.0 || >=26.3.0}
|
|
@@ -1281,6 +1306,11 @@ packages:
|
|
|
1281
1306
|
resolution: {integrity: sha512-7p3DrVEIopW1B1avAGLuCSh1jubc01H2JHc8B4qqGblmg5gI9yumBgACjWo4JlIc04ufug4xJ3SQI8HkS/Rgzw==}
|
|
1282
1307
|
engines: {node: ^20.19.0 || ^22.13.0 || >=24}
|
|
1283
1308
|
|
|
1309
|
+
esprima@4.0.1:
|
|
1310
|
+
resolution: {integrity: sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==}
|
|
1311
|
+
engines: {node: '>=4'}
|
|
1312
|
+
hasBin: true
|
|
1313
|
+
|
|
1284
1314
|
esquery@1.7.0:
|
|
1285
1315
|
resolution: {integrity: sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g==}
|
|
1286
1316
|
engines: {node: '>=0.10'}
|
|
@@ -1375,6 +1405,9 @@ packages:
|
|
|
1375
1405
|
resolution: {integrity: sha512-7nF7C9fIPFEMHgEMEfgIlO9wDdZ8CyHw27rWciFZfHvHDReIiPhsYuzPRXsfvBCqFy1l8RRyyWV7QLM+ZhUJsQ==}
|
|
1376
1406
|
engines: {node: '>=20.20.0'}
|
|
1377
1407
|
|
|
1408
|
+
gifenc@1.0.3:
|
|
1409
|
+
resolution: {integrity: sha512-xdr6AdrfGBcfzncONUOlXMBuc5wJDtOueE3c5rdG0oNgtINLD+f2iFZltrBRZYzACRbKr+mSVU/x98zv2u3jmw==}
|
|
1410
|
+
|
|
1378
1411
|
github-slugger@2.0.0:
|
|
1379
1412
|
resolution: {integrity: sha512-IaOQ9puYtjrkq7Y0Ygl9KDZnrf/aiUJYUpVf89y8kyaxbRG7Y1SrX/jaumrv81vc61+kiMempujsM3Yw7w5qcw==}
|
|
1380
1413
|
|
|
@@ -1422,6 +1455,12 @@ packages:
|
|
|
1422
1455
|
http-cache-semantics@4.2.0:
|
|
1423
1456
|
resolution: {integrity: sha512-dTxcvPXqPvXBQpq5dUr6mEMJX4oIEFv6bwom3FDwKRDsuIjjJGANqhBuoAn9c1RQJIdAKav33ED65E2ys+87QQ==}
|
|
1424
1457
|
|
|
1458
|
+
i18next-browser-languagedetector@4.3.1:
|
|
1459
|
+
resolution: {integrity: sha512-KIToAzf8zwWvacgnRwJp63ase26o24AuNUlfNVJ5YZAFmdGhsJpmFClxXPuk9rv1FMI4lnc8zLSqgZPEZMrW4g==}
|
|
1460
|
+
|
|
1461
|
+
i18next@19.9.2:
|
|
1462
|
+
resolution: {integrity: sha512-0i6cuo6ER6usEOtKajUUDj92zlG+KArFia0857xxiEHAQcUwh/RtOQocui1LPJwunSYT574Pk64aNva1kwtxZg==}
|
|
1463
|
+
|
|
1425
1464
|
ignore@5.3.2:
|
|
1426
1465
|
resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==}
|
|
1427
1466
|
engines: {node: '>= 4'}
|
|
@@ -1512,6 +1551,9 @@ packages:
|
|
|
1512
1551
|
resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==}
|
|
1513
1552
|
engines: {node: '>= 0.8.0'}
|
|
1514
1553
|
|
|
1554
|
+
libtess@1.2.2:
|
|
1555
|
+
resolution: {integrity: sha512-Nps8HPeVVcsmJxUvFLKVJcCgcz+1ajPTXDVAVPs6+giOQP4AHV31uZFFkh+CKow/bkB7GbZWKmwmit7myaqDSw==}
|
|
1556
|
+
|
|
1515
1557
|
lightningcss-android-arm64@1.32.0:
|
|
1516
1558
|
resolution: {integrity: sha512-YK7/ClTt4kAK0vo6w3X+Pnm0D2cf2vPHbhOXdoNti1Ga0al1P4TBZhwjATvjNwLEBCnKvjJc2jQgHXH0NEwlAg==}
|
|
1517
1559
|
engines: {node: '>= 12.0.0'}
|
|
@@ -1739,9 +1781,15 @@ packages:
|
|
|
1739
1781
|
ofetch@1.5.1:
|
|
1740
1782
|
resolution: {integrity: sha512-2W4oUZlVaqAPAil6FUg/difl6YhqhUR7x2eZY4bQCko22UXg3hptq9KLQdqFClV+Wu85UX7hNtdGTngi/1BxcA==}
|
|
1741
1783
|
|
|
1784
|
+
ogl@1.0.11:
|
|
1785
|
+
resolution: {integrity: sha512-kUpC154AFfxi16pmZUK4jk3J+8zxwTWGPo03EoYA8QPbzikHoaC82n6pNTbd+oEaJonaE8aPWBlX7ad9zrqLsA==}
|
|
1786
|
+
|
|
1742
1787
|
ohash@2.0.11:
|
|
1743
1788
|
resolution: {integrity: sha512-RdR9FQrFwNBNXAr4GixM8YaRZRJ5PUWbKYbE5eOsrwAjJW0q2REGcf79oYPsLyskQCZG1PLN+S/K1V00joZAoQ==}
|
|
1744
1789
|
|
|
1790
|
+
omggif@1.0.10:
|
|
1791
|
+
resolution: {integrity: sha512-LMJTtvgc/nugXj0Vcrrs68Mn2D1r0zf630VNtqtpI1FEO7e+O9FP4gqs9AcnBaSEeoHIPm28u6qgPR0oyEpGSw==}
|
|
1792
|
+
|
|
1745
1793
|
oniguruma-parser@0.12.2:
|
|
1746
1794
|
resolution: {integrity: sha512-6HVa5oIrgMC6aA6WF6XyyqbhRPJrKR02L20+2+zpDtO5QAzGHAUGw5TKQvwi5vctNnRHkJYmjAhRVQF2EKdTQw==}
|
|
1747
1795
|
|
|
@@ -1772,12 +1820,14 @@ packages:
|
|
|
1772
1820
|
resolution: {integrity: sha512-AxTM2wDGORHGEkPCt8yqxOTMgpfbEHqF51f/5fJCmwFC3C/zNcGT63SymH2ttOAaiIws2zVg4+izQCjrakcwHg==}
|
|
1773
1821
|
engines: {node: '>=20'}
|
|
1774
1822
|
|
|
1823
|
+
p5@2.3.1:
|
|
1824
|
+
resolution: {integrity: sha512-YOzt3oP+xagNKtCiOfXK6EaEi4i7F4+5MNGFPUu6/yEJ1QhIsZQl1Tp/uYFNldi3Y0Uwmre997Ke0vDoFwBFBw==}
|
|
1825
|
+
|
|
1775
1826
|
package-manager-detector@1.8.0:
|
|
1776
1827
|
resolution: {integrity: sha512-yQA4H19AmPEoMUeavPMDIe1higySl/gH/yaQrkT/s07Qp+7pp2hYz30N3z2l5BkjVkF9Ow6o0wjJamm2y7Sn0A==}
|
|
1777
1828
|
|
|
1778
|
-
|
|
1779
|
-
resolution: {integrity: sha512-
|
|
1780
|
-
engines: {node: '>=8.0.0'}
|
|
1829
|
+
pako@2.2.0:
|
|
1830
|
+
resolution: {integrity: sha512-zJq6RP/5q+TO2OpFV3FHzlPnFjmkb7Nc99a5SNjJE+uu/PkpChs+NIZSSzbBoD+6kjiISXjfYdwj1ZRQ81dz/w==}
|
|
1781
1831
|
|
|
1782
1832
|
parse5@7.3.0:
|
|
1783
1833
|
resolution: {integrity: sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw==}
|
|
@@ -1993,6 +2043,10 @@ packages:
|
|
|
1993
2043
|
resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==}
|
|
1994
2044
|
engines: {node: '>=0.10.0'}
|
|
1995
2045
|
|
|
2046
|
+
source-map@0.6.1:
|
|
2047
|
+
resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==}
|
|
2048
|
+
engines: {node: '>=0.10.0'}
|
|
2049
|
+
|
|
1996
2050
|
space-separated-tokens@2.0.2:
|
|
1997
2051
|
resolution: {integrity: sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q==}
|
|
1998
2052
|
|
|
@@ -2530,6 +2584,8 @@ snapshots:
|
|
|
2530
2584
|
dependencies:
|
|
2531
2585
|
'@babel/types': 7.29.7
|
|
2532
2586
|
|
|
2587
|
+
'@babel/runtime@7.29.7': {}
|
|
2588
|
+
|
|
2533
2589
|
'@babel/types@7.29.7':
|
|
2534
2590
|
dependencies:
|
|
2535
2591
|
'@babel/helper-string-parser': 7.29.7
|
|
@@ -2582,6 +2638,8 @@ snapshots:
|
|
|
2582
2638
|
fast-wrap-ansi: 0.2.2
|
|
2583
2639
|
sisteransi: 1.0.5
|
|
2584
2640
|
|
|
2641
|
+
'@davepagurek/bezier-path@0.0.7': {}
|
|
2642
|
+
|
|
2585
2643
|
'@emmetio/abbreviation@2.3.3':
|
|
2586
2644
|
dependencies:
|
|
2587
2645
|
'@emmetio/scanner': 1.0.4
|
|
@@ -2857,6 +2915,8 @@ snapshots:
|
|
|
2857
2915
|
'@img/sharp-win32-x64@0.35.3':
|
|
2858
2916
|
optional: true
|
|
2859
2917
|
|
|
2918
|
+
'@japont/unicode-range@1.0.0': {}
|
|
2919
|
+
|
|
2860
2920
|
'@jridgewell/gen-mapping@0.3.13':
|
|
2861
2921
|
dependencies:
|
|
2862
2922
|
'@jridgewell/sourcemap-codec': 1.5.5
|
|
@@ -3228,6 +3288,10 @@ snapshots:
|
|
|
3228
3288
|
dependencies:
|
|
3229
3289
|
acorn: 8.17.0
|
|
3230
3290
|
|
|
3291
|
+
acorn-walk@8.3.5:
|
|
3292
|
+
dependencies:
|
|
3293
|
+
acorn: 8.17.0
|
|
3294
|
+
|
|
3231
3295
|
acorn@8.17.0: {}
|
|
3232
3296
|
|
|
3233
3297
|
ajv-draft-04@1.0.0(ajv@8.20.0):
|
|
@@ -3421,6 +3485,8 @@ snapshots:
|
|
|
3421
3485
|
|
|
3422
3486
|
color-name@1.1.4: {}
|
|
3423
3487
|
|
|
3488
|
+
colorjs.io@0.6.1: {}
|
|
3489
|
+
|
|
3424
3490
|
comma-separated-tokens@2.0.3: {}
|
|
3425
3491
|
|
|
3426
3492
|
commander@11.1.0: {}
|
|
@@ -3560,6 +3626,14 @@ snapshots:
|
|
|
3560
3626
|
|
|
3561
3627
|
escape-string-regexp@4.0.0: {}
|
|
3562
3628
|
|
|
3629
|
+
escodegen@2.1.0:
|
|
3630
|
+
dependencies:
|
|
3631
|
+
esprima: 4.0.1
|
|
3632
|
+
estraverse: 5.3.0
|
|
3633
|
+
esutils: 2.0.3
|
|
3634
|
+
optionalDependencies:
|
|
3635
|
+
source-map: 0.6.1
|
|
3636
|
+
|
|
3563
3637
|
eslint-plugin-astro@3.0.1(@emnapi/core@1.11.1)(@emnapi/runtime@1.11.1)(@typescript-eslint/parser@8.65.0(eslint@10.8.0(jiti@2.7.0))(typescript@5.9.3))(eslint@10.8.0(jiti@2.7.0)):
|
|
3564
3638
|
dependencies:
|
|
3565
3639
|
'@eslint-community/eslint-utils': 4.10.1(eslint@10.8.0(jiti@2.7.0))
|
|
@@ -3632,6 +3706,8 @@ snapshots:
|
|
|
3632
3706
|
acorn-jsx: 5.3.2(acorn@8.17.0)
|
|
3633
3707
|
eslint-visitor-keys: 5.0.1
|
|
3634
3708
|
|
|
3709
|
+
esprima@4.0.1: {}
|
|
3710
|
+
|
|
3635
3711
|
esquery@1.7.0:
|
|
3636
3712
|
dependencies:
|
|
3637
3713
|
estraverse: 5.3.0
|
|
@@ -3707,6 +3783,8 @@ snapshots:
|
|
|
3707
3783
|
dependencies:
|
|
3708
3784
|
resolve-pkg-maps: 1.0.0
|
|
3709
3785
|
|
|
3786
|
+
gifenc@1.0.3: {}
|
|
3787
|
+
|
|
3710
3788
|
github-slugger@2.0.0: {}
|
|
3711
3789
|
|
|
3712
3790
|
glob-parent@6.0.2:
|
|
@@ -3787,6 +3865,14 @@ snapshots:
|
|
|
3787
3865
|
|
|
3788
3866
|
http-cache-semantics@4.2.0: {}
|
|
3789
3867
|
|
|
3868
|
+
i18next-browser-languagedetector@4.3.1:
|
|
3869
|
+
dependencies:
|
|
3870
|
+
'@babel/runtime': 7.29.7
|
|
3871
|
+
|
|
3872
|
+
i18next@19.9.2:
|
|
3873
|
+
dependencies:
|
|
3874
|
+
'@babel/runtime': 7.29.7
|
|
3875
|
+
|
|
3790
3876
|
ignore@5.3.2: {}
|
|
3791
3877
|
|
|
3792
3878
|
ignore@7.0.6: {}
|
|
@@ -3840,6 +3926,8 @@ snapshots:
|
|
|
3840
3926
|
prelude-ls: 1.2.1
|
|
3841
3927
|
type-check: 0.4.0
|
|
3842
3928
|
|
|
3929
|
+
libtess@1.2.2: {}
|
|
3930
|
+
|
|
3843
3931
|
lightningcss-android-arm64@1.32.0:
|
|
3844
3932
|
optional: true
|
|
3845
3933
|
|
|
@@ -4025,8 +4113,12 @@ snapshots:
|
|
|
4025
4113
|
node-fetch-native: 1.6.7
|
|
4026
4114
|
ufo: 1.6.4
|
|
4027
4115
|
|
|
4116
|
+
ogl@1.0.11: {}
|
|
4117
|
+
|
|
4028
4118
|
ohash@2.0.11: {}
|
|
4029
4119
|
|
|
4120
|
+
omggif@1.0.10: {}
|
|
4121
|
+
|
|
4030
4122
|
oniguruma-parser@0.12.2: {}
|
|
4031
4123
|
|
|
4032
4124
|
oniguruma-to-es@4.3.6:
|
|
@@ -4063,9 +4155,25 @@ snapshots:
|
|
|
4063
4155
|
|
|
4064
4156
|
p-timeout@7.0.1: {}
|
|
4065
4157
|
|
|
4158
|
+
p5@2.3.1:
|
|
4159
|
+
dependencies:
|
|
4160
|
+
'@davepagurek/bezier-path': 0.0.7
|
|
4161
|
+
'@japont/unicode-range': 1.0.0
|
|
4162
|
+
acorn: 8.17.0
|
|
4163
|
+
acorn-walk: 8.3.5
|
|
4164
|
+
colorjs.io: 0.6.1
|
|
4165
|
+
escodegen: 2.1.0
|
|
4166
|
+
gifenc: 1.0.3
|
|
4167
|
+
i18next: 19.9.2
|
|
4168
|
+
i18next-browser-languagedetector: 4.3.1
|
|
4169
|
+
libtess: 1.2.2
|
|
4170
|
+
omggif: 1.0.10
|
|
4171
|
+
pako: 2.2.0
|
|
4172
|
+
zod: 4.4.3
|
|
4173
|
+
|
|
4066
4174
|
package-manager-detector@1.8.0: {}
|
|
4067
4175
|
|
|
4068
|
-
|
|
4176
|
+
pako@2.2.0: {}
|
|
4069
4177
|
|
|
4070
4178
|
parse5@7.3.0:
|
|
4071
4179
|
dependencies:
|
|
@@ -4256,6 +4364,9 @@ snapshots:
|
|
|
4256
4364
|
|
|
4257
4365
|
source-map-js@1.2.1: {}
|
|
4258
4366
|
|
|
4367
|
+
source-map@0.6.1:
|
|
4368
|
+
optional: true
|
|
4369
|
+
|
|
4259
4370
|
space-separated-tokens@2.0.2: {}
|
|
4260
4371
|
|
|
4261
4372
|
split-type@0.3.4: {}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: hedgehog-bootstrap-landing-page-core
|
|
3
|
-
description: Use once, at the start of a new Hedgehog project on the landing-page core, to land the pre-verified Astro + Tailwind workspace and verify it's green. Runs as the only move of the `bootstrap` agent on this core — there are no add-on steps, unlike full-stack-app. Invoked automatically by `planner` after Confirm & Lock.
|
|
3
|
+
description: Use once, at the start of a new Hedgehog project on the landing-page core, to land the pre-verified Astro + Tailwind v4 workspace and verify it's green. Runs as the only move of the `bootstrap` agent on this core — there are no add-on steps, unlike full-stack-app. Invoked automatically by `planner` after Confirm & Lock.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# Hedgehog Bootstrap — landing-page Core
|
|
@@ -9,8 +9,9 @@ Lands the whole of a `landing-page` project's workspace — there's no
|
|
|
9
9
|
add-on layer to run after it, unlike `full-stack-app`'s
|
|
10
10
|
`hedgehog-bootstrap` — by copying a pre-built, pre-verified workspace
|
|
11
11
|
(`src/golden-cores/landing-page/` in the Hedgehog package) rather than
|
|
12
|
-
generating it live: Astro workspace, Tailwind token-layer
|
|
13
|
-
library set this core is built on (GSAP, Lenis, SplitType,
|
|
12
|
+
generating it live: Astro workspace, Tailwind v4 CSS-first token-layer
|
|
13
|
+
config, the library set this core is built on (GSAP, Lenis, SplitType,
|
|
14
|
+
p5.js, ogl).
|
|
14
15
|
This piece is deterministic — the same commands produce the same output
|
|
15
16
|
on every project — so the output is committed once, upstream, and copied
|
|
16
17
|
here instead of re-derived by an agent on every run.
|
|
@@ -27,17 +28,15 @@ Hedgehog package, copied to the repo root:
|
|
|
27
28
|
- Root: `astro.config.mjs`, `package.json` (with the `dev` script —
|
|
28
29
|
`astro dev` — and every library in the stack pinned), `tsconfig.json`,
|
|
29
30
|
`eslint.config.mjs`, `.prettierrc.js`, `.gitignore`, `pnpm-lock.yaml`.
|
|
30
|
-
- `tailwind.config.ts` — the token layer only: no component classes, no
|
|
31
|
-
plugin beyond the base. Ships with placeholder tokens (a neutral
|
|
32
|
-
starting palette, a system type stack, a 4px spacing unit) that
|
|
33
|
-
`landing-systems` overwrites at its own phase — this file existing and
|
|
34
|
-
being wired into the build is what core guarantees, not any specific
|
|
35
|
-
token values.
|
|
36
31
|
- `src/pages/index.astro` — a minimal placeholder page (proves the build
|
|
37
32
|
pipeline works end to end), replaced by `landing-builder`'s own output
|
|
38
33
|
at the build phase.
|
|
39
|
-
- `src/styles/global.css` — the Tailwind import and
|
|
40
|
-
|
|
34
|
+
- `src/styles/global.css` — the Tailwind v4 CSS-first import and the
|
|
35
|
+
`@theme` token block: no component classes, no plugin beyond the base.
|
|
36
|
+
Ships with placeholder tokens (a neutral starting palette, a system
|
|
37
|
+
type stack, a 4px spacing unit) that `landing-systems` overwrites
|
|
38
|
+
entirely at its own phase — this block existing and being wired into
|
|
39
|
+
the build is what core guarantees, not any specific token values.
|
|
41
40
|
- `src/sections/`, `src/motifs/` — empty, with a `.gitkeep`; real content
|
|
42
41
|
starts at the systems and build phases.
|
|
43
42
|
|
|
@@ -125,13 +124,6 @@ like an unnecessary pin.
|
|
|
125
124
|
root. All four are stripped before syncing — they'd otherwise collide
|
|
126
125
|
with (or silently shadow) the project's real root `CLAUDE.md` and
|
|
127
126
|
Hedgehog's own workspace conventions.
|
|
128
|
-
- **MorphSVGPlugin ships inside the `gsap` package itself** — no
|
|
129
|
-
separate install, no Club GreenSock membership, no private registry.
|
|
130
|
-
GreenSock made every plugin free when GSAP joined Webflow in 2024.
|
|
131
|
-
Import it as `import { MorphSVGPlugin } from 'gsap/MorphSVGPlugin'`
|
|
132
|
-
directly from the `gsap` dependency already in `package.json`. Don't
|
|
133
|
-
reintroduce a separate paid-plugin workaround if this comes up again —
|
|
134
|
-
verify current licensing against gsap.com before assuming otherwise.
|
|
135
127
|
|
|
136
128
|
## If verification fails
|
|
137
129
|
|
|
@@ -182,9 +182,6 @@ Lock has held and its commit has landed. If not, stop and ask.
|
|
|
182
182
|
- **The Critic's veto is real.** `landing-critic` can send any phase back
|
|
183
183
|
to its owning agent, citing which audit failed; it cannot rewrite the
|
|
184
184
|
artifact itself.
|
|
185
|
-
- **Figma/Stitch MCP output is input only.** Anything handed off from
|
|
186
|
-
those tools is re-derived through the token system (phase 6) before it
|
|
187
|
-
touches Tailwind config — never copied through as final values.
|
|
188
185
|
|
|
189
186
|
## Core Reference Points
|
|
190
187
|
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: motif-authoring
|
|
3
|
+
description: Use whenever `landing-systems` authors the signature motif (Chain Method step 6, `hedgehog-landing-loop`) or `landing-builder` implements one from `src/motifs/`. Trigger on "draw the motif", "author the motif", "write src/motifs/". Picks the right construction technique — p5.js, CSS, or Canvas 2D — per motif type, and gives the technique for producing each without hand-typed coordinate guessing.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Motif Authoring
|
|
7
|
+
|
|
8
|
+
A motif is constructed from a formula or a measurement, never a
|
|
9
|
+
hand-typed coordinate. Freehand numeric coordinates — a bezier control
|
|
10
|
+
point, a magic pixel offset — are unreadable as numbers: there's no way
|
|
11
|
+
to tell what a shape looks like from its raw values while writing them,
|
|
12
|
+
so hand-typed geometry drifts into lumpy, asymmetric, or misaligned
|
|
13
|
+
results that read as generic rather than the sourced, deliberate motif
|
|
14
|
+
step 6 specifies.
|
|
15
|
+
|
|
16
|
+
## Pick the technique from the motif type
|
|
17
|
+
|
|
18
|
+
`landing-systems` step 6 names the motif's source, persistence,
|
|
19
|
+
continuity, scale range, and literalness. That spec determines which of
|
|
20
|
+
three techniques applies — pick one, don't mix by default:
|
|
21
|
+
|
|
22
|
+
1. **Organic / generative** (a material's grain, a growth pattern, a
|
|
23
|
+
natural form that evolves) → **p5.js**. Write the motif as a rule —
|
|
24
|
+
noise, jitter, growth, a formula-driven point set — not a curve typed
|
|
25
|
+
out point by point. The generator is legible and adjustable; a
|
|
26
|
+
hand-typed curve is neither.
|
|
27
|
+
2. **Static geometric** (a spine, a chevron, a blob, a simple silhouette
|
|
28
|
+
that doesn't need to evolve) → **CSS** (`clip-path`, gradients,
|
|
29
|
+
`border-radius`). Build the shape from `clip-path` polygon/shape
|
|
30
|
+
functions, layered gradients, or `border-radius` percentage strings —
|
|
31
|
+
values you can reason about exactly, animatable directly by GSAP
|
|
32
|
+
(e.g. tweening a `border-radius` string in place of shape morphing).
|
|
33
|
+
3. **Measured / connective** (a thread, a line, a connector that must
|
|
34
|
+
align to real element positions across the page) → **Canvas 2D with
|
|
35
|
+
computed coordinates**. Measure the actual DOM positions
|
|
36
|
+
(`getBoundingClientRect` or equivalent) at draw time and derive the
|
|
37
|
+
path from those measured values — never an eyeballed or imagined
|
|
38
|
+
coordinate.
|
|
39
|
+
|
|
40
|
+
## The rule within each technique
|
|
41
|
+
|
|
42
|
+
**Never hand-write multi-point geometry as raw guessed numbers**, in any
|
|
43
|
+
of the three:
|
|
44
|
+
|
|
45
|
+
- **p5.js** — construct from a formula (sine-based waveform, noise
|
|
46
|
+
function, L-system, Voronoi cell, particle rule) with named parameters,
|
|
47
|
+
not a manually plotted point list. Express motif variation
|
|
48
|
+
(augmentation/inversion/retrograde, per `landing-systems` step 6's
|
|
49
|
+
music-theory vocabulary) as parameter changes on the same generator,
|
|
50
|
+
not a hand-edited copy.
|
|
51
|
+
- Use **instance mode** (`new p5(sketch, container)`), not global mode
|
|
52
|
+
— a global-mode sketch leaks `setup`/`draw`/every p5 function onto
|
|
53
|
+
`window`, which collides with Astro's own module scope and with
|
|
54
|
+
GSAP/ScrollTrigger's own render loop running on the same page.
|
|
55
|
+
- Seed every source of randomness explicitly —
|
|
56
|
+
`p.randomSeed(seed); p.noiseSeed(seed);` — with a fixed, committed
|
|
57
|
+
seed value. This is what makes "derive from a formula" mean anything
|
|
58
|
+
in practice: the same seed must always reproduce the exact same
|
|
59
|
+
motif, so a reviewer (or `landing-critic`) can re-run it and get the
|
|
60
|
+
committed result, not a fresh roll.
|
|
61
|
+
- Collect the formula's inputs (particle count, noise scale, growth
|
|
62
|
+
rate, angle — whatever the generator exposes) into one named
|
|
63
|
+
`params` object at the top of the sketch, not scattered magic
|
|
64
|
+
numbers through `draw()`. This is the same object the "state the
|
|
65
|
+
parameters and what each one is for" verification step below reads
|
|
66
|
+
from — an ungrouped generator is harder to audit, not just harder to
|
|
67
|
+
read.
|
|
68
|
+
- Mount inside a `client:*` island only where the sequencer's beat
|
|
69
|
+
structure actually calls for the motif to animate; a motif that's
|
|
70
|
+
static per section doesn't need a live p5 instance at all — render
|
|
71
|
+
once and let CSS/GSAP handle any transform-level movement instead.
|
|
72
|
+
- **CSS** — build from `clip-path`'s named shape functions
|
|
73
|
+
(`polygon()`, `circle()`, `ellipse()`, `inset()` with rounded corners)
|
|
74
|
+
or `border-radius`'s percentage syntax, composed via layering and
|
|
75
|
+
transforms (rotate, scale, translate) rather than freehand
|
|
76
|
+
percentages guessed to "look right."
|
|
77
|
+
- **Canvas 2D** — derive every coordinate from a measurement (a DOM
|
|
78
|
+
element's rect, a computed grid position, a formula applied to those
|
|
79
|
+
measurements) — never a literal pixel value typed from eyeballing the
|
|
80
|
+
page.
|
|
81
|
+
|
|
82
|
+
## Verifying a motif before committing it
|
|
83
|
+
|
|
84
|
+
A motif is not correct because it compiles. Before writing it into
|
|
85
|
+
`src/motifs/` and handing off:
|
|
86
|
+
|
|
87
|
+
- **Render it and look.** Use the Bash tool to run the dev server or a
|
|
88
|
+
standalone preview and view the actual output — don't judge geometry
|
|
89
|
+
or a Canvas draw call from the source alone.
|
|
90
|
+
- **State the construction's parameters and what each one is for** — a
|
|
91
|
+
p5.js formula's inputs, a `clip-path` shape's control values, a Canvas
|
|
92
|
+
draw's measured inputs — before accepting it. If you can't say why a
|
|
93
|
+
value is what it is, it was guessed, not authored — redo it via the
|
|
94
|
+
technique's proper primitives.
|
|
95
|
+
- **For p5.js, confirm the seed is fixed and committed**, not left to
|
|
96
|
+
default/time-based randomness — re-running the sketch must reproduce
|
|
97
|
+
the exact motif that was reviewed, not a new variation each load.
|
|
98
|
+
- **Check symmetry/proportion deliberately** where the source motif
|
|
99
|
+
implies it (step 6's "literalness" and "scale range" fields).
|
|
100
|
+
- **Prefer fewer parameters.** A motif with 4 deliberate formula inputs
|
|
101
|
+
or shape values reads as designed; one with 20 guessed numbers reads as
|
|
102
|
+
noise, regardless of what it depicts.
|
|
103
|
+
|
|
104
|
+
## Constraints
|
|
105
|
+
|
|
106
|
+
- This skill governs *how* the motif is constructed, not *what* it is —
|
|
107
|
+
the source, persistence, continuity, scale range, and literalness are
|
|
108
|
+
`landing-systems` step 6's decisions (see `landing-systems.md`); this
|
|
109
|
+
skill only prevents the geometry itself from being guessed.
|
|
110
|
+
- Don't reach for an icon library or stock asset as a shortcut around
|
|
111
|
+
hard geometry — `landing-systems`'s existing constraint against generic
|
|
112
|
+
decoration still applies. A hard-to-construct motif is a signal to
|
|
113
|
+
simplify the formula or measurement, not to substitute a decorative
|
|
114
|
+
asset.
|
|
115
|
+
- **Never hand-write an SVG `<path d="...">` with freehand bezier
|
|
116
|
+
coordinates**, even as a fallback when none of the three techniques
|
|
117
|
+
above feels like a clean fit. Bezier control points typed as raw
|
|
118
|
+
numbers are unreadable — there's no way to tell what a curve looks
|
|
119
|
+
like from its `d` string while writing it, so hand-typed paths drift
|
|
120
|
+
into lumpy, asymmetric, or self-intersecting geometry regardless of
|
|
121
|
+
how carefully they're written. If a motif genuinely doesn't fit p5.js,
|
|
122
|
+
CSS, or Canvas 2D, that's a signal to reconsider the motif's source or
|
|
123
|
+
literalness with `landing-systems` — not a reason to fall back to
|
|
124
|
+
hand-authored SVG.
|
|
125
|
+
- `landing-builder` implements the motif exactly as authored here — a
|
|
126
|
+
motif that's hard to render cleanly should be fixed at this step, not
|
|
127
|
+
smoothed over during build.
|
|
@@ -65,23 +65,29 @@ edited after a phase closes.
|
|
|
65
65
|
### Stack (locked, every project — no add-ons on this core)
|
|
66
66
|
|
|
67
67
|
**Astro** (zero-JS-by-default shell, islands only where interaction is
|
|
68
|
-
genuinely needed) · **Tailwind** (config as token layer
|
|
69
|
-
component library on top) · **GSAP + ScrollTrigger
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
(line/word/char copy-reveal splitting) · **
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
68
|
+
genuinely needed) · **Tailwind v4, CSS-first** (config as token layer
|
|
69
|
+
only — no component library on top) · **GSAP + ScrollTrigger**, scoped to
|
|
70
|
+
CSS/transform targets only, no plugins (primary animation engine; owns
|
|
71
|
+
Sequencer pacing and top/heart/base fade timing) · **Lenis** (smooth-
|
|
72
|
+
scroll feel, the "weight and suspension" dial) · **SplitType**
|
|
73
|
+
(line/word/char copy-reveal splitting) · **p5.js** (organic/generative
|
|
74
|
+
motifs — described as a rule: noise, jitter, growth — not hand-typed path
|
|
75
|
+
data) · **CSS `clip-path` / gradients / `border-radius`** (static
|
|
76
|
+
geometric motifs — spines, chevrons, blobs — GSAP-animatable directly,
|
|
77
|
+
zero coordinate-guessing risk) · **Canvas 2D with computed coordinates**
|
|
78
|
+
(measured/connective motifs — threads/lines that align to real DOM
|
|
79
|
+
positions, drawn from measured values) · **`ogl`** (lightweight WebGL) or
|
|
80
|
+
a raw shader (a continuous background field spanning the full page
|
|
81
|
+
height, so sections read as windows onto one surface) · **CSS
|
|
82
|
+
`clip-path` irregular edges + `mix-blend-mode` overlap + negative-margin
|
|
83
|
+
overlap** (section boundary treatment — breaks the hard horizontal seam
|
|
84
|
+
between sections without a new dependency) · **CSS `mask-image` + noise
|
|
85
|
+
pattern** (texture/grain layer) · **React Three Fiber** (rare — only when
|
|
86
|
+
the subject is genuinely spatial; default is to skip it).
|
|
79
87
|
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
Systems Designer's token system (step 5) before it touches Tailwind
|
|
84
|
-
config.
|
|
88
|
+
This core has no design-handoff tool. All visual decisions are derived
|
|
89
|
+
directly through the Systems Designer's token system (step 5) and the
|
|
90
|
+
motif techniques above — never imported from an external design file.
|
|
85
91
|
|
|
86
92
|
Don't substitute libraries. If a package name changed upstream, verify
|
|
87
93
|
against current docs before running — don't swap in a different one, and
|
|
@@ -90,16 +96,22 @@ above doesn't cover; that gap is a signal to go back to the Ingredient
|
|
|
90
96
|
Vocabulary and derive the right choice, not to default to something
|
|
91
97
|
off-the-shelf.
|
|
92
98
|
|
|
99
|
+
Motifs are always constructed from a formula or a measurement, never
|
|
100
|
+
hand-typed coordinates: an organic motif is a p5.js rule (noise, jitter,
|
|
101
|
+
growth), a static geometric motif is CSS (`clip-path`, gradients,
|
|
102
|
+
`border-radius`), and a measured/connective motif is Canvas 2D drawn from
|
|
103
|
+
real DOM positions. See the `motif-authoring` skill for the technique
|
|
104
|
+
per motif type.
|
|
105
|
+
|
|
93
106
|
### Layout
|
|
94
107
|
|
|
95
108
|
```
|
|
96
109
|
astro.config.mjs Astro workspace root
|
|
97
|
-
tailwind.config.ts token layer only — hex values, type roles, spacing unit, easing family from Step 5
|
|
98
110
|
src/
|
|
99
111
|
pages/ one file per page (usually just index.astro)
|
|
100
112
|
sections/ one component per page section, in Sequencer order
|
|
101
|
-
motifs/ the signature
|
|
102
|
-
styles/ global.css — Tailwind import +
|
|
113
|
+
motifs/ the signature motif (p5.js / CSS / Canvas 2D) + its variation rules
|
|
114
|
+
styles/ global.css — Tailwind v4 CSS-first import + the `@theme` token layer (hex values, type roles, spacing unit, easing family from Step 5)
|
|
103
115
|
.hedgehog/
|
|
104
116
|
BMAD/ vendored BMAD-METHOD shelf's raw output (brief, PR-FAQ, PRD, UX spec, research) —
|
|
105
117
|
write-once, from planner
|
|
@@ -1,88 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: svg-motif-authoring
|
|
3
|
-
description: Use whenever `landing-systems` authors the signature motif (Chain Method step 6, `hedgehog-landing-loop`) — hand-authoring an SVG or Paper.js sketch from scratch. Trigger on "draw the motif", "author the SVG", "write src/motifs/". Technique for producing a clean, distinctive vector shape without freehand bezier-path guessing, which is where hand-drawn motifs go wrong.
|
|
4
|
-
---
|
|
5
|
-
|
|
6
|
-
# SVG Motif Authoring
|
|
7
|
-
|
|
8
|
-
Freehand `<path d="...">` coordinates written directly, number by number, are
|
|
9
|
-
the failure mode this skill exists to avoid. Bezier control points are
|
|
10
|
-
unreadable as numbers — there's no way to tell what a curve looks like from
|
|
11
|
-
its `d` string while writing it, so hand-typed paths drift into lumpy,
|
|
12
|
-
asymmetric, or self-intersecting geometry that reads as generic clip-art
|
|
13
|
-
rather than the sourced, deliberate motif `landing-systems` step 6 specifies.
|
|
14
|
-
|
|
15
|
-
## The rule
|
|
16
|
-
|
|
17
|
-
**Never hand-write a multi-point bezier path as raw numbers.** Build the
|
|
18
|
-
motif from primitives and operations you can reason about exactly, in this
|
|
19
|
-
order of preference:
|
|
20
|
-
|
|
21
|
-
1. **Primitive composition** — circles, rects, polygons, and single-arc paths
|
|
22
|
-
(`M`/`L`/`A` only, no freehand `C`/`Q`), combined via position, rotation,
|
|
23
|
-
and scale. Most sourced motifs (a material's cross-section, a tool's
|
|
24
|
-
silhouette, a natural form reduced to its defining contour) decompose into
|
|
25
|
-
2–4 primitives plus boolean ops, not one continuous freehand outline.
|
|
26
|
-
2. **Boolean ops on primitives** — union, subtract, intersect (as
|
|
27
|
-
`<clipPath>`/`<mask>`, or Paper.js's `PathItem.unite/subtract/intersect`)
|
|
28
|
-
to derive the actual silhouette. This is how the motif stays exact and
|
|
29
|
-
reproducible instead of eyeballed.
|
|
30
|
-
3. **Parametric/generative construction** — when the source genuinely has an
|
|
31
|
-
organic contour (a leaf vein, a wave, a woodgrain line), generate it: a
|
|
32
|
-
Paper.js script driven by a formula (sine-based waveform, L-system,
|
|
33
|
-
Voronoi cell, noise-perturbed circle) rather than a hand-typed curve.
|
|
34
|
-
Write the *generator*, not the resulting points — the generator is
|
|
35
|
-
legible and adjustable, a hand-typed curve is neither.
|
|
36
|
-
4. **Single freehand bezier segment, only as last resort** — if a genuinely
|
|
37
|
-
organic, non-formulaic curve is unavoidable (rare — most "organic" shapes
|
|
38
|
-
in step 6's Ingredient Vocabulary are formula-expressible per #3), keep it
|
|
39
|
-
to one continuous stroke, symmetric where the source is symmetric, and
|
|
40
|
-
verify per the check below before accepting it.
|
|
41
|
-
|
|
42
|
-
## Verifying a path before committing it
|
|
43
|
-
|
|
44
|
-
A path is not correct because it compiles. Before writing it into
|
|
45
|
-
`src/motifs/` and handing off:
|
|
46
|
-
|
|
47
|
-
- **Render it and look.** Use the Bash tool to write a standalone HTML file
|
|
48
|
-
wrapping the SVG (or the Paper.js canvas output) and open it, or inline it
|
|
49
|
-
in the dev server's page temporarily — don't judge geometry from the
|
|
50
|
-
markup alone.
|
|
51
|
-
- **State the path's point count and what each segment is for**, in a
|
|
52
|
-
one-line comment or in your own reasoning, before accepting it. If you
|
|
53
|
-
can't say why a control point is where it is, it was guessed, not
|
|
54
|
-
authored — redo it via primitives instead.
|
|
55
|
-
- **Check symmetry/proportion deliberately** where the source motif implies
|
|
56
|
-
it (step 6's "literalness" and "scale range" fields) — a hand-guessed
|
|
57
|
-
curve almost always drifts asymmetric even when the source is symmetric.
|
|
58
|
-
- **Prefer fewer anchor points.** A motif with 4 deliberate anchor points
|
|
59
|
-
reads as designed; one with 20 freehand points reads as a mouse-drawn
|
|
60
|
-
scribble, regardless of what it depicts.
|
|
61
|
-
|
|
62
|
-
## Paper.js specifics
|
|
63
|
-
|
|
64
|
-
For motifs that must evolve across sections (`landing-systems` step 6's
|
|
65
|
-
persistence/continuity fields):
|
|
66
|
-
|
|
67
|
-
- Construct the base shape from `Path.Circle`, `Path.Rectangle`,
|
|
68
|
-
`Path.RegularPolygon`, or a formula-driven `Path` built point-by-point in a
|
|
69
|
-
loop (e.g. `for (let t = 0; t <= 1; t += step)` sampling a parametric
|
|
70
|
-
function) — never `Path()` with hand-typed segment coordinates.
|
|
71
|
-
- Express augmentation/inversion/retrograde (the motif-variation vocabulary
|
|
72
|
-
step 6 borrows from music theory) as transforms (`scale`, `rotate`,
|
|
73
|
-
`reflect`) or formula-parameter changes on the same generator, not as a
|
|
74
|
-
hand-edited copy of the base path.
|
|
75
|
-
|
|
76
|
-
## Constraints
|
|
77
|
-
|
|
78
|
-
- This skill governs *how* the motif is drawn, not *what* it is — the
|
|
79
|
-
source, persistence, continuity, scale range, and literalness are
|
|
80
|
-
`landing-systems` step 6's decisions (see `landing-systems.md`); this
|
|
81
|
-
skill only prevents the geometry itself from being guessed.
|
|
82
|
-
- Don't reach for an icon library or stock SVG asset as a shortcut around
|
|
83
|
-
hard geometry — `landing-systems`'s existing constraint against generic
|
|
84
|
-
decoration still applies. A hard-to-draw motif is a signal to simplify via
|
|
85
|
-
more primitives, not to substitute a decorative asset.
|
|
86
|
-
- `landing-builder` implements the motif exactly as authored here — a motif
|
|
87
|
-
that's hard to render cleanly should be fixed at this step, not smoothed
|
|
88
|
-
over during build.
|