@hypersocial/decks-cli 0.2.1 → 0.3.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.
@@ -0,0 +1,102 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1">
6
+ <title>__TITLE__</title>
7
+ <!-- Loading state (keep verbatim; `hyperdecks check` requires it). Until the
8
+ player marks body[data-hd-ready] the page shows only the slide card, at its
9
+ final size, in the deck's --hd-ground (its first slide's colour) on the
10
+ page's brand colour, with a quiet loader in --hd-ground-ink; then the
11
+ slides fade in. If the player never arrives, the slides show after 10 s
12
+ rather than never. Put data-layout="overlay" on <html> for the overlay. -->
13
+ <link rel="modulepreload" href="https://decks.hypersocial.ai/player/v1/player.js">
14
+ <link rel="preload" as="style" href="https://decks.hypersocial.ai/player/v1/player.css">
15
+ <script>if (self !== top || /[?&]thumb\b/.test(location.search)) document.documentElement.dataset.hdFrame = "";</script>
16
+ <style data-hd-loading>
17
+ body:not([data-hd-ready]) { overflow: hidden; background: var(--hd-frame, var(--hd-ground, var(--hd-accent, #ffda1b))); animation: hd-fail-open 0s 10s forwards; }
18
+ body:not([data-hd-ready]) > * { visibility: hidden; animation: hd-fail-open 0s 10s forwards; }
19
+ body[data-hd-ready] > * { animation: hd-in .2s ease-out; }
20
+ body::before, body::after { content: ""; position: fixed; z-index: -1; pointer-events: none; transition: opacity .2s ease-out; }
21
+ /* The card as the player draws it (player.css, framed): 16:9, scaled to fit
22
+ between the 64px masthead and the 56px dock, 24px in from the sides. */
23
+ body::before { inset: 64px 24px 56px; margin: auto; width: min(100vw - 48px, (100dvh - 120px) * 16 / 9); height: min(100dvh - 120px, (100vw - 48px) * 9 / 16); border-radius: calc(min(100vw - 48px, (100dvh - 120px) * 16 / 9) * .01125); background: var(--hd-ground, #fff); box-shadow: 0 0 0 1px color-mix(in srgb, var(--hd-ground-ink, #0b0b0f) 16%, transparent); }
24
+ body::after { left: 50%; top: 50%; width: 12px; height: 12px; margin: -6px 0 0 -6px; border-radius: 50%; color: var(--hd-ground-ink, #0b0b0f); background: currentColor; box-shadow: -24px 0 currentColor, 24px 0 currentColor; opacity: 0; animation: hd-dots .7s ease-in-out .6s infinite alternate; }
25
+ body[data-hd-ready]::before, body[data-hd-ready]::after { opacity: 0; animation: none; }
26
+ /* The overlay (embedded, ?thumb, or data-layout="overlay"): the stage fills the window. */
27
+ :is([data-hd-frame], [data-layout="overlay"]) body::before { inset: 0; width: min(100vw, 100dvh * 16 / 9); height: min(100dvh, 100vw * 9 / 16); border-radius: calc(min(100vw, 100dvh * 16 / 9) * .01125); box-shadow: none; }
28
+ [data-layout="overlay"] body:not([data-hd-ready]) { background: var(--hd-backdrop, #16161c); }
29
+ [data-hd-frame] body:not([data-hd-ready]) { background: transparent; }
30
+ [data-hd-frame] body::before { border-radius: 0; }
31
+ /* Phones: the card fills the space between a 52px masthead and the dock, 8px in. */
32
+ @media (max-width: 650px) {
33
+ body::before { inset: 52px 8px calc(56px + env(safe-area-inset-bottom)); width: auto; height: auto; border-radius: 14px; }
34
+ :is([data-hd-frame], [data-layout="overlay"]) body::before { inset: 0; width: auto; height: auto; border-radius: 0; }
35
+ }
36
+ @media (prefers-reduced-motion: reduce) {
37
+ body::before, body::after { transition: none; }
38
+ body:not([data-hd-ready])::after { animation: none; opacity: .4; }
39
+ body[data-hd-ready] > * { animation: none; }
40
+ }
41
+ @keyframes hd-in { from { opacity: 0; } }
42
+ @keyframes hd-dots { from { opacity: .15; } to { opacity: .6; } }
43
+ @keyframes hd-fail-open { to { visibility: visible; overflow: auto; } }
44
+ </style>
45
+ <link rel="preconnect" href="https://fonts.googleapis.com">
46
+ <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
47
+ <link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Space+Grotesk:wght@500;700&family=Space+Mono:wght@400;700&display=swap">
48
+ <style>
49
+ /* A narrated deck assembled from the layout library (`deck new --layouts`).
50
+ The hosted player (player/v1) scales the 1600×900 stage, draws the chrome
51
+ and the presenter, and plays the narration. Change the palette and fonts
52
+ here; every layout reads them. */
53
+ :root {
54
+ --ink: #0b0b0f; --paper: #fafaf7; --accent: #ffda1b; --accent-2: #27ceff; --card: #ffffff;
55
+ --font: "Space Grotesk", system-ui, sans-serif; --mono: "Space Mono", ui-monospace, monospace;
56
+ /* The type scale: one display size per slide at most, then title, sub (a title beside a visual), lead, body, label. */
57
+ --t-display: 128px; --t-title: 84px; --t-sub: 56px; --t-lead: 30px; --t-body: 24px; --t-label: 17px;
58
+ --hd-ground: var(--accent); --hd-ground-ink: var(--ink); /* the loading state: the first slide's colours */
59
+ }
60
+ * { box-sizing: border-box; margin: 0; padding: 0; }
61
+ body { color: var(--ink); font-family: var(--font); font-weight: 500; -webkit-font-smoothing: antialiased; --hd-font: var(--font); --hd-mono: var(--mono); }
62
+ .slide { display: flex; flex-direction: column; gap: 24px; padding: 64px 72px 56px; background: var(--paper); color: var(--ink); --hd-speech: #f3c9dc; }
63
+ .slide.on-accent { background: var(--accent); --hd-speech: var(--card); }
64
+ .slide.on-ink { background: var(--ink); color: var(--paper); --hd-speech: #d9ccff; }
65
+ .kicker { font: var(--t-label) var(--mono); letter-spacing: .16em; text-transform: uppercase; }
66
+ .tt { font-weight: 700; font-size: var(--t-title); line-height: .95; letter-spacing: -.045em; text-wrap: balance; }
67
+ .lead { font-size: var(--t-lead); line-height: 1.3; max-width: 28em; text-wrap: pretty; }
68
+ .muted { opacity: .65; }
69
+ /* The presenter glides to each slide's slot: bottom-right by default,
70
+ bottom-left on .slot-left, top-right on .slot-top. */
71
+ .narration-slot { position: absolute; right: 56px; bottom: 64px; }
72
+ .slot-left .narration-slot { right: auto; left: 56px; }
73
+ .slot-top .narration-slot { top: 96px; bottom: auto; }
74
+ .reveal { opacity: 0; transform: translateY(12px); transition: opacity .5s, transform .5s; }
75
+ .reveal.is-revealed { opacity: 1; transform: none; }
76
+ /* Phones: the slide is the 374×736 card; the presenter is a small head in
77
+ the corner, so keep the bottom 170px clear. */
78
+ @media (max-width: 650px) {
79
+ :root { --t-display: 54px; --t-title: 38px; --t-sub: 28px; --t-lead: 17px; --t-body: 15px; --t-label: 12px; }
80
+ .slide { padding: 28px 20px 170px; gap: 14px; }
81
+ .narration-slot { right: 12px; left: 12px; bottom: 64px; }
82
+ }
83
+ </style>
84
+ <!-- LAYOUT STYLES -->
85
+ </head>
86
+ <body>
87
+
88
+ <!-- One <section class="slide" id> per slide, one idea each, from
89
+ packages/decks-cli/templates/layouts/. The id joins the slide to its
90
+ narration (`## <id>` in script.md); ids inside a slide start with its id
91
+ so the [go]/[look] cues in script.md stay unique. Every slide needs a
92
+ data-note (where its facts come from) and, over 28 characters, a
93
+ data-title-mobile on its title. -->
94
+ <!-- SLIDES -->
95
+
96
+ <!-- `hyperdecks narrate decks/__SLUG__` fills data-manifest with the manifest
97
+ URL it writes. data-presenter: head (live Minimoji, needs data-avatar),
98
+ static (data-presenter-image) or none (captions only). -->
99
+ <script type="module" src="https://decks.hypersocial.ai/player/v1/player.js"
100
+ data-manifest="" data-stage="1600x900" data-presenter="none" data-presenter-style="__PRESENTER_STYLE__"></script>
101
+ </body>
102
+ </html>
@@ -0,0 +1,39 @@
1
+ <!--
2
+ layout: chart
3
+ summary: A chart of real numbers with its takeaway in one line; the presenter beside it.
4
+ use: a trend or a comparison in numbers. Draw it with `hyperdecks chart` (never a generated picture of a chart) and name the data's source.
5
+ slot: bottom-right
6
+ presenter: stage
7
+ cues: [look: #__ID__-chart] when the narration turns to it; [reveal: #__ID__-takeaway] at the point.
8
+ script: Here are the numbers. [look: #__ID__-chart] The last bar is the one to see. [reveal: #__ID__-takeaway]
9
+ -->
10
+ <style>
11
+ .l-chart { display: grid; grid-template-columns: 960px 1fr; grid-template-rows: auto auto 1fr; column-gap: 56px; row-gap: 20px; }
12
+ .l-chart .kicker, .l-chart .tt { grid-column: 1; }
13
+ .l-chart .tt { font-size: var(--t-sub); line-height: 1.02; }
14
+ /* Swap the svg for an <img class="chart"> of your file (hyperdecks chart). */
15
+ .l-chart .chart { grid-column: 1; width: 100%; height: 100%; min-height: 0; object-fit: contain; object-position: left bottom; }
16
+ .l-chart .chart .bar { fill: color-mix(in srgb, var(--ink) 18%, transparent); }
17
+ .l-chart .chart .bar.hi { fill: var(--accent); stroke: var(--ink); stroke-width: 3; }
18
+ .l-chart .chart text { font: 22px var(--mono); fill: currentColor; }
19
+ .l-chart .chart .v { font: 700 30px var(--font); }
20
+ .l-chart .takeaway { grid-column: 2; grid-row: 1 / 3; align-self: start; font-size: var(--t-lead); line-height: 1.25; font-weight: 700; padding-left: 20px; border-left: 6px solid var(--accent); }
21
+ @media (max-width: 650px) {
22
+ .l-chart { display: flex; flex-direction: column; }
23
+ .l-chart .chart { height: 210px; flex: none; }
24
+ .l-chart .takeaway { padding-left: 12px; border-left-width: 4px; }
25
+ }
26
+ </style>
27
+ <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
+ <div class="kicker">The numbers</div>
29
+ <h2 class="tt" data-title-mobile="The trend.">The trend, in one line.</h2>
30
+ <svg class="chart" id="__ID__-chart" viewBox="0 0 960 470" role="img" aria-label="Bar chart placeholder: four periods, the last highest">
31
+ <line x1="0" y1="420" x2="960" y2="420" stroke="currentColor" stroke-opacity=".25" stroke-width="2"/>
32
+ <rect class="bar" x="20" y="300" width="180" height="120" rx="10"/><text class="v" x="110" y="285" text-anchor="middle">12</text><text x="110" y="458" text-anchor="middle">Q1</text>
33
+ <rect class="bar" x="260" y="250" width="180" height="170" rx="10"/><text class="v" x="350" y="235" text-anchor="middle">17</text><text x="350" y="458" text-anchor="middle">Q2</text>
34
+ <rect class="bar" x="500" y="190" width="180" height="230" rx="10"/><text class="v" x="590" y="175" text-anchor="middle">23</text><text x="590" y="458" text-anchor="middle">Q3</text>
35
+ <rect class="bar hi" x="740" y="60" width="180" height="360" rx="10"/><text class="v" x="830" y="45" text-anchor="middle">36</text><text x="830" y="458" text-anchor="middle">Q4</text>
36
+ </svg>
37
+ <p class="takeaway reveal" id="__ID__-takeaway">The takeaway, in one sentence a listener could repeat.</p>
38
+ <div class="narration-slot"></div>
39
+ </section>
@@ -0,0 +1,28 @@
1
+ <!--
2
+ layout: closer
3
+ summary: The last slide. One line, the one action to take (a command, a link) and the presenter's goodbye.
4
+ use: the end. One call to action, never three. Label an ask that is not agreed as Proposed.
5
+ slot: bottom-left
6
+ presenter: stage
7
+ cues: [go: #__ID__-cta] at the action, [go: slot] and [wave] at the goodbye.
8
+ script: That's it. [go: #__ID__-cta] Here is the one thing to do next. Thanks [go: slot] for watching! [wave]
9
+ -->
10
+ <style>
11
+ .l-closer .content { flex: 1; display: flex; flex-direction: column; justify-content: center; gap: 32px; padding-left: 500px; }
12
+ .l-closer .tt { font-size: var(--t-display); line-height: .9; }
13
+ .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 .contact { font: var(--t-label) var(--mono); letter-spacing: .12em; text-transform: uppercase; }
15
+ @media (max-width: 650px) {
16
+ .l-closer .content { padding-left: 0; justify-content: flex-start; gap: 16px; }
17
+ .l-closer .cta { padding: 12px 16px; border-radius: 14px; font-size: 15px; }
18
+ }
19
+ </style>
20
+ <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
+ <div class="content">
22
+ <h2 class="tt" data-title-mobile="Thanks.">Thanks.</h2>
23
+ <p class="lead">One sentence on the one thing to do next.</p>
24
+ <a class="cta" id="__ID__-cta" href="https://example.com" target="_blank" rel="noopener">example.com →</a>
25
+ <div class="contact muted">your@email · your.site</div>
26
+ </div>
27
+ <div class="narration-slot"></div>
28
+ </section>
@@ -0,0 +1,33 @@
1
+ <!--
2
+ layout: compare
3
+ summary: Before and after (or them and us) side by side, three short lines each.
4
+ use: the change your idea makes. Keep the rows parallel so each line has its counterpart.
5
+ slot: bottom-right
6
+ presenter: stage
7
+ cues: [look: #__ID__-before] on the old way, [go: #__ID__-after] on the new; [go: slot] to come home.
8
+ script: Today it looks like this. [look: #__ID__-before] With us, [go: #__ID__-after] it looks like this. [go: slot]
9
+ -->
10
+ <style>
11
+ .l-compare .cols { flex: 1; display: grid; grid-template-columns: 1fr 1fr; gap: 24px; max-width: 960px; align-content: center; }
12
+ .l-compare .col { border-radius: 28px; padding: 32px 34px; background: color-mix(in srgb, var(--ink) 6%, transparent); }
13
+ .l-compare .col.is-after { background: var(--ink); color: var(--paper); }
14
+ .l-compare .label { font: 700 var(--t-label) var(--mono); letter-spacing: .16em; text-transform: uppercase; margin-bottom: 20px; }
15
+ .l-compare .is-after .label { color: var(--accent); }
16
+ .l-compare li { list-style: none; font-size: var(--t-body); line-height: 1.3; padding: 14px 0; border-top: 1px solid color-mix(in srgb, currentColor 18%, transparent); }
17
+ .l-compare .tt { max-width: 11em; }
18
+ @media (max-width: 650px) {
19
+ .l-compare .cols { flex: none; grid-template-columns: 1fr; gap: 10px; }
20
+ .l-compare .col { border-radius: 16px; padding: 12px 16px; }
21
+ .l-compare .label { margin-bottom: 4px; }
22
+ .l-compare li { padding: 5px 0; }
23
+ }
24
+ </style>
25
+ <section class="slide l-compare" id="__ID__" data-chapter="Before and after" data-note="Source: name where each side's facts come from.">
26
+ <div class="kicker">Before and after</div>
27
+ <h2 class="tt" data-title-mobile="Before, after.">What changes.</h2>
28
+ <div class="cols">
29
+ <div class="col" id="__ID__-before"><div class="label">Before</div><ul><li>The old way, step one</li><li>Where it hurts</li><li>What it costs</li></ul></div>
30
+ <div class="col is-after" id="__ID__-after"><div class="label">After</div><ul><li>The new way, step one</li><li>What stops hurting</li><li>What it saves</li></ul></div>
31
+ </div>
32
+ <div class="narration-slot"></div>
33
+ </section>
@@ -0,0 +1,35 @@
1
+ <!--
2
+ layout: features
3
+ summary: Three features side by side, an icon, a name and one line each; the presenter flies under each card.
4
+ use: what it does, the three reasons, the three parts. Fill the icons with `hyperdecks icons` in the deck's palette.
5
+ slot: bottom-right
6
+ presenter: stage
7
+ cues: [go: #__ID__-f1], [go: #__ID__-f2], [go: #__ID__-f3] at the word that starts each, then [go: slot].
8
+ 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
+ <style>
11
+ .l-features .cards { display: grid; grid-template-columns: repeat(3, 1fr); gap: 24px; margin-top: 20px; }
12
+ .l-features .card { list-style: none; display: flex; flex-direction: column; gap: 10px; padding: 28px 30px; border-radius: 28px; background: var(--card); box-shadow: 0 0 0 1px color-mix(in srgb, var(--ink) 10%, transparent); }
13
+ /* Swap each svg for an <img class="icon"> of your file (hyperdecks icons). */
14
+ .l-features .icon { width: 64px; height: 64px; object-fit: contain; color: var(--ink); }
15
+ .l-features .icon .fill { fill: var(--accent); }
16
+ .l-features b { font-size: 32px; letter-spacing: -.02em; line-height: 1.05; }
17
+ .l-features p { font-size: 20px; line-height: 1.3; opacity: .7; }
18
+ @media (max-width: 650px) {
19
+ .l-features .cards { grid-template-columns: 1fr; gap: 8px; margin-top: 4px; }
20
+ .l-features .card { display: grid; grid-template-columns: 40px 1fr; column-gap: 12px; row-gap: 2px; padding: 12px 14px; border-radius: 16px; }
21
+ .l-features .icon { width: 40px; height: 40px; grid-row: span 2; }
22
+ .l-features b { font-size: 18px; }
23
+ .l-features p { font-size: 13px; }
24
+ }
25
+ </style>
26
+ <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
+ <div class="kicker">What it does</div>
28
+ <h2 class="tt" data-title-mobile="Three things.">It does three things.</h2>
29
+ <ul class="cards">
30
+ <li class="card" id="__ID__-f1"><svg class="icon" viewBox="0 0 64 64" fill="none" stroke="currentColor" stroke-width="3" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect class="fill" x="10" y="10" width="44" height="44" rx="12" stroke="none"/><path d="M22 42l4-12 16-16 8 8-16 16-12 4z"/></svg><b>It writes</b><p>One line on the first feature.</p></li>
31
+ <li class="card" id="__ID__-f2"><svg class="icon" viewBox="0 0 64 64" fill="none" stroke="currentColor" stroke-width="3" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle class="fill" cx="32" cy="32" r="24" stroke="none"/><rect x="26" y="14" width="12" height="24" rx="6"/><path d="M18 32a14 14 0 0 0 28 0M32 46v6"/></svg><b>It speaks</b><p>One line on the second feature.</p></li>
32
+ <li class="card" id="__ID__-f3"><svg class="icon" viewBox="0 0 64 64" fill="none" stroke="currentColor" stroke-width="3" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path class="fill" d="M10 54L32 8l22 46z" stroke="none"/><path d="M14 32l38-16-12 36-8-14z"/></svg><b>It sends</b><p>One line on the third feature.</p></li>
33
+ </ul>
34
+ <div class="narration-slot"></div>
35
+ </section>
@@ -0,0 +1,35 @@
1
+ <!--
2
+ layout: hero
3
+ summary: The opening. One display-size line, a visual on the right, the presenter's hello.
4
+ use: the first slide; a section opener. Pair with a generated illustration (gen-image) in .art.
5
+ slot: bottom-right
6
+ presenter: stage
7
+ cues: [wave] at the hello, [look: h1] when the narration says the title.
8
+ script: Hi, [wave] this is __TITLE__. [look: h1] One idea, in a few minutes.
9
+ -->
10
+ <style>
11
+ .l-hero { overflow: hidden; }
12
+ .l-hero .content { flex: 1; display: flex; flex-direction: column; justify-content: center; gap: 28px; max-width: 980px; position: relative; z-index: 1; }
13
+ .l-hero .tt { font-size: var(--t-display); line-height: .9; }
14
+ /* Swap the div for an <img class="art"> of your file (gen-image, wide). */
15
+ .l-hero .art { position: absolute; top: 0; right: 0; width: 820px; height: 100%; object-fit: cover; -webkit-mask-image: linear-gradient(to right, transparent, #000 32%); mask-image: linear-gradient(to right, transparent, #000 32%); }
16
+ .l-hero div.art { background:
17
+ radial-gradient(circle at 64% 36%, var(--paper) 0 168px, transparent 169px),
18
+ radial-gradient(circle at 64% 36%, var(--ink) 0 176px, transparent 177px),
19
+ radial-gradient(circle at 34% 78%, var(--accent-2) 0 92px, transparent 93px),
20
+ repeating-linear-gradient(135deg, color-mix(in srgb, var(--ink) 10%, transparent) 0 2px, transparent 2px 22px); }
21
+ @media (max-width: 650px) {
22
+ .l-hero .content { justify-content: flex-start; gap: 16px; padding-top: 200px; }
23
+ .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); }
24
+ .l-hero div.art { background-size: 180% 180%; background-position: 70% 30%; }
25
+ }
26
+ </style>
27
+ <section class="slide on-accent l-hero" id="__ID__" data-chapter="Hello" data-note="Title slide: no facts.">
28
+ <div class="art" role="presentation"></div>
29
+ <div class="content">
30
+ <div class="kicker">__SLUG__</div>
31
+ <h1 class="tt" data-title-mobile="__TITLE__">__TITLE__</h1>
32
+ <p class="lead">One sentence on what this deck is about.</p>
33
+ </div>
34
+ <div class="narration-slot"></div>
35
+ </section>
@@ -0,0 +1,29 @@
1
+ <!--
2
+ layout: number
3
+ summary: One big number, what it measures and its source. The number is the slide.
4
+ use: proof, traction, a before/after delta. Never an estimate shown as fact: the source line is required.
5
+ slot: bottom-right
6
+ presenter: stage
7
+ cues: [look: #__ID__-figure] as the narration says the number; [reveal: #__ID__-source] optional.
8
+ script: Here is the number that matters. [look: #__ID__-figure] Three times faster.
9
+ -->
10
+ <style>
11
+ .l-number .content { flex: 1; display: flex; flex-direction: column; justify-content: center; gap: 20px; max-width: 980px; }
12
+ .l-number .figure { font-weight: 700; font-size: 300px; line-height: .82; letter-spacing: -.06em; color: var(--accent); }
13
+ .l-number .figure small { font-size: .45em; letter-spacing: -.02em; margin-left: 8px; }
14
+ .l-number .tt { font-size: var(--t-sub); line-height: 1.02; max-width: 15em; }
15
+ .l-number .source { font: var(--t-label)/1.4 var(--mono); }
16
+ @media (max-width: 650px) {
17
+ .l-number .content { justify-content: flex-start; gap: 12px; }
18
+ .l-number .figure { font-size: 120px; }
19
+ }
20
+ </style>
21
+ <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
+ <div class="content">
23
+ <div class="kicker">Proof</div>
24
+ <div class="figure" id="__ID__-figure">3<small>×</small></div>
25
+ <h2 class="tt" data-title-mobile="What it measures.">What the number measures, in one line.</h2>
26
+ <p class="source muted" id="__ID__-source">Source: the report, with its date.</p>
27
+ </div>
28
+ <div class="narration-slot"></div>
29
+ </section>
@@ -0,0 +1,57 @@
1
+ <!--
2
+ layout: product
3
+ summary: A product screenshot in a browser frame (or .frame.phone for a phone shot), the point in the column beside it.
4
+ use: a demo moment. Fill .shot with `hyperdecks screenshot <url>` output; a callout chip names what to look at.
5
+ slot: bottom-right
6
+ presenter: stage
7
+ cues: [look: #__ID__-frame] when the narration turns to the product; [reveal: #__ID__-callout] for the detail.
8
+ script: This is the product. [look: #__ID__-frame] Look at this part. [reveal: #__ID__-callout]
9
+ -->
10
+ <style>
11
+ .l-product { display: grid; grid-template-columns: 960px 1fr; grid-template-areas: "frame text"; column-gap: 56px; align-items: center; }
12
+ .l-product .text { grid-area: text; align-self: start; display: flex; flex-direction: column; gap: 20px; }
13
+ .l-product .tt { font-size: var(--t-sub); line-height: 1.02; }
14
+ .l-product .lead { font-size: var(--t-body); }
15
+ .l-product .frame { grid-area: frame; position: relative; border-radius: 18px; overflow: hidden; background: var(--card); box-shadow: 0 0 0 1px color-mix(in srgb, var(--ink) 14%, transparent), 0 30px 70px color-mix(in srgb, var(--ink) 18%, transparent); }
16
+ .l-product .bar { display: flex; align-items: center; gap: 8px; height: 44px; padding: 0 18px; background: color-mix(in srgb, var(--ink) 6%, var(--card)); }
17
+ .l-product .bar i { width: 12px; height: 12px; border-radius: 50%; background: color-mix(in srgb, var(--ink) 22%, transparent); }
18
+ .l-product .bar span { margin-left: 14px; flex: 1; max-width: 420px; padding: 5px 14px; border-radius: 999px; background: var(--card); font: 14px var(--mono); opacity: .7; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
19
+ /* Swap the div for an <img class="shot"> of your file (a 16:10 screenshot). */
20
+ /* The shot keeps its own aspect ratio: cover-cropping a screenshot cuts its edges. */
21
+ .l-product img.shot { display: block; width: 100%; height: auto; }
22
+ .l-product div.shot { display: block; width: 100%; aspect-ratio: 16 / 10; }
23
+ .l-product div.shot { background:
24
+ linear-gradient(var(--accent) 0 0) 248px 40px / 320px 26px no-repeat,
25
+ linear-gradient(color-mix(in srgb, var(--ink) 12%, transparent) 0 0) 248px 92px / 640px 14px no-repeat,
26
+ linear-gradient(color-mix(in srgb, var(--ink) 12%, transparent) 0 0) 248px 120px / 520px 14px no-repeat,
27
+ linear-gradient(var(--accent-2) 0 0) 248px 176px / 300px 300px no-repeat,
28
+ linear-gradient(color-mix(in srgb, var(--ink) 8%, transparent) 0 0) 580px 176px / 308px 300px no-repeat,
29
+ linear-gradient(color-mix(in srgb, var(--ink) 6%, transparent) 0 0) 0 0 / 210px 100% no-repeat; }
30
+ .l-product .frame.phone { width: 300px; justify-self: center; border-radius: 40px; padding: 12px; background: var(--ink); }
31
+ .l-product .frame.phone .bar { display: none; }
32
+ .l-product .frame.phone .shot { aspect-ratio: 9 / 19.5; border-radius: 28px; }
33
+ .l-product .callout { position: absolute; left: 28px; bottom: 28px; padding: 12px 20px; border-radius: 999px; background: var(--ink); color: var(--paper); font-weight: 700; font-size: 22px; }
34
+ @media (max-width: 650px) {
35
+ .l-product { display: flex; flex-direction: column; align-items: stretch; }
36
+ .l-product .text { gap: 10px; }
37
+ .l-product .frame { border-radius: 12px; }
38
+ .l-product .bar { height: 26px; padding: 0 10px; gap: 5px; }
39
+ .l-product .bar i { width: 7px; height: 7px; }
40
+ .l-product .bar span { font-size: 9px; padding: 2px 8px; margin-left: 6px; }
41
+ .l-product div.shot { background-size: 30% 6%, 60% 2%, 50% 2%, 28% 40%, 28% 40%, 20% 100%; background-position: 26% 8%, 40% 18%, 36% 23%, 26% 70%, 62% 70%, 0 0; }
42
+ .l-product .callout { left: 10px; bottom: 10px; padding: 6px 12px; font-size: 12px; }
43
+ }
44
+ </style>
45
+ <section class="slide l-product" id="__ID__" data-chapter="The product" data-note="Screenshot: name the page and the date it was captured.">
46
+ <div class="text">
47
+ <div class="kicker">The product</div>
48
+ <h2 class="tt" data-title-mobile="Here it is.">Here it is, doing the job.</h2>
49
+ <p class="lead">One line on what the screenshot shows.</p>
50
+ </div>
51
+ <div class="frame" id="__ID__-frame">
52
+ <div class="bar"><i></i><i></i><i></i><span>app.example.com</span></div>
53
+ <div class="shot" role="img" aria-label="Product screenshot placeholder"></div>
54
+ <div class="callout reveal" id="__ID__-callout">The part to look at</div>
55
+ </div>
56
+ <div class="narration-slot"></div>
57
+ </section>
@@ -0,0 +1,31 @@
1
+ <!--
2
+ layout: quote
3
+ summary: One quote, large, with who said it. The quote is the title.
4
+ use: a customer or user in their own words. Quote them exactly and name the source in data-note.
5
+ slot: bottom-left
6
+ presenter: stage
7
+ cues: [look: #__ID__-quote] as the narration reads it.
8
+ script: In their words. [look: #__ID__-quote] Here is what they told us.
9
+ -->
10
+ <style>
11
+ .l-quote .content { flex: 1; display: flex; flex-direction: column; justify-content: center; gap: 36px; padding-left: 500px; }
12
+ .l-quote .quote { font-size: 76px; line-height: 1.02; letter-spacing: -.035em; text-indent: -.42em; }
13
+ .l-quote figcaption { display: flex; align-items: center; gap: 18px; }
14
+ /* Swap the span for an <img class="avatar"> of your file with their permission. */
15
+ .l-quote .avatar { display: grid; place-items: center; width: 72px; height: 72px; border-radius: 50%; object-fit: cover; background: var(--ink); color: var(--accent); font: 700 26px var(--font); }
16
+ .l-quote figcaption b { display: block; font-size: var(--t-body); }
17
+ .l-quote figcaption small { font: var(--t-label) var(--mono); letter-spacing: .08em; text-transform: uppercase; opacity: .7; }
18
+ @media (max-width: 650px) {
19
+ .l-quote .content { padding-left: 0; justify-content: flex-start; gap: 18px; }
20
+ .l-quote .quote { font-size: 32px; }
21
+ .l-quote .avatar { width: 44px; height: 44px; font-size: 16px; }
22
+ }
23
+ </style>
24
+ <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
+ <figure class="content">
26
+ <div class="kicker">In their words</div>
27
+ <h2 class="tt quote" id="__ID__-quote" data-title-mobile="“It explained itself.”">“The deck explained itself before I got on the call.”</h2>
28
+ <figcaption><span class="avatar">AD</span><span><b>Their name</b><small>Role, company</small></span></figcaption>
29
+ </figure>
30
+ <div class="narration-slot"></div>
31
+ </section>
@@ -0,0 +1,37 @@
1
+ <!--
2
+ layout: team
3
+ summary: Up to four people, a face, a name and a role each; the presenter flies under each as it names them.
4
+ use: who is behind it, who to talk to. Use real photos only with permission; initials otherwise.
5
+ slot: bottom-right
6
+ presenter: stage
7
+ cues: [go: #__ID__-p1] … [go: #__ID__-p4] at each name, then [go: slot].
8
+ 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
+ <style>
11
+ .l-team .people { display: grid; grid-template-columns: repeat(4, 1fr); gap: 24px; margin-top: 20px; }
12
+ .l-team .person { list-style: none; display: flex; flex-direction: column; align-items: flex-start; gap: 6px; padding: 24px 26px; border-radius: 28px; background: var(--card); box-shadow: 0 0 0 1px color-mix(in srgb, var(--ink) 10%, transparent); }
13
+ /* Swap the span for an <img class="face"> of your file with their permission. */
14
+ .l-team .face { display: grid; place-items: center; width: 96px; height: 96px; margin-bottom: 8px; border-radius: 50%; object-fit: cover; background: var(--accent); font: 700 34px var(--font); }
15
+ .l-team .person:nth-child(2) .face { background: var(--accent-2); }
16
+ .l-team .person:nth-child(3) .face { background: var(--ink); color: var(--paper); }
17
+ .l-team b { font-size: 30px; letter-spacing: -.02em; }
18
+ .l-team small { font: var(--t-label) var(--mono); letter-spacing: .08em; text-transform: uppercase; opacity: .7; }
19
+ @media (max-width: 650px) {
20
+ .l-team .people { grid-template-columns: 1fr 1fr; gap: 8px; margin-top: 4px; }
21
+ .l-team .person { padding: 12px; border-radius: 16px; gap: 2px; }
22
+ .l-team .face { width: 48px; height: 48px; font-size: 17px; margin-bottom: 4px; }
23
+ .l-team b { font-size: 16px; }
24
+ .l-team small { font-size: 10px; }
25
+ }
26
+ </style>
27
+ <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
+ <div class="kicker">The team</div>
29
+ <h2 class="tt" data-title-mobile="The team.">Who is behind it.</h2>
30
+ <ul class="people">
31
+ <li class="person" id="__ID__-p1"><span class="face">AN</span><b>Ana</b><small>Builds it</small></li>
32
+ <li class="person" id="__ID__-p2"><span class="face">SA</span><b>Sam</b><small>Sells it</small></li>
33
+ <li class="person" id="__ID__-p3"><span class="face">LE</span><b>Lee</b><small>Runs it</small></li>
34
+ <li class="person" id="__ID__-p4"><span class="face">KA</span><b>Kai</b><small>Designs it</small></li>
35
+ </ul>
36
+ <div class="narration-slot"></div>
37
+ </section>
@@ -0,0 +1,39 @@
1
+ <!--
2
+ layout: timeline
3
+ summary: Four milestones on a line, left to right, the presenter flying under each in turn.
4
+ use: history, a roadmap, a process over time. Label future steps "Proposed" if not agreed.
5
+ slot: bottom-right
6
+ presenter: stage
7
+ cues: [go: #__ID__-m1] … [go: #__ID__-m4] at the word that starts each milestone, then [go: slot].
8
+ 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
+ <style>
11
+ .l-timeline .line { display: grid; grid-template-columns: repeat(4, 1fr); gap: 24px; margin-top: 28px; position: relative; }
12
+ .l-timeline .line::before { content: ""; position: absolute; left: 0; right: 0; top: 13px; height: 4px; border-radius: 2px; background: color-mix(in srgb, var(--ink) 16%, transparent); }
13
+ .l-timeline li { list-style: none; position: relative; padding: 48px 26px 26px; border-radius: 24px; }
14
+ .l-timeline li::before { content: ""; position: absolute; left: 26px; top: 3px; width: 24px; height: 24px; border-radius: 50%; background: var(--ink); box-shadow: 0 0 0 6px var(--paper); }
15
+ .l-timeline li.is-next::before { background: var(--paper); box-shadow: inset 0 0 0 4px var(--ink), 0 0 0 6px var(--paper); }
16
+ .l-timeline time { display: block; font: 700 var(--t-label) var(--mono); letter-spacing: .12em; text-transform: uppercase; margin-bottom: 10px; }
17
+ .l-timeline b { display: block; font-size: 32px; letter-spacing: -.02em; line-height: 1.05; margin-bottom: 8px; }
18
+ .l-timeline p { font-size: 20px; line-height: 1.3; opacity: .7; }
19
+ @media (max-width: 650px) {
20
+ .l-timeline .line { grid-template-columns: 1fr; gap: 4px; margin-top: 4px; padding-left: 26px; }
21
+ .l-timeline .line::before { left: 7px; right: auto; top: 6px; bottom: 6px; width: 3px; height: auto; }
22
+ .l-timeline li { padding: 4px 0 8px 8px; border-radius: 0; }
23
+ .l-timeline li::before { left: -26px; top: 6px; width: 15px; height: 15px; box-shadow: 0 0 0 4px var(--paper); }
24
+ .l-timeline time { margin-bottom: 2px; }
25
+ .l-timeline b { font-size: 18px; margin-bottom: 2px; }
26
+ .l-timeline p { font-size: 13px; }
27
+ }
28
+ </style>
29
+ <section class="slide l-timeline" id="__ID__" data-chapter="How we got here" data-note="Source: name where each date comes from.">
30
+ <div class="kicker">How we got here</div>
31
+ <h2 class="tt" data-title-mobile="How we got here.">Four steps, so far.</h2>
32
+ <ol class="line">
33
+ <li id="__ID__-m1"><time>Jan</time><b>A sketch</b><p>The first version, on paper.</p></li>
34
+ <li id="__ID__-m2"><time>Apr</time><b>A first user</b><p>Someone used it for real.</p></li>
35
+ <li id="__ID__-m3"><time>Sep</time><b>Launch</b><p>Open to everyone.</p></li>
36
+ <li id="__ID__-m4" class="is-next"><time>Next</time><b>Proposed</b><p>Not agreed yet.</p></li>
37
+ </ol>
38
+ <div class="narration-slot"></div>
39
+ </section>
@@ -4,29 +4,71 @@
4
4
  <meta charset="UTF-8">
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1">
6
6
  <title>__TITLE__</title>
7
+ <!-- Loading state (keep verbatim; `hyperdecks check` requires it). Until the
8
+ player marks body[data-hd-ready] the page shows only the slide card, at its
9
+ final size, in the deck's --hd-ground (its first slide's colour) on the
10
+ page's brand colour, with a quiet loader in --hd-ground-ink; then the
11
+ slides fade in. If the player never arrives, the slides show after 10 s
12
+ rather than never. Put data-layout="overlay" on <html> for the overlay. -->
13
+ <link rel="modulepreload" href="https://decks.hypersocial.ai/player/v1/player.js">
14
+ <link rel="preload" as="style" href="https://decks.hypersocial.ai/player/v1/player.css">
15
+ <script>if (self !== top || /[?&]thumb\b/.test(location.search)) document.documentElement.dataset.hdFrame = "";</script>
16
+ <style data-hd-loading>
17
+ body:not([data-hd-ready]) { overflow: hidden; background: var(--hd-frame, var(--hd-ground, var(--hd-accent, #ffda1b))); animation: hd-fail-open 0s 10s forwards; }
18
+ body:not([data-hd-ready]) > * { visibility: hidden; animation: hd-fail-open 0s 10s forwards; }
19
+ body[data-hd-ready] > * { animation: hd-in .2s ease-out; }
20
+ body::before, body::after { content: ""; position: fixed; z-index: -1; pointer-events: none; transition: opacity .2s ease-out; }
21
+ /* The card as the player draws it (player.css, framed): 16:9, scaled to fit
22
+ between the 64px masthead and the 56px dock, 24px in from the sides. */
23
+ body::before { inset: 64px 24px 56px; margin: auto; width: min(100vw - 48px, (100dvh - 120px) * 16 / 9); height: min(100dvh - 120px, (100vw - 48px) * 9 / 16); border-radius: calc(min(100vw - 48px, (100dvh - 120px) * 16 / 9) * .01125); background: var(--hd-ground, #fff); box-shadow: 0 0 0 1px color-mix(in srgb, var(--hd-ground-ink, #0b0b0f) 16%, transparent); }
24
+ body::after { left: 50%; top: 50%; width: 12px; height: 12px; margin: -6px 0 0 -6px; border-radius: 50%; color: var(--hd-ground-ink, #0b0b0f); background: currentColor; box-shadow: -24px 0 currentColor, 24px 0 currentColor; opacity: 0; animation: hd-dots .7s ease-in-out .6s infinite alternate; }
25
+ body[data-hd-ready]::before, body[data-hd-ready]::after { opacity: 0; animation: none; }
26
+ /* The overlay (embedded, ?thumb, or data-layout="overlay"): the stage fills the window. */
27
+ :is([data-hd-frame], [data-layout="overlay"]) body::before { inset: 0; width: min(100vw, 100dvh * 16 / 9); height: min(100dvh, 100vw * 9 / 16); border-radius: calc(min(100vw, 100dvh * 16 / 9) * .01125); box-shadow: none; }
28
+ [data-layout="overlay"] body:not([data-hd-ready]) { background: var(--hd-backdrop, #16161c); }
29
+ [data-hd-frame] body:not([data-hd-ready]) { background: transparent; }
30
+ [data-hd-frame] body::before { border-radius: 0; }
31
+ /* Phones: the card fills the space between a 52px masthead and the dock, 8px in. */
32
+ @media (max-width: 650px) {
33
+ body::before { inset: 52px 8px calc(56px + env(safe-area-inset-bottom)); width: auto; height: auto; border-radius: 14px; }
34
+ :is([data-hd-frame], [data-layout="overlay"]) body::before { inset: 0; width: auto; height: auto; border-radius: 0; }
35
+ }
36
+ @media (prefers-reduced-motion: reduce) {
37
+ body::before, body::after { transition: none; }
38
+ body:not([data-hd-ready])::after { animation: none; opacity: .4; }
39
+ body[data-hd-ready] > * { animation: none; }
40
+ }
41
+ @keyframes hd-in { from { opacity: 0; } }
42
+ @keyframes hd-dots { from { opacity: .15; } to { opacity: .6; } }
43
+ @keyframes hd-fail-open { to { visibility: visible; overflow: auto; } }
44
+ </style>
7
45
  <link rel="preconnect" href="https://fonts.googleapis.com">
8
46
  <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
9
47
  <link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Space+Grotesk:wght@500;700&family=Space+Mono:wght@400;700&display=swap">
10
48
  <style>
11
49
  /* A narrated deck: slides only. The hosted player (player/v1) scales the
12
50
  stage, draws the chrome and the presenter, and plays the narration. */
13
- :root { --ink: #0b0b0f; --paper: #fafaf7; --accent: #ffda1b; --font: "Space Grotesk", system-ui, sans-serif; --mono: "Space Mono", ui-monospace, monospace; }
51
+ :root { --ink: #0b0b0f; --paper: #fafaf7; --accent: #ffda1b; --font: "Space Grotesk", system-ui, sans-serif; --mono: "Space Mono", ui-monospace, monospace;
52
+ --hd-ground: var(--accent); --hd-ground-ink: var(--ink); /* the loading state: the first slide's colours */ }
14
53
  body { color: var(--ink); font-family: var(--font); --hd-font: var(--font); --hd-mono: var(--mono); }
15
54
  .slide { display: flex; flex-direction: column; gap: 28px; padding: 64px 72px 56px; background: var(--paper); }
16
55
  .slide.accent { background: var(--accent); }
17
56
  .kicker { font: 18px var(--mono); letter-spacing: .16em; text-transform: uppercase; }
18
57
  .tt { font-size: 104px; line-height: .95; letter-spacing: -.045em; margin: 0; text-wrap: balance; }
19
58
  .lead { font-size: 32px; line-height: 1.3; max-width: 30em; margin: 0; }
20
- .content { flex: 1; display: flex; flex-direction: column; justify-content: center; gap: 28px; padding-right: 320px; }
21
- /* The presenter (face + caption bubble) moves into each slide's slot. */
59
+ .content { flex: 1; display: flex; flex-direction: column; justify-content: center; gap: 28px; padding-right: 500px; }
60
+ /* The presenter glides to each slide's slot; slots alternate sides so the
61
+ move shows. A .slot-left slide keeps its text clear of the left side. */
22
62
  .narration-slot { position: absolute; right: 56px; bottom: 72px; }
63
+ .slot-left .narration-slot { right: auto; left: 56px; }
64
+ .slot-left .content { padding-right: 0; padding-left: 500px; }
23
65
  .reveal { opacity: 0; transition: opacity .4s; }
24
66
  .reveal.is-revealed { opacity: 1; }
25
67
  @media (max-width: 650px) {
26
68
  .slide { padding: 40px 20px 150px; }
27
69
  .tt { font-size: 40px; }
28
70
  .lead { font-size: 18px; }
29
- .content { padding-right: 0; justify-content: flex-start; }
71
+ .content, .slot-left .content { padding: 0; justify-content: flex-start; }
30
72
  .narration-slot { right: 12px; left: 12px; bottom: 72px; }
31
73
  }
32
74
  </style>
@@ -39,7 +81,9 @@
39
81
  `hyperdecks check` fails a slide without one.
40
82
  data-intro: the bubble's text before the narration plays.
41
83
  data-title-mobile: shorter text below 650px; check requires it on any title
42
- over 28 characters. Every slide here carries one. -->
84
+ over 28 characters. Every slide here carries one.
85
+ data-presenter-style: this slide's presenter (stage, bubble, glass, corner),
86
+ overriding the deck's on the player tag below. -->
43
87
  <section class="slide accent" id="hello" data-chapter="Hello" data-intro="Hi! Press play." data-note="Title slide: no facts.">
44
88
  <div class="content">
45
89
  <div class="kicker">__SLUG__</div>
@@ -48,7 +92,7 @@
48
92
  <div class="narration-slot"></div>
49
93
  </section>
50
94
 
51
- <section class="slide" id="problem" data-chapter="Problem" data-note="Source: name the document, email or thread the problem comes from.">
95
+ <section class="slide slot-left" id="problem" data-chapter="Problem" data-note="Source: name the document, email or thread the problem comes from.">
52
96
  <div class="content">
53
97
  <div class="kicker">The problem</div>
54
98
  <h2 class="tt" data-title-mobile="The problem.">The problem, in one line.</h2>
@@ -66,7 +110,7 @@
66
110
  <div class="narration-slot"></div>
67
111
  </section>
68
112
 
69
- <section class="slide" id="idea" data-chapter="The idea" data-note="Source: name the doc or conversation the idea is drawn from.">
113
+ <section class="slide slot-left" id="idea" data-chapter="The idea" data-note="Source: name the doc or conversation the idea is drawn from.">
70
114
  <div class="content">
71
115
  <div class="kicker">The idea</div>
72
116
  <h2 class="tt" data-title-mobile="The idea.">One idea per slide.</h2>
@@ -84,7 +128,7 @@
84
128
  <div class="narration-slot"></div>
85
129
  </section>
86
130
 
87
- <section class="slide" id="proof" data-chapter="Proof" data-note="Source: name the metric's dashboard, report or email, with its date.">
131
+ <section class="slide slot-left" id="proof" data-chapter="Proof" data-note="Source: name the metric's dashboard, report or email, with its date.">
88
132
  <div class="content">
89
133
  <div class="kicker">Proof</div>
90
134
  <h2 class="tt" data-title-mobile="The proof.">The evidence so far.</h2>
@@ -102,7 +146,7 @@
102
146
  <div class="narration-slot"></div>
103
147
  </section>
104
148
 
105
- <section class="slide" id="bye" data-chapter="Bye" data-note="Closing slide: no facts.">
149
+ <section class="slide slot-left" id="bye" data-chapter="Bye" data-note="Closing slide: no facts.">
106
150
  <div class="content">
107
151
  <h2 class="tt" data-title-mobile="Thanks.">Thanks for watching.</h2>
108
152
  </div>
@@ -111,9 +155,11 @@
111
155
 
112
156
  <!-- `hyperdecks narrate decks/__SLUG__` fills data-manifest with the manifest
113
157
  URL it writes. data-presenter: head (live Minimoji, needs
114
- data-avatar), static (data-presenter-image) or none (captions only). -->
158
+ data-avatar), static (data-presenter-image) or none (captions only).
159
+ data-presenter-style: stage (large head, lower-third captions), bubble,
160
+ glass (frosted panel) or corner (small head, subtitles). -->
115
161
  <script type="module" src="https://decks.hypersocial.ai/player/v1/player.js"
116
- data-manifest="" data-stage="1600x900" data-presenter="none"></script>
162
+ data-manifest="" data-stage="1600x900" data-presenter="none" data-presenter-style="__PRESENTER_STYLE__"></script>
117
163
  <!-- Slide controllers for anything the built-in cues don't cover:
118
164
  <script type="module">
119
165
  window.hyperdecks.register("point", {