@marver-design/marver 0.19.2 → 0.21.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.
Files changed (39) hide show
  1. package/CHANGELOG.md +90 -0
  2. package/README.md +8 -10
  3. package/dist/{bake-kaf5kGZ7.mjs → bake-BID6mo-N.mjs} +1 -1
  4. package/dist/{boards-BmxcT3Lc.mjs → boards-BwiDAmPf.mjs} +95 -48
  5. package/dist/{boards-PuVzw5Wp.mjs → boards-DnLewfj8.mjs} +20 -11
  6. package/dist/{build-7ed5H2vT.mjs → build-C7MqQ7hq.mjs} +18 -8
  7. package/dist/cli.mjs +19 -13
  8. package/dist/{daemon-DbHvLQUL.mjs → daemon-CRZFpl6K.mjs} +1 -1
  9. package/dist/{dev-D3mP2x27.mjs → dev-BNZF4Mup.mjs} +5 -5
  10. package/dist/{init-BQYCS3EU.mjs → init-C34BY3R4.mjs} +34 -33
  11. package/dist/{manifest-B01PSyDc.mjs → manifest-mMfUhPtL.mjs} +8 -5
  12. package/dist/{plugin-DI-7NAnx.mjs → plugin-omHLCn91.mjs} +34 -26
  13. package/dist/{poster-DNh6N27C.mjs → poster-BvxiAzy1.mjs} +1 -1
  14. package/dist/{publish-bakes-Dp-ZFk3d.mjs → publish-bakes-BqzAAa3w.mjs} +8 -2
  15. package/dist/{shot-DMDvDbeP.mjs → shot-DswS4iRK.mjs} +7 -7
  16. package/docs/live-jam.md +1 -1
  17. package/docs/slides.md +89 -89
  18. package/docs/sticky-notes.md +9 -0
  19. package/package.json +1 -1
  20. package/src/client/const.ts +27 -9
  21. package/src/client/content/chart.tsx +8 -8
  22. package/src/client/content/index.tsx +5 -4
  23. package/src/client/content/slide.tsx +26 -201
  24. package/src/client/frame-host/main.tsx +10 -0
  25. package/src/client/shell/BoardList.tsx +111 -52
  26. package/src/client/shell/Comments.tsx +12 -4
  27. package/src/client/shell/Play.tsx +26 -14
  28. package/src/client/shell/Toolbar.tsx +7 -5
  29. package/src/client/shell/canvas/FrameNode.tsx +16 -2
  30. package/src/client/shell/store.ts +8 -8
  31. package/src/client/shell/styles.css +10 -9
  32. package/src/client/stage/main.tsx +56 -7
  33. package/src/shared/board-tree.ts +271 -140
  34. package/templates/AGENTS-embedded.md +3 -3
  35. package/templates/AGENTS-studio.md +3 -3
  36. package/templates/instructions/boards.md +47 -22
  37. package/templates/instructions/reference/deck-layouts.md +153 -199
  38. package/templates/instructions/reference/deck-story.md +6 -6
  39. package/templates/instructions/slides.md +275 -383
@@ -1,342 +1,278 @@
1
- # Slides - decks that argue, on frames that move
1
+ # Slides - decks in code
2
2
 
3
3
  Run this when the work is a DECK: the human asks for slides, a presentation,
4
4
  a pitch, a review - or a scene of `slide: true` frames exists. Read
5
- `design/slides.md` too, ALWAYS: it is the project's own layout list and house
6
- rules, and where it disagrees with this file, **the project file wins**.
7
-
8
- A slide is an ordinary frame with `slide: true` in its meta - 1280×720, the
9
- slide badge, and slides mode when published. Everything you know holds:
10
- real components, the project theme, comments, variants, promotion. What
11
- changes is the CRAFT BAR - a deck is an argument wearing the product's
12
- clothes, and every rule below is binding.
13
-
14
- **The stage fits every screen.** You author at exactly 1280×720 and the
15
- Slide root scales and centers itself to any viewport - fill window, a
16
- laptop, a viewer's phone. One coordinate system: your px, Tailwind classes,
17
- and charts scale together, so what you compose is what plays. This is a
18
- guarantee to LEAN ON, not to fight:
19
- - lay out with flex/grid and the stage's own proportions (percentages,
20
- `--sl-margin`, the type roles) - never against the window;
21
- - no viewport units (`vw/vh`) and no media queries inside a slide - the
22
- stage is the world, and it is always 1280×720 to your code;
23
- - images and video posters at 2x the box they sit in, so an upscaled fill
24
- stage stays sharp.
5
+ `design/slides.md` too, always: it holds this project's deck look and house
6
+ habits, and where it disagrees with this file, **the project file wins**.
7
+
8
+ A slide is an ordinary frame with `slide: true` in its meta. That is the
9
+ whole contract. What goes inside is your code - any layout, any typeface,
10
+ any image, any drawing, any animation the browser can render. This file is
11
+ not a rulebook. It is the craft of decks that look made rather than typed,
12
+ the method that gets the argument right before the pixels, and the few
13
+ mechanics of how a slide plays. Take what serves the deck in front of you.
14
+
15
+ | File | When |
16
+ |---|---|
17
+ | reference/deck-story.md | intake is thin or rich, the room is senior, the slide list reads like a table of contents, or the words need work |
18
+ | reference/deck-layouts.md | a slide needs a composition and none comes - an idea bank, plus rebuilding an existing deck and chart craft |
19
+ | craft.md + its references | a slide's type, colour, layout or motion feels off - reference/typography.md, color.md, motion.md and slop.md hold for slides as for screens |
20
+
21
+ ## What a slide is
25
22
 
26
23
  ```tsx
27
- import { Slide } from '@marver-design/marver/content'
28
- export const meta = { title: 'Cover', slide: true }
29
- export default () => (
30
- <Slide>
31
- <h1 className="sl-assertion">Churn halved after onboarding v2</h1>
32
- </Slide>
33
- )
24
+ export const meta = { title: 'Onboarding time halved in one quarter', slide: true }
25
+
26
+ export default function Frame() {
27
+ return (
28
+ <main className="dk-page dk-ink dk-statement">
29
+ <h1>Onboarding time<br />halved in one quarter.</h1>
30
+ </main>
31
+ )
32
+ }
34
33
  ```
35
34
 
36
- This file is the floor. Depth lives in instructions/reference/:
35
+ - **The stage.** A slide renders at its stage size: 1280×720 by default.
36
+ Declare a `viewport` (any name in `design/config.ts`, e.g. `'laptop'` for
37
+ 1280×800) for another shape, and keep one stage per deck. Compose in px
38
+ at that size: let your root fill the stage (`min-height: 100vh`) and place
39
+ things where you want them.
40
+ - **The host scales, not you.** A slide never reflows: slides mode renders
41
+ the stage and scales the whole of it to the screen - up on a projector,
42
+ down on a laptop or a phone - and a resized canvas node shows it the same
43
+ way, smaller. The document IS the stage, so no breakpoints are needed and
44
+ viewport units are stage units (`100vh` is the stage's height).
45
+ - **On the canvas** a slide is a frame like any other: comments, laser,
46
+ variants, Live Jam, plus the slide badge. The board's reading order (top to
47
+ bottom, left to right) is the play order - drag slides to reorder the deck.
48
+ - **Notes.** `<slide>.note.md` beside the frame is its sticky note - the
49
+ presenter's script and the next agent's memory (the method, below).
50
+ - `<Slide>` from `@marver-design/marver/content` is an optional wrapper that
51
+ fills the frame; earlier decks use it. Nothing requires it.
52
+
53
+ ## Motion
54
+
55
+ Code means the motion is yours: CSS keyframes and transitions, SVG
56
+ animation, a JS library the project already uses. Three habits make it play
57
+ well:
58
+
59
+ - **At rest, the finished slide.** On the canvas, in `marver shot`, in a
60
+ thumbnail, the slide shows its final composition. Animate while the deck
61
+ plays: the stage puts `data-sl-play` on `<html>` for the whole show and adds
62
+ `data-sl-entered` once each slide has arrived. Key motion off them:
63
+
64
+ ```css
65
+ :root[data-sl-entered] .dk-loop path { animation: dk-draw 900ms ease-out both }
66
+ @keyframes dk-draw { from { stroke-dashoffset: 600 } to { stroke-dashoffset: 0 } }
67
+ @media (prefers-reduced-motion: reduce) {
68
+ :root[data-sl-entered] .dk-loop path { animation: none }
69
+ }
70
+ ```
71
+
72
+ In React, `useSlidePlay()` from `/content` says the deck is playing (it
73
+ stays true for the whole show); to start something when THIS slide
74
+ arrives, watch `data-sl-entered` on `<html>` - the stage removes it at
75
+ each swap and sets it again once the new slide has settled.
76
+ - **Between slides, morphs.** Give an element the same
77
+ `view-transition-name` on two adjacent slides and it travels or resizes
78
+ between them; the rest crossfades. A persistent element (the mark, a
79
+ diagram that grows) reads as continuity; a hard cut (no shared names)
80
+ reads as a new chapter. One duration for the deck: `--marver-slide-tempo`
81
+ in the theme (default 350ms).
82
+ - **Builds.** Progressive disclosure is sibling frames (`04a-`, `04b-`)
83
+ sharing morph names, so every step stays visible and commentable.
84
+
85
+ Shortcuts, if they help: `data-animate="fade-up | fade | scale-in"` plus
86
+ `data-animate-delay="1 | 2 | 3"` run once after a slide arrives (never on an
87
+ element that also morphs - one owner per transform).
88
+
89
+ ## The deck kit - build it once per deck
90
+
91
+ A strong deck is not twenty bespoke pages; it is one small system applied
92
+ with variety. Before the slides, write the kit into the scene - `_parts.tsx`
93
+ and `_style.css`, the leading underscore keeps them off the canvas:
94
+
95
+ - **The master** - a shell every content slide wears: the mark, a context
96
+ line (who it is prepared for, the date, "confidential"), the body area.
97
+ Covers and closings step outside it.
98
+ - **Tones** - two to four whole-slide colour sets as CSS variables (paper,
99
+ ink, one accent ground), swapped by a class. A tone change is a pacing tool.
100
+ - **Type** - the brand's family, weights and tracking, and a handful of
101
+ sizes: a display, a heading, a body, a small label. Hierarchy through size
102
+ and a muted colour, rarely through weight.
103
+ - **Rules and labels** - the hairline, the numbered label, the spacing rhythm.
104
+ - **The drawing helper** - one component that renders the deck's
105
+ illustrations by name, with their alt text.
37
106
 
38
- | File | When |
39
- |---|---|
40
- | reference/deck-layouts.md | REQUIRED at step 4 of every deck - the full atlas, the grid, the budgets, charts; and BEFORE step 1 when rebuilding an existing deck (its mode decision comes first) |
41
- | reference/deck-story.md | when intake is thin or rich, the room is senior, the slide list reads like a table of contents, or the words need work |
42
-
43
- ## The pipeline (in order, no skipping)
44
-
45
- **1. The answer.** Before any frame: write the deck's one-paragraph answer -
46
- what the audience should believe or do when the last slide lands. If the
47
- human's material is too thin for a substantive deck, SAY SO and ask - never
48
- pad. Then the slide list: one line per slide, each line the slide's single
49
- message as a full-sentence assertion. Walk that list once more asking
50
- "could I draft this slide without inventing a single fact?" - the gaps
51
- become specific questions to the human, or a smaller deck (the evidence
52
- check, reference/deck-story.md). The scaffold (step 2) may carry gaps as
53
- visible placeholders; the build (step 5) may not - a factual gap blocks its
54
- slide until answered or cut, while editorial copy (framing, captions) you
55
- draft and label as proposed.
56
-
57
- **2. Show the deck.** Scaffold every listed slide immediately as a
58
- placeholder frame - `<Slide>` + its assertion in `sl-assertion` - in one
59
- scene (one scene = one deck), numbered files (`01-cover.tsx`,
60
- `02-problem.tsx`), pinned on the board, marked working
61
- (`npx marver work start ...`). The outline now lives ON the canvas,
62
- reorderable and vetoable while every slide is still one sentence. THEN
63
- research, gather evidence, design.
64
-
65
- **3. The sequence test.** Read only the assertions, in file order. They must
66
- tell the complete argument - specifically enough that a stranger could guess
67
- whose deck this is. Generic titles mean the thinking is not done; fix the
68
- titles before touching layout.
69
-
70
- **4. Storyboard the silhouettes.** Before any markup, one line per slide:
71
-
72
- `message | dominant object | silhouette | density | recipe`
73
-
74
- The dominant object first - what the eye lands on (a number, a quote, a
75
- chart, the claim itself; for a grid the peer set as one shape, for a stream
76
- the path) - then the silhouette that serves it (the seven, below), density (airy / balanced / dense), and only
77
- then the recipe from the list below + the atlas in
78
- reference/deck-layouts.md + `design/slides.md`, picked against the content's
79
- real volume. Read the finished list as THUMBNAILS, not as recipe names.
80
- Pacing, for any deck of eight or more content slides:
81
- - no silhouette on more than 40% of the deck;
82
- - no silhouette twice running, except inside a declared visual group
83
- (three pillars, four pipeline stages - those share ONE layout, variety
84
- comes between groups) or a build sequence;
85
- - never three dense slides in a row;
86
- - an airy statement, hero, or bookend at the opening answer, at every
87
- major turn of the argument, and at the close.
88
- Do not alternate mechanically - pace follows the argument. A recipe's
89
- budget breached = a different recipe or a split, decided here.
90
-
91
- **5. Build.** Real markup inside `<Slide>`, the project's own classes and
92
- components, the type roles, the theme's tokens. Name morph anchors as you
93
- go (choreography, below). The assertion is always the `h1`, but it need not
94
- sit at the top or be the largest thing: when the slide is about a number,
95
- a quote, a chart, or a source, THAT dominates and the assertion frames it.
96
- Never write one wrapper that fixes the title geometry for every slide -
97
- share tokens, the source treatment, and primitives; give each silhouette
98
- its own shell. HTML stays honest: images carry `alt`, a chart or diagram
99
- gets a one-line text summary in a caption, every colour pair reads in both
100
- themes.
101
-
102
- **6. The review gate.** Run it before presenting, every time (bottom of this
103
- file).
104
-
105
- ## The words
106
-
107
- - **Assertions, not labels.** "Q3 revenue beat plan by 12%" - never "Q3
108
- revenue". One line, it commits to a position. (The one exception: a
109
- FAITHFUL rebuild of an existing deck keeps its titles as written -
110
- reference/deck-layouts.md.)
111
- - **Overflow is a second slide.** Never fix a full slide by shrinking type.
112
- - Numbers over adjectives - every FACTUAL claim carries a figure, a name, or
113
- a date; a conceptual assertion earns its place by being specific to this
114
- company, not generic.
115
- - Active voice. Write like you talk, then cut every word that isn't earning.
116
- - Kill on sight: "leverage", "robust", "world-class", "streamline",
117
- "going forward", "potentially", "we believe", "it is important to note".
118
- - Negatives in brackets: (123). Units once, in the header or axis; within a
119
- metric family one unit and one time-basis ($M everywhere revenue appears,
120
- FY or CY - never both).
121
- - Sources are a short `sl-caption` slug at the foot of the slide - "OpenAI
122
- technical report, §IV.B" - never a bibliographic sentence; that band
123
- repeated seventeen times is a report template. Full citations go in the
124
- frame's comment.
125
- - The closing slide is a specific, time-bound ask. "Questions?" is not a
126
- closing slide.
127
-
128
- ## The type and the space
129
-
130
- The `<Slide>` root provides the roles - use them, never font-size by hand.
131
- The values are fixed (one coordinate system with the stage):
132
-
133
- | Role class | Size | Job |
134
- |---|---|---|
135
- | `sl-display` | 160px | the oversize: a hero number, a section numeral, the manifesto line - never running text; at most once per argument group, never on adjacent slides |
136
- | `sl-stat` | 88px | a ROW of figures (3-4 across), where `sl-display` would not fit |
137
- | `sl-assertion` | 56px, heavy | the one-line claim (~40 characters full-width, ~20 inside a split - two lines is the ceiling, verify the render) |
138
- | `sl-support` | 30px | the second voice |
139
- | `sl-body` | 24px | evidence text - the floor for anything read |
140
- | `sl-caption` | 18px | sources, footnotes, kickers |
141
-
142
- Nothing smaller than 18px, ever. One family (`--marver-slide-font`, the
143
- theme's); the roles carry their weights - add none of your own. One
144
- reading intent per slide - a single object, a peer set, or a path, never two
145
- competing. Within a visual group, shared elements keep the SAME
146
- position unless the movement is the message.
147
-
148
- ## Silhouette - the deck at thumbnail size
149
-
150
- A silhouette is the largest geometry the eye sees when the words are
151
- blurred. Swapping a card row for a stat row under the same standing header
152
- changes nothing at thumbnail size, and the review gate looks at thumbnails.
153
- Choose the silhouette before the recipe. Seven:
154
-
155
- - **statement** - one claim owns the canvas. No kicker, no header, at most
156
- one short support line. The opening answer, a turn, a synthesis.
157
- - **hero** - one number, quote, image, or source object owns 60-80% of the
158
- canvas; the assertion frames it, smaller, and does not compete.
159
- - **split** - two UNEQUAL fields, 40/60 or 60/40: one argues, one proves.
160
- - **grid** - 2-6 true peers in one field. Equal weight only when the ideas
161
- are equal - a 2×2 of causes makes them look like feature cards.
162
- - **stream** - a path across the canvas: time, sequence, causality,
163
- escalation, hand-off. The path IS the geometry, not a ruled list.
164
- - **field** - one chart, table, diagram, or document fragment fills the
165
- slide; the assertion sits at an edge or inside the field.
166
- - **bookend** - cover, section turn, closing: a statement or hero that
167
- ALSO carries the mark and drops the source line, so it reads as a door,
168
- not a page. Count it as its own silhouette only when that geometry is
169
- visibly different from the statements around it.
170
-
171
- The kicker + assertion + hairline over a body is ONE way to build a grid or
172
- split - it is not the default shell for content slides, and shared margins
173
- never require shared title geometry. Whitespace needs no defence when it
174
- establishes dominance; an added companion panel does. Alignment before
175
- enclosure: if spacing and a hairline establish the group, remove the box -
176
- cards, panels, and badges are interface furniture, and a deck of them reads
177
- as a dashboard.
178
-
179
- ## The space IS the design
180
-
181
- This is what separates a deck that looks made from one that looks typed.
182
- The stage is 1280×720 with ASYMMETRIC margins - 88px at the sides, 44px top
183
- and bottom - so the title sits high, the footnote sits low, and the middle
184
- is the tallest band on the slide. Content box: **1104×632px**, at every
185
- viewport. (Override `--marver-slide-pad-x` / `--marver-slide-pad-y` in px,
186
- never a percentage: a percentage resolves against the viewport, not the
187
- stage.)
188
-
189
- When a slide carries a title band (grids and splits usually do; statements,
190
- heroes, and fields usually do not), the three bands are:
191
-
192
- | Band | Height | Holds |
193
- |---|---|---|
194
- | Title | ~113px | kicker (18px) over the assertion (56px), a hairline under |
195
- | Body | **~438px** | the recipe - and it is the star, so give it the room |
196
- | Foot | ~25px | the source slug, or the takeaway bar above it |
197
-
198
- **The 85% rule.** Content fills at most ~85% of whatever band it lives in
199
- (≈372 of a 438px body). The remaining sliver is not waste - it is the void
200
- that makes a slide read as a slide. If your content fills the band, you
201
- have a document: cut a sentence, drop a card, or split the slide. Never
202
- close the gap by shrinking type.
203
-
204
- **One spacing scale**, in px, every value from it and nothing between:
205
-
206
- | Step | Use |
207
- |---|---|
208
- | 8 | label to its value, icon to its text |
209
- | 16 | rows inside one list, line to hairline |
210
- | 24 | siblings inside a card or a group |
211
- | 32 | padding inside a card; between columns |
212
- | 40 | between distinct groups in the body |
213
- | 48 | title block to body, body to the foot |
214
-
215
- Rhythm comes from CONTRAST between those steps - tight inside a group, wide
216
- between groups. One value repeated everywhere is the flattest thing you can
217
- do to a slide. Gaps go on the parent (`gap`), never as per-child margins.
218
-
219
- ## The evidence
220
-
221
- - **One anchor visual per slide, at most** - a peer set or a path counts as
222
- one.
223
- - **Charts** (`Chart`): pick the FORM from the Apache ECharts docs
224
- (https://echarts.apache.org/en/option.html), inside the supported surface
225
- - series bar, line, pie, scatter, radar, gauge, heatmap, funnel, treemap, sunburst, sankey, boxplot; components grid, polar, radar, tooltip, legend, title, dataset (+ transform), markLine, markPoint, markArea, visualMap, dataZoom; anything else is dropped without an
226
- error. marver supplies the house theme (colors, type, tooltip); styling
227
- you pass overrides it, so pass DATA and STRUCTURE, never styling. One message per chart; the takeaway is the
228
- slide's assertion; direct labels over legends; bar baselines at zero
229
- (lines may zoom - annotate when they do); hue = category, shade = variant,
230
- fixed across the whole deck.
231
- - **Diagrams** (`Diagram`) for structure, plain shapes + arrows for
232
- concepts - a 2×2 or a flow in divs beats imported artwork.
233
- - **Images** (`Img`): full-bleed with a scrim and a short assertion, or
234
- generously matted. Never a small image floating in space.
235
- - **Video** (`Video src poster`): the poster IS the slide at rest - choose
236
- it like a photograph. Omit `poster` and marver renders one from the clip
237
- (`<clip>.poster.png` beside it, committed like any asset); author one when
238
- the clip's opening is not the picture you want. In slides mode the
239
- player mounts on its own; everywhere else a frame is live, the poster is
240
- the play button (the same primitive serves screens and specs).
241
- - **Backgrounds are code**: theme-derived gradients, an oversized numeral, a
242
- clipped photo, one geometric accent. ONE effect per slide, and decoration
243
- never touches the evidence's contrast.
244
-
245
- ## The recipes
246
-
247
- Scan all of them (plus `design/slides.md`) for every slide. Each entry:
248
- silhouette · skeleton · budget (breach = split, never shrink) · anchor (the
249
- element that morphs INSIDE a group or build; "none" = a hard cut).
250
-
251
- 1. **cover** (bookend) - deck title + one line + the mark. Budget: title ≤6
252
- words. Anchor: the mark.
253
- 2. **section** (bookend) - an oversized numeral/word divider in
254
- `sl-display`. Budget: ≤3 words. Anchor: none.
255
- 3. **assertion-evidence** (split or field) - the workhorse: `sl-assertion`
256
- + ONE visual. Budget: assertion 1 line, caption 1 line. Anchor: the
257
- visual.
258
- 4. **big-number** (hero) - one `sl-display` stat + a context line. Budget:
259
- 1 stat. Anchor: the number.
260
- 5. **stat-row** (grid) - 3-4 quick proofs in a row. Budget: each ≤4 words +
261
- value. Anchor: the row.
262
- 6. **metric-grid** (grid) - a 2×2 of labeled values. Budget: 4 cells
263
- exactly. Anchor: the grid.
264
- 7. **quote** (hero) - the words, the person, nothing else. Budget: ≤30
265
- words. Anchor: none.
266
- 8. **quote-wall** (grid) - 3-6 short quotes. Budget: each ≤15 words.
267
- Anchor: the wall.
268
- 9. **two-up** (split) - comparison / before-after. Budget: ≤4 rows per
269
- side. Anchor: the divider.
270
- 10. **two-stage** (stream) - diagnosis → prescription with a connector.
271
- Budget: one sentence per stage. Anchor: the connector.
272
- 11. **numbered-reasons** (grid) - 3-5 ordered points. Budget: each ≤12
273
- words. Anchor: the numerals.
274
- 12. **bento** (grid) - 3-5 cells for a system view. Budget: cell = title +
275
- 1 line. Anchor: the largest cell.
276
- 13. **timeline** (stream) - a horizontal spine, 3-6 beats. Budget: beat ≤5
277
- words. Anchor: the spine.
278
- 14. **roadmap-phases** (stream) - 2-4 phases with contents. Budget: ≤3
279
- items/phase. Anchor: the phase heads.
280
- 15. **matrix** (field) - a 2×2 positioning. Budget: ≤6 plotted items.
281
- Anchor: the axes.
282
- 16. **full-bleed** (hero) - image + scrim + assertion. Budget: assertion
283
- only. Anchor: the image.
284
- 17. **chart-focus** (field) - one `Chart`, near full-slide. Anchor: the
285
- chart.
286
- 18. **wall** (grid) - logos/team grid. Budget: 6-12 cells, no captions.
287
- Anchor: the grid.
288
- 19. **closing** (bookend) - the ask, one CTA, contact. Budget: ask ≤2
289
- lines. Anchor: none.
290
-
291
- These are the core. The atlas in reference/deck-layouts.md carries the rest
292
- - split, cards, spectrum, insight + evidence, trajectory, table, scenarios,
293
- flow, cycle, chain, swim lanes, funnel, schedule, layers, concentric,
294
- pyramid, number line, capability matrix, scorecard, heat map, tracker,
295
- testimonials, team, manifesto, framed source - each with its budget, plus
296
- the shared stage, margins, and the optional banded grid they draw from. Scan it for every slide.
297
-
298
- ## Choreography - the diff IS the animation
299
-
300
- You never animate. You name elements consistently, and slides mode
301
- interpolates the difference between adjacent stills. The board is the
302
- timeline: design motion by designing the diff.
303
-
304
- **Five verbs** via `view-transition-name` (style prop or class):
305
-
306
- | Verb | How | Reads as |
307
- |---|---|---|
308
- | persist | same name, same box | continuity - the anchor |
309
- | travel | same name, new position | "follow this" |
310
- | grow | same name, new size | "this is now the point" |
311
- | swap | unmatched content | the default crossfade |
312
- | reveal | new element + `data-animate` | "and then" |
313
-
314
- **Binding rules:**
315
- - Adjacent slides inside a visual group or a build share AT LEAST one stable
316
- named element - the anchor (each recipe names its default above). Across
317
- a turn of the argument, or into and out of a statement, hero, or bookend,
318
- a HARD CUT (zero shared names) is the right punctuation - use it. Never
319
- name the assertion `headline` on every slide as a deck-wide fallback: a
320
- title that morphs into the next title on seventeen slides is the
321
- strongest possible signal that every slide has the same shape.
322
- - AT MOST one element changes position or size per transition. Persist
323
- freely, travel once.
324
- - Build steps are sibling frames (`03a-`, `03b-`) sharing morph names -
325
- progressive disclosure that stays visible and commentable. Variants are
326
- for exploration, siblings for builds - never both on one slide.
327
- - Entrances: `data-animate="fade-up | fade | scale-in"` +
328
- `data-animate-delay="0|1|2|3"`. Never on an element that carries a morph
329
- name. Runs once, after the transition settles - trust it, don't stack it.
330
- - Morphs tween bounds and crossfade pixels - a chart "morph" is the picture
331
- growing, not bars re-plotting. Design for that honestly.
332
- - One tempo per deck (the root's token). Motion never varies per slide.
333
- - NOTHING loops, scrolls, or free-runs. A resting slide is still - that is
334
- what keeps a 40-slide canvas fast, and the review gate checks it.
107
+ ```tsx
108
+ // design/scenes/<deck>/_parts.tsx
109
+ import type { ReactNode } from 'react'
110
+ import './_style.css'
111
+
112
+ export function Page({ tone = 'paper', className = '', children }: {
113
+ tone?: 'paper' | 'ink' | 'accent'; className?: string; children: ReactNode
114
+ }) {
115
+ return (
116
+ <main className={`dk-page dk-${tone} ${className}`}>
117
+ <header className="dk-header"><Mark /><span>Prepared for Acme · Confidential · May 2026</span></header>
118
+ <div className="dk-body">{children}</div>
119
+ </main>
120
+ )
121
+ }
122
+ ```
123
+
124
+ ```css
125
+ /* _style.css - tones are variable swaps, so every rule reads the same names */
126
+ .dk-page { --ground: #f1f0ea; --ink: #151616; --muted: #63645f; --line: #cacac2;
127
+ min-height: 100vh; padding: 0 48px; background: var(--ground); color: var(--ink);
128
+ font: 400 20px/1.4 var(--brand-font); letter-spacing: -.015em }
129
+ .dk-ink { --ground: #151616; --ink: #f1f0ea; --muted: #b5b7ad; --line: #474a44 }
130
+ .dk-page h1 { font-weight: 400; font-size: 64px; line-height: 1.05; letter-spacing: -.045em; margin: 0 }
131
+ ```
132
+
133
+ Derive every value from `design/DESIGN.md` and `theme.css`, and use the
134
+ project's real mark component. If the brand is not written down yet, that
135
+ comes first (instructions/brand.md): a deck look invented on slide one has
136
+ drifted by slide five.
137
+
138
+ ## The craft - what makes a deck look made
139
+
140
+ The habits that carry the most, distilled from the best decks built on
141
+ marver:
142
+
143
+ 1. **The brand, not a deck style.** The identity's own typeface, weights,
144
+ colours and imagery. Large type at regular weight with tight tracking
145
+ looks designed; bold everywhere looks generated.
146
+ 2. **One idea per slide.** The headline is the message, written as a
147
+ sentence. Under it, at most a short line and a few supporting items. The
148
+ nuance, the caveats and the talk track go in the note.
149
+ 3. **Structure with space and hairlines, not boxes.** Group by alignment and
150
+ gaps, separate with 1px rules, order with small numbered labels in the
151
+ muted colour. A card, a shadow or a badge is for the rare element that is
152
+ genuinely a separate object.
153
+ 4. **Real images, used big.** The client's or the product's own photography,
154
+ full-bleed or bleeding off one edge, under a uniform scrim where text sits
155
+ on it. Never a small picture floating in space; never stock that could
156
+ belong to anyone.
157
+ 5. **A drawing system of your own.** When an idea needs a picture, draw it as
158
+ native SVG in one style: consistent line weights, a shared grid, mostly
159
+ ink, ONE accent per slide marking the point (the approval, the bottleneck,
160
+ the result). Light and dark versions where tones change. Colour that means
161
+ something (red for the rework loop, green for the outcome) is introduced
162
+ on purpose and kept consistent.
163
+ 6. **Diagrams built for the argument.** A process with its failure loop drawn
164
+ back across it, a context and a solution in two illustrated lanes, three
165
+ numbers in a row - composed in HTML and SVG for this message, not picked
166
+ from a menu.
167
+ 7. **Pace the deck.** A sparse statement after the cover; working slides on
168
+ the light ground; a dark slide at a turn of the argument; the accent ground
169
+ once, for the proof. Dense slides alternate with quiet ones.
170
+ 8. **Bookends are doors.** The cover pairs the marks (yours and the
171
+ audience's) with one strong image and no header. The closing is a quiet
172
+ card - the mark, a contact, a photograph - with the ask on the slide before.
173
+ 9. **Honest numbers.** Evidence is big and specific; its limits sit on the
174
+ slide in small type when they matter ("results from a reference project,
175
+ not a forecast").
176
+ 10. **Finish the details.** Control the line breaks in headlines, balance the
177
+ gaps, align each drawing with the text beside it, check every tone. The
178
+ distance between good and very good is twenty small passes - and a frozen
179
+ copy of the deck before each big change, so nothing approved is lost.
180
+
181
+ Variety comes from the message: choose each slide's composition for what it
182
+ has to show, and let the kit hold the deck together.
183
+ reference/deck-layouts.md is a bank of compositions to borrow from when you
184
+ are stuck.
185
+
186
+ ## The method
187
+
188
+ 1. **The answer.** Before any frame: one paragraph - what the audience should
189
+ believe or do when the last slide lands. If the material is too thin for a
190
+ substantive deck, say so and ask; never pad.
191
+ 2. **The slide list.** One line per slide, each its message as a sentence.
192
+ Read the lines alone: they should tell the whole argument, specifically
193
+ enough that a stranger could guess whose deck it is. Could you draft each
194
+ slide without inventing a fact? The gaps become questions for the human.
195
+ 3. **The brief.** Write `_brief.md` in the scene: the answer, the sequence as
196
+ a storyboard (`message | what the eye lands on | composition | density`),
197
+ the visual system (kit, tones, imagery, drawings) and the sources. It keeps
198
+ a long iteration coherent.
199
+ 4. **Scaffold, then build.** Put every slide on the board early - a frame
200
+ holding just its sentence, in one scene, numbered files (`01-cover.tsx`) -
201
+ so the outline is reorderable and vetoable on the canvas. Mark the work
202
+ (`npx marver work start ...`). Then build the kit, then the slides.
203
+ 5. **Notes as you go.** Each slide's `.note.md`, in four short parts:
204
+
205
+ ```md
206
+ ## Aim
207
+ What this slide must do in the argument.
208
+
209
+ ## Say
210
+ The talk track, in the presenter's voice.
211
+
212
+ ## Visual
213
+ Why it looks the way it does - what the image or drawing carries.
214
+
215
+ ## Source context
216
+ Where the facts come from, and their limits.
217
+ ```
218
+
219
+ Notes ship with a published canvas: keep anything the audience must not
220
+ read out of them.
221
+ 6. **Review**, below - then iterate.
222
+
223
+ ## Words
224
+
225
+ - Headlines that say something: "Every new market adds a week of manual
226
+ reconciliation", not "Reporting challenges". A label suits a door (a
227
+ section, an agenda, "How we work with your team") - not an argument.
228
+ - Numbers, names and dates over adjectives; units once.
229
+ - Active voice. Cut every word that is not earning its place. Kill on sight:
230
+ "leverage", "robust", "world-class", "streamline", "seamless", "unlock",
231
+ "going forward", "we believe", "it is important to note".
232
+ - Sources as a short line on the slide; the full citation in the note.
233
+ - When a slide is full, split it or move the detail to the note - shrinking
234
+ the type to fit is the slide telling you it holds two ideas.
235
+
236
+ ## Evidence
237
+
238
+ - **Chart** (`/content`): an Apache ECharts option on a fixed surface -
239
+ series bar, line, pie, scatter, radar, gauge, heatmap, funnel, treemap,
240
+ sunburst, sankey, boxplot; components grid, polar, radar, tooltip, legend,
241
+ title, dataset (+ transform), markLine, markPoint, markArea, visualMap,
242
+ dataZoom (anything else is dropped without an error). It inherits the
243
+ slide's ink and typeface and reads `--marver-slide-accent`; pass data and
244
+ structure, and style only what the deck needs. One message per chart,
245
+ direct labels, bars from zero. When the form is simple and the brand
246
+ matters more, draw the chart yourself in SVG.
247
+ - **Images**: `Img` for a framed asset from `design/assets/`, or a plain
248
+ `<img>` / CSS background when the slide needs full control (`object-fit`,
249
+ `object-position`, a scrim). Use files at least 2x the size they show -
250
+ the player scales slides up.
251
+ - **Video** (`Video src poster`): the poster is the slide at rest; in slides
252
+ mode the player mounts on its own. Omit `poster` and marver renders one
253
+ from the clip.
254
+ - **Diagram** (Mermaid) for quick structure; hand-built SVG and HTML when the
255
+ diagram IS the slide.
256
+
257
+ ## Review - before you present
258
+
259
+ - **The contact sheet.** `npx marver shot --scene <deck>`, then look at every
260
+ slide small, side by side. Does it read as one deck with range, or one
261
+ shape repeated with different words? Squint: where does the eye land on each?
262
+ - **Play it.** Slides mode, start to end, in a big window and a small one:
263
+ nothing clipped or spilling past the stage, every tone legible, motion
264
+ finished at rest.
265
+ - **The cold read.** The headlines alone, in order: do they deliver the
266
+ answer? Each slide alone, without a presenter: does it land its one
267
+ message? A miss is a narrative question for the human, not a polish job.
268
+ - **The generated tells.** Heavy weights everywhere, five type sizes on one
269
+ slide, a card around everything, a tiny uppercase kicker over every
270
+ headline, filler numbers, the same composition three slides running with no
271
+ reason. Delete before you add.
335
272
 
336
273
  ## Publishing a deck
337
274
 
338
- The board is the deck: reading order (top-left to bottom-right) is play
339
- order - rearrange the board to reorder the deck. Publish with:
275
+ The board is the deck. Publish with:
340
276
 
341
277
  ```json
342
278
  { "boards": { "pitch": { "max": "comment", "type": "slides",
@@ -345,58 +281,14 @@ order - rearrange the board to reorder the deck. Publish with:
345
281
 
346
282
  `transition`: `fade` (default) or `none`. `chrome`: `full` (default - the
347
283
  standard prototype toolbar and walker), `minimal` (a progress strip +
348
- comments only), or `none`. Add `"lock": true` for a share that is ONLY the
349
- deck.
350
-
351
- ## The living list - `design/slides.md`
352
-
353
- The project's own recipes and rules; it OVERRIDES this file. Its first
354
- section, **the deck look**, is a fill-in template (tokens, type, the mark,
355
- colour meaning, imagery, tempo, numbers, voice, terminology, end card): on
356
- the FIRST deck in a project, draft it from `design/DESIGN.md` and
357
- `theme.css` as a reviewed edit, tell the human, and build on with the
358
- theme's tokens meanwhile - fields you cannot settle stay `TBD`, never
359
- invented. No DESIGN.md yet means the brand doc comes first
360
- (instructions/brand.md). When the human
361
- asks you to study `design/slides-inspiration/` (PPTX, PDFs, screenshots),
362
- propose additions to `design/slides.md` as a normal reviewed edit - each
363
- with a gap justification (what no existing recipe serves) and a stress pass
364
- (minimal / typical / worst-case content, both themes) before it earns its
365
- entry.
366
-
367
- ## The review gate (run it, every deck, before presenting)
368
-
369
- Twelve tells, each a defect: label titles · bullet walls · lines past ~15
370
- words · data without a "so what" · provenance slides (how the work was
371
- done - a process that IS the subject, an operating model or a rollout plan,
372
- is content) · hedge language ·
373
- audience-mismatched jargon · filler words · passive voice · claims missing
374
- numbers · formatting drift between slides · a weak closing.
375
-
376
- Then: the sequence test (titles alone tell the argument) · BOTH themes ·
377
- the slide view AND fill window (the fit scales your composition - check
378
- nothing relied on the window) and one 390px glance · every slide still at
379
- rest (no loops, no autoplay) · the silhouette pacing from step 4, checked
380
- against the storyboard, not the recipe names · anchors inside groups, hard
381
- cuts at the turns.
382
-
383
- Then the two reads that catch what polish hides:
384
- - **Landing, per slide.** Read each slide cold - no presenter, no
385
- neighbours. Does it deliver the one message you planned for it? Landed ·
386
- partial (present but buried or hedged) · missed. A missed message on a
387
- polished slide is still a must-fix.
388
- - **The cold read, whole deck.** Read every assertion and every takeaway
389
- bar in sequence, nothing else. Do they alone deliver the one thing the
390
- human said the audience must leave with? If not, no surface edit fixes it
391
- - take the gap to the human as a narrative question, do not polish
392
- around it.
393
-
394
- Finally the contact sheet: all frames small on the canvas, then squint. If
395
- the deck blurs into one repeated shape with different fillings, it failed -
396
- whatever the recipe names say. One silhouette on more than 40% of the
397
- content slides (decks of eight or more), the same top and bottom horizon on
398
- every slide, dense slides clumped
399
- together, accent fills bunched on neighbours, a card row where one card is
400
- 8 words and the others 40 - each a defect. Iterate until the gate passes; after three passes that
401
- still surface defects, the remaining list goes to the human and the deck
402
- ships at their call.
284
+ comments) or `none`. Add `"lock": true` for a share that is ONLY the deck.
285
+
286
+ ## design/slides.md - this project's deck look
287
+
288
+ The project's own file: the deck look (master, tones, type, mark, imagery,
289
+ drawing style, colour meaning, motion, numbers, voice, end card) and any
290
+ compositions and habits the team wants repeated. On the first deck in a
291
+ project, draft its deck look from `design/DESIGN.md` and `theme.css` as a
292
+ reviewed edit and tell the human; it then outlives every deck. When the
293
+ human asks you to study `design/slides-inspiration/` (PPTX, PDFs,
294
+ screenshots), propose additions to it the same way.