@marver-design/marver 0.13.0 → 0.14.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +73 -0
- package/README.md +41 -19
- package/dist/{build-BxGrHFT2.mjs → build-ByYafIhj.mjs} +37 -5
- package/dist/cli.mjs +19 -5
- package/dist/{daemon-BChkzDqQ.mjs → daemon-Bfucyf1o.mjs} +1 -1
- package/dist/{dev-DLwt3Brb.mjs → dev-yZMyQeUj.mjs} +4 -4
- package/dist/{init-BpitOqRQ.mjs → init-Dvaso7YO.mjs} +66 -2
- package/dist/{manifest-CS6krOTe.mjs → manifest-DvOmglFp.mjs} +7 -0
- package/dist/{marver-id-gate-B2uraTHS.mjs → marver-id-gate-D6By7XHj.mjs} +1 -1
- package/dist/{plugin-DNc4Jpae.mjs → plugin-BsmG5i2X.mjs} +21 -3
- package/dist/{serve-EjEqsiYa.mjs → serve-Bcwfpvhl.mjs} +3 -2
- package/dist/{shot-Cyv3GN79.mjs → shot-kbR_xzJH.mjs} +7 -1
- package/docs/live-jam.md +173 -0
- package/docs/publish.md +270 -0
- package/docs/sharing.md +333 -0
- package/docs/slides.md +134 -0
- package/package.json +3 -1
- package/src/client/const.ts +13 -0
- package/src/client/content/chart-engine.ts +33 -0
- package/src/client/content/chart.tsx +100 -0
- package/src/client/content/index.tsx +25 -4
- package/src/client/content/slide.tsx +238 -0
- package/src/client/content/video.tsx +126 -0
- package/src/client/shell/App.tsx +30 -12
- package/src/client/shell/LockedApp.tsx +7 -2
- package/src/client/shell/Play.tsx +138 -24
- package/src/client/shell/Toolbar.tsx +12 -3
- package/src/client/shell/canvas/FrameNode.tsx +5 -3
- package/src/client/shell/hash.ts +3 -1
- package/src/client/shell/icons.tsx +2 -0
- package/src/client/shell/play-order.ts +22 -0
- package/src/client/shell/store.ts +29 -8
- package/src/client/shell/styles.css +17 -27
- package/src/client/stage/main.tsx +54 -3
- package/src/shared/utm.ts +3 -2
- package/templates/AGENTS-embedded.md +1 -0
- package/templates/AGENTS-studio.md +1 -0
- package/templates/instructions/publish.md +7 -0
- package/templates/instructions/reference/deck-layouts.md +230 -0
- package/templates/instructions/reference/deck-story.md +110 -0
- package/templates/instructions/slides.md +398 -0
|
@@ -21,6 +21,14 @@ const params = new URLSearchParams(location.search)
|
|
|
21
21
|
// token systems, .dark for class-keyed ones (Tailwind/shadcn). Missing the class made
|
|
22
22
|
// play render class-keyed apps light while the canvas showed them dark.
|
|
23
23
|
const bootTheme = params.get('theme') ?? 'light'
|
|
24
|
+
// slides mode (v1.5): the shell says so in the URL; the stage stamps the ONE
|
|
25
|
+
// attribute the content primitives observe (data-sl-play lifts the rest-state
|
|
26
|
+
// motion reset; data-sl-entered arms the entrance presets after each swap
|
|
27
|
+
// settles). `tr=none` and prefers-reduced-motion both skip view transitions.
|
|
28
|
+
const slidesMode = params.get('slides') === '1'
|
|
29
|
+
const deckTransition = params.get('tr') ?? 'fade'
|
|
30
|
+
if (slidesMode) document.documentElement.setAttribute('data-sl-play', '')
|
|
31
|
+
const reducedMotion = typeof matchMedia !== 'undefined' && matchMedia('(prefers-reduced-motion: reduce)').matches
|
|
24
32
|
document.documentElement.dataset.theme = bootTheme
|
|
25
33
|
document.documentElement.classList.toggle('dark', bootTheme === 'dark')
|
|
26
34
|
const startId = params.get('at') ?? ''
|
|
@@ -95,9 +103,41 @@ function Stage() {
|
|
|
95
103
|
// inspect.getId() never reports the new frame while the old DOM is still live -
|
|
96
104
|
// a pick / anchor-resolve landing mid-swap then carries the old id and the shell
|
|
97
105
|
// guards drop it instead of stamping it onto the wrong frame.
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
106
|
+
// slides: the entrance presets re-arm per swap. The disarm (drop `entered`,
|
|
107
|
+
// strip data-animate from morph-owned elements) runs INSIDE the transition's
|
|
108
|
+
// update callback - after the new DOM commits, before the NEW-state capture.
|
|
109
|
+
// Disarming before startViewTransition would capture the OUTGOING slide with
|
|
110
|
+
// its [data-animate] elements at opacity 0 (they'd vanish from the old
|
|
111
|
+
// snapshot), and a morphed element still carrying data-animate would be
|
|
112
|
+
// captured transparent and pop in after the morph.
|
|
113
|
+
const disarm = () => {
|
|
114
|
+
if (!slidesMode) return
|
|
115
|
+
document.documentElement.removeAttribute('data-sl-entered')
|
|
116
|
+
// one transform owner: an element that morphs must not also run an
|
|
117
|
+
// entrance preset - CSS cannot see a computed view-transition-name,
|
|
118
|
+
// so the stage strips data-animate from morph-owned elements here
|
|
119
|
+
for (const el of document.querySelectorAll('[data-animate]'))
|
|
120
|
+
if (getComputedStyle(el).viewTransitionName !== 'none') el.removeAttribute('data-animate')
|
|
121
|
+
}
|
|
122
|
+
const apply = () => { if (seq === swapSeq.current) { flushSync(() => { setErr(null); setMounted(next) }); current.current = id; disarm() } }
|
|
123
|
+
const entered = () => {
|
|
124
|
+
if (!slidesMode || seq !== swapSeq.current) return
|
|
125
|
+
document.documentElement.setAttribute('data-sl-entered', '')
|
|
126
|
+
}
|
|
127
|
+
const skipVt = reducedMotion || (slidesMode && deckTransition === 'none')
|
|
128
|
+
if (document.startViewTransition && !skipVt) {
|
|
129
|
+
const vt = document.startViewTransition(apply)
|
|
130
|
+
vt.finished.then(entered, entered)
|
|
131
|
+
} else if (skipVt) { apply(); entered() }
|
|
132
|
+
else {
|
|
133
|
+
// no view transitions here: a plain crossfade at the deck's tempo, so
|
|
134
|
+
// the one-tempo contract holds even where morphs cannot
|
|
135
|
+
apply(); entered()
|
|
136
|
+
const raw = getComputedStyle(document.documentElement).getPropertyValue('--marver-slide-tempo').trim()
|
|
137
|
+
const m = /^(\d*\.?\d+)\s*(ms|s)?$/i.exec(raw)
|
|
138
|
+
const tempo = m ? parseFloat(m[1]) * (m[2]?.toLowerCase() === 's' ? 1000 : 1) : 350 // a CSS <time>: 350ms or .35s; 0 is honoured
|
|
139
|
+
if (tempo > 0) document.getElementById('root')?.animate([{ opacity: 0.35 }, { opacity: 1 }], { duration: tempo, easing: 'ease-out' })
|
|
140
|
+
}
|
|
101
141
|
if (announce) post({ type: 'sh:stage-at', at: id })
|
|
102
142
|
} catch (e) {
|
|
103
143
|
if (seq !== swapSeq.current) return
|
|
@@ -129,6 +169,12 @@ function Stage() {
|
|
|
129
169
|
// laser/comment click owns the press instead - it must not navigate.
|
|
130
170
|
const onClick = (e: MouseEvent) => {
|
|
131
171
|
if (inspect.modeActive()) return
|
|
172
|
+
// slides: a background click advances (posted as the Space key) - never
|
|
173
|
+
// on anything interactive, and data-goto (below) always wins
|
|
174
|
+
if (slidesMode && e.target instanceof Element
|
|
175
|
+
&& !e.target.closest('a, button, input, textarea, select, video, .mv-video, [contenteditable], [data-goto]')) {
|
|
176
|
+
post({ type: 'sh:stage-key', key: ' ', code: 'Space' })
|
|
177
|
+
}
|
|
132
178
|
const el = e.target instanceof Element ? e.target.closest('[data-goto]') : null
|
|
133
179
|
if (!el) return
|
|
134
180
|
e.preventDefault()
|
|
@@ -149,6 +195,11 @@ function Stage() {
|
|
|
149
195
|
// l/c toggle laser/comment, C (shift+c) hides pins; the shell acts and broadcasts back.
|
|
150
196
|
if (/^Digit[0-9]$/.test(e.code) || ['d', 'h', 'r', 'l', 'c', 'C', '[', ']', 'ArrowRight', 'ArrowLeft'].includes(e.key))
|
|
151
197
|
post({ type: 'sh:stage-key', key: e.key, code: e.code })
|
|
198
|
+
// slides: Space advances - but never stolen from anything interactive
|
|
199
|
+
if (slidesMode && e.key === ' ' && !(e.target instanceof Element && e.target.closest('button, input, textarea, select, video, .mv-video, a, [contenteditable]'))) {
|
|
200
|
+
e.preventDefault()
|
|
201
|
+
post({ type: 'sh:stage-key', key: ' ', code: e.code })
|
|
202
|
+
}
|
|
152
203
|
}
|
|
153
204
|
window.addEventListener('keydown', onKey)
|
|
154
205
|
|
package/src/shared/utm.ts
CHANGED
|
@@ -4,12 +4,13 @@
|
|
|
4
4
|
* utm_source = the surface class ('published-canvas' | 'dev-canvas')
|
|
5
5
|
* utm_medium = the link unit ('powered-by')
|
|
6
6
|
* utm_campaign = THIS canvas's name, slugged ("Marver tour" -> "marver-tour")
|
|
7
|
-
* utm_content = the placement ('gate' badge | 'shell' wordmark | 'sign-in' finish page
|
|
7
|
+
* utm_content = the placement ('gate' badge | 'shell' wordmark | 'sign-in' finish page |
|
|
8
|
+
* 'play-brand' the present/slides brand pill)
|
|
8
9
|
*/
|
|
9
10
|
export function poweredByUrl(
|
|
10
11
|
canvasName: string | undefined,
|
|
11
12
|
source: 'published-canvas' | 'dev-canvas',
|
|
12
|
-
content: 'gate' | 'shell' | 'sign-in',
|
|
13
|
+
content: 'gate' | 'shell' | 'sign-in' | 'play-brand',
|
|
13
14
|
): string {
|
|
14
15
|
const slug = (canvasName ?? '').toLowerCase().trim().replace(/[^a-z0-9]+/g, '-').replace(/^-+|-+$/g, '')
|
|
15
16
|
const q = new URLSearchParams({
|
|
@@ -22,6 +22,7 @@ file in design/instructions/ - they are short, strict, and part of this contract
|
|
|
22
22
|
| Iterate | changing a frame the human has seen, or retiring explorations | instructions/iterate.md |
|
|
23
23
|
| Review | before presenting anything | instructions/review.md |
|
|
24
24
|
| Boards | creating a board, choosing what ships | instructions/boards.md |
|
|
25
|
+
| Slides | a deck is asked for, or `slide: true` frames exist | instructions/slides.md + design/slides.md |
|
|
25
26
|
| Publish | deploying the canvas: gate, volume, accounts, invites | instructions/publish.md |
|
|
26
27
|
| Live Jam | responding to an `@marver` comment (a spawned job); on by default - confirm it names YOUR tool | instructions/jam.md |
|
|
27
28
|
|
|
@@ -22,6 +22,7 @@ file in design/instructions/ - they are short, strict, and part of this contract
|
|
|
22
22
|
| Iterate | changing a frame the human has seen, or retiring explorations | instructions/iterate.md |
|
|
23
23
|
| Review | before presenting anything | instructions/review.md |
|
|
24
24
|
| Boards | creating a board, choosing what ships | instructions/boards.md |
|
|
25
|
+
| Slides | a deck is asked for, or `slide: true` frames exist | instructions/slides.md + design/slides.md |
|
|
25
26
|
| Publish | deploying the canvas: gate, volume, accounts, invites | instructions/publish.md |
|
|
26
27
|
| Live Jam | responding to an `@marver` comment (a spawned job); on by default - confirm it names YOUR tool | instructions/jam.md |
|
|
27
28
|
|
|
@@ -51,6 +51,13 @@ vars if the host has no CLI.
|
|
|
51
51
|
container disk is the one real deploy mistake - comments would vanish on
|
|
52
52
|
redeploy; marver fails loudly if the dir cannot be created.
|
|
53
53
|
|
|
54
|
+
Then one line before you build: **name the canvas** -
|
|
55
|
+
`share: { name: "Your App" }` in `design/config.ts`. The name is the gate's
|
|
56
|
+
title, the brand pill's tooltip, and the `utm_campaign` on every powered-by
|
|
57
|
+
link the canvas emits (the wordmark, the gate, the play brand pill). With no
|
|
58
|
+
name it falls back to the ROOT DIRECTORY, which in a container is `app` -
|
|
59
|
+
every containerised canvas you never named reports as the same campaign.
|
|
60
|
+
|
|
54
61
|
## The serve contract (env vars, complete list)
|
|
55
62
|
|
|
56
63
|
| Var | Meaning |
|
|
@@ -0,0 +1,230 @@
|
|
|
1
|
+
# Deck layouts - the atlas, the grid, the budgets
|
|
2
|
+
|
|
3
|
+
Required reading at step 4 of every deck. The doctrine's recipe list is the core;
|
|
4
|
+
this is the full atlas grouped by the JOB a slide does, the shared stage and the
|
|
5
|
+
optional banded grid recipes draw from, and the content budgets that keep type at design size. The atlas
|
|
6
|
+
is a vocabulary, not a fence: when nothing fits the concept you wrote for the
|
|
7
|
+
slide, compose it from divs.
|
|
8
|
+
|
|
9
|
+
Words used below: **kicker** = the small-caps `sl-caption` label above a title;
|
|
10
|
+
**hero** = a card's one-line headline in `sl-support`; **ghost numeral** = a large,
|
|
11
|
+
low-contrast number behind or beside a card that carries order; **display** =
|
|
12
|
+
`sl-display`, the one oversize role; **stat** = `sl-stat`, the row-of-figures size.
|
|
13
|
+
|
|
14
|
+
## The stage and the banded grid (content box 1104×632px)
|
|
15
|
+
|
|
16
|
+
Stage margins are asymmetric: 88px at the sides, 44px top and bottom, in px
|
|
17
|
+
at every viewport. Every silhouette shares those margins and nothing else.
|
|
18
|
+
The BANDED grid below is the shell for grid and split recipes that carry a
|
|
19
|
+
title band; statements, heroes, fields, and bookends build their own
|
|
20
|
+
geometry inside the same margins. (The doctrine's 85% rule and spacing scale
|
|
21
|
+
govern every silhouette.)
|
|
22
|
+
|
|
23
|
+
- **Title band** - the top ~113px: kicker (18px, one line) over the assertion
|
|
24
|
+
(56px, one line), a hairline under. Within a visual group it sits in the
|
|
25
|
+
same place on each slide, so a travelling title lands where it left.
|
|
26
|
+
- **Body band** - full width, ~438px, starting 48px below the title block.
|
|
27
|
+
Content fills at most ~372px of it. This band is the slide.
|
|
28
|
+
- **Foot** - the source line (25px), 48px under the body. A takeaway bar sits
|
|
29
|
+
between them: 56px tall, 40px clear above it.
|
|
30
|
+
- **Split** - text left at 43% of the width, visual right at 48%, a 9% gutter.
|
|
31
|
+
Argument reads first, proof confirms it. A `sl-assertion` in a 43% column
|
|
32
|
+
holds ~20 characters a line - write to it.
|
|
33
|
+
- **Columns** - three equal at a 32px gap (~347px each); five narrow (~192px)
|
|
34
|
+
for spectrums; a 2×2 when the four cells are peers. Card padding 32px.
|
|
35
|
+
- **Dominance before containers.** Decide what is biggest on the slide before
|
|
36
|
+
choosing what holds the rest. Whitespace that makes the dominant object read
|
|
37
|
+
as dominant needs no defence; a companion panel added to "fill the other
|
|
38
|
+
half" does - if it is not evidence, leave the half empty.
|
|
39
|
+
|
|
40
|
+
The banded skeleton, in the project's own Tailwind - for the grid and split
|
|
41
|
+
slides that carry a title band, and only those:
|
|
42
|
+
|
|
43
|
+
```tsx
|
|
44
|
+
<Slide>
|
|
45
|
+
{/* one child at flex:1 claims the box, so the bands land in the same
|
|
46
|
+
place across a visual group; gap 48 is the title-to-body / body-to-foot step */}
|
|
47
|
+
<div className="flex-1 min-h-0 flex flex-col gap-12">
|
|
48
|
+
<header className="shrink-0">
|
|
49
|
+
<p className="sl-caption uppercase tracking-[.14em]">Retention</p>
|
|
50
|
+
<h1 className="sl-assertion mt-2">Churn halved after onboarding v2</h1>
|
|
51
|
+
<hr className="mt-5 border-0 h-px bg-black/10" />
|
|
52
|
+
</header>
|
|
53
|
+
<div className="flex-1 min-h-0 grid grid-cols-[43fr_9fr_48fr] items-center gap-8">
|
|
54
|
+
<div className="sl-body space-y-6">…argument…</div>
|
|
55
|
+
<div />
|
|
56
|
+
<Chart option={…} />
|
|
57
|
+
</div>
|
|
58
|
+
<footer className="sl-caption shrink-0">Source: product analytics, Aug 2026</footer>
|
|
59
|
+
</div>
|
|
60
|
+
</Slide>
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
## The atlas (when · skeleton · budget · anchor)
|
|
64
|
+
|
|
65
|
+
A recipe without a named anchor does not morph - hard cut. Anchors are named
|
|
66
|
+
only inside a declared visual group or build; never a deck-wide fallback.
|
|
67
|
+
Budgets are heuristics: the rendered 1280×720 frame and the Slide's overflow
|
|
68
|
+
outline are the authority - when they disagree with a number here, the frame
|
|
69
|
+
wins. And a slide that merely FITS is not done: the 85% rule is the bar.
|
|
70
|
+
|
|
71
|
+
**Parallel points**
|
|
72
|
+
- **cards** - 2-6 equal cards (kicker · hero · body), ghost numerals for order,
|
|
73
|
+
at most ONE accented card for the emphasised option. Budget: 2-3 cards carry a
|
|
74
|
+
body (≤120 chars, 3 lines); 4-6 cards are kicker + hero only. Anchor: the row.
|
|
75
|
+
- **spectrum** - 3-7 narrow cards for a progression or maturity model, low to
|
|
76
|
+
high left to right. Budget: kicker ≤8 chars, hero ≤15, body ≤40 (≤5 cards) or
|
|
77
|
+
none (6-7).
|
|
78
|
+
- **columns** - N headers + descriptions + an optional metric strip beneath:
|
|
79
|
+
product lines, tracks, team areas. Budget: ≤4 columns with bodies, ≤6 without.
|
|
80
|
+
- **stacked list** - 4-6 items in the right field, argument on the left; the
|
|
81
|
+
numbered variant carries ghost numerals for ordered reasons. Budget: item ≤2
|
|
82
|
+
lines at 24px. Anchor: the list.
|
|
83
|
+
- **split** - argument left (1-3 short paragraphs, optional `sl-support`
|
|
84
|
+
sub-head), ONE visual right (metric, card, image, chart). The workhorse of
|
|
85
|
+
analytical slides. Anchor: the visual.
|
|
86
|
+
- **insight + evidence** - one large insight left (≤30 words, `sl-support`),
|
|
87
|
+
3-4 evidence items right (one-line title + one line). Anchor: the insight.
|
|
88
|
+
|
|
89
|
+
**Proof**
|
|
90
|
+
- **metric** - one hero number (`sl-display`) with label + sub-line, enclosed
|
|
91
|
+
only when the boundary means something;
|
|
92
|
+
pair with a split or a stat row. Budget: value ≤8 chars, label ≤20, sub ≤30.
|
|
93
|
+
- **stat row** - 3-4 figures across in `sl-stat` with a label under each.
|
|
94
|
+
Budget: value ≤7 chars at 3 across, ≤5 at 4; label ≤4 words. Anchor: the row.
|
|
95
|
+
- **trajectory** - stacked from → to pairs with a label ("$100k → $480k MRR").
|
|
96
|
+
Budget: 3-4 pairs. Anchor: the arrows.
|
|
97
|
+
- **table** - header row with a rule under it, zebra rows, numbers right-aligned,
|
|
98
|
+
units in the header. Budget at 24px: ≤5 columns × ≤6 rows, header ≤15 chars,
|
|
99
|
+
cell ≤14; more than that is two slides or a chart.
|
|
100
|
+
- **mini grid** - N×M small value + label cells with hairline dividers, for a
|
|
101
|
+
dashboard glance. Budget: ≤12 cells (4×3).
|
|
102
|
+
- **takeaway bar** (modifier) - a full-width dark bar at the foot with the
|
|
103
|
+
so-what, centred, no trailing full stop, ≤12 words. Never a paraphrase of the
|
|
104
|
+
assertion - a different angle or nothing.
|
|
105
|
+
|
|
106
|
+
**Contrast**
|
|
107
|
+
- **before / after** - the doctrine's two-up, the "after" side accented.
|
|
108
|
+
- **scenarios** - bear / base / bull columns over a metric list, the recommended
|
|
109
|
+
column highlighted. Budget: 3 scenarios × ≤5 metrics.
|
|
110
|
+
|
|
111
|
+
**Process** (the subject, never the provenance)
|
|
112
|
+
- **flow** - step cards with forward arrows; ≤5 steps keep bodies, 6+ drop to
|
|
113
|
+
labels only. Budget: label ≤15 chars, body ≤40.
|
|
114
|
+
- **cycle** - 3-6 auto-numbered nodes around a centre; four nodes sit square at
|
|
115
|
+
the corners, others on a circle. Budget: label ≤15, body ≤40. Anchor: the ring.
|
|
116
|
+
- **chain** - primary chevrons for the value chain with support bars beneath (the
|
|
117
|
+
enabling activities). Budget: ≤6 chevrons, ≤3 bars.
|
|
118
|
+
- **swim lanes** - lanes (rows) × stages (columns) with mini-cards at the
|
|
119
|
+
intersections: hand-offs, RACI, cross-functional flow. Budget: ≤4 lanes × ≤5
|
|
120
|
+
columns, card ≤8 words.
|
|
121
|
+
- **funnel** - 3-8 narrowing tiers, the drop-off stated. Budget: label + one
|
|
122
|
+
line ≤5 tiers; labels only at 6-8.
|
|
123
|
+
|
|
124
|
+
**Time**
|
|
125
|
+
- **schedule** - sections × time columns, task bars, milestone diamonds. Budget:
|
|
126
|
+
≤7 rows, ≤8 columns. Anchor: the time header.
|
|
127
|
+
- **timeline**, **roadmap phases** - the doctrine's; alternate event labels
|
|
128
|
+
above and below the spine when they crowd.
|
|
129
|
+
|
|
130
|
+
**Structure and position**
|
|
131
|
+
- **layers** - full-width stacked layers with tag pills; the foundation layer
|
|
132
|
+
dark. Budget: ≤5 layers, ≤4 tags each.
|
|
133
|
+
- **org** - boxes + connectors, two levels max; deeper goes to an appendix.
|
|
134
|
+
- **venn** - 2-3 circles with 2-3 items each and a named overlap.
|
|
135
|
+
- **concentric** - TAM / SAM / SOM rings, labels inside the rings, legend right.
|
|
136
|
+
- **pyramid** - 3-6 trapezoid tiers, widest at the top, each tier a label + 1-3
|
|
137
|
+
items. For priority, never for volume (that is the funnel).
|
|
138
|
+
- **number line** - ticks with labels, one highlighted range: pricing tiers, a
|
|
139
|
+
valuation range, benchmarks. Budget: ≤6 ticks.
|
|
140
|
+
- **capability matrix** - competitors × capabilities with empty / half / full
|
|
141
|
+
circles (CSS), us in the first column. Budget: ≤6 × ≤7.
|
|
142
|
+
|
|
143
|
+
**Status**
|
|
144
|
+
- **scorecard** - rows with a red / amber / green dot + a one-line note. ≤7 rows.
|
|
145
|
+
- **heat map** - rows × columns of RAG cells, a legend, no numbers inside cells.
|
|
146
|
+
Budget: ≤6 × ≤6.
|
|
147
|
+
- **tracker** - initiative · owner · phase · next milestone; or decision · owner ·
|
|
148
|
+
date · status. Budget: ≤6 rows, owners as initials badges.
|
|
149
|
+
|
|
150
|
+
**People and voice**
|
|
151
|
+
- **testimonials** - 1-6 quote cards with an initials avatar, name, company -
|
|
152
|
+
attributed voices (the doctrine's quote-wall is unattributed fragments, ≤15
|
|
153
|
+
words). Budget: ≤25 words a quote at ≤4 cards, ≤15 at 5-6. Anchor: the avatars.
|
|
154
|
+
- **team** - 1-8 people: initials, name (≤15 chars), role (≤22). Budget: ≤4
|
|
155
|
+
people carry a bio (≤30 words); 5-8 are name + role.
|
|
156
|
+
- **manifesto** - a single large claim in `sl-support` or `sl-display`, one
|
|
157
|
+
accent-coloured phrase, an attribution line. Budget: ≤20 words. Anchor: the
|
|
158
|
+
accent phrase.
|
|
159
|
+
|
|
160
|
+
**Images**
|
|
161
|
+
- **framed source** - a screenshot, a chart from a PDF, a product shot: the real
|
|
162
|
+
image on the right, framing text on the left saying what it shows. The bitmap
|
|
163
|
+
is at least 2× the CSS box it renders in. Never redraw a source chart as a
|
|
164
|
+
fake: rebuild it as a `Chart` when the underlying data is available, embed the
|
|
165
|
+
render when it is not.
|
|
166
|
+
|
|
167
|
+
## Budgets that keep type at design size
|
|
168
|
+
|
|
169
|
+
| Element | Cap |
|
|
170
|
+
|---|---|
|
|
171
|
+
| card kicker · hero · body | 20 · 30 · 120 chars (bodies only at ≤3 cards) |
|
|
172
|
+
| narrow (spectrum) card | 8 · 15 · 40 chars |
|
|
173
|
+
| metric value · label · sub | 8 · 20 · 30 chars |
|
|
174
|
+
| table header · cell | 15 · 14 chars, ≤5 × ≤6 |
|
|
175
|
+
| flow / cycle label · body | 15 · 40 chars |
|
|
176
|
+
| timeline date · title · body | 8 · 20 · 20 chars |
|
|
177
|
+
| quote | 30 words; testimonial 25 (≤4) / 15 (5-6); quote-wall 15 |
|
|
178
|
+
| bio | 30 words at ≤4 people; name 15 chars, role 22 |
|
|
179
|
+
| takeaway bar | 12 words, one line |
|
|
180
|
+
| body paragraphs | 3-5 short paragraphs, ~600 chars total |
|
|
181
|
+
|
|
182
|
+
A breach is a different recipe or a split. Type never shrinks to fit - the review
|
|
183
|
+
gate reads shrunk type as the tell it is.
|
|
184
|
+
|
|
185
|
+
## Rebuilding an existing deck
|
|
186
|
+
|
|
187
|
+
When the human hands you a finished deck to rebuild on the canvas, ask which
|
|
188
|
+
mode - and default to faithful:
|
|
189
|
+
|
|
190
|
+
- **Faithful** - their order, their words, exactly. You may normalise
|
|
191
|
+
punctuation (em dashes → commas or periods) and number formats; you may not
|
|
192
|
+
change a word. Label titles stay labels. Suggested rewrites go in a comment on
|
|
193
|
+
the frame, never on the slide.
|
|
194
|
+
- **Editorial** (opt-in) - order kept, copy passed through the doctrine's words
|
|
195
|
+
rules: jargon, hedges, filler out; numbers, names, dates verbatim; titles
|
|
196
|
+
turned into assertions where the source supports the claim.
|
|
197
|
+
|
|
198
|
+
Then map shapes - a companion visual ONLY where the source supplies it; a
|
|
199
|
+
paragraph with no metric, image, or chart behind it is a text-led composition,
|
|
200
|
+
and that whitespace is honest:
|
|
201
|
+
|
|
202
|
+
| Source shape | Layout |
|
|
203
|
+
|---|---|
|
|
204
|
+
| a paragraph | split when the source has a companion (metric, image, chart); else text-led |
|
|
205
|
+
| 3 bullets | cards |
|
|
206
|
+
| 4-6 bullets | stacked list (numbered if ordered) |
|
|
207
|
+
| up to 4 numbers | metric grid or stat row |
|
|
208
|
+
| a quote | quote |
|
|
209
|
+
| a table | table (or two slides past the budget) |
|
|
210
|
+
| a chart with its data | `Chart` from the data |
|
|
211
|
+
| an image, chart, schedule, diagram you cannot rebuild losslessly | framed source |
|
|
212
|
+
|
|
213
|
+
## Charts and diagrams - the extra mile
|
|
214
|
+
|
|
215
|
+
- **Decision flows**: boil choices to yes / no, quantify the branches (%, volumes)
|
|
216
|
+
so the eye follows the path that matters, hang customer quotes on the node
|
|
217
|
+
they support.
|
|
218
|
+
- **Waterfalls** beat tables for build-ups and breakdowns: left to right in the
|
|
219
|
+
logical order, the one or two bars that matter highlighted, a few callouts that
|
|
220
|
+
pre-empt the room's questions.
|
|
221
|
+
- **When a slide must be complex**: large visual cues (boxes, highlights) on the
|
|
222
|
+
point, grouping and colour that steer interpretation, and the voiceover ON the
|
|
223
|
+
page - the slide must make sense with no presenter.
|
|
224
|
+
- **Aggregate.** The chart is not the model. Single series is fine. Overlay
|
|
225
|
+
detail (lines, shading) on the base chart instead of adding a second chart.
|
|
226
|
+
- **Formatting**: label bars directly and drop the value axis when the chart is
|
|
227
|
+
simple (keep the axis for dense or grouped series); growth rates visible; one
|
|
228
|
+
label size across the deck; series in logical order (base first, growth
|
|
229
|
+
next); same hue = same thing on every slide; charts aligned to the grid and to
|
|
230
|
+
each other across slides.
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
# Deck story - the argument before the slides
|
|
2
|
+
|
|
3
|
+
The slides doctrine (instructions/slides.md) gives the pipeline. This file is the
|
|
4
|
+
depth behind steps 1-3: how to find the answer, shape the argument, calibrate it to
|
|
5
|
+
the room, and write words that carry it. Pull it when the material is thin or
|
|
6
|
+
rich, the audience is senior, or the first slide list reads like a table of
|
|
7
|
+
contents.
|
|
8
|
+
|
|
9
|
+
## Intake - seven questions, one message
|
|
10
|
+
|
|
11
|
+
Ask them all at once; skip any the human already answered (pasted bullets, a linked
|
|
12
|
+
doc). The first three are required - ask again if skipped, they shape everything.
|
|
13
|
+
|
|
14
|
+
0. **The one thing.** If they remember nothing else, what? ("Approve the Q3 budget",
|
|
15
|
+
"Retention is the lever, not acquisition".)
|
|
16
|
+
1. **The goal.** What happens after the last slide? (a decision, alignment, a meeting)
|
|
17
|
+
2. **The audience.** Executives / cross-functional team / own team / external
|
|
18
|
+
(client, partner, board). Named people help.
|
|
19
|
+
3. **Raw material.** Bullets, a doc, "start from scratch" - messy is fine.
|
|
20
|
+
4. **Numbers.** Metrics and proof points. Numbers make slides land.
|
|
21
|
+
5. **The energy.** Urgent / confident / informational / exploratory.
|
|
22
|
+
6. **Constraints.** Time, slide cap, topics to avoid, must-have slides, who presents.
|
|
23
|
+
|
|
24
|
+
## Find the answer first - five questions, in order
|
|
25
|
+
|
|
26
|
+
| Ask | Yields |
|
|
27
|
+
|---|---|
|
|
28
|
+
| What is top of mind for the audience - goal, worry, definition of success? | the objective |
|
|
29
|
+
| Twenty seconds in a lift: what do you tell them? | THE ANSWER |
|
|
30
|
+
| Which logical steps take them from where they are to the answer? | the storyline |
|
|
31
|
+
| Where will they disagree? What moves them to act? | the slides |
|
|
32
|
+
| What do you not know? What is the burden of proof? | the evidence |
|
|
33
|
+
|
|
34
|
+
Top-down, always. Never start from the slides or the analysis. The answer's shape:
|
|
35
|
+
context ("this matters, in these ways") · options ("two paths, here they are") ·
|
|
36
|
+
recommendation ("the first, for these reasons") · next steps ("what it takes, by
|
|
37
|
+
when"). "We don't know yet, but here is how we find out" IS an answer; a hedge is not.
|
|
38
|
+
|
|
39
|
+
**The pyramid.** Slides 1-2 carry the conclusion. Each argument is a slide group.
|
|
40
|
+
Evidence sits under its argument, never free-floating. A deck where the answer
|
|
41
|
+
arrives on slide 14 has been built bottom-up - rebuild it.
|
|
42
|
+
|
|
43
|
+
**Insights first, outputs second, provenance never.** How the model works,
|
|
44
|
+
what alternatives were considered, how long it took, what went wrong - none
|
|
45
|
+
of it belongs in the room. Time spent making a slide earns it nothing. (A
|
|
46
|
+
process that IS the subject - the operating model you propose, the rollout
|
|
47
|
+
plan - is content, and the atlas has layouts for it.)
|
|
48
|
+
|
|
49
|
+
## Calibrate to the room
|
|
50
|
+
|
|
51
|
+
- **Executives** - so-what framing, 12-15 slides, one ask.
|
|
52
|
+
- **The team** - actionable detail: owners, dates, dependencies.
|
|
53
|
+
- **External (client, partner, investor)** - polished narrative, social proof,
|
|
54
|
+
evidence-heavy, the firm's specific language in the titles.
|
|
55
|
+
- **Board** - trajectory, risks, asks. Concise.
|
|
56
|
+
- **Summary vs full material.** A summary is the conversation about the
|
|
57
|
+
answer: sized to HALF the meeting (a 45-minute slot carries 12-20 slides;
|
|
58
|
+
the rest is discussion). The full deck is the reference ("see slide 53"),
|
|
59
|
+
organised behind the thesis and its drivers, as long as it needs to be.
|
|
60
|
+
Know which you are building; never blend them.
|
|
61
|
+
- **Wayfinding.** An agenda only when there are three or more sections, each
|
|
62
|
+
item a section name + the slide it starts on. Section dividers only past ~25
|
|
63
|
+
slides - below that, section changes live in the assertions themselves.
|
|
64
|
+
|
|
65
|
+
## The evidence check - before designing anything
|
|
66
|
+
|
|
67
|
+
Walk every planned slide with one question: could I draft this without inventing a
|
|
68
|
+
single fact? Mark it has-enough or not. For the gaps, write SPECIFIC questions (not
|
|
69
|
+
"more on the team" but "which four people, prior firms, role on this project?"),
|
|
70
|
+
at most two or three per slide, only where the answer changes the slide. Then one
|
|
71
|
+
deck-level call:
|
|
72
|
+
- **ask** - the default when any slide lacks material; put the consolidated list
|
|
73
|
+
to the human before building;
|
|
74
|
+
- **shrink to the evidence** - when most slides lack material and the human
|
|
75
|
+
plainly has no more (early stage, the narrative is the product) - propose the
|
|
76
|
+
smaller deck;
|
|
77
|
+
- **proceed with placeholders** - only when the gaps are editorial (framing,
|
|
78
|
+
taglines), never data (numbers, names, dates).
|
|
79
|
+
|
|
80
|
+
Every claim traces to source, and the gap has a stage. In the scaffold (the
|
|
81
|
+
one-sentence slides on the canvas) a missing fact is a visible `[PLACEHOLDER:
|
|
82
|
+
what belongs here]`. In the build, a factual placeholder BLOCKS its slide -
|
|
83
|
+
answered, or the slide is cut - never filled with plausible prose. Editorial
|
|
84
|
+
gaps (a tagline, a caption, a transition line) you DO draft, labelled as
|
|
85
|
+
proposed in the frame's comment - that is writing, not invention.
|
|
86
|
+
|
|
87
|
+
## Writing that carries
|
|
88
|
+
|
|
89
|
+
- **Distil the voice first.** Scan the material for concepts that recur on three
|
|
90
|
+
or more slides; give each a 2-4 word mnemonic, imperative verb preferred
|
|
91
|
+
("Decide fast", "See everything"), and use it identically everywhere it applies.
|
|
92
|
+
- **Mine the material for specifics** and keep them verbatim: "19 of 25 operators"
|
|
93
|
+
beats "most operators"; "$100k to $480k MRR" (from X to Y) beats "grew strongly".
|
|
94
|
+
- **Assertions fit their box.** ~40 characters full-width, ~20 inside a split,
|
|
95
|
+
two lines the ceiling - compress the phrasing, keep the claim, never shrink
|
|
96
|
+
the type, and check the render.
|
|
97
|
+
- **Paragraphs over bullets for narrative.** 15-30 words, one to three per block.
|
|
98
|
+
Bullets are for parallel lists and action items; a bullet with "and" is two.
|
|
99
|
+
- **Tone follows the energy.** Urgent: "Double down now or miss the target."
|
|
100
|
+
Confident: "Retention hit 85%, the best quarter yet." Informational: "Retention
|
|
101
|
+
stands at 85%, up 12 points." Exploratory: "Three approaches, different trade-offs."
|
|
102
|
+
- **Voice follows the deck type.** Strategy commits to positions. A pitch is warm
|
|
103
|
+
and aspirational. A case study attributes results to named actions. A status
|
|
104
|
+
update is crisp - state, delta, next.
|
|
105
|
+
- **Kill list, extended.** Beyond the doctrine's: "utilize", "unlock", "harness",
|
|
106
|
+
"empower", "seamless", "delve", "unleash", "synergize", "operationalize",
|
|
107
|
+
"cutting-edge", "best-in-class", "at the end of the day", "in terms of".
|
|
108
|
+
- **The ask closes.** Decision, owner, date: "Approve $200k for Q3 retention by
|
|
109
|
+
Friday." The closing slide is that ask - if the house style ends on a bare
|
|
110
|
+
end card (mark on an image), the ask is the slide before it.
|