@hypersocial/decks-cli 0.9.6 → 0.9.8
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/README.md +1 -1
- package/package.json +1 -1
- package/skills/hyperdecks/SKILL.md +104 -17
- package/skills/hyperdecks/chat.md +10 -7
- package/src/checkRules.mjs +107 -0
- package/src/commands.mjs +42 -25
- package/src/files.mjs +1 -0
- package/src/guide.mjs +2 -2
- package/src/init.mjs +8 -4
- package/src/layouts.mjs +3 -3
- package/src/loadingBlock.mjs +43 -12
- package/src/ops.mjs +46 -15
- package/src/presenter.mjs +102 -16
- package/src/preview.mjs +2 -2
- package/src/release.mjs +11 -7
- package/src/runtime.mjs +62 -2
- package/templates/layouts/_deck.html +51 -0
- package/templates/layouts/chart.html +5 -0
- package/templates/layouts/closer.html +5 -0
- package/templates/layouts/compare.html +5 -0
- package/templates/layouts/features.html +6 -0
- package/templates/layouts/hero.html +5 -0
- package/templates/layouts/number.html +5 -0
- package/templates/layouts/phones.html +5 -0
- package/templates/layouts/product.html +5 -0
- package/templates/layouts/quote.html +6 -0
- package/templates/layouts/split.html +53 -0
- package/templates/layouts/team.html +6 -0
- package/templates/layouts/timeline.html +5 -0
|
@@ -56,12 +56,17 @@
|
|
|
56
56
|
/* The type scale: one display size per slide at most, then title, sub (a title beside a visual), lead, body, label. */
|
|
57
57
|
--t-display: 128px; --t-title: 84px; --t-sub: 56px; --t-lead: 30px; --t-body: 24px; --t-label: 17px;
|
|
58
58
|
--hd-ground: var(--accent); --hd-ground-ink: var(--ink); /* the loading state: the first slide's colours */
|
|
59
|
+
/* Soft grounds (on-tint, on-tint-2, on-tint-3): washes of the accents, so slide changes read without going loud. */
|
|
60
|
+
--tint-1: color-mix(in srgb, var(--accent) 18%, var(--paper)); --tint-2: color-mix(in srgb, var(--accent-2) 20%, var(--paper)); --tint-3: color-mix(in srgb, var(--accent-3, var(--accent)) 24%, var(--paper));
|
|
59
61
|
}
|
|
60
62
|
* { box-sizing: border-box; margin: 0; padding: 0; }
|
|
61
63
|
body { color: var(--ink); font-family: var(--font); font-weight: 500; -webkit-font-smoothing: antialiased; --hd-font: var(--font); --hd-mono: var(--mono); }
|
|
62
64
|
.slide { display: flex; flex-direction: column; gap: 24px; padding: 64px 72px 56px; background: var(--paper); color: var(--ink); --hd-speech: #f3c9dc; }
|
|
63
65
|
.slide.on-accent { background: var(--accent); --hd-speech: var(--card); }
|
|
64
66
|
.slide.on-ink { background: var(--ink); color: var(--paper); --hd-speech: #d9ccff; }
|
|
67
|
+
.slide.on-tint { background: var(--tint-1); --hd-speech: var(--card); }
|
|
68
|
+
.slide.on-tint-2 { background: var(--tint-2); --hd-speech: var(--card); }
|
|
69
|
+
.slide.on-tint-3 { background: var(--tint-3); --hd-speech: var(--card); }
|
|
65
70
|
.kicker { font: var(--t-label) var(--mono); letter-spacing: .16em; text-transform: uppercase; }
|
|
66
71
|
.tt { font-family: var(--display, var(--font)); font-weight: 700; font-size: var(--t-title); line-height: .95; letter-spacing: -.045em; text-wrap: balance; }
|
|
67
72
|
.lead { font-size: var(--t-lead); line-height: 1.3; max-width: 28em; text-wrap: pretty; }
|
|
@@ -71,6 +76,12 @@
|
|
|
71
76
|
.narration-slot { position: absolute; right: 56px; bottom: 64px; }
|
|
72
77
|
.slot-left .narration-slot { right: auto; left: 56px; }
|
|
73
78
|
.slot-top .narration-slot { top: 96px; bottom: auto; }
|
|
79
|
+
/* No presenter (no face AND no captions, e.g. presenter none on a
|
|
80
|
+
data-silent deck; or forced off by setPresenterOff): the player puts
|
|
81
|
+
.hd-no-presenter on the root and hides the slot, each layout's
|
|
82
|
+
no-presenter variant (:root.hd-no-presenter .l-…) uses the corner, and on
|
|
83
|
+
phones the slide drops its 170px bottom padding (below). Keep custom slides
|
|
84
|
+
compatible: leave the corner to .narration-slot, no hard-coded right gutter. */
|
|
74
85
|
.reveal { opacity: 0; transform: translateY(12px); transition: opacity .5s, transform .5s; }
|
|
75
86
|
.reveal.is-revealed { opacity: 1; transform: none; }
|
|
76
87
|
/* The phone card (product's .frame.card, the phones row): a frameless phone,
|
|
@@ -97,17 +108,57 @@
|
|
|
97
108
|
.slide.bg-dots::before { content: ""; position: absolute; inset: 0; z-index: -1; pointer-events: none; background: radial-gradient(color-mix(in srgb, currentColor 24%, transparent) 3px, transparent 3.6px) 0 0 / 36px 36px; -webkit-mask-image: linear-gradient(var(--dots-fade, 90deg), transparent 40%, #000 80%); mask-image: linear-gradient(var(--dots-fade, 90deg), transparent 40%, #000 80%); }
|
|
98
109
|
.slide > .deco { position: absolute; inset: 0; z-index: -1; pointer-events: none; }
|
|
99
110
|
.slide > .deco > span { position: absolute; display: grid; place-items: center; width: 80px; height: 80px; border: 3px solid var(--ink); border-radius: 20px; background: var(--card); box-shadow: 8px 8px 0 var(--ink); color: var(--ink); font: 700 34px var(--font); }
|
|
111
|
+
/* The look kit (deck_guide topic look): one texture per deck, one icon set, real pictures.
|
|
112
|
+
Textures go on the section, behind the content, on a few slides: bg-lines, diagonal
|
|
113
|
+
speed lines fading out towards the text (--fade-at: where they are strongest, default
|
|
114
|
+
the right); bg-halftone, a corner of halftone dots (--fade-at, default top right);
|
|
115
|
+
bg-rays, rays from a point (--rays-at), for an opener or a closer. */
|
|
116
|
+
.slide:is(.bg-lines, .bg-halftone, .bg-rays) { isolation: isolate; overflow: hidden; }
|
|
117
|
+
.slide:is(.bg-lines, .bg-halftone, .bg-rays)::before { content: ""; position: absolute; inset: 0; z-index: -1; pointer-events: none; }
|
|
118
|
+
.slide.bg-lines::before { background: repeating-linear-gradient(-22deg, transparent 0 30px, color-mix(in srgb, currentColor 10%, transparent) 30px 32px); -webkit-mask-image: radial-gradient(1000px 780px at var(--fade-at, 82% 52%), #000 12%, transparent 70%); mask-image: radial-gradient(1000px 780px at var(--fade-at, 82% 52%), #000 12%, transparent 70%); }
|
|
119
|
+
.slide.bg-halftone::before { background: radial-gradient(color-mix(in srgb, currentColor 22%, transparent) 2.6px, transparent 3px) 0 0 / 22px 22px; -webkit-mask-image: radial-gradient(640px 640px at var(--fade-at, 88% 14%), #000 25%, transparent 70%); mask-image: radial-gradient(640px 640px at var(--fade-at, 88% 14%), #000 25%, transparent 70%); }
|
|
120
|
+
.slide.bg-rays::before { background: repeating-conic-gradient(from 0deg at var(--rays-at, 72% 50%), color-mix(in srgb, currentColor 9%, transparent) 0deg 2.2deg, transparent 2.2deg 9deg); -webkit-mask-image: radial-gradient(circle at var(--rays-at, 72% 50%), transparent 10%, #000 45%); mask-image: radial-gradient(circle at var(--rays-at, 72% 50%), transparent 10%, #000 45%); }
|
|
121
|
+
/* Pieces. .sticker: a logo or icon tile, tilted (--tilt), ink edge, hard offset
|
|
122
|
+
shadow (.sticker.photo for a face or an app icon that fills it). .ticks: a short
|
|
123
|
+
list with accent-square bullets. .panel: a quiet card. .pill: a small tag. */
|
|
124
|
+
.sticker { --tilt: -3deg; display: inline-grid; place-items: center; flex: none; width: 96px; height: 96px; padding: 18px; border: 4px solid var(--ink); border-radius: 26px; background: var(--card); color: var(--ink); box-shadow: 6px 6px 0 var(--ink); transform: rotate(var(--tilt)); }
|
|
125
|
+
.sticker > :is(img, svg) { width: 100%; height: 100%; object-fit: contain; }
|
|
126
|
+
.sticker.photo { padding: 0; overflow: hidden; }
|
|
127
|
+
.sticker.photo > img { object-fit: cover; }
|
|
128
|
+
.ticks { list-style: none; display: flex; flex-direction: column; gap: 14px; }
|
|
129
|
+
.ticks li { position: relative; padding-left: 34px; font-size: var(--t-body); line-height: 1.3; font-weight: 600; }
|
|
130
|
+
.ticks li::before { content: ""; position: absolute; left: 0; top: .4em; width: 16px; height: 16px; border-radius: 5px; background: var(--accent); }
|
|
131
|
+
.on-accent .ticks li::before { background: var(--ink); }
|
|
132
|
+
.panel { padding: 24px 28px; border-radius: 22px; background: color-mix(in srgb, currentColor 6%, transparent); }
|
|
133
|
+
.pill { display: inline-flex; align-items: center; gap: 8px; width: fit-content; padding: 8px 16px; border-radius: 999px; background: var(--card); color: var(--ink); font: 700 var(--t-label) var(--mono); letter-spacing: .08em; text-transform: uppercase; box-shadow: 4px 4px 0 var(--accent); }
|
|
134
|
+
.on-accent .pill { box-shadow: 4px 4px 0 var(--ink); }
|
|
135
|
+
/* A laptop for a desktop screenshot or clip: a .frame.laptop holding an img.shot or video.shot. */
|
|
136
|
+
.slide .frame.laptop { position: relative; width: 860px; max-width: 100%; padding: 14px 14px 22px; border-radius: 20px 20px 6px 6px; background: #1a1a1d; box-shadow: 0 30px 70px color-mix(in srgb, var(--ink) 22%, transparent); }
|
|
137
|
+
.slide .frame.laptop::after { content: ""; position: absolute; left: -6%; right: -6%; bottom: -16px; height: 16px; border-radius: 0 0 16px 16px; background: linear-gradient(#d9d9de, #a9a9b0); }
|
|
138
|
+
.slide .frame.laptop > .shot { display: block; width: 100%; aspect-ratio: 16 / 10; border-radius: 6px; object-fit: cover; object-position: top; background: var(--paper); }
|
|
100
139
|
/* Phones: the slide is the 374×736 card; the presenter is a small head in
|
|
101
140
|
the corner, so keep the bottom 170px clear. */
|
|
102
141
|
@media (max-width: 650px) {
|
|
103
142
|
:root { --t-display: 54px; --t-title: 38px; --t-sub: 28px; --t-lead: 17px; --t-body: 15px; --t-label: 12px; }
|
|
104
143
|
.slide { padding: 28px 20px 170px; gap: 14px; }
|
|
105
144
|
.narration-slot { right: 12px; left: 12px; bottom: 64px; }
|
|
145
|
+
:root.hd-no-presenter .slide { padding-bottom: 28px; }
|
|
106
146
|
.slide .frame.card { width: 160px; padding: 5px; border-width: 2px; border-radius: 24px; box-shadow: 8px 8px 0 var(--shadow); }
|
|
107
147
|
.slide .frame.card > .shot { border-radius: 19px; border-width: 1px; }
|
|
108
148
|
/* The text fills the card's width: the dots fade in towards the bottom, and the tiles stay off. */
|
|
109
149
|
.slide.bg-dots::before { background-size: 22px 22px; background-image: radial-gradient(color-mix(in srgb, currentColor 24%, transparent) 2px, transparent 2.5px); -webkit-mask-image: linear-gradient(180deg, transparent 45%, #000 85%); mask-image: linear-gradient(180deg, transparent 45%, #000 85%); }
|
|
110
150
|
.slide > .deco { display: none; }
|
|
151
|
+
/* Textures fade in towards the bottom, under the presenter, away from the text. */
|
|
152
|
+
.slide:is(.bg-lines, .bg-halftone)::before { -webkit-mask-image: linear-gradient(180deg, transparent 40%, #000 90%); mask-image: linear-gradient(180deg, transparent 40%, #000 90%); }
|
|
153
|
+
.slide.bg-halftone::before { background-size: 14px 14px; background-image: radial-gradient(color-mix(in srgb, currentColor 22%, transparent) 1.6px, transparent 2px); }
|
|
154
|
+
.sticker { width: 48px; height: 48px; padding: 9px; border-width: 2px; border-radius: 13px; box-shadow: 3px 3px 0 var(--ink); }
|
|
155
|
+
.ticks { gap: 6px; }
|
|
156
|
+
.ticks li { padding-left: 18px; }
|
|
157
|
+
.ticks li::before { width: 9px; height: 9px; border-radius: 3px; }
|
|
158
|
+
.panel { padding: 10px 12px; border-radius: 12px; }
|
|
159
|
+
.pill { padding: 4px 10px; box-shadow: 2px 2px 0 var(--accent); }
|
|
160
|
+
.slide .frame.laptop { padding: 5px 5px 9px; border-radius: 10px 10px 3px 3px; }
|
|
161
|
+
.slide .frame.laptop::after { bottom: -7px; height: 7px; border-radius: 0 0 8px 8px; }
|
|
111
162
|
}
|
|
112
163
|
</style>
|
|
113
164
|
<!-- LAYOUT STYLES -->
|
|
@@ -4,6 +4,7 @@ summary: A chart of real numbers with its takeaway in one line; the presenter be
|
|
|
4
4
|
use: a trend or a comparison in numbers. Its svg is a placeholder of made-up numbers check fails on: draw the real data with `hyperdecks chart` (render_chart; never a generated picture of a chart) as <img class="chart"> and name the data's source.
|
|
5
5
|
slot: bottom-right
|
|
6
6
|
presenter: stage
|
|
7
|
+
nopresenter: The chart spans both columns, under the takeaway.
|
|
7
8
|
cues: [look: #__ID__-chart] when the narration turns to it; [reveal: #__ID__-takeaway] at the point.
|
|
8
9
|
script: Here are the numbers. [look: #__ID__-chart] The last bar is the one to see. [reveal: #__ID__-takeaway]
|
|
9
10
|
-->
|
|
@@ -23,6 +24,10 @@ script: Here are the numbers. [look: #__ID__-chart] The last bar is the one to s
|
|
|
23
24
|
.l-chart .chart { height: 210px; flex: none; }
|
|
24
25
|
.l-chart .takeaway { padding-left: 12px; border-left-width: 4px; }
|
|
25
26
|
}
|
|
27
|
+
/* No presenter (:root.hd-no-presenter: no face and no captions, deck_guide look): the corner is free. Phones keep this layout's rules. */
|
|
28
|
+
@media (min-width: 651px) {
|
|
29
|
+
:root.hd-no-presenter .l-chart .chart { grid-column: 1 / -1; }
|
|
30
|
+
}
|
|
26
31
|
</style>
|
|
27
32
|
<section class="slide l-chart" id="__ID__" data-chapter="The numbers" data-note="Data: name the source of the numbers and the period they cover.">
|
|
28
33
|
<div class="kicker">The numbers</div>
|
|
@@ -4,6 +4,7 @@ summary: The last slide. One line, the one action to take (a command, a link) an
|
|
|
4
4
|
use: the end. One call to action, never three. Label an ask that is not agreed as Proposed.
|
|
5
5
|
slot: bottom-left
|
|
6
6
|
presenter: stage
|
|
7
|
+
nopresenter: The line and the action drop the left gutter and re-centre in the full frame.
|
|
7
8
|
cues: [go: #__ID__-cta] at the action, [go: slot] and [wave] at the goodbye.
|
|
8
9
|
script: That's it. [go: #__ID__-cta] Here is the one thing to do next. Thanks [go: slot] for watching! [wave]
|
|
9
10
|
-->
|
|
@@ -16,6 +17,10 @@ script: That's it. [go: #__ID__-cta] Here is the one thing to do next. Thanks [g
|
|
|
16
17
|
.l-closer .content { padding-left: 0; justify-content: flex-start; gap: 16px; }
|
|
17
18
|
.l-closer .cta { padding: 12px 16px; border-radius: 14px; font-size: 15px; }
|
|
18
19
|
}
|
|
20
|
+
/* No presenter (:root.hd-no-presenter: no face and no captions, deck_guide look): the corner is free. Phones keep this layout's rules. */
|
|
21
|
+
@media (min-width: 651px) {
|
|
22
|
+
:root.hd-no-presenter .l-closer .content { padding-left: 0; align-self: center; align-items: center; text-align: center; }
|
|
23
|
+
}
|
|
19
24
|
</style>
|
|
20
25
|
<section class="slide on-ink l-closer slot-left" id="__ID__" data-chapter="Next" data-note="Closing slide: the link or command is the deck's own call to action.">
|
|
21
26
|
<div class="content">
|
|
@@ -4,6 +4,7 @@ summary: Before and after (or them and us) side by side, three short lines each.
|
|
|
4
4
|
use: the change your idea makes. Keep the rows parallel so each line has its counterpart.
|
|
5
5
|
slot: bottom-right
|
|
6
6
|
presenter: stage
|
|
7
|
+
nopresenter: The two columns widen to the full frame.
|
|
7
8
|
cues: [look: #__ID__-before] on the old way, [go: #__ID__-after] on the new; [go: slot] to come home.
|
|
8
9
|
script: Today it looks like this. [look: #__ID__-before] With us, [go: #__ID__-after] it looks like this. [go: slot]
|
|
9
10
|
-->
|
|
@@ -21,6 +22,10 @@ script: Today it looks like this. [look: #__ID__-before] With us, [go: #__ID__-a
|
|
|
21
22
|
.l-compare .label { margin-bottom: 4px; }
|
|
22
23
|
.l-compare li { padding: 5px 0; }
|
|
23
24
|
}
|
|
25
|
+
/* No presenter (:root.hd-no-presenter: no face and no captions, deck_guide look): the corner is free. Phones keep this layout's rules. */
|
|
26
|
+
@media (min-width: 651px) {
|
|
27
|
+
:root.hd-no-presenter .l-compare .cols { max-width: none; }
|
|
28
|
+
}
|
|
24
29
|
</style>
|
|
25
30
|
<section class="slide l-compare" id="__ID__" data-chapter="Before and after" data-note="Source: name where each side's facts come from.">
|
|
26
31
|
<div class="kicker">Before and after</div>
|
|
@@ -4,6 +4,7 @@ summary: Three features side by side, an icon, a name and one line each; the pre
|
|
|
4
4
|
use: what it does, the three reasons, the three parts. Swap each icon for a real one: `hyperdecks icons search <word>` (search_icons) gives inline SVG in currentColor.
|
|
5
5
|
slot: bottom-right
|
|
6
6
|
presenter: stage
|
|
7
|
+
nopresenter: The title and cards centre vertically and the cards grow a little, instead of leaving a strip below for the presenter.
|
|
7
8
|
cues: [go: #__ID__-f1], [go: #__ID__-f2], [go: #__ID__-f3] at the word that starts each, then [go: slot].
|
|
8
9
|
script: It does three things. First, [go: #__ID__-f1] it writes. Then [go: #__ID__-f2] it speaks. Last, [go: #__ID__-f3] it sends. [go: slot]
|
|
9
10
|
-->
|
|
@@ -22,6 +23,11 @@ script: It does three things. First, [go: #__ID__-f1] it writes. Then [go: #__ID
|
|
|
22
23
|
.l-features b { font-size: 18px; }
|
|
23
24
|
.l-features p { font-size: 13px; }
|
|
24
25
|
}
|
|
26
|
+
/* No presenter (:root.hd-no-presenter: no face and no captions, deck_guide look): the corner is free. Phones keep this layout's rules. */
|
|
27
|
+
@media (min-width: 651px) {
|
|
28
|
+
:root.hd-no-presenter .l-features { justify-content: center; }
|
|
29
|
+
:root.hd-no-presenter .l-features .card { padding: 36px 34px; }
|
|
30
|
+
}
|
|
25
31
|
</style>
|
|
26
32
|
<section class="slide l-features" id="__ID__" data-chapter="What it does" data-note="Source: name the spec, docs or repo each feature is described in.">
|
|
27
33
|
<div class="kicker">What it does</div>
|
|
@@ -4,6 +4,7 @@ summary: The opening. One display-size line, a visual on the right, the presente
|
|
|
4
4
|
use: the first slide; a section opener. Its .art is a placeholder check fails on: put in a picture of the real subject (gen-image / generate_image) as <img class="art">, or delete the div and let the presenter be the visual.
|
|
5
5
|
slot: bottom-right
|
|
6
6
|
presenter: stage
|
|
7
|
+
nopresenter: With art (the placeholder div counts), unchanged: the art already fills the right. Delete the art and the line re-centres in the full frame.
|
|
7
8
|
cues: [wave] at the hello, [look: h1] when the narration says the title.
|
|
8
9
|
script: Hi, [wave] this is __TITLE__. [look: h1] One idea, in a few minutes.
|
|
9
10
|
-->
|
|
@@ -21,6 +22,10 @@ script: Hi, [wave] this is __TITLE__. [look: h1] One idea, in a few minutes.
|
|
|
21
22
|
.l-hero .art { width: 100%; height: 230px; -webkit-mask-image: linear-gradient(to bottom, #000 60%, transparent); mask-image: linear-gradient(to bottom, #000 60%, transparent); }
|
|
22
23
|
.l-hero div.art::after { left: 50%; top: 45%; padding: 8px 14px; border-width: 2px; font-size: 13px; }
|
|
23
24
|
}
|
|
25
|
+
/* No presenter (:root.hd-no-presenter: no face and no captions, deck_guide look): the corner is free. Phones keep this layout's rules. */
|
|
26
|
+
@media (min-width: 651px) {
|
|
27
|
+
:root.hd-no-presenter .l-hero:not(:has(> .art)) .content { align-self: center; align-items: center; text-align: center; max-width: 1200px; }
|
|
28
|
+
}
|
|
24
29
|
</style>
|
|
25
30
|
<section class="slide on-accent l-hero" id="__ID__" data-chapter="Hello" data-note="Title slide: no facts.">
|
|
26
31
|
<div class="art" role="presentation"></div>
|
|
@@ -4,6 +4,7 @@ summary: One big number, what it measures and its source. The number is the slid
|
|
|
4
4
|
use: proof, traction, a before/after delta. Never an estimate shown as fact: the source line is required.
|
|
5
5
|
slot: bottom-right
|
|
6
6
|
presenter: stage
|
|
7
|
+
nopresenter: The figure, title and source re-centre in the full frame.
|
|
7
8
|
cues: [look: #__ID__-figure] as the narration says the number; [reveal: #__ID__-source] optional.
|
|
8
9
|
script: Here is the number that matters. [look: #__ID__-figure] Three times faster.
|
|
9
10
|
-->
|
|
@@ -17,6 +18,10 @@ script: Here is the number that matters. [look: #__ID__-figure] Three times fast
|
|
|
17
18
|
.l-number .content { justify-content: flex-start; gap: 12px; }
|
|
18
19
|
.l-number .figure { font-size: 120px; }
|
|
19
20
|
}
|
|
21
|
+
/* No presenter (:root.hd-no-presenter: no face and no captions, deck_guide look): the corner is free. Phones keep this layout's rules. */
|
|
22
|
+
@media (min-width: 651px) {
|
|
23
|
+
:root.hd-no-presenter .l-number .content { align-self: center; align-items: center; text-align: center; max-width: 1200px; }
|
|
24
|
+
}
|
|
20
25
|
</style>
|
|
21
26
|
<section class="slide on-ink l-number" id="__ID__" data-chapter="The number" data-note="Source: name the dashboard, report or email the number comes from, with its date.">
|
|
22
27
|
<div class="content">
|
|
@@ -4,6 +4,7 @@ summary: A fanned row of two to four phone cards (the inner ones larger and in f
|
|
|
4
4
|
use: a phone app's flow or its key screens. Each card's .shot is a placeholder check fails on: put in a phone-size screenshot (`hyperdecks screenshot <url> --width 390 --height 844`, capture_url) as <img class="shot">, or a screen recording as <video class="shot" autoplay muted loop playsinline>. Two to four cards: the row spaces and tilts them (on phones only the first three show); change one card's --tilt or --shadow on it. One phone only: use product with .frame.card.
|
|
5
5
|
slot: bottom-left
|
|
6
6
|
presenter: stage
|
|
7
|
+
nopresenter: The copy centres vertically beside the row instead of leaving the bottom-left free.
|
|
7
8
|
cues: [look: #__ID__-row] when the narration turns to the app; [go: #__ID__-p1] … [go: #__ID__-p3] to walk the screens, then [go: slot].
|
|
8
9
|
script: Here is the app on a phone. [look: #__ID__-row] You start here, [go: #__ID__-p1] you pick one, [go: #__ID__-p2] and it is done. [go: #__ID__-p3] [go: slot]
|
|
9
10
|
-->
|
|
@@ -32,6 +33,10 @@ script: Here is the app on a phone. [look: #__ID__-row] You start here, [go: #__
|
|
|
32
33
|
.l-phones .row > .frame.card:nth-child(n + 4) { display: none; }
|
|
33
34
|
.l-phones .row:has(> :nth-child(4)) > .frame.card:nth-child(3) { --tilt: 7deg; --shadow: var(--accent-3); width: 108px; translate: 0 16px; }
|
|
34
35
|
}
|
|
36
|
+
/* No presenter (:root.hd-no-presenter: no face and no captions, deck_guide look): the corner is free. Phones keep this layout's rules. */
|
|
37
|
+
@media (min-width: 651px) {
|
|
38
|
+
:root.hd-no-presenter .l-phones .text { align-self: center; }
|
|
39
|
+
}
|
|
35
40
|
</style>
|
|
36
41
|
<section class="slide l-phones slot-left bg-dots" id="__ID__" data-chapter="On a phone" data-note="Phone screens: name the app build and the date they were captured.">
|
|
37
42
|
<div class="text">
|
|
@@ -4,6 +4,7 @@ summary: A product screenshot in a browser frame (for a phone shot, .frame.card:
|
|
|
4
4
|
use: a demo moment. Its .shot is a placeholder check fails on: put in `hyperdecks screenshot <url>` (capture_url) output as <img class="shot">; a callout chip names what to look at. For a phone app, make the frame `<div class="frame card" id="__ID__-frame">` holding only the shot (a phone screenshot or a `<video class="shot" autoplay muted loop playsinline>` clip) and the callout; tilt and shadow colour are `--tilt` and `--shadow` on it. `.frame.phone` (the black bezel) stays for older decks.
|
|
5
5
|
slot: bottom-right
|
|
6
6
|
presenter: stage
|
|
7
|
+
nopresenter: The copy centres vertically beside the screenshot instead of leaving the bottom-right free.
|
|
7
8
|
cues: [look: #__ID__-frame] when the narration turns to the product; [reveal: #__ID__-callout] for the detail.
|
|
8
9
|
script: This is the product. [look: #__ID__-frame] Look at this part. [reveal: #__ID__-callout]
|
|
9
10
|
-->
|
|
@@ -45,6 +46,10 @@ script: This is the product. [look: #__ID__-frame] Look at this part. [reveal: #
|
|
|
45
46
|
.l-product .frame.card { align-self: center; }
|
|
46
47
|
.l-product .callout { left: 10px; bottom: 10px; padding: 6px 12px; font-size: 12px; }
|
|
47
48
|
}
|
|
49
|
+
/* No presenter (:root.hd-no-presenter: no face and no captions, deck_guide look): the corner is free. Phones keep this layout's rules. */
|
|
50
|
+
@media (min-width: 651px) {
|
|
51
|
+
:root.hd-no-presenter .l-product .text { align-self: center; }
|
|
52
|
+
}
|
|
48
53
|
</style>
|
|
49
54
|
<section class="slide l-product" id="__ID__" data-chapter="The product" data-note="Screenshot: name the page and the date it was captured.">
|
|
50
55
|
<div class="text">
|
|
@@ -4,6 +4,7 @@ summary: One quote, large, with who said it. The quote is the title.
|
|
|
4
4
|
use: a customer or user in their own words. Quote them exactly and name the source in data-note.
|
|
5
5
|
slot: bottom-left
|
|
6
6
|
presenter: stage
|
|
7
|
+
nopresenter: The quote drops its left gutter and re-centres in the full frame.
|
|
7
8
|
cues: [look: #__ID__-quote] as the narration reads it.
|
|
8
9
|
script: In their words. [look: #__ID__-quote] Here is what they told us.
|
|
9
10
|
-->
|
|
@@ -20,6 +21,11 @@ script: In their words. [look: #__ID__-quote] Here is what they told us.
|
|
|
20
21
|
.l-quote .quote { font-size: 32px; }
|
|
21
22
|
.l-quote .avatar { width: 44px; height: 44px; font-size: 16px; }
|
|
22
23
|
}
|
|
24
|
+
/* No presenter (:root.hd-no-presenter: no face and no captions, deck_guide look): the corner is free. Phones keep this layout's rules. */
|
|
25
|
+
@media (min-width: 651px) {
|
|
26
|
+
:root.hd-no-presenter .l-quote .content { padding-left: 0; align-self: center; align-items: center; text-align: center; max-width: 1240px; }
|
|
27
|
+
:root.hd-no-presenter .l-quote .quote { text-indent: 0; }
|
|
28
|
+
}
|
|
23
29
|
</style>
|
|
24
30
|
<section class="slide on-accent l-quote slot-left" id="__ID__" data-chapter="In their words" data-note="Quote: name who said it, where (email, call, review) and when.">
|
|
25
31
|
<figure class="content">
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
<!--
|
|
2
|
+
layout: split
|
|
3
|
+
summary: Image plus copy: the copy on the left (a sticker for the logo or icon, kicker, title, one line, three ticks), a real picture on the right in a phone card, on speed lines.
|
|
4
|
+
use: the workhorse for a product, a feature or an app: most slides of a good deck are this one. The phone's .shot is a placeholder check fails on: put in a phone screenshot (capture_url at 390×844) or a screen recording (upload_deck_asset) as <img class="shot"> or <video class="shot" autoplay muted loop playsinline>. For a desktop app, replace the card with <div class="frame laptop" id="__ID__-frame"><img class="shot" src="…" alt="…"></div>; for a 16:9 clip or photo, <img class="shot wide" src="…" alt="…" id="__ID__-frame">. Swap the sticker's icon for the product's logo (<span class="sticker photo"><img src="…" alt=""></span>) or one icon from the deck's set.
|
|
5
|
+
slot: bottom-left
|
|
6
|
+
presenter: stage
|
|
7
|
+
nopresenter: The copy centres vertically beside the picture instead of leaving the bottom-left free.
|
|
8
|
+
cues: [look: #__ID__-frame] when the narration turns to the picture; [go: #__ID__-t1], [go: #__ID__-t2], [go: #__ID__-t3] at the word that starts each tick, then [go: slot].
|
|
9
|
+
script: Here it is, doing the job. [look: #__ID__-frame] It starts with [go: #__ID__-t1] the first thing. Then [go: #__ID__-t2] the second. And [go: #__ID__-t3] the third. [go: slot]
|
|
10
|
+
-->
|
|
11
|
+
<style>
|
|
12
|
+
.l-split { display: grid; grid-template-columns: 680px 1fr; column-gap: 64px; align-items: center; }
|
|
13
|
+
.l-split .text { align-self: start; display: flex; flex-direction: column; gap: 22px; padding-top: 24px; }
|
|
14
|
+
.l-split .head { display: flex; align-items: center; gap: 22px; }
|
|
15
|
+
.l-split .tt { font-size: var(--t-sub); line-height: 1.02; }
|
|
16
|
+
.l-split .lead { font-size: var(--t-body); }
|
|
17
|
+
.l-split .ticks { margin-top: 6px; }
|
|
18
|
+
.l-split .media { display: grid; place-items: center; height: 100%; }
|
|
19
|
+
.l-split .frame.card { width: 300px; --tilt: 4deg; }
|
|
20
|
+
.l-split .shot.wide { display: block; width: 100%; aspect-ratio: 16 / 9; border-radius: 18px; object-fit: cover; box-shadow: 14px 14px 0 var(--accent); }
|
|
21
|
+
.on-accent.l-split .shot.wide { box-shadow: 14px 14px 0 var(--ink); }
|
|
22
|
+
@media (max-width: 650px) {
|
|
23
|
+
.l-split { display: flex; flex-direction: column; align-items: stretch; }
|
|
24
|
+
.l-split .text { gap: 10px; padding-top: 0; }
|
|
25
|
+
.l-split .head { gap: 12px; }
|
|
26
|
+
.l-split .media { height: auto; }
|
|
27
|
+
.l-split .frame.card { width: 128px; }
|
|
28
|
+
.l-split .shot.wide { border-radius: 10px; box-shadow: 6px 6px 0 var(--accent); }
|
|
29
|
+
}
|
|
30
|
+
/* No presenter (:root.hd-no-presenter: no face and no captions, deck_guide look): the corner is free. Phones keep this layout's rules. */
|
|
31
|
+
@media (min-width: 651px) {
|
|
32
|
+
:root.hd-no-presenter .l-split .text { align-self: center; padding-top: 0; }
|
|
33
|
+
}
|
|
34
|
+
</style>
|
|
35
|
+
<section class="slide l-split slot-left bg-lines" id="__ID__" data-chapter="The product" data-note="Picture: name the screen or clip and the date it was captured.">
|
|
36
|
+
<div class="text">
|
|
37
|
+
<div class="head">
|
|
38
|
+
<span class="sticker" id="__ID__-logo"><svg class="lucide-smartphone" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect width="14" height="20" x="5" y="2" rx="2" ry="2"/><path d="M12 18h.01"/></svg></span>
|
|
39
|
+
<div class="kicker">The product · Live</div>
|
|
40
|
+
</div>
|
|
41
|
+
<h2 class="tt" data-title-mobile="Here it is.">Here it is, doing the job.</h2>
|
|
42
|
+
<p class="lead">One line on what the picture shows.</p>
|
|
43
|
+
<ul class="ticks">
|
|
44
|
+
<li id="__ID__-t1">The first thing it does</li>
|
|
45
|
+
<li id="__ID__-t2">The second thing</li>
|
|
46
|
+
<li id="__ID__-t3">The third thing</li>
|
|
47
|
+
</ul>
|
|
48
|
+
</div>
|
|
49
|
+
<div class="media">
|
|
50
|
+
<div class="frame card" id="__ID__-frame"><div class="shot" role="img" aria-label="Phone screen placeholder"></div></div>
|
|
51
|
+
</div>
|
|
52
|
+
<div class="narration-slot"></div>
|
|
53
|
+
</section>
|
|
@@ -4,6 +4,7 @@ summary: Up to four people, a face, a name and a role each; the presenter flies
|
|
|
4
4
|
use: who is behind it, who to talk to. Use real photos only with permission; initials otherwise.
|
|
5
5
|
slot: bottom-right
|
|
6
6
|
presenter: stage
|
|
7
|
+
nopresenter: The title and people centre vertically and the cards grow a little, instead of leaving a strip below for the presenter.
|
|
7
8
|
cues: [go: #__ID__-p1] … [go: #__ID__-p4] at each name, then [go: slot].
|
|
8
9
|
script: Meet the team. [go: #__ID__-p1] Ana builds it. [go: #__ID__-p2] Sam sells it. [go: #__ID__-p3] Lee runs it. [go: #__ID__-p4] Kai designs it. [go: slot]
|
|
9
10
|
-->
|
|
@@ -23,6 +24,11 @@ script: Meet the team. [go: #__ID__-p1] Ana builds it. [go: #__ID__-p2] Sam sell
|
|
|
23
24
|
.l-team b { font-size: 16px; }
|
|
24
25
|
.l-team small { font-size: 10px; }
|
|
25
26
|
}
|
|
27
|
+
/* No presenter (:root.hd-no-presenter: no face and no captions, deck_guide look): the corner is free. Phones keep this layout's rules. */
|
|
28
|
+
@media (min-width: 651px) {
|
|
29
|
+
:root.hd-no-presenter .l-team { justify-content: center; }
|
|
30
|
+
:root.hd-no-presenter .l-team .person { padding: 32px 30px; }
|
|
31
|
+
}
|
|
26
32
|
</style>
|
|
27
33
|
<section class="slide l-team" id="__ID__" data-chapter="The team" data-note="People: names and roles as they gave them; photos only with their permission.">
|
|
28
34
|
<div class="kicker">The team</div>
|
|
@@ -4,6 +4,7 @@ summary: Four milestones on a line, left to right, the presenter flying under ea
|
|
|
4
4
|
use: history, a roadmap, a process over time. Label future steps "Proposed" if not agreed.
|
|
5
5
|
slot: bottom-right
|
|
6
6
|
presenter: stage
|
|
7
|
+
nopresenter: The title and milestones centre vertically instead of leaving a strip below for the presenter.
|
|
7
8
|
cues: [go: #__ID__-m1] … [go: #__ID__-m4] at the word that starts each milestone, then [go: slot].
|
|
8
9
|
script: It started [go: #__ID__-m1] with a sketch. Then [go: #__ID__-m2] a first user. Then [go: #__ID__-m3] a launch. Next, [go: #__ID__-m4] the plan. [go: slot]
|
|
9
10
|
-->
|
|
@@ -25,6 +26,10 @@ script: It started [go: #__ID__-m1] with a sketch. Then [go: #__ID__-m2] a first
|
|
|
25
26
|
.l-timeline b { font-size: 18px; margin-bottom: 2px; }
|
|
26
27
|
.l-timeline p { font-size: 13px; }
|
|
27
28
|
}
|
|
29
|
+
/* No presenter (:root.hd-no-presenter: no face and no captions, deck_guide look): the corner is free. Phones keep this layout's rules. */
|
|
30
|
+
@media (min-width: 651px) {
|
|
31
|
+
:root.hd-no-presenter .l-timeline { justify-content: center; }
|
|
32
|
+
}
|
|
28
33
|
</style>
|
|
29
34
|
<section class="slide l-timeline" id="__ID__" data-chapter="How we got here" data-note="Source: name where each date comes from.">
|
|
30
35
|
<div class="kicker">How we got here</div>
|