@hypersocial/decks-cli 0.9.8 → 0.9.10
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 -0
- package/package.json +1 -1
- package/skills/hyperdecks/SKILL.md +94 -28
- package/skills/hyperdecks/chat.md +13 -2
- package/src/avatar.mjs +13 -2
- package/src/brand.mjs +38 -5
- package/src/checkRules.mjs +79 -2
- package/src/commands.mjs +53 -15
- package/src/draftFace.mjs +56 -0
- package/src/export-video.mjs +15 -10
- package/src/mediaPreviewMake.mjs +72 -0
- package/src/mediaPreviews.mjs +160 -0
- package/src/narrate.mjs +6 -1
- package/src/ops.mjs +70 -12
- package/src/play.mjs +2 -2
- package/src/presenter.mjs +73 -9
- package/src/release.mjs +83 -11
- package/src/runtime.mjs +1 -1
- package/src/scaffold.mjs +27 -6
- package/src/source.mjs +2 -2
- package/templates/layouts/_deck.html +71 -32
- package/templates/layouts/closer.html +1 -1
- package/templates/layouts/phones.html +5 -5
- package/templates/layouts/split.html +2 -2
- package/templates/narrated-deck.html +3 -1
|
@@ -55,20 +55,26 @@
|
|
|
55
55
|
--font: "Space Grotesk", system-ui, sans-serif; --mono: "Space Mono", ui-monospace, monospace;
|
|
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
|
+
/* The text colour on an accent ground. A brand with a dark accent sets it to its paper. */
|
|
59
|
+
--accent-ink: var(--ink);
|
|
58
60
|
--hd-ground: var(--accent); --hd-ground-ink: var(--ink); /* the loading state: the first slide's colours */
|
|
59
61
|
/* Soft grounds (on-tint, on-tint-2, on-tint-3): washes of the accents, so slide changes read without going loud. */
|
|
60
62
|
--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));
|
|
61
63
|
}
|
|
62
64
|
* { box-sizing: border-box; margin: 0; padding: 0; }
|
|
63
65
|
body { color: var(--ink); font-family: var(--font); font-weight: 500; -webkit-font-smoothing: antialiased; --hd-font: var(--font); --hd-mono: var(--mono); }
|
|
64
|
-
|
|
65
|
-
|
|
66
|
+
/* The caption bubble is always a fixed light fill with dark ink, so it reads whatever the
|
|
67
|
+
brand's --card or --ink (a dark brand's card is dark). A slide can still set its own. */
|
|
68
|
+
.slide { display: flex; flex-direction: column; gap: 24px; padding: 64px 72px 56px; background: var(--paper); color: var(--ink); --hd-speech: #f3c9dc; --hd-speech-ink: #0b0b0f; }
|
|
69
|
+
.slide.on-accent { background: var(--accent); color: var(--accent-ink); --hd-speech: #ffffff; }
|
|
66
70
|
.slide.on-ink { background: var(--ink); color: var(--paper); --hd-speech: #d9ccff; }
|
|
67
|
-
.slide.on-tint { background: var(--tint-1); --hd-speech:
|
|
68
|
-
.slide.on-tint-2 { background: var(--tint-2); --hd-speech:
|
|
69
|
-
.slide.on-tint-3 { background: var(--tint-3); --hd-speech:
|
|
71
|
+
.slide.on-tint { background: var(--tint-1); --hd-speech: #ffffff; }
|
|
72
|
+
.slide.on-tint-2 { background: var(--tint-2); --hd-speech: #ffffff; }
|
|
73
|
+
.slide.on-tint-3 { background: var(--tint-3); --hd-speech: #ffffff; }
|
|
70
74
|
.kicker { font: var(--t-label) var(--mono); letter-spacing: .16em; text-transform: uppercase; }
|
|
71
|
-
|
|
75
|
+
/* Titles take the display face's weight and tracking (brand.mjs sets them for a face the
|
|
76
|
+
template was not tuned for) and never fake a weight the face lacks. */
|
|
77
|
+
.tt { font-family: var(--display, var(--font)); font-weight: var(--display-weight, 700); font-synthesis: none; font-size: var(--t-title); line-height: .95; letter-spacing: var(--display-tracking, -.045em); text-wrap: balance; }
|
|
72
78
|
.lead { font-size: var(--t-lead); line-height: 1.3; max-width: 28em; text-wrap: pretty; }
|
|
73
79
|
.muted { opacity: .65; }
|
|
74
80
|
/* The presenter glides to each slide's slot: bottom-right by default,
|
|
@@ -98,26 +104,57 @@
|
|
|
98
104
|
linear-gradient(color-mix(in srgb, var(--ink) 14%, transparent) 0 0) 14% 67% / 44% 2.4% no-repeat,
|
|
99
105
|
linear-gradient(var(--accent) 0 0) 50% 90% / 84% 6% no-repeat,
|
|
100
106
|
var(--paper); }
|
|
101
|
-
/*
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
holds small inked tiles, each a <span> placed by its inline left/top (and
|
|
106
|
-
background, rotate). Both sit behind the slide's content. */
|
|
107
|
-
.slide.bg-dots, .slide:has(> .deco) { isolation: isolate; }
|
|
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%); }
|
|
107
|
+
/* Decorations: a <div class="deco" aria-hidden="true"> in the slide holds small
|
|
108
|
+
inked tiles, each a <span> placed by its inline left/top (and background, rotate),
|
|
109
|
+
behind the slide's content. */
|
|
110
|
+
.slide:has(> .deco) { isolation: isolate; }
|
|
109
111
|
.slide > .deco { position: absolute; inset: 0; z-index: -1; pointer-events: none; }
|
|
110
112
|
.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
|
-
/*
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
bg-
|
|
116
|
-
|
|
117
|
-
.slide:is(.bg-
|
|
118
|
-
.slide.bg-
|
|
119
|
-
|
|
120
|
-
|
|
113
|
+
/* Backgrounds (deck_guide topic look). Four classes on the section, tokens only, each painted
|
|
114
|
+
behind the content (a ::before at z-index -1 in an isolated slide) and confined to the object
|
|
115
|
+
it backs, never under the text. Each carries its own per-layout rules (.l-<layout>.bg-<name>),
|
|
116
|
+
so on a layout with nothing to back it paints nothing. Plain grounds come first; one signature
|
|
117
|
+
(bg-corner or bg-mark) per deck on three slides at most; bg-pool and bg-stage only on a slide
|
|
118
|
+
with a picture. A deck may add its own in its <style> under the same contract. */
|
|
119
|
+
.slide:is(.bg-pool, .bg-corner, .bg-stage, .bg-mark) { isolation: isolate; overflow: hidden; }
|
|
120
|
+
.slide:is(.bg-pool, .bg-corner, .bg-stage, .bg-mark)::before { content: ""; position: absolute; inset: 0; z-index: -1; pointer-events: none; }
|
|
121
|
+
/* bg-pool: one soft light of the next accent (accent-2 on paper, accent on a tint, a screened
|
|
122
|
+
accent-3 on an accent ground, accent on ink), placed per layout as the spotlight of the picture. */
|
|
123
|
+
.slide.bg-pool { --pool: color-mix(in srgb, var(--accent-2) 34%, transparent); }
|
|
124
|
+
.slide:is(.on-tint, .on-tint-2, .on-tint-3).bg-pool { --pool: color-mix(in srgb, var(--accent) 38%, transparent); }
|
|
125
|
+
.slide.on-accent.bg-pool { --pool: color-mix(in srgb, var(--accent-3, var(--accent-2)) 55%, transparent); }
|
|
126
|
+
.slide.on-accent.bg-pool::before { mix-blend-mode: screen; }
|
|
127
|
+
.slide.on-ink.bg-pool { --pool: color-mix(in srgb, var(--accent) 32%, transparent); }
|
|
128
|
+
.slide.bg-pool::before { background: radial-gradient(var(--pw, 760px) var(--ph, 600px) at var(--px, 82%) var(--py, 28%), var(--pool), transparent 70%); }
|
|
129
|
+
.l-hero.bg-pool { --px: 82%; --py: 28%; --pw: 760px; --ph: 600px; }
|
|
130
|
+
.l-split.bg-pool { --px: 73%; --py: 50%; --pw: 900px; --ph: 860px; }
|
|
131
|
+
.l-product.bg-pool { --px: 34%; --py: 50%; --pw: 1180px; --ph: 860px; }
|
|
132
|
+
.l-phones.bg-pool { --px: 68%; --py: 50%; --pw: 900px; --ph: 760px; }
|
|
133
|
+
.l-chart.bg-pool { --px: 84%; --py: 40%; --pw: 640px; --ph: 520px; }
|
|
134
|
+
.l-quote.bg-pool { --px: 10%; --py: 14%; --pw: 760px; --ph: 560px; }
|
|
135
|
+
.l-closer.bg-pool { --px: 90%; --py: 4%; --pw: 820px; --ph: 640px; }
|
|
136
|
+
/* bg-corner: a hard-edged quarter-disc of halftone, top-right, behind the stickers. A signature: cover, closer. */
|
|
137
|
+
.slide.bg-corner::before {
|
|
138
|
+
--corner-r: 580px; --corner-dot: color-mix(in srgb, currentColor var(--corner-a, 15%), transparent);
|
|
139
|
+
inset: auto; right: 0; top: 0; width: var(--corner-r); height: var(--corner-r); border-bottom-left-radius: 100%;
|
|
140
|
+
background: radial-gradient(var(--corner-dot) 2.8px, transparent 3.3px) 0 0 / 20px 20px;
|
|
141
|
+
-webkit-mask-image: radial-gradient(circle at 100% 0, #000 45%, rgba(0,0,0,.4) 100%); mask-image: radial-gradient(circle at 100% 0, #000 45%, rgba(0,0,0,.4) 100%); }
|
|
142
|
+
.l-closer.bg-corner::before { --corner-r: 460px; }
|
|
143
|
+
.on-ink.bg-corner::before { --corner-a: 22%; }
|
|
144
|
+
:is(.l-split, .l-product, .l-chart, .l-quote, .l-number, .l-features, .l-team, .l-timeline, .l-compare).bg-corner::before { content: none; }
|
|
145
|
+
/* bg-stage: a rounded dot plate exactly the picture's column plus 32px, so the frame or the phones stand on it; on the hero a tile behind the stickers. */
|
|
146
|
+
.slide.bg-stage::before { inset: auto; background: radial-gradient(color-mix(in srgb, currentColor var(--stage-a, 24%), transparent) 2.4px, transparent 2.9px) 0 0 / 22px 22px; border-radius: 40px; }
|
|
147
|
+
.l-product.bg-stage::before { position: relative; grid-area: frame; align-self: stretch; margin: var(--stage-m, -32px -24px -32px -40px); }
|
|
148
|
+
.l-phones.bg-stage::before { position: relative; grid-area: row; align-self: stretch; margin: var(--stage-m, -32px); }
|
|
149
|
+
.l-hero.bg-stage::before { right: 110px; top: 110px; width: 410px; height: 350px; }
|
|
150
|
+
:is(.l-split, .l-chart, .l-quote, .l-closer, .l-number, .l-features, .l-team, .l-timeline, .l-compare).bg-stage::before { content: none; }
|
|
151
|
+
/* bg-mark: the slide number, set as style="--mark:'04'" on the section, huge in --display, faint,
|
|
152
|
+
cropped by the top edge; right on the hero, in the indent on slot-left slides. A signature: cover, an opener, closer. */
|
|
153
|
+
.slide.bg-mark::before { content: var(--mark, ""); inset: auto; right: 24px; top: -.26em; font: var(--display-weight, 700) var(--mark-size, 560px)/1 var(--display, var(--font)); font-synthesis: none; letter-spacing: var(--display-tracking, -.05em); white-space: nowrap;
|
|
154
|
+
color: color-mix(in srgb, currentColor var(--mark-a, 8%), transparent); }
|
|
155
|
+
.slide.on-ink.bg-mark::before { --mark-a: 6%; }
|
|
156
|
+
.slide.slot-left.bg-mark::before { right: auto; left: -.08em; font-size: var(--mark-size, 440px); } /* ends inside the 500px indent, clear of the title */
|
|
157
|
+
:is(.l-split, .l-product, .l-chart, .l-phones, .l-number, .l-features, .l-team, .l-timeline, .l-compare).bg-mark::before { content: none; }
|
|
121
158
|
/* Pieces. .sticker: a logo or icon tile, tilted (--tilt), ink edge, hard offset
|
|
122
159
|
shadow (.sticker.photo for a face or an app icon that fills it). .ticks: a short
|
|
123
160
|
list with accent-square bullets. .panel: a quiet card. .pill: a small tag. */
|
|
@@ -128,10 +165,10 @@
|
|
|
128
165
|
.ticks { list-style: none; display: flex; flex-direction: column; gap: 14px; }
|
|
129
166
|
.ticks li { position: relative; padding-left: 34px; font-size: var(--t-body); line-height: 1.3; font-weight: 600; }
|
|
130
167
|
.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); }
|
|
168
|
+
.on-accent .ticks li::before { background: var(--accent-ink); }
|
|
132
169
|
.panel { padding: 24px 28px; border-radius: 22px; background: color-mix(in srgb, currentColor 6%, transparent); }
|
|
133
170
|
.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); }
|
|
171
|
+
.on-accent .pill { box-shadow: 4px 4px 0 var(--accent-ink); }
|
|
135
172
|
/* A laptop for a desktop screenshot or clip: a .frame.laptop holding an img.shot or video.shot. */
|
|
136
173
|
.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
174
|
.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); }
|
|
@@ -145,12 +182,12 @@
|
|
|
145
182
|
:root.hd-no-presenter .slide { padding-bottom: 28px; }
|
|
146
183
|
.slide .frame.card { width: 160px; padding: 5px; border-width: 2px; border-radius: 24px; box-shadow: 8px 8px 0 var(--shadow); }
|
|
147
184
|
.slide .frame.card > .shot { border-radius: 19px; border-width: 1px; }
|
|
148
|
-
/* The text fills the card's width
|
|
149
|
-
|
|
185
|
+
/* The text fills the card's width, so the backgrounds keep off it: the corner fades in
|
|
186
|
+
towards the bottom, under the presenter, at a finer pitch; the stage and the mark hide;
|
|
187
|
+
the pool (a soft light) stays as it is; the tiles stay off. */
|
|
188
|
+
.slide.bg-corner::before { inset: 0; width: auto; height: auto; border-radius: 0; background-size: 14px 14px; background-image: radial-gradient(var(--corner-dot) 1.6px, transparent 2px); -webkit-mask-image: linear-gradient(180deg, transparent 40%, #000 90%); mask-image: linear-gradient(180deg, transparent 40%, #000 90%); }
|
|
189
|
+
.slide:is(.bg-stage, .bg-mark)::before { content: none; }
|
|
150
190
|
.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
191
|
.sticker { width: 48px; height: 48px; padding: 9px; border-width: 2px; border-radius: 13px; box-shadow: 3px 3px 0 var(--ink); }
|
|
155
192
|
.ticks { gap: 6px; }
|
|
156
193
|
.ticks li { padding-left: 18px; }
|
|
@@ -175,7 +212,9 @@
|
|
|
175
212
|
|
|
176
213
|
<!-- `hyperdecks narrate decks/__SLUG__` fills data-manifest with the manifest
|
|
177
214
|
URL it writes. data-presenter: head (live Minimoji, needs data-avatar),
|
|
178
|
-
static (data-presenter-image) or none (captions only).
|
|
215
|
+
static (data-presenter-image) or none (captions only). deck new, deck
|
|
216
|
+
narrator and narrate write the narrator's face here
|
|
217
|
+
(data-presenter-from="narrator", so release follows a later narrator). -->
|
|
179
218
|
<script type="module" src="https://hyperdecks.ai/player/v1/player.js"
|
|
180
219
|
data-manifest="" data-stage="1600x900" data-presenter="none" data-presenter-style="__PRESENTER_STYLE__"></script>
|
|
181
220
|
</body>
|
|
@@ -11,7 +11,7 @@ script: That's it. [go: #__ID__-cta] Here is the one thing to do next. Thanks [g
|
|
|
11
11
|
<style>
|
|
12
12
|
.l-closer .content { flex: 1; display: flex; flex-direction: column; justify-content: center; gap: 32px; padding-left: 500px; }
|
|
13
13
|
.l-closer .tt { font-size: var(--t-display); line-height: .9; }
|
|
14
|
-
.l-closer .cta { display: inline-flex; align-items: center; gap: 16px; width: fit-content; max-width: 100%; padding: 22px 34px; border-radius: 22px; background: var(--accent); color: var(--ink); font: 700 34px var(--mono); letter-spacing: -.01em; text-decoration: none; }
|
|
14
|
+
.l-closer .cta { display: inline-flex; align-items: center; gap: 16px; width: fit-content; max-width: 100%; padding: 22px 34px; border-radius: 22px; background: var(--accent); color: var(--accent-ink); font: 700 34px var(--mono); letter-spacing: -.01em; text-decoration: none; }
|
|
15
15
|
.l-closer .contact { font: var(--t-label) var(--mono); letter-spacing: .12em; text-transform: uppercase; }
|
|
16
16
|
@media (max-width: 650px) {
|
|
17
17
|
.l-closer .content { padding-left: 0; justify-content: flex-start; gap: 16px; }
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
<!--
|
|
2
2
|
layout: phones
|
|
3
|
-
summary: A fanned row of two to four phone cards (the inner ones larger and in front, the outer ones tilted out), the point in the column beside it.
|
|
3
|
+
summary: A fanned row of two to four phone cards (the inner ones larger and in front, the outer ones tilted out), the point in the column beside it. The row stands on a dot plate (bg-stage).
|
|
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
|
|
@@ -18,7 +18,7 @@ script: Here is the app on a phone. [look: #__ID__-row] You start here, [go: #__
|
|
|
18
18
|
.l-phones .row { grid-area: row; display: flex; justify-content: center; align-items: center; padding: 0 0 40px; }
|
|
19
19
|
.l-phones .row > .frame.card { --tilt: 0deg; flex: none; width: 260px; margin: 0 -14px; }
|
|
20
20
|
.l-phones .row > .frame.card:first-child { --tilt: -7deg; --shadow: var(--accent-2); translate: 0 36px; }
|
|
21
|
-
.l-phones .row > .frame.card:last-child { --tilt: 7deg; --shadow: var(--accent-3); translate: 0 36px; }
|
|
21
|
+
.l-phones .row > .frame.card:last-child { --tilt: 7deg; --shadow: var(--accent-3, var(--accent-2)); translate: 0 36px; }
|
|
22
22
|
.l-phones .row > .frame.card:not(:first-child, :last-child) { width: 300px; z-index: 1; }
|
|
23
23
|
.l-phones .row:has(> :nth-child(4)) > .frame.card { width: 220px; }
|
|
24
24
|
.l-phones .row:has(> :nth-child(4)) > .frame.card:not(:first-child, :last-child) { width: 250px; }
|
|
@@ -31,14 +31,14 @@ script: Here is the app on a phone. [look: #__ID__-row] You start here, [go: #__
|
|
|
31
31
|
.l-phones .row > .frame.card:is(:first-child, :last-child) { translate: 0 16px; }
|
|
32
32
|
/* Four do not fit the phone card: the row keeps the first three, the third as its end. */
|
|
33
33
|
.l-phones .row > .frame.card:nth-child(n + 4) { display: none; }
|
|
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
|
+
.l-phones .row:has(> :nth-child(4)) > .frame.card:nth-child(3) { --tilt: 7deg; --shadow: var(--accent-3, var(--accent-2)); width: 108px; translate: 0 16px; }
|
|
35
35
|
}
|
|
36
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
37
|
@media (min-width: 651px) {
|
|
38
38
|
:root.hd-no-presenter .l-phones .text { align-self: center; }
|
|
39
39
|
}
|
|
40
40
|
</style>
|
|
41
|
-
<section class="slide l-phones slot-left bg-
|
|
41
|
+
<section class="slide l-phones slot-left bg-stage" id="__ID__" data-chapter="On a phone" data-note="Phone screens: name the app build and the date they were captured.">
|
|
42
42
|
<div class="text">
|
|
43
43
|
<div class="kicker">On a phone</div>
|
|
44
44
|
<h2 class="tt" data-title-mobile="Three taps.">Three taps, start to finish.</h2>
|
|
@@ -53,7 +53,7 @@ script: Here is the app on a phone. [look: #__ID__-row] You start here, [go: #__
|
|
|
53
53
|
<div class="deco" aria-hidden="true">
|
|
54
54
|
<span style="left: 52%; top: 8%; background: var(--accent); rotate: -10deg;">★</span>
|
|
55
55
|
<span style="left: 92%; top: 42%; background: var(--accent-2); rotate: 12deg;">♪</span>
|
|
56
|
-
<span style="left: 48%; top: 78%; background: var(--accent-3); rotate: 8deg;">☺</span>
|
|
56
|
+
<span style="left: 48%; top: 78%; background: var(--accent-3, var(--accent-2)); rotate: 8deg;">☺</span>
|
|
57
57
|
</div> -->
|
|
58
58
|
<div class="narration-slot"></div>
|
|
59
59
|
</section>
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
<!--
|
|
2
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
|
|
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 (the picture is the background; add bg-pool to light it).
|
|
4
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
5
|
slot: bottom-left
|
|
6
6
|
presenter: stage
|
|
@@ -32,7 +32,7 @@ script: Here it is, doing the job. [look: #__ID__-frame] It starts with [go: #__
|
|
|
32
32
|
:root.hd-no-presenter .l-split .text { align-self: center; padding-top: 0; }
|
|
33
33
|
}
|
|
34
34
|
</style>
|
|
35
|
-
<section class="slide l-split slot-left
|
|
35
|
+
<section class="slide l-split slot-left" id="__ID__" data-chapter="The product" data-note="Picture: name the screen or clip and the date it was captured.">
|
|
36
36
|
<div class="text">
|
|
37
37
|
<div class="head">
|
|
38
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>
|
|
@@ -54,7 +54,7 @@
|
|
|
54
54
|
.slide { display: flex; flex-direction: column; gap: 28px; padding: 64px 72px 56px; background: var(--paper); }
|
|
55
55
|
.slide.accent { background: var(--accent); }
|
|
56
56
|
.kicker { font: 18px var(--mono); letter-spacing: .16em; text-transform: uppercase; }
|
|
57
|
-
.tt { font-family: var(--display, var(--font)); font-size: 104px; line-height: .95; letter-spacing: -.045em; margin: 0; text-wrap: balance; }
|
|
57
|
+
.tt { font-family: var(--display, var(--font)); font-weight: var(--display-weight, 700); font-synthesis: none; font-size: 104px; line-height: .95; letter-spacing: var(--display-tracking, -.045em); margin: 0; text-wrap: balance; }
|
|
58
58
|
.lead { font-size: 32px; line-height: 1.3; max-width: 30em; margin: 0; }
|
|
59
59
|
.content { flex: 1; display: flex; flex-direction: column; justify-content: center; gap: 28px; padding-right: 500px; }
|
|
60
60
|
/* The presenter glides to each slide's slot; slots alternate sides so the
|
|
@@ -156,6 +156,8 @@
|
|
|
156
156
|
<!-- `hyperdecks narrate decks/__SLUG__` fills data-manifest with the manifest
|
|
157
157
|
URL it writes. data-presenter: head (live Minimoji, needs
|
|
158
158
|
data-avatar), static (data-presenter-image) or none (captions only).
|
|
159
|
+
deck new, deck narrator and narrate write the narrator's face here
|
|
160
|
+
(data-presenter-from="narrator", so release follows a later narrator).
|
|
159
161
|
data-presenter-style: stage (large head, lower-third captions), bubble,
|
|
160
162
|
glass (frosted panel) or corner (small head, subtitles). -->
|
|
161
163
|
<script type="module" src="https://hyperdecks.ai/player/v1/player.js"
|