octocode-cli 1.3.0 → 1.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (106) hide show
  1. package/README.md +129 -28
  2. package/out/chunks/chunk-7476PETK.js +309 -0
  3. package/out/chunks/chunk-CVNNNSMQ.js +26 -0
  4. package/out/chunks/chunk-OQBJTZWK.js +60 -0
  5. package/out/chunks/chunk-UCZCF3BQ.js +9 -0
  6. package/out/chunks/command-help-specs-JZXVSLZ5.js +8 -0
  7. package/out/chunks/commands-XBFPLHSQ.js +8 -0
  8. package/out/chunks/help-P7TCOYAJ.js +10 -0
  9. package/out/chunks/main-help-ULF5PAQY.js +10 -0
  10. package/out/chunks/prompts-5E6VKRX5.js +8 -0
  11. package/out/chunks/spinner-URV2OX6O.js +8 -0
  12. package/out/chunks/tool-command-M6VA7P2F.js +8 -0
  13. package/out/octocode-cli.js +1 -1
  14. package/package.json +5 -3
  15. package/skills/README.md +60 -58
  16. package/skills/agentic-flow-best-practices/SKILL.md +280 -0
  17. package/skills/agentic-flow-best-practices/references/agent-collaboration-patterns.md +75 -0
  18. package/skills/agentic-flow-best-practices/references/pr-review-agent-example.md +47 -0
  19. package/skills/agentic-flow-best-practices/references/resources.md +112 -0
  20. package/skills/octocode-brainstorming/.env.example +11 -0
  21. package/skills/octocode-brainstorming/SKILL.md +262 -0
  22. package/skills/octocode-brainstorming/scripts/tavily-search.mjs +138 -0
  23. package/skills/octocode-chrome-devtools/README.md +541 -0
  24. package/skills/octocode-chrome-devtools/SKILL.md +197 -0
  25. package/skills/octocode-chrome-devtools/agents/openai.yaml +7 -0
  26. package/skills/octocode-chrome-devtools/references/CDP_AGENT_REFERENCE.md +401 -0
  27. package/skills/octocode-chrome-devtools/references/CHROME_FLAGS.md +234 -0
  28. package/skills/octocode-chrome-devtools/references/INTENTS.md +108 -0
  29. package/skills/octocode-chrome-devtools/references/INTENTS_AUTH.md +179 -0
  30. package/skills/octocode-chrome-devtools/references/INTENTS_AUTOMATION.md +214 -0
  31. package/skills/octocode-chrome-devtools/references/INTENTS_DEBUG.md +329 -0
  32. package/skills/octocode-chrome-devtools/references/INTENTS_ENVIRONMENT.md +237 -0
  33. package/skills/octocode-chrome-devtools/references/INTENTS_INSPECT.md +263 -0
  34. package/skills/octocode-chrome-devtools/references/INTENTS_STORAGE_CONSENT.md +214 -0
  35. package/skills/octocode-chrome-devtools/references/RECOVERY.md +39 -0
  36. package/skills/octocode-chrome-devtools/references/SCRIPT_PATTERNS.md +43 -0
  37. package/skills/octocode-chrome-devtools/references/SCRIPT_PATTERNS_ASYNC_WORKERS.md +345 -0
  38. package/skills/octocode-chrome-devtools/references/SCRIPT_PATTERNS_BROWSER.md +403 -0
  39. package/skills/octocode-chrome-devtools/references/SCRIPT_PATTERNS_OBSERVE.md +275 -0
  40. package/skills/octocode-chrome-devtools/references/SCRIPT_PATTERNS_SPECIAL.md +18 -0
  41. package/skills/octocode-chrome-devtools/scripts/cdp-runner.mjs +503 -0
  42. package/skills/octocode-chrome-devtools/scripts/cdp-sandbox.mjs +123 -0
  43. package/skills/octocode-chrome-devtools/scripts/cdp-template.mjs +81 -0
  44. package/skills/octocode-chrome-devtools/scripts/octocode-chrome-devtools.vpn.example.json +8 -0
  45. package/skills/octocode-chrome-devtools/scripts/open-browser.mjs +362 -0
  46. package/skills/octocode-chrome-devtools/scripts/sourcemap-resolver.mjs +193 -0
  47. package/skills/octocode-chrome-devtools/scripts/undercover.mjs +226 -0
  48. package/skills/octocode-design/README.md +2 -2
  49. package/skills/octocode-documentation-writer/README.md +1 -1
  50. package/skills/octocode-engineer/README.md +1 -1
  51. package/skills/octocode-engineer/SKILL.md +137 -306
  52. package/skills/octocode-engineer/references/cli-reference.md +13 -0
  53. package/skills/octocode-engineer/references/output-files.md +3 -3
  54. package/skills/octocode-engineer/scripts/run.js +146 -146
  55. package/skills/octocode-engineer/src/pipeline/main.ts +1 -17
  56. package/skills/octocode-engineer/src/pipeline/progress.ts +4 -0
  57. package/skills/octocode-engineer/src/reporting/summary-md.test.ts +48 -0
  58. package/skills/octocode-engineer/src/reporting/summary-md.ts +43 -2
  59. package/skills/octocode-install/SKILL.md +1 -1
  60. package/skills/octocode-pull-request-reviewer/README.md +5 -5
  61. package/skills/octocode-pull-request-reviewer/SKILL.md +1 -1
  62. package/skills/octocode-research/AGENTS.md +1 -1
  63. package/skills/octocode-research/README.md +2 -2
  64. package/skills/octocode-research/docs/ARCHITECTURE.md +1 -1
  65. package/skills/octocode-research/scripts/server.js +184 -239
  66. package/skills/octocode-research/src/routes/github.ts +4 -21
  67. package/skills/octocode-research/src/routes/local.ts +4 -21
  68. package/skills/octocode-research/src/utils/fileContentTransform.ts +44 -0
  69. package/skills/octocode-search-skill/SKILL.md +337 -0
  70. package/skills/octocode-search-skill/references/agent-skills-guide.md +177 -0
  71. package/skills/octocode-search-skill/references/discovery-surfaces.md +162 -0
  72. package/skills/octocode-search-skill/references/fetch-and-create-locally.md +57 -0
  73. package/skills/octocode-search-skill/references/install-reference.md +130 -0
  74. package/skills/octocode-search-skill/references/references-template.md +27 -0
  75. package/skills/octocode-search-skill/references/references.md +62 -0
  76. package/skills/octocode-slides/README.md +307 -0
  77. package/skills/octocode-slides/SKILL.md +410 -0
  78. package/skills/octocode-slides/references/01-brief.md +156 -0
  79. package/skills/octocode-slides/references/02-research.md +149 -0
  80. package/skills/octocode-slides/references/03-outline.md +172 -0
  81. package/skills/octocode-slides/references/04-design.md +301 -0
  82. package/skills/octocode-slides/references/05-implementation.md +213 -0
  83. package/skills/octocode-slides/references/06-review.md +258 -0
  84. package/skills/octocode-slides/references/animation.md +281 -0
  85. package/skills/octocode-slides/references/design-system.md +316 -0
  86. package/skills/octocode-slides/references/html-templates.md +673 -0
  87. package/skills/octocode-slides/references/image-generation.md +448 -0
  88. package/skills/octocode-slides/references/resources.md +840 -0
  89. package/skills/octocode-slides/references/slide-rules.md +541 -0
  90. package/skills/octocode-slides/references/wireframes.md +727 -0
  91. package/skills/octocode-slides/scripts/animation.js +182 -0
  92. package/skills/octocode-slides/scripts/base.css +353 -0
  93. package/skills/octocode-slides/scripts/base.html +655 -0
  94. package/skills/octocode-slides/scripts/generate_image.py +221 -0
  95. package/skills/octocode-slides/scripts/navbridge.js +79 -0
  96. package/skills/octocode-slides/scripts/presenter.js +316 -0
  97. package/skills/octocode-slides/scripts/slide.html +248 -0
  98. package/skills/octocode-stats/SKILL.md +73 -0
  99. package/skills/octocode-stats/assets/template.html +1332 -0
  100. package/skills/octocode-stats/scripts/build_dashboard.mjs +407 -0
  101. package/out/chunks/chunk-LH4AZJPA.js +0 -389
  102. package/out/chunks/command-help-specs-CQ3RBLP6.js +0 -8
  103. package/out/chunks/commands-M3QTWKWE.js +0 -51
  104. package/out/chunks/help-XPXP46ZT.js +0 -10
  105. package/out/chunks/main-help-HXFAFHPG.js +0 -10
  106. package/out/chunks/tool-command-VHFLPIHY.js +0 -8
@@ -0,0 +1,840 @@
1
+ # Slide Libraries & Design Resources
2
+
3
+ CDN libraries and design references available to any slide. The agent chooses what fits the deck — nothing here is mandatory unless the slide type needs it.
4
+
5
+ ---
6
+
7
+ ## Markdown Rendering
8
+
9
+ ### marked.js — Markdown → HTML, zero dependencies
10
+ **Rating:** ★★★★☆ — solid workhorse; only needed when slide content is Markdown-sourced
11
+ **CDN:** `https://cdn.jsdelivr.net/npm/marked/lib/marked.umd.js`
12
+ **Repo:** [markedjs/marked](https://github.com/markedjs/marked) | 35k+ stars
13
+ **Use when:** A content slide sources text from a `.md` file, or the user provides long-form content as Markdown.
14
+
15
+ ```html
16
+ <script src="https://cdn.jsdelivr.net/npm/marked/lib/marked.umd.js"></script>
17
+ <div class="slide-body" data-md>
18
+ # Heading
19
+ - point one
20
+ - point two
21
+ </div>
22
+ <script>
23
+ document.querySelectorAll('[data-md]').forEach(el => {
24
+ el.innerHTML = marked.parse(el.textContent.trim());
25
+ });
26
+ </script>
27
+ ```
28
+
29
+ **Configuration for presentations:**
30
+ ```js
31
+ marked.setOptions({
32
+ breaks: true, // newline → <br>
33
+ gfm: true, // GitHub Flavored Markdown
34
+ });
35
+ ```
36
+
37
+ ---
38
+
39
+ ## Animation
40
+
41
+ ### CSS-native stagger — zero dependencies (Chrome + Safari; Firefox in progress)
42
+ **Rating:** ★★★★★ — best default for bullet/card stagger; no import, no bundle, adapts to DOM changes automatically
43
+ **Spec:** [CSS Wrapped 2025](https://chrome.dev/css-wrapped-2025/) · [Smashing Mag deep-dive](https://www.smashingmagazine.com/2025/12/state-logic-native-power-css-wrapped-2025/)
44
+ **Use when:** Bullets, cards, or tiles need a staggered entrance. Replaces Motion.dev stagger for most slide use cases — no import, adapts dynamically to DOM changes.
45
+
46
+ ```css
47
+ /* Add to slide <style>. Works with any list of siblings. */
48
+ .bullet {
49
+ transition: opacity 0.25s ease, translate 0.25s ease;
50
+ transition-delay: calc(0.1s * (sibling-index() - 1)); /* 1-based, subtract 1 so first = 0s */
51
+ @starting-style {
52
+ opacity: 0;
53
+ translate: 0 0.75em;
54
+ }
55
+ }
56
+ ```
57
+
58
+ **Gate with `@supports` for older browsers:**
59
+ ```css
60
+ @supports (transition-delay: calc(sibling-index() * 0s)) {
61
+ .bullet { /* stagger rules */ }
62
+ }
63
+ ```
64
+
65
+ ---
66
+
67
+ ### Motion — Production-grade JS animations
68
+ **Rating:** ★★★★★ — essential for counters, timelines, and spring physics; nothing else matches its API quality
69
+ **CDN (ESM):** `https://cdn.jsdelivr.net/npm/motion@latest/+esm`
70
+ **Docs:** [motion.dev/docs/quick-start](https://motion.dev/docs/quick-start)
71
+ **Repo:** [motiondotdev/motion](https://github.com/motiondotdev/motion) | 26k+ stars
72
+ **Use when:** Timelines, number counters, spring physics, or slide-local transitions that CSS can't express.
73
+
74
+ **Counter / number animation:**
75
+ ```html
76
+ <script type="module">
77
+ import { animate } from "https://cdn.jsdelivr.net/npm/motion@latest/+esm";
78
+ animate(0, 2_400_000, {
79
+ duration: 1.6,
80
+ easing: [0.22, 1, 0.36, 1],
81
+ onUpdate(v) {
82
+ document.getElementById('counter').textContent = Math.round(v).toLocaleString();
83
+ }
84
+ });
85
+ </script>
86
+ ```
87
+
88
+ **Timeline sequence (title → subtitle → body):**
89
+ ```html
90
+ <script type="module">
91
+ import { timeline } from "https://cdn.jsdelivr.net/npm/motion@latest/+esm";
92
+ timeline([
93
+ ['.slide-title', { opacity: [0, 1], y: [-12, 0] }, { duration: 0.4 }],
94
+ ['.slide-subtitle', { opacity: [0, 1] }, { duration: 0.3, at: '+0.1' }],
95
+ ['.slide-body', { opacity: [0, 1], y: [8, 0] }, { duration: 0.4, at: '+0.1' }],
96
+ ]);
97
+ </script>
98
+ ```
99
+
100
+ **Stagger (use CSS-native first; fall back to this when `sibling-index()` unsupported):**
101
+ ```html
102
+ <script type="module">
103
+ import { animate, stagger } from "https://cdn.jsdelivr.net/npm/motion@latest/+esm";
104
+ animate('.bullet', { opacity: [0, 1], y: [16, 0] }, { delay: stagger(0.12), duration: 0.45, easing: [0.22, 1, 0.36, 1] });
105
+ </script>
106
+ ```
107
+
108
+ ---
109
+
110
+ ### GSAP — Complex timelines and SVG choreography
111
+ **Rating:** ★★★☆☆ — overkill for most slides; reach for it only when Motion.dev and CSS both fall short
112
+ **CDN:** `https://cdnjs.cloudflare.com/ajax/libs/gsap/3.12.5/gsap.min.js`
113
+ **Docs:** [gsap.com/docs](https://gsap.com/docs/)
114
+ **Use when:** SVG path animations or complex choreography where Motion.dev is insufficient. Avoid scroll-driven patterns inside slides because slide content should remain fixed within the frame.
115
+
116
+ ```html
117
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.12.5/gsap.min.js"></script>
118
+ <script>
119
+ gsap.from('.slide-body > *', { opacity: 0, y: 20, stagger: 0.12, duration: 0.5, ease: 'power2.out' });
120
+ </script>
121
+ ```
122
+
123
+ ---
124
+
125
+ **Animation decision table:**
126
+
127
+ | Situation | Use |
128
+ |-----------|-----|
129
+ | Simple fade / slide-up on load | CSS `.fade-in`, `.slide-up` from base.css |
130
+ | Staggered bullets/cards (modern browsers) | CSS `sibling-index()` + `@starting-style` |
131
+ | Staggered bullets/cards (broad browser support) | Motion `stagger()` |
132
+ | Number counters, progress fills | Motion `animate(0, N, onUpdate)` |
133
+ | Sequenced multi-element choreography | Motion `timeline()` |
134
+ | SVG path animation or complex choreography | GSAP |
135
+ | Spring / physics-based motion | Motion spring easing |
136
+
137
+ ---
138
+
139
+ ## Slide Transitions (View Transitions API)
140
+
141
+ **Rating:** ★★★★☆ — powerful and zero-dependency; iframe caveat limits the simplest path, but SPA pattern works cleanly
142
+ **No library needed — browser-native.**
143
+ **MDN:** [Using the View Transition API](https://developer.mozilla.org/en-US/docs/Web/API/View_Transition_API/Using)
144
+ **Recipes:** [Piccalilli — practical VT examples](https://piccalil.li/blog/some-practical-examples-of-view-transitions-to-elevate-your-ui/)
145
+ **Toolkit:** [vtbag.dev](https://vtbag.dev/) — "Bag of Tricks" for view transitions (named patterns, debugging, demos)
146
+
147
+ **SPA path — wrap iframe swap in `index.html`:**
148
+
149
+ ```js
150
+ // In index.html navigation controller — wrap slide change in a transition
151
+ function goToSlide(n) {
152
+ if (!document.startViewTransition) { updateSlide(n); return; }
153
+ document.startViewTransition(() => updateSlide(n));
154
+ }
155
+ ```
156
+
157
+ **Directional transitions — modern approach (`:active-view-transition-type`):**
158
+ ```js
159
+ // Pass a direction type so CSS can target forward vs backward separately
160
+ function goToSlide(n, direction = 'forward') {
161
+ if (!document.startViewTransition) { updateSlide(n); return; }
162
+ document.startViewTransition({
163
+ update: () => updateSlide(n),
164
+ types: [direction] // 'forward' or 'backward'
165
+ });
166
+ }
167
+ ```
168
+
169
+ ```css
170
+ /* In index.html <style> — direction-aware keyframes */
171
+ @keyframes slide-out-left { to { transform: translateX(-100%); opacity: 0; } }
172
+ @keyframes slide-in-right { from { transform: translateX( 100%); opacity: 0; } }
173
+ @keyframes slide-out-right { to { transform: translateX( 100%); opacity: 0; } }
174
+ @keyframes slide-in-left { from { transform: translateX(-100%); opacity: 0; } }
175
+
176
+ :active-view-transition-type(forward) {
177
+ &::view-transition-old(root) { animation: slide-out-left 0.3s ease; }
178
+ &::view-transition-new(root) { animation: slide-in-right 0.3s ease; }
179
+ }
180
+ :active-view-transition-type(backward) {
181
+ &::view-transition-old(root) { animation: slide-out-right 0.3s ease; }
182
+ &::view-transition-new(root) { animation: slide-in-left 0.3s ease; }
183
+ }
184
+
185
+ /* Gate reduced-motion */
186
+ @media (prefers-reduced-motion: reduce) {
187
+ ::view-transition-old(root), ::view-transition-new(root) { animation: none; }
188
+ }
189
+ ```
190
+
191
+ > **What VT animates in this architecture:** `document.startViewTransition` in `index.html` snapshots the **parent `#stage` wrapper** (the iframe container). The slide content *inside* the iframe is captured as a pixel snapshot. This is correct and visually convincing — the animation happens at the parent level, not inside the iframe.
192
+
193
+ **MPA / cross-document path (only for non-iframe decks):**
194
+ ```css
195
+ /* Only use when each slide is a top-level page (no iframe wrapper). */
196
+ @view-transition { navigation: auto; }
197
+
198
+ @media (prefers-reduced-motion: reduce) {
199
+ @view-transition { navigation: none; }
200
+ }
201
+ ```
202
+
203
+ **Named shared elements (logo/title that morphs between slides):**
204
+ ```css
205
+ /* Apply to the *same* element in old and new slide — must be unique per transition */
206
+ .slide-logo { view-transition-name: deck-logo; contain: layout; }
207
+ ```
208
+
209
+ > **iframe caveat:** cross-document VT and `view-transition-name` on elements *inside* iframes do not propagate to the parent. Use the SPA path (`document.startViewTransition` in `index.html`) and name elements on the **parent** (e.g. a HUD logo or progress bar) for morphing effects.
210
+
211
+ ---
212
+
213
+ ## Code Syntax Highlighting
214
+
215
+ ### highlight.js — Syntax highlighting, 200+ languages
216
+ **Rating:** ★★★★★ — drop-in, theme-matched, no config required; mandatory for any code slide
217
+ **CDN:**
218
+ ```html
219
+ <link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/highlightjs/cdn-release@11/build/styles/github-dark.min.css">
220
+ <script src="https://cdn.jsdelivr.net/gh/highlightjs/cdn-release@11/build/highlight.min.js"></script>
221
+ ```
222
+ **Repo:** [highlightjs/highlight.js](https://github.com/highlightjs/highlight.js) | 24k+ stars
223
+ **Use when:** A code slide needs real syntax coloring (not just a monospace block). Better than a CSS `.language-*` class alone.
224
+
225
+ ```html
226
+ <pre><code class="language-typescript">async function fetchUser(id: string): Promise<User> {
227
+ const res = await fetch(`/api/users/${id}`);
228
+ if (!res.ok) throw new Error(`HTTP ${res.status}`);
229
+ return res.json();
230
+ }</code></pre>
231
+ <script>
232
+ document.querySelectorAll('pre code').forEach(el => hljs.highlightElement(el));
233
+ </script>
234
+ ```
235
+
236
+ **Suggested themes by background energy — pick what fits your palette:**
237
+
238
+ | Background | Recommended | Alt |
239
+ |------------|-------------|-----|
240
+ | Dark cool / neutral | `github-dark` | `monokai-sublime` |
241
+ | Dark warm / very dark | `tokyo-night-dark` | `nord` |
242
+ | Light | `github` | `xcode` |
243
+ | Minimal / low-contrast | `ascetic` | `base16/one-light` |
244
+
245
+ ---
246
+
247
+ ## Data Visualization — Library Decision
248
+
249
+ Pick the lightest library that delivers the chart type needed. Avoid loading multiple chart libraries in one slide.
250
+
251
+ | Chart need | Library | Why |
252
+ |------------|---------|-----|
253
+ | Bar, line, area, donut, scatter, radar | **Chart.js** | Lightest CDN, built-in animation, official CDN support |
254
+ | Heatmap, geo/map, treemap, candlestick, graph | **ECharts** | Broadest type catalog; handles complex multi-panel layouts |
255
+ | Dense time-series, 10k+ points, perf-critical | **uPlot** | Smallest footprint, vanilla IIFE, zero dependencies |
256
+ | Polished multi-type with strong defaults | **ApexCharts** | SVG-based, real-time hooks, wide type catalog |
257
+ | Custom SVG/bespoke layouts, networks, projections | **D3.js** | Full control, no defaults; high authoring cost |
258
+ | CSS bar comparison (≤6 bars, static) | **CSS only** | No library needed; use `width: X%` + `--accent` bars |
259
+
260
+ **KPI / counter / progress widgets (no chart library needed):**
261
+
262
+ | Widget | Tool |
263
+ |--------|------|
264
+ | Number count-up | Motion `animate(0, N, onUpdate)` (see Animation section) |
265
+ | Progress bar | Motion `animate(el, { width: ['0%', 'N%'] })` or CSS `@starting-style` |
266
+ | Sparkline (mini trend line) | Chart.js mini canvas — see pattern below |
267
+ | Static bar comparison ≤6 bars | CSS only — see pattern below |
268
+
269
+ ---
270
+
271
+ ### CSS-only bar chart — no library needed
272
+
273
+ Use when the comparison is static, ≤6 bars, and no interactivity is required. Avoids a Chart.js import entirely.
274
+
275
+ ```html
276
+ <div class="bar-chart">
277
+ <div class="bar-row">
278
+ <span class="bar-label">Q1</span>
279
+ <div class="bar-track">
280
+ <div class="bar-fill" style="--pct: 45%"><span>45%</span></div>
281
+ </div>
282
+ </div>
283
+ <div class="bar-row">
284
+ <span class="bar-label">Q2</span>
285
+ <div class="bar-track">
286
+ <div class="bar-fill" style="--pct: 72%"><span>72%</span></div>
287
+ </div>
288
+ </div>
289
+ <div class="bar-row">
290
+ <span class="bar-label">Q3</span>
291
+ <div class="bar-track">
292
+ <div class="bar-fill" style="--pct: 58%"><span>58%</span></div>
293
+ </div>
294
+ </div>
295
+ </div>
296
+
297
+ <style>
298
+ .bar-chart { display: grid; gap: var(--sp-3); }
299
+ .bar-row { display: grid; grid-template-columns: 5rem 1fr; align-items: center; gap: var(--sp-3); }
300
+ .bar-label { font-size: var(--t-small); color: var(--muted); text-align: right; }
301
+ .bar-track { background: var(--surface); border-radius: var(--r-sm); overflow: hidden; height: 2.2rem; }
302
+ .bar-fill {
303
+ width: var(--pct);
304
+ height: 100%;
305
+ background: var(--accent);
306
+ border-radius: var(--r-sm);
307
+ display: flex; align-items: center; padding-left: var(--sp-2);
308
+ font-size: var(--t-small); font-weight: 600; color: var(--bg);
309
+ /* entrance animation — no library */
310
+ animation: bar-grow 0.6s cubic-bezier(0.22, 1, 0.36, 1) both;
311
+ }
312
+ @keyframes bar-grow { from { width: 0; opacity: 0; } to { width: var(--pct); opacity: 1; } }
313
+ </style>
314
+ ```
315
+
316
+ ---
317
+
318
+ ### Sparkline — mini trend line beside a KPI number
319
+
320
+ Use alongside a `stats`-type slide to show directional trend without a full chart. Requires Chart.js.
321
+
322
+ ```html
323
+ <div class="kpi-block">
324
+ <span class="kpi-number" id="kpi">0</span>
325
+ <canvas id="spark" width="160" height="48"></canvas>
326
+ </div>
327
+
328
+ <script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
329
+ <script type="module">
330
+ import { animate } from "https://cdn.jsdelivr.net/npm/motion@latest/+esm";
331
+
332
+ /* count-up */
333
+ animate(0, 2_847_000, {
334
+ duration: 1.4, easing: [0.22, 1, 0.36, 1],
335
+ onUpdate(v) { document.getElementById('kpi').textContent = Math.round(v).toLocaleString(); }
336
+ });
337
+
338
+ /* sparkline */
339
+ const accent = getComputedStyle(document.documentElement).getPropertyValue('--accent').trim();
340
+ new Chart(document.getElementById('spark'), {
341
+ type: 'line',
342
+ data: {
343
+ labels: Array(8).fill(''),
344
+ datasets: [{
345
+ data: [38, 45, 41, 60, 54, 71, 68, 82],
346
+ borderColor: accent,
347
+ borderWidth: 2,
348
+ tension: 0.4,
349
+ fill: false,
350
+ pointRadius: 0,
351
+ }]
352
+ },
353
+ options: {
354
+ responsive: false,
355
+ animation: false,
356
+ plugins: { legend: { display: false }, tooltip: { enabled: false } },
357
+ scales: { x: { display: false }, y: { display: false } },
358
+ }
359
+ });
360
+ </script>
361
+
362
+ <style>
363
+ .kpi-block { display: flex; align-items: center; gap: var(--sp-4); }
364
+ .kpi-number { font-size: var(--t-display); font-weight: 700; color: var(--accent); }
365
+ </style>
366
+ ```
367
+
368
+ ---
369
+
370
+ ### Chart.js — Bar, line, area, donut, scatter, radar
371
+ **Rating:** ★★★★☆ — best default for standard chart types; easy theming via CSS variables; 11M weekly downloads
372
+ **CDN:** `https://cdn.jsdelivr.net/npm/chart.js`
373
+ **Repo:** [chartjs/Chart.js](https://github.com/chartjs/Chart.js) | 65k+ stars
374
+ **Use when:** Standard bar, line, area, donut, scatter, or radar chart. The CSS bar template is not enough. Real data with labels and animation.
375
+
376
+ ```html
377
+ <canvas id="chart" width="800" height="380"></canvas>
378
+ <script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
379
+ <script>
380
+ new Chart(document.getElementById('chart'), {
381
+ type: 'bar',
382
+ data: {
383
+ labels: ['Q1', 'Q2', 'Q3', 'Q4'],
384
+ datasets: [{
385
+ label: 'Revenue ($M)',
386
+ data: [12, 19, 8, 24],
387
+ backgroundColor: getComputedStyle(document.documentElement)
388
+ .getPropertyValue('--accent').trim(),
389
+ }]
390
+ },
391
+ options: {
392
+ responsive: false,
393
+ animation: { duration: 800, easing: 'easeOutQuart' },
394
+ plugins: { legend: { display: false } },
395
+ scales: { y: { grid: { color: getComputedStyle(document.documentElement).getPropertyValue('--border').trim() } } }
396
+ }
397
+ });
398
+ </script>
399
+ ```
400
+
401
+ ---
402
+
403
+ ### ECharts — Heatmaps, geo, treemaps, complex dashboards
404
+ **Rating:** ★★★★☆ — broadest chart type catalog; right choice when Chart.js cannot produce the chart type; 2.7M weekly downloads
405
+ **CDN:** `https://cdn.jsdelivr.net/npm/echarts/dist/echarts.min.js`
406
+ **Repo:** [apache/echarts](https://github.com/apache/echarts) | 61k+ stars
407
+ **Use when:** Heatmap, geo/map, treemap, candlestick, graph/network, calendar chart, or any multi-series complex layout that Chart.js cannot render.
408
+
409
+ ```html
410
+ <div id="chart" class="chart-surface"></div>
411
+ <script src="https://cdn.jsdelivr.net/npm/echarts/dist/echarts.min.js"></script>
412
+ <script>
413
+ const chartEl = document.getElementById('chart');
414
+ const styles = getComputedStyle(document.documentElement);
415
+ const chart = echarts.init(chartEl, null, { renderer: 'canvas' });
416
+ chart.setOption({
417
+ backgroundColor: 'transparent',
418
+ tooltip: { trigger: 'item' },
419
+ series: [{
420
+ type: 'heatmap',
421
+ data: [/* [col, row, value] */],
422
+ label: { show: true },
423
+ emphasis: { itemStyle: { shadowBlur: 10 } }
424
+ }],
425
+ visualMap: {
426
+ min: 0, max: 100,
427
+ calculable: true,
428
+ inRange: {
429
+ color: [
430
+ styles.getPropertyValue('--surface').trim(),
431
+ styles.getPropertyValue('--accent').trim()
432
+ ]
433
+ }
434
+ }
435
+ });
436
+ </script>
437
+ <style>
438
+ .chart-surface { width: 100%; height: min(58vh, 26rem); }
439
+ </style>
440
+ ```
441
+
442
+ ---
443
+
444
+ ### uPlot — Dense time-series and performance-critical charts
445
+ **Rating:** ★★★★☆ — smallest footprint for time-series; vanilla IIFE, no dependencies; 694K weekly downloads
446
+ **CDN (JS):** `https://cdn.jsdelivr.net/npm/uplot/dist/uPlot.iife.min.js`
447
+ **CDN (CSS):** `https://cdn.jsdelivr.net/npm/uplot/dist/uPlot.min.css`
448
+ **Repo:** [leeoniya/uPlot](https://github.com/leeoniya/uPlot) | 9k+ stars
449
+ **Use when:** A time-series slide has many data points (100+) and Chart.js feels sluggish, or when minimal bundle footprint is critical.
450
+
451
+ ```html
452
+ <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/uplot/dist/uPlot.min.css">
453
+ <div id="chart" class="chart-surface"></div>
454
+ <script src="https://cdn.jsdelivr.net/npm/uplot/dist/uPlot.iife.min.js"></script>
455
+ <script>
456
+ const chartEl = document.getElementById('chart');
457
+ const styles = getComputedStyle(document.documentElement);
458
+ const border = styles.getPropertyValue('--border').trim();
459
+ const accent = styles.getPropertyValue('--accent').trim();
460
+ const data = [
461
+ [1700000000, 1700003600, 1700007200], // timestamps (x)
462
+ [42, 58, 37], // series 1 (y)
463
+ ];
464
+ new uPlot({
465
+ width: chartEl.clientWidth,
466
+ height: chartEl.clientHeight,
467
+ series: [
468
+ {},
469
+ { label: 'Requests/s', stroke: accent, width: 2 }
470
+ ],
471
+ axes: [
472
+ { stroke: border, grid: { stroke: border } },
473
+ { stroke: border, grid: { stroke: border } },
474
+ ],
475
+ }, data, chartEl);
476
+ </script>
477
+ <style>
478
+ .chart-surface { width: 100%; height: min(54vh, 24rem); }
479
+ </style>
480
+ ```
481
+
482
+ ---
483
+
484
+ ### ApexCharts — Polished multi-type charts with strong defaults
485
+ **Rating:** ★★★★☆ — SVG-based, clean defaults, real-time update API; good alternative to Chart.js when visual polish matters more than bundle size
486
+ **CDN:** `https://cdn.jsdelivr.net/npm/apexcharts`
487
+ **Repo:** [apexcharts/apexcharts.js](https://github.com/apexcharts/apexcharts.js) | 14k+ stars
488
+ **Use when:** You want professional-looking charts without custom styling effort — polished donut, area, radial bar, or mixed chart types.
489
+
490
+ ```html
491
+ <div id="chart" class="chart-surface"></div>
492
+ <script src="https://cdn.jsdelivr.net/npm/apexcharts"></script>
493
+ <script>
494
+ const accent = getComputedStyle(document.documentElement).getPropertyValue('--accent').trim();
495
+ new ApexCharts(document.getElementById('chart'), {
496
+ chart: { type: 'area', height: '100%', background: 'transparent', animations: { speed: 800 } },
497
+ theme: { mode: 'dark' },
498
+ colors: [accent],
499
+ series: [{ name: 'Users', data: [31, 40, 28, 51, 42, 109, 100] }],
500
+ xaxis: { categories: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'] },
501
+ dataLabels: { enabled: false },
502
+ stroke: { curve: 'smooth', width: 2 },
503
+ }).render();
504
+ </script>
505
+ <style>
506
+ .chart-surface { width: 100%; height: min(54vh, 24rem); }
507
+ </style>
508
+ ```
509
+
510
+ ---
511
+
512
+ ### D3.js — Custom SVG, networks, projections, bespoke charts
513
+ **Rating:** ★★★☆☆ — maximum control, highest authoring cost; use only when chart libraries cannot express the visual honestly
514
+ **CDN (ESM):** `https://cdn.jsdelivr.net/npm/d3@7/+esm`
515
+ **Repo:** [d3/d3](https://github.com/d3/d3) | 109k+ stars
516
+ **Use when:** Custom SVG layouts, force networks, geographic projections, unusual annotations, or bespoke chart grammar.
517
+
518
+ ```html
519
+ <svg id="chart" class="chart-surface" role="img" aria-label="{{chart description}}"></svg>
520
+ <script type="module">
521
+ import * as d3 from "https://cdn.jsdelivr.net/npm/d3@7/+esm";
522
+
523
+ const svg = d3.select('#chart');
524
+ const styles = getComputedStyle(document.documentElement);
525
+ const accent = styles.getPropertyValue('--accent').trim();
526
+ const muted = styles.getPropertyValue('--muted').trim();
527
+ const width = svg.node().clientWidth;
528
+ const height = svg.node().clientHeight;
529
+
530
+ svg.attr('viewBox', `0 0 ${width} ${height}`);
531
+ svg.append('circle')
532
+ .attr('cx', width / 2)
533
+ .attr('cy', height / 2)
534
+ .attr('r', Math.min(width, height) / 4)
535
+ .attr('fill', accent);
536
+ svg.append('text')
537
+ .attr('x', width / 2)
538
+ .attr('y', height / 2)
539
+ .attr('text-anchor', 'middle')
540
+ .attr('fill', muted)
541
+ .text('{{label}}');
542
+ </script>
543
+ <style>
544
+ .chart-surface { width: 100%; height: min(54vh, 24rem); }
545
+ </style>
546
+ ```
547
+
548
+ ---
549
+
550
+ ## Diagrams
551
+
552
+ ### Mermaid.js — Diagrams from text
553
+ **Rating:** ★★★★★ — best-in-class for architecture/flow diagrams; text-based so content stays editable
554
+ **CDN:** `https://cdn.jsdelivr.net/npm/mermaid/dist/mermaid.min.js`
555
+ **Repo:** [mermaid-js/mermaid](https://github.com/mermaid-js/mermaid) | 75k+ stars
556
+ **Use when:** A slide needs a flowchart, sequence diagram, Gantt, or architecture diagram.
557
+
558
+ ```html
559
+ <div class="mermaid">
560
+ sequenceDiagram
561
+ Client->>+API Gateway: POST /checkout
562
+ API Gateway->>+Order Service: createOrder(cart)
563
+ Order Service-->>-API Gateway: orderId: 4821
564
+ API Gateway->>+Payment Service: charge(orderId)
565
+ Payment Service-->>-API Gateway: status: ok
566
+ API Gateway-->>-Client: 200 { orderId, status }
567
+ </div>
568
+ <script src="https://cdn.jsdelivr.net/npm/mermaid/dist/mermaid.min.js"></script>
569
+ <script>
570
+ // theme: 'dark' | 'default' | 'neutral' | 'forest' | 'base'
571
+ // Pick based on --bg: dark themes → 'dark'; light themes → 'neutral' or 'default'
572
+ mermaid.initialize({
573
+ theme: 'dark',
574
+ startOnLoad: true,
575
+ flowchart: { curve: 'basis' }
576
+ });
577
+ </script>
578
+ ```
579
+
580
+ ---
581
+
582
+ ## PDF Export
583
+
584
+ ### Decktape — universal HTML slide → PDF exporter
585
+ **Rating:** ★★★★☆ — works with any HTML slide framework; no dependency on the slide code itself
586
+ **Repo:** [astefanutti/decktape](https://github.com/astefanutti/decktape) | 2.4k+ stars
587
+ **Use when:** User asks to export the deck to PDF for sharing, printing, or archiving.
588
+
589
+ ```bash
590
+ # Serve the deck first (required — Decktape fetches from a live URL)
591
+ npx serve .octocode/slides/{{slideName}}
592
+
593
+ # Export all slides to PDF
594
+ npx decktape http://localhost:3000 deck.pdf
595
+
596
+ # Export with explicit size (matches 1280×720 stage)
597
+ npx decktape --size 1280x720 http://localhost:3000 deck.pdf
598
+
599
+ # Export specific slides (1-indexed)
600
+ npx decktape --slides 1-10 http://localhost:3000 deck.pdf
601
+ ```
602
+
603
+ **How it works:** Decktape drives a headless Chromium via Puppeteer, advances each slide via keyboard, and prints each to a PDF page. It auto-detects Reveal.js, Impress, and generic HTML decks.
604
+
605
+ **Alternative — browser `@media print`:**
606
+ `base.css` already defines `@media print { .slide { width: 1280px; height: 720px; page-break-after: always; } }`. Open `index.html` in Chrome → File → Print → Save as PDF. Lower fidelity than Decktape (no JS, no charts) but requires no installation.
607
+
608
+ ---
609
+
610
+ ## Pointer & Click Feedback
611
+
612
+ A two-piece pointer-chrome layer that makes a live deck feel like a debugger console: a themed cursor that follows the speaker, plus a short spark on every click. Both libs are tiny, vanilla, MIT, and themable through the deck's existing CSS variables. **Default: OFF — opt-in only.** Enable only when the brief signals a live talk, demo, or dark/tech context (see `SKILL.md → Strong defaults → Pointer chrome` and `references/04-design.md` Step 5b).
613
+
614
+ > **Where they load:** parent `index.html` only — never per slide. Slides are iframes with separate documents, so loading these inside slides would create one cursor per slide and break the spark on slide chrome.
615
+
616
+ ### tholman/cursor-effects — themable custom cursor (vanilla JS)
617
+ **Rating:** ★★★★☆ — battle-tested, ships ESM + UMD, already respects `prefers-reduced-motion` (matches the deck's animation policy)
618
+ **CDN (ESM):** `https://unpkg.com/cursor-effects@latest/dist/esm.js`
619
+ **Repo:** [tholman/cursor-effects](https://github.com/tholman/cursor-effects) | MIT
620
+ **Use when:** A live presentation or dark/tech deck wants a themed pointer (`followingDotCursor` / `trailingCursor` / `rainbowCursor`). Skip on print-first or async decks.
621
+
622
+ ```html
623
+ <!-- in index.html, just before </body> -->
624
+ <script type="module">
625
+ import { followingDotCursor } from "https://unpkg.com/cursor-effects@latest/dist/esm.js";
626
+ const accent = getComputedStyle(document.documentElement).getPropertyValue('--accent').trim();
627
+ new followingDotCursor({ color: accent });
628
+ </script>
629
+ ```
630
+
631
+ **Available effects:** `followingDotCursor`, `trailingCursor`, `rainbowCursor`, `bubbleCursor`, `fairyDustCursor`, `ghostCursor`, `springyEmojiCursor`, `emojiCursor`, `clockCursor`, `characterCursor`, `textFlag`. For a presentation default, prefer `followingDotCursor` (smallest visual footprint) or `trailingCursor` (slightly more presence on big-screen projectors).
632
+
633
+ ### hexagoncircle/click-spark — `<click-spark>` Web Component (mouse-down feedback)
634
+ **Rating:** ★★★★★ — one file, no build step, themable via a single CSS custom property
635
+ **Source:** [hexagoncircle/click-spark/click-spark.js](https://github.com/hexagoncircle/click-spark/blob/main/click-spark.js) | MIT
636
+ **Use when:** Click feedback should reinforce live interactions — demos, button-led walkthroughs, anything where the speaker is clicking on stage.
637
+
638
+ ```html
639
+ <!-- in index.html, just before </body> -->
640
+ <script type="module" src="js/vendor/click-spark.js"></script>
641
+ <click-spark style="--click-spark-color: var(--accent);"></click-spark>
642
+ ```
643
+
644
+ **Notes for the slide deck context:**
645
+ - Wrap the spark element so it sits **above** slide iframes but **below** chrome (HUD, progress bar, counter): give it `position: fixed; inset: 0; pointer-events: none; z-index: 5;` and keep the HUD at `z-index: 50`.
646
+ - Click events fired inside an iframe are captured by the iframe's document, not the parent — the spark fires on parent-level chrome (overview thumbnails, navigation hints) which is the intended behaviour.
647
+ - For a focal-lane variant, use `--click-spark-color: var(--violet)` on a second `<click-spark>` scoped to a specific container.
648
+
649
+ ### Wiring on `index.html` (recommended pattern)
650
+ ```html
651
+ <!-- ── Pointer chrome (parent only) ────────────────────── -->
652
+ <click-spark style="--click-spark-color: var(--accent); position: fixed; inset: 0; pointer-events: none; z-index: 5;"></click-spark>
653
+ <script type="module">
654
+ import { followingDotCursor } from "https://unpkg.com/cursor-effects@latest/dist/esm.js";
655
+ import "https://cdn.jsdelivr.net/gh/hexagoncircle/click-spark/click-spark.js";
656
+ const accent = getComputedStyle(document.documentElement).getPropertyValue('--accent').trim();
657
+ if (!matchMedia('(pointer: coarse)').matches && !matchMedia('(prefers-reduced-motion: reduce)').matches) {
658
+ new followingDotCursor({ color: accent });
659
+ }
660
+ </script>
661
+ ```
662
+
663
+ `pointer: coarse` short-circuit opts touch devices out cleanly. `prefers-reduced-motion` short-circuit honours OS settings even though the cursor library handles it internally too. For offline-friendly decks, vendor both files into `js/vendor/` and replace the two URLs with relative paths.
664
+
665
+ ---
666
+
667
+ ### Catppuccin — Warm pastel palette system, 4 flavors
668
+ **Rating:** ★★★☆☆ — strong palette for pastel/cozy aesthetics; too niche for general use
669
+ **Repo:** [catppuccin/catppuccin](https://github.com/catppuccin/catppuccin) | 18k+ stars
670
+ **Use when:** User wants soft, pastel-toned themes. 26 named colors × 4 flavors (Latte → Mocha).
671
+ ```
672
+ Latte (light) · Frappe · Macchiato · Mocha (darkest)
673
+ Colors: Rosewater, Flamingo, Pink, Mauve, Red, Peach, Yellow, Green, Teal, Sapphire, Blue, Lavender + neutrals
674
+ ```
675
+
676
+ **Mocha (dark) key values — map to CSS variable contract:**
677
+ ```css
678
+ /* Catppuccin Mocha → theme.css */
679
+ :root {
680
+ --bg: #1e1e2e; /* Base */
681
+ --surface: #313244; /* Surface0 */
682
+ --border: #45475a; /* Surface1 */
683
+ --text: #cdd6f4; /* Text */
684
+ --muted: #6c7086; /* Overlay0 */
685
+ --accent: #cba6f7; /* Mauve — or swap: Sapphire #89b4fa, Peach #fab387 */
686
+ }
687
+ ```
688
+
689
+ ### Nord — Arctic minimal
690
+ **Rating:** ★★★☆☆ — iconic muted palette; works for understated tech decks, limited expressive range
691
+ **Repo:** [nordtheme/nord](https://github.com/nordtheme/nord) | 6k+ stars
692
+ 16 colors: Polar Night (dark), Snow Storm (light text), Frost (accent blues), Aurora (semantic).
693
+
694
+ **Nord → theme.css:**
695
+ ```css
696
+ :root {
697
+ --bg: #2e3440; /* Polar Night 0 */
698
+ --surface: #3b4252; /* Polar Night 1 */
699
+ --border: #434c5e; /* Polar Night 2 */
700
+ --text: #eceff4; /* Snow Storm 2 */
701
+ --muted: #4c566a; /* Polar Night 3 */
702
+ --accent: #88c0d0; /* Frost — or #81a1c1 for cooler blue */
703
+ }
704
+ ```
705
+
706
+ ### Coolors Contrast Checker — WCAG AA/AAA verification
707
+ **Rating:** ★★★★☆ — fast, visual, covers AA/AAA for normal and large text; free, no sign-in
708
+ **URL:** [coolors.co/contrast-checker](https://coolors.co/contrast-checker)
709
+ **Use when:** Review phase `06-review.md` requires WCAG AA (4.5:1 normal / 3:1 large text). Paste hex values for text and background, read ratio instantly.
710
+
711
+ Alternative: [WebAIM Contrast Checker](https://webaim.org/resources/contrastchecker/) — same function, more detail on pass/fail thresholds.
712
+
713
+ > **Minimum targets for slides:** body text ≥ 4.5:1, heading text (≥24px bold) ≥ 3:1, UI labels ≥ 4.5:1. Dark-on-light and light-on-dark both need checking.
714
+
715
+ ---
716
+
717
+ ### Radix Colors — Perceptually uniform color scales
718
+ **Rating:** ★★★★☆ — best tool for building custom surface/muted/border steps from a base hue; perceptually uniform in dark + light
719
+ **Repo:** [radix-ui/colors](https://github.com/radix-ui/colors)
720
+ **CDN:** `https://cdn.jsdelivr.net/npm/@radix-ui/colors/dist/index.css`
721
+ Semantic + decorative color scales. Each hue has 12 steps (1=bg tint, 9=solid accent, 12=text). Automatic P3 wide-gamut.
722
+
723
+ **Pick a hue, map steps to the CSS variable contract:**
724
+ ```css
725
+ /* Example: Slate (neutral) + Violet (accent) — dark theme */
726
+ @import "https://cdn.jsdelivr.net/npm/@radix-ui/colors/dist/dark/slate.css";
727
+ @import "https://cdn.jsdelivr.net/npm/@radix-ui/colors/dist/dark/violet.css";
728
+
729
+ :root {
730
+ --bg: var(--slate-1); /* darkest background */
731
+ --surface: var(--slate-3);
732
+ --border: var(--slate-6);
733
+ --text: var(--slate-12);
734
+ --muted: var(--slate-9);
735
+ --accent: var(--violet-9); /* solid accent — always WCAG AA on step-1 bg */
736
+ }
737
+ ```
738
+
739
+ ---
740
+
741
+ ## Fonts
742
+
743
+ ### Google Fonts (CDN, no install)
744
+ **Rating:** ★★★★★ — largest free library, zero install, reliable CDN; default first stop for every deck
745
+ ```html
746
+ <!-- Dev / technical — JetBrains Mono heading + Inter body -->
747
+ <link href="https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;700&family=Inter:wght@400;500&display=swap" rel="stylesheet">
748
+
749
+ <!-- Academic / editorial — Lora heading + Inter body -->
750
+ <link href="https://fonts.googleapis.com/css2?family=Lora:ital,wght@0,700;1,400&family=Inter:wght@400;500&display=swap" rel="stylesheet">
751
+
752
+ <!-- Modern technical — Space Grotesk heading + JetBrains Mono body -->
753
+ <link href="https://fonts.googleapis.com/css2?family=Space+Grotesk:wght@400;700&family=JetBrains+Mono:wght@400&display=swap" rel="stylesheet">
754
+
755
+ <!-- Warm creative — Instrument Serif heading + Sora body -->
756
+ <link href="https://fonts.googleapis.com/css2?family=Instrument+Serif:ital@0;1&family=Sora:wght@400;500&display=swap" rel="stylesheet">
757
+
758
+ <!-- Premium / keynote — Playfair Display heading + Inter body -->
759
+ <link href="https://fonts.googleapis.com/css2?family=Playfair+Display:wght@700&family=Inter:wght@400;500&display=swap" rel="stylesheet">
760
+
761
+ <!-- Dark bold — Bricolage Grotesque heading + DM Sans body -->
762
+ <link href="https://fonts.googleapis.com/css2?family=Bricolage+Grotesque:wght@400;700&family=DM+Sans:wght@400;500&display=swap" rel="stylesheet">
763
+ ```
764
+ These are starting points — research new pairings via Font Joy or Google Fonts explorer for each deck.
765
+
766
+ ### Fontshare (alternative CDN, open-source)
767
+ **Rating:** ★★★★☆ — fewer fonts but higher design quality than Google Fonts average; good for distinctive display faces
768
+ ```html
769
+ <link href="https://api.fontshare.com/v2/css?f[]=satoshi@700,400&f[]=cabinet-grotesk@700&display=swap" rel="stylesheet">
770
+ ```
771
+ Notable: Satoshi, Cabinet Grotesk, Clash Display, General Sans, Switzer.
772
+
773
+ ### Font Joy — ML-powered pairing discovery
774
+ **Rating:** ★★★☆☆ — useful research tool, not a CDN; run it during Phase 4 when standard pairings feel wrong
775
+ **URL:** [fontjoy.com](https://fontjoy.com/)
776
+ **Use when:** Browsing Google Fonts manually isn't surfacing the right pair. Font Joy generates pairings with a "generate" button — lock the heading or body font and regenerate the other. Different job than Fontshare/Google Fonts browsing.
777
+
778
+ ### Type-Scale — Modular type scale calculator
779
+ **Rating:** ★★★★☆ — instant visual preview of any base size + ratio; generates the full CSS scale
780
+ **URL:** [type-scale.com](https://type-scale.com/)
781
+ **Use when:** Choosing heading/body/caption sizes for a new deck; pick a ratio and base, then copy the resulting `font-size` values into `base.css`.
782
+
783
+ **Recommended scales for 1280×720 slides:**
784
+ | Body (base) | Ratio | H1 result | Notes |
785
+ |-------------|-------|-----------|-------|
786
+ | 24px | 1.333 (Perfect Fourth) | ~57px | Clean, technical |
787
+ | 28px | 1.25 (Major Third) | ~55px | Balanced, editorial |
788
+ | 26px | 1.414 (√2) | ~74px | Bold, keynote-style |
789
+
790
+ Plug into CSS variables: `--fs-body: 26px; --fs-h2: 37px; --fs-h1: 52px; --fs-label: 18px;`
791
+
792
+ ---
793
+
794
+ ## Design Research (agent tool guide)
795
+
796
+ When the user wants a custom aesthetic, the agent SHOULD actively research beyond these defaults:
797
+
798
+ ```
799
+ GitHub/Octocode repository search — search "presentation design CSS" or "slide deck aesthetic"
800
+ GitHub/Octocode code search — find SKILL.md files with slide design systems
801
+ Web search — search "best CSS presentation aesthetics {{current year}}" or "beautiful HTML deck examples"
802
+ Web fetch/browser — read codepen.io/trending, dribbble, awwwards for visual inspiration
803
+ ```
804
+
805
+ The agent may deviate from the 5 named themes in `design-system.md` if:
806
+ - The user describes a specific aesthetic not covered
807
+ - Research reveals a clearly better match
808
+ - Custom brand colors are provided
809
+
810
+ When deviating: define a `/* Custom: <name> */` block at the top of `theme.css` and document the creative choices.
811
+
812
+ ---
813
+
814
+ ## Quick selection
815
+
816
+ | Need | Use |
817
+ |------|-----|
818
+ | Rich markdown content in slides | marked.js |
819
+ | Staggered bullets/cards (modern browsers) | CSS `sibling-index()` + `@starting-style` |
820
+ | Staggered bullets/cards (broad support) | Motion `stagger()` |
821
+ | Number counters, progress fills | Motion `animate(0, N)` |
822
+ | Sequenced multi-element choreography | Motion `timeline()` |
823
+ | SVG path animation or complex choreography | GSAP |
824
+ | Slide-to-slide transition (with animation) | View Transitions API |
825
+ | Real syntax highlighting | highlight.js |
826
+ | Bar / line / area / donut / scatter / radar | Chart.js |
827
+ | Heatmap / geo / treemap / complex dashboard | ECharts |
828
+ | Dense time-series (100+ points, perf-critical) | uPlot |
829
+ | Polished multi-type charts with strong defaults | ApexCharts |
830
+ | Custom SVG / network / bespoke layout | D3.js |
831
+ | Flowcharts, sequence diagrams, architecture | Mermaid.js |
832
+ | Soft pastel palette | Catppuccin |
833
+ | Arctic minimal palette | Nord |
834
+ | Perceptual color scales | Radix Colors |
835
+ | Font pairing discovery | Font Joy |
836
+ | Type scale (base + ratio → CSS sizes) | type-scale.com |
837
+ | WCAG contrast check (AA/AAA) | Coolors contrast checker |
838
+ | Export deck to PDF | `npx decktape http://localhost:port deck.pdf` |
839
+ | Themed live-presentation cursor | tholman/cursor-effects (`followingDotCursor`) |
840
+ | Mouse-down click spark | hexagoncircle/click-spark (`<click-spark>`) |