decklight 0.1.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 (82) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +257 -0
  3. package/SPEC.md +372 -0
  4. package/cli/bundle.mjs +388 -0
  5. package/cli/decklight.mjs +95 -0
  6. package/cli/edit.mjs +142 -0
  7. package/cli/init.mjs +215 -0
  8. package/cli/rec.mjs +538 -0
  9. package/dist/decklight.css +1068 -0
  10. package/dist/decklight.js +239 -0
  11. package/dist/decklight.js.map +7 -0
  12. package/docs/architecture.svg +94 -0
  13. package/docs/demo.svg +124 -0
  14. package/package.json +54 -0
  15. package/themes/README.md +61 -0
  16. package/themes/aliens.css +84 -0
  17. package/themes/apple2.css +126 -0
  18. package/themes/aurora.css +84 -0
  19. package/themes/berry.css +80 -0
  20. package/themes/blade-runner.css +83 -0
  21. package/themes/c64.css +85 -0
  22. package/themes/carbon.css +82 -0
  23. package/themes/citrus.css +80 -0
  24. package/themes/coastal.css +80 -0
  25. package/themes/cosmos.css +86 -0
  26. package/themes/dune.css +80 -0
  27. package/themes/eclipse.css +82 -0
  28. package/themes/ember.css +80 -0
  29. package/themes/fjord.css +80 -0
  30. package/themes/friends.css +82 -0
  31. package/themes/gallery.html +203 -0
  32. package/themes/gameboy.css +118 -0
  33. package/themes/genesis.css +84 -0
  34. package/themes/glacier.css +82 -0
  35. package/themes/godfather.css +82 -0
  36. package/themes/graphite.css +80 -0
  37. package/themes/harvest.css +80 -0
  38. package/themes/ibm-modern.css +83 -0
  39. package/themes/ibm-oldschool.css +84 -0
  40. package/themes/ink.css +82 -0
  41. package/themes/latte.css +80 -0
  42. package/themes/linen.css +80 -0
  43. package/themes/meadow.css +80 -0
  44. package/themes/metropolis.css +85 -0
  45. package/themes/miami-vice.css +84 -0
  46. package/themes/midnight.css +80 -0
  47. package/themes/mint.css +82 -0
  48. package/themes/moss.css +82 -0
  49. package/themes/obsidian.css +82 -0
  50. package/themes/orchid.css +82 -0
  51. package/themes/packs.json +89 -0
  52. package/themes/paper.css +83 -0
  53. package/themes/peony.css +84 -0
  54. package/themes/porcelain.css +82 -0
  55. package/themes/pulp-fiction.css +84 -0
  56. package/themes/reveal-beige.css +87 -0
  57. package/themes/reveal-black.css +83 -0
  58. package/themes/reveal-blood.css +84 -0
  59. package/themes/reveal-dracula.css +83 -0
  60. package/themes/reveal-league.css +88 -0
  61. package/themes/reveal-moon.css +83 -0
  62. package/themes/reveal-night.css +86 -0
  63. package/themes/reveal-serif.css +82 -0
  64. package/themes/reveal-simple.css +84 -0
  65. package/themes/reveal-sky.css +85 -0
  66. package/themes/reveal-solarized.css +83 -0
  67. package/themes/reveal-white.css +82 -0
  68. package/themes/sepia.css +81 -0
  69. package/themes/seriph.css +82 -0
  70. package/themes/severance.css +82 -0
  71. package/themes/slate.css +80 -0
  72. package/themes/snes.css +82 -0
  73. package/themes/star-wars.css +85 -0
  74. package/themes/storm.css +80 -0
  75. package/themes/stranger-things.css +84 -0
  76. package/themes/synthwave.css +90 -0
  77. package/themes/terminator.css +84 -0
  78. package/themes/velvet.css +80 -0
  79. package/tools/gemini-tts.mjs +140 -0
  80. package/tools/publish-site-voices.mjs +71 -0
  81. package/tools/voiceover-server.mjs +0 -0
  82. package/tools/voiceover.mjs +155 -0
@@ -0,0 +1,94 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 920 560" font-family="-apple-system, 'Segoe UI', Roboto, Helvetica, sans-serif">
2
+ <defs>
3
+ <marker id="arr" markerWidth="9" markerHeight="7" refX="8" refY="3.5" orient="auto">
4
+ <polygon points="0 0, 9 3.5, 0 7" fill="#8b90a3"/>
5
+ </marker>
6
+ <marker id="arrb" markerWidth="9" markerHeight="7" refX="8" refY="3.5" orient="auto">
7
+ <polygon points="0 0, 9 3.5, 0 7" fill="#7c9cff"/>
8
+ </marker>
9
+ </defs>
10
+
11
+ <rect x="0" y="0" width="920" height="560" rx="14" fill="#14161d"/>
12
+ <text x="460" y="34" text-anchor="middle" font-size="17" font-weight="700" fill="#e8eaf2">Decklight — how it's put together</text>
13
+
14
+ <!-- ── authoring column ─────────────────────────────────────────── -->
15
+ <rect x="40" y="70" width="230" height="86" rx="10" fill="#24335c" stroke="#46567f" stroke-width="1.5"/>
16
+ <text x="155" y="100" text-anchor="middle" font-size="14" font-weight="700" fill="#e8eaf2">deck.html</text>
17
+ <text x="155" y="120" text-anchor="middle" font-size="10.5" fill="#aeb4c6">sections · notes · inline casts</text>
18
+ <text x="155" y="136" text-anchor="middle" font-size="10.5" fill="#aeb4c6">one file, written by humans &amp; agents</text>
19
+
20
+ <rect x="40" y="186" width="230" height="72" rx="10" fill="#23444d" stroke="#3f6a76" stroke-width="1.5"/>
21
+ <text x="155" y="212" text-anchor="middle" font-size="13" font-weight="700" fill="#e8eaf2">theme.css — 61 shipped</text>
22
+ <text x="155" y="232" text-anchor="middle" font-size="10.5" fill="#aeb4c6">one token contract (~50 vars)</text>
23
+ <text x="155" y="246" text-anchor="middle" font-size="10.5" fill="#aeb4c6">+ runtime generator (⌃T)</text>
24
+
25
+ <!-- ── browser runtime ──────────────────────────────────────────── -->
26
+ <rect x="330" y="70" width="330" height="240" rx="12" fill="#191c26" stroke="#7c9cff" stroke-width="2"/>
27
+ <text x="495" y="96" text-anchor="middle" font-size="13.5" font-weight="700" fill="#7c9cff">browser runtime — zero dependencies</text>
28
+ <text x="495" y="112" text-anchor="middle" font-size="10" fill="#8b90a3">dist/decklight.js + decklight.css · works on file://</text>
29
+
30
+ <g font-size="10.5" fill="#dfe3ee">
31
+ <rect x="348" y="126" width="140" height="30" rx="6" fill="#252a3a"/><text x="418" y="145" text-anchor="middle">engine · builds · nav</text>
32
+ <rect x="500" y="126" width="142" height="30" rx="6" fill="#252a3a"/><text x="571" y="145" text-anchor="middle">themes · generator</text>
33
+ <rect x="348" y="164" width="140" height="30" rx="6" fill="#252a3a"/><text x="418" y="183" text-anchor="middle">terminal player</text>
34
+ <rect x="500" y="164" width="142" height="30" rx="6" fill="#252a3a"/><text x="571" y="183" text-anchor="middle">markdown · svg · code</text>
35
+ <rect x="348" y="202" width="140" height="30" rx="6" fill="#252a3a"/><text x="418" y="221" text-anchor="middle">narration · captions</text>
36
+ <rect x="500" y="202" width="142" height="30" rx="6" fill="#252a3a"/><text x="571" y="221" text-anchor="middle">speaker · overlays</text>
37
+ <rect x="348" y="240" width="294" height="30" rx="6" fill="#252a3a"/><text x="495" y="259" text-anchor="middle">quiz slides · transcript · debug log · edit mode</text>
38
+ </g>
39
+ <text x="495" y="296" text-anchor="middle" font-size="10" fill="#8b90a3">every feature verifiable by a headless render</text>
40
+
41
+ <!-- ── local servers ────────────────────────────────────────────── -->
42
+ <rect x="710" y="70" width="180" height="76" rx="10" fill="#274035" stroke="#43695a" stroke-width="1.5"/>
43
+ <text x="800" y="96" text-anchor="middle" font-size="13" font-weight="700" fill="#e8eaf2">decklight edit</text>
44
+ <text x="800" y="114" text-anchor="middle" font-size="10.5" fill="#aeb4c6">watches the file · SSE reload</text>
45
+ <text x="800" y="130" text-anchor="middle" font-size="10.5" fill="#aeb4c6">E saves notes back to disk</text>
46
+
47
+ <rect x="710" y="176" width="180" height="70" rx="10" fill="#4a3057" stroke="#75548a" stroke-width="1.5"/>
48
+ <text x="800" y="202" text-anchor="middle" font-size="13" font-weight="700" fill="#e8eaf2">decklight tts</text>
49
+ <text x="800" y="220" text-anchor="middle" font-size="10.5" fill="#aeb4c6">sentence cache · cost estimates</text>
50
+ <text x="800" y="236" text-anchor="middle" font-size="10.5" fill="#aeb4c6">localhost bridge</text>
51
+
52
+ <rect x="710" y="276" width="180" height="52" rx="10" fill="#20232e" stroke="#3a3f52" stroke-width="1.5" stroke-dasharray="5 4"/>
53
+ <text x="800" y="298" text-anchor="middle" font-size="12" font-weight="700" fill="#c9cede">Vertex AI · Gemini TTS</text>
54
+ <text x="800" y="316" text-anchor="middle" font-size="10" fill="#8b90a3">30 voices · styled delivery</text>
55
+
56
+ <!-- ── cli row ──────────────────────────────────────────────────── -->
57
+ <rect x="40" y="356" width="620" height="86" rx="10" fill="#52402a" stroke="#7d6544" stroke-width="1.5"/>
58
+ <text x="350" y="382" text-anchor="middle" font-size="13" font-weight="700" fill="#e8eaf2">CLI — node, the only place with native deps</text>
59
+ <g font-size="10.5" fill="#efe9dd">
60
+ <rect x="58" y="396" width="130" height="30" rx="6" fill="#453722"/><text x="123" y="415" text-anchor="middle">rec — real PTY casts</text>
61
+ <rect x="200" y="396" width="130" height="30" rx="6" fill="#453722"/><text x="265" y="415" text-anchor="middle">refresh — drift check</text>
62
+ <rect x="342" y="396" width="140" height="30" rx="6" fill="#453722"/><text x="412" y="415" text-anchor="middle">export — asciicast v2</text>
63
+ <rect x="494" y="396" width="148" height="30" rx="6" fill="#453722"/><text x="568" y="415" text-anchor="middle">bundle — one-file deck</text>
64
+ </g>
65
+
66
+ <!-- ── verification band ────────────────────────────────────────── -->
67
+ <rect x="40" y="470" width="850" height="60" rx="10" fill="#1c2620" stroke="#39584a" stroke-width="1.5"/>
68
+ <text x="465" y="494" text-anchor="middle" font-size="12.5" font-weight="700" fill="#9fd6b4">verification — SPEC.md is the contract</text>
69
+ <text x="465" y="514" text-anchor="middle" font-size="10.5" fill="#8fae9c">WCAG contrast gates · R1–R8 palette rules · headless render assertions · property tests across seeds · data-overflow guardrail</text>
70
+
71
+ <!-- ── arrows ───────────────────────────────────────────────────── -->
72
+ <line x1="270" y1="113" x2="324" y2="140" stroke="#8b90a3" stroke-width="1.5" marker-end="url(#arr)"/>
73
+ <line x1="270" y1="222" x2="324" y2="200" stroke="#8b90a3" stroke-width="1.5" marker-end="url(#arr)"/>
74
+ <text x="292" y="106" text-anchor="middle" font-size="9.5" fill="#8b90a3">loads</text>
75
+ <text x="288" y="242" text-anchor="middle" font-size="9.5" fill="#8b90a3">tokens</text>
76
+
77
+ <path d="M660 118 L704 106" stroke="#7c9cff" stroke-width="1.5" fill="none" marker-end="url(#arrb)"/>
78
+ <path d="M704 128 L660 140" stroke="#7c9cff" stroke-width="1.5" fill="none" marker-end="url(#arrb)"/>
79
+ <text x="683" y="98" text-anchor="middle" font-size="9.5" fill="#7c9cff">save notes</text>
80
+ <text x="682" y="152" text-anchor="middle" font-size="9.5" fill="#7c9cff">reload (SSE)</text>
81
+
82
+ <path d="M660 200 L704 206" stroke="#7c9cff" stroke-width="1.5" fill="none" marker-end="url(#arrb)"/>
83
+ <text x="682" y="192" text-anchor="middle" font-size="9.5" fill="#7c9cff">sentences</text>
84
+ <line x1="800" y1="246" x2="800" y2="270" stroke="#8b90a3" stroke-width="1.5" marker-end="url(#arr)"/>
85
+
86
+ <path d="M110 396 C90 320, 120 180, 148 160" stroke="#8b90a3" stroke-width="1.2" fill="none" marker-end="url(#arr)"/>
87
+ <text x="76" y="300" text-anchor="middle" font-size="9.5" fill="#8b90a3">casts</text>
88
+ <text x="76" y="313" text-anchor="middle" font-size="9.5" fill="#8b90a3">embed</text>
89
+
90
+ <line x1="465" y1="466" x2="465" y2="450" stroke="#5f8a72" stroke-width="1.5" marker-end="url(#arr)"/>
91
+ <line x1="300" y1="466" x2="300" y2="446" stroke="#5f8a72" stroke-width="1.5" marker-end="url(#arr)"/>
92
+ <line x1="640" y1="466" x2="640" y2="380" stroke="#5f8a72" stroke-width="1.5" marker-end="url(#arr)"/>
93
+ <text x="740" y="462" text-anchor="middle" font-size="9.5" fill="#5f8a72">gates themes, features, and tools alike</text>
94
+ </svg>
package/docs/demo.svg ADDED
@@ -0,0 +1,124 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 960 540" width="960" height="540" role="img"
2
+ aria-label="A Decklight slide building in: title, bullets and a diagram step in one by one, then the theme cycles from indigo light to dark to warm parchment.">
3
+ <!-- Hand-authored animated demo (no JS — safe in <img>). One 14s loop:
4
+ 0–43% builds step in (title, subtitle, bullets, diagram draw)
5
+ 47–51% theme cycles to dark (as if pressing .)
6
+ 53–72% generator toast (⌃T)
7
+ 73–77% theme cycles to warm parchment
8
+ 97–100% content fades for the loop restart
9
+ Reduced motion: animations off → static, fully-built slide. -->
10
+ <style>
11
+ * { animation-duration: 14s; animation-timing-function: linear; animation-iteration-count: infinite; }
12
+ text { font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif; }
13
+ .mono { font-family: "SF Mono", SFMono-Regular, ui-monospace, Menlo, Consolas, monospace; }
14
+
15
+ .bg { fill: #f6f6fa; animation-name: kBg; }
16
+ .ttl { fill: #23268f; animation-name: kTtl; }
17
+ .ink { fill: #2b2e44; animation-name: kInk; }
18
+ .mut { fill: #7c8095; animation-name: kMut; }
19
+ .acc { fill: #3438c9; animation-name: kAcc; }
20
+ .strk { stroke: #9297cf; animation-name: kStrk; }
21
+ /* animation-name lists don't merge across rules: anything needing a
22
+ color animation AND a reveal/draw animation names both in ONE rule */
23
+ .nf1 { fill: #e4e5f7; stroke: #9297cf; animation-name: kF1, kStrk; }
24
+ .nf2 { fill: #dfeaf6; stroke: #9297cf; animation-name: kF2, kStrk; }
25
+ .nf3 { fill: #ece3f4; stroke: #9297cf; animation-name: kF3, kStrk; }
26
+
27
+ .rTitle { animation-name: kTtl, kInTitle; }
28
+ .rSub { animation-name: kMut, kInSub; }
29
+ .rB1 { animation-name: kInB1; }
30
+ .rB2 { animation-name: kInB2; }
31
+ .rB3 { animation-name: kInB3; }
32
+ .rN1 { animation-name: kInN1; }
33
+ .rN2 { animation-name: kInN2; }
34
+ .rN3 { animation-name: kInN3; }
35
+ .rA1 { animation-name: kStrk, kDrawA1; }
36
+ .rA2 { animation-name: kStrk, kDrawA2; }
37
+ .rA1h { animation-name: kAcc, kA1Head; }
38
+ .rA2h { animation-name: kAcc, kA2Head; }
39
+ .toast { animation-name: kToast; }
40
+ .pfill { animation-name: kAcc, kProgress; transform-origin: 0 0; }
41
+
42
+ /* theme color cycle: A(indigo light) → B(night) → C(parchment) → A */
43
+ @keyframes kBg { 0%,47% {fill:#f6f6fa} 51%,73% {fill:#131519} 77%,97% {fill:#faf7f2} 100% {fill:#f6f6fa} }
44
+ @keyframes kTtl { 0%,47% {fill:#23268f} 51%,73% {fill:#e9edf4} 77%,97% {fill:#4d5527} 100% {fill:#23268f} }
45
+ @keyframes kInk { 0%,47% {fill:#2b2e44} 51%,73% {fill:#c9d1dc} 77%,97% {fill:#2e2a24} 100% {fill:#2b2e44} }
46
+ @keyframes kMut { 0%,47% {fill:#7c8095} 51%,73% {fill:#848da0} 77%,97% {fill:#8d8577} 100% {fill:#7c8095} }
47
+ @keyframes kAcc { 0%,47% {fill:#3438c9} 51%,73% {fill:#8fbfe8} 77%,97% {fill:#75823f} 100% {fill:#3438c9} }
48
+ @keyframes kF1 { 0%,47% {fill:#e4e5f7} 51%,73% {fill:#232833} 77%,97% {fill:#e7e5d4} 100% {fill:#e4e5f7} }
49
+ @keyframes kF2 { 0%,47% {fill:#dfeaf6} 51%,73% {fill:#223028} 77%,97% {fill:#dfe6df} 100% {fill:#dfeaf6} }
50
+ @keyframes kF3 { 0%,47% {fill:#ece3f4} 51%,73% {fill:#2a2536} 77%,97% {fill:#ece2d8} 100% {fill:#ece3f4} }
51
+ @keyframes kStrk { 0%,47% {stroke:#9297cf} 51%,73% {stroke:#9db8cd} 77%,97% {stroke:#837e5a} 100% {stroke:#9297cf} }
52
+
53
+ /* builds (Keynote-style steps) */
54
+ @keyframes kInTitle { 0% {opacity:0; transform:translateY(14px)} 3.5% {opacity:1; transform:none} 96.5% {opacity:1} 100% {opacity:0} }
55
+ @keyframes kInSub { 0%,4% {opacity:0; transform:translateY(10px)} 7% {opacity:1; transform:none} 96.5% {opacity:1} 100% {opacity:0} }
56
+ @keyframes kInB1 { 0%,9% {opacity:0; transform:translateY(10px)} 12% {opacity:1; transform:none} 96.5% {opacity:1} 100% {opacity:0} }
57
+ @keyframes kInB2 { 0%,15% {opacity:0; transform:translateY(10px)} 18% {opacity:1; transform:none} 96.5% {opacity:1} 100% {opacity:0} }
58
+ @keyframes kInB3 { 0%,21% {opacity:0; transform:translateY(10px)} 24% {opacity:1; transform:none} 96.5% {opacity:1} 100% {opacity:0} }
59
+ @keyframes kInN1 { 0%,27% {opacity:0; transform:translateY(10px)} 30% {opacity:1; transform:none} 96.5% {opacity:1} 100% {opacity:0} }
60
+ @keyframes kInN2 { 0%,33.5% {opacity:0; transform:translateY(10px)} 36.5% {opacity:1; transform:none} 96.5% {opacity:1} 100% {opacity:0} }
61
+ @keyframes kInN3 { 0%,40% {opacity:0; transform:translateY(10px)} 43% {opacity:1; transform:none} 96.5% {opacity:1} 100% {opacity:0} }
62
+ @keyframes kDrawA1 { 0%,30% {opacity:0; stroke-dashoffset:1} 30.5% {opacity:1} 33.5% {stroke-dashoffset:0} 96.5% {opacity:1; stroke-dashoffset:0} 100% {opacity:0} }
63
+ @keyframes kDrawA2 { 0%,36.5% {opacity:0; stroke-dashoffset:1} 37% {opacity:1} 40% {stroke-dashoffset:0} 96.5% {opacity:1; stroke-dashoffset:0} 100% {opacity:0} }
64
+ @keyframes kA1Head { 0%,33% {opacity:0} 34.5% {opacity:1} 96.5% {opacity:1} 100% {opacity:0} }
65
+ @keyframes kA2Head { 0%,39.5% {opacity:0} 41% {opacity:1} 96.5% {opacity:1} 100% {opacity:0} }
66
+ @keyframes kToast { 0%,52% {opacity:0; transform:translateY(8px)} 55% {opacity:1; transform:none} 69% {opacity:1; transform:none} 72% {opacity:0} 100% {opacity:0} }
67
+ @keyframes kProgress{ 0% {transform:scaleX(0.04)} 11% {transform:scaleX(0.04)} 12% {transform:scaleX(0.2)}
68
+ 17% {transform:scaleX(0.2)} 18% {transform:scaleX(0.36)} 23% {transform:scaleX(0.36)}
69
+ 24% {transform:scaleX(0.52)} 29% {transform:scaleX(0.52)} 30% {transform:scaleX(0.68)}
70
+ 36% {transform:scaleX(0.68)} 36.5% {transform:scaleX(0.84)} 42% {transform:scaleX(0.84)}
71
+ 43%,100% {transform:scaleX(1)} }
72
+
73
+ @media (prefers-reduced-motion: reduce) { * { animation: none !important; } }
74
+ </style>
75
+
76
+ <rect class="bg" width="960" height="540"/>
77
+
78
+ <!-- chrome -->
79
+ <text class="mut" x="912" y="38" font-size="15" text-anchor="end">12 / 40</text>
80
+ <rect class="mut" x="0" y="536" width="960" height="4" opacity="0.22"/>
81
+ <rect class="acc pfill" x="0" y="536" width="960" height="4"/>
82
+
83
+ <!-- pinned title + subtitle -->
84
+ <text class="ttl rTitle" x="480" y="96" font-size="44" font-weight="700" text-anchor="middle">Composing Agents</text>
85
+ <text class="mut rSub" x="480" y="132" font-size="19" text-anchor="middle">Patterns for multi-agent systems</text>
86
+
87
+ <!-- bullets (one data-build container in a real deck) -->
88
+ <g class="rB1">
89
+ <circle class="acc" cx="96" cy="238" r="5"/>
90
+ <text class="ink" x="120" y="246" font-size="22">Sequential — hand off step by step</text>
91
+ </g>
92
+ <g class="rB2">
93
+ <circle class="acc" cx="96" cy="308" r="5"/>
94
+ <text class="ink" x="120" y="316" font-size="22">Parallel — fan out, then aggregate</text>
95
+ </g>
96
+ <g class="rB3">
97
+ <circle class="acc" cx="96" cy="378" r="5"/>
98
+ <text class="ink" x="120" y="386" font-size="22">Supervisor — one agent routes the rest</text>
99
+ </g>
100
+
101
+ <!-- diagram (an inline SVG with data-build="draw" in a real deck) -->
102
+ <g class="rN1">
103
+ <rect class="nf1" x="620" y="180" width="240" height="62" rx="12" stroke-width="2"/>
104
+ <text class="ink" x="740" y="218" font-size="19" font-weight="600" text-anchor="middle">Intent Agent</text>
105
+ </g>
106
+ <line class="strk rA1" x1="740" y1="244" x2="740" y2="276" stroke-width="2.5" pathLength="1" stroke-dasharray="1"/>
107
+ <path class="acc rA1h" d="M 733 272 L 747 272 L 740 283 Z"/>
108
+ <g class="rN2">
109
+ <rect class="nf2" x="620" y="286" width="240" height="62" rx="12" stroke-width="2"/>
110
+ <text class="ink" x="740" y="324" font-size="19" font-weight="600" text-anchor="middle">Research Agent</text>
111
+ </g>
112
+ <line class="strk rA2" x1="740" y1="350" x2="740" y2="382" stroke-width="2.5" pathLength="1" stroke-dasharray="1"/>
113
+ <path class="acc rA2h" d="M 733 378 L 747 378 L 740 389 Z"/>
114
+ <g class="rN3">
115
+ <rect class="nf3" x="620" y="392" width="240" height="62" rx="12" stroke-width="2"/>
116
+ <text class="ink" x="740" y="430" font-size="19" font-weight="600" text-anchor="middle">Response Agent</text>
117
+ </g>
118
+
119
+ <!-- generator toast (⌃T) -->
120
+ <g class="toast">
121
+ <rect x="290" y="472" width="380" height="34" rx="17" fill="#333338" opacity="0.92"/>
122
+ <text class="mono" x="480" y="494" font-size="14" fill="#f2f2f4" text-anchor="middle">✨ gen-onyx-0b81 — ⌃T re-roll · ⌃⇧T save</text>
123
+ </g>
124
+ </svg>
package/package.json ADDED
@@ -0,0 +1,54 @@
1
+ {
2
+ "name": "decklight",
3
+ "version": "0.1.0",
4
+ "description": "A presentation library designed to be authored by AI agents and humans alike: single-file decks, Keynote-style builds, theme-aware SVG diagrams, and truthful terminal recordings.",
5
+ "type": "module",
6
+ "main": "dist/decklight.js",
7
+ "bin": {
8
+ "decklight": "cli/decklight.mjs"
9
+ },
10
+ "files": [
11
+ "cli/",
12
+ "tools/",
13
+ "dist/",
14
+ "themes/",
15
+ "docs/",
16
+ "SPEC.md"
17
+ ],
18
+ "homepage": "https://decklight.io",
19
+ "repository": {
20
+ "type": "git",
21
+ "url": "git+https://github.com/decklight/decklight.git"
22
+ },
23
+ "bugs": "https://github.com/decklight/decklight/issues",
24
+ "keywords": [
25
+ "presentation",
26
+ "slides",
27
+ "deck",
28
+ "reveal",
29
+ "keynote",
30
+ "terminal",
31
+ "asciicast",
32
+ "tts",
33
+ "ai",
34
+ "agent"
35
+ ],
36
+ "scripts": {
37
+ "build": "node build.mjs",
38
+ "test": "node --test 'test/*.test.mjs'",
39
+ "verify": "npm run build && node test/render.mjs && node test/contrast.mjs && node test/palette-rules.mjs"
40
+ },
41
+ "engines": {
42
+ "node": ">=20"
43
+ },
44
+ "devDependencies": {
45
+ "esbuild": "^0.24.0",
46
+ "highlight.js": "^11.10.0",
47
+ "marked": "^15.0.0"
48
+ },
49
+ "optionalDependencies": {
50
+ "js-yaml": "^4.3.0",
51
+ "node-pty": "^1.1.0"
52
+ },
53
+ "license": "MIT"
54
+ }
@@ -0,0 +1,61 @@
1
+ # Decklight themes
2
+
3
+ 61 themes, one contract. A theme is **a single CSS file that defines tokens on `.decklight`** — the
4
+ runtime (`dist/decklight.css`) owns all structure; themes own only color, type, and mood. Link exactly
5
+ one theme per deck:
6
+
7
+ ```html
8
+ <link rel="stylesheet" href="decklight/dist/decklight.css">
9
+ <link rel="stylesheet" href="decklight/themes/fjord.css">
10
+ ```
11
+
12
+ Browse them: serve this directory (`python3 -m http.server`) and open [`gallery.html`](gallery.html).
13
+
14
+ ## The token contract (SPEC §5)
15
+
16
+ Every theme must define **all** of these on `.decklight`:
17
+
18
+ | Group | Tokens | Notes |
19
+ |---|---|---|
20
+ | Canvas | `--bg` `--bg-accent` `--fg` `--muted` | `--bg`/`--bg-accent` may be gradients |
21
+ | Type | `--font-body` `--font-heading` `--font-mono` `--heading-color` `--heading-weight` `--link` | font stacks must degrade offline |
22
+ | Accent | `--accent` `--accent-contrast` | contrast = text placed *on* the accent |
23
+ | Blocks | `--block-bg` `--block-border` `--block-radius` `--shadow` | `--block-border` is a full border value |
24
+ | Code | `--code-bg` `--code-fg` `--hl-keyword` `--hl-string` `--hl-number` `--hl-comment` `--hl-function` `--hl-type` `--hl-punct` | no separate highlighter themes — these are it |
25
+ | Diagram | `--d-stroke` `--d-text` `--d-muted` `--d-accent` `--d-fill-1…6` | inline SVGs authored with `var(--d-*)` restyle across all themes |
26
+ | Terminal | `--term-bg` `--term-fg` `--term-prompt` `--term-cursor` `--term-selection` + 16 × `--ansi-*` | the 16 ANSI names map recorded output to the theme |
27
+ | Builds (optional) | `--build-duration` `--dim-opacity` `--term-chrome` | `--term-chrome: none` hides the window chrome |
28
+
29
+ ## Accessibility gate
30
+
31
+ `node test/contrast.mjs` validates every theme (run from the repo root; part of `npm run verify`):
32
+
33
+ - `--fg`/`--bg` ≥ 4.5 · `--muted`, `--heading-color`, `--link`, `--d-text` ≥ 3.0 (gradient canvases: **every stop** must pass)
34
+ - `--code-fg` and all `--hl-*` ≥ 4.5 on `--code-bg` (`--hl-comment` ≥ 3.0)
35
+ - `--term-fg`, `--term-prompt`, and **all 16** `--ansi-*` ≥ 3.0 on `--term-bg` — yes, including `--ansi-black` on dark terminals: recorded output must stay readable on a projector, so "black" is a visible gray
36
+ - `--accent-contrast` ≥ 4.5 on `--accent`
37
+
38
+ A PR that adds or edits a theme must keep the validator green.
39
+
40
+ ## Authoring a new theme
41
+
42
+ 1. Copy the closest existing theme (dark → `fjord`, light → `porcelain`, gradient → `aurora`).
43
+ 2. Rework **every** group — hue-rotating one palette produces a clone, not a theme. Decide the
44
+ personality first (one line, like the taglines below), then pick canvas → type → accent →
45
+ code mood → terminal mood in that order.
46
+ 3. Fonts: system stacks preferred. A Google-font `@import` is allowed if the stack degrades
47
+ gracefully offline (the import goes at the very top of the file).
48
+ 4. Optional `.decklight h1/h2` cosmetic rules (letter-spacing, text-transform, font-style) are the
49
+ only non-token CSS a theme should contain.
50
+ 5. Run `node test/contrast.mjs` and fix until green; check your theme's card in `gallery.html`.
51
+
52
+ ## The set
53
+
54
+ **Dark (15):** aurora · graphite · obsidian · midnight · fjord · cosmos · ember · moss · velvet · carbon · synthwave · ink · eclipse · storm · ibm-modern
55
+ **Light (16):** porcelain · paper · meadow · glacier · citrus · dune · orchid · harvest · coastal · linen · berry · slate · latte · peony · mint · sepia
56
+ Plus the Classics, Old Machines, TV Series, and Movies packs (`packs.json` is the authoritative roster).
57
+
58
+ Serif-headed: moss, velvet, porcelain, dune, peony, sepia. Gradient canvases:
59
+ aurora, cosmos, synthwave, storm, coastal. Webfont-enhanced (all with offline fallbacks): carbon,
60
+ synthwave, porcelain, paper, peony, mint. Deliberately corporate-safe:
61
+ slate (and arguably graphite) — the rest have opinions.
@@ -0,0 +1,84 @@
1
+ /* ═══════════════════════════════════════════════════════════════
2
+ Decklight theme · aliens
3
+ dark · military phosphor, tracker green, amber warnings
4
+ Inspired by Aliens — the motion tracker and the Sulaco CRTs — palette kept canonical where possible,
5
+ every gated pair fitted to the WCAG contract.
6
+ Token contract: SPEC.md §5 — validated by test/contrast.mjs
7
+ ═══════════════════════════════════════════════════════════════ */
8
+
9
+ .decklight {
10
+ /* ── canvas ─────────────────────────────── */
11
+ --bg: #0a0f0d;
12
+ --bg-accent: none;
13
+ --fg: #b8e0c8;
14
+ --muted: #6f9a80;
15
+
16
+ /* ── type ───────────────────────────────── */
17
+ --font-body: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
18
+ --font-heading: "SF Mono", SFMono-Regular, ui-monospace, "Cascadia Code", Menlo, Consolas, monospace;
19
+ --font-mono: "SF Mono", SFMono-Regular, ui-monospace, "Cascadia Code", Menlo, Consolas, monospace;
20
+ --heading-color: #8fe8b0;
21
+ --heading-weight: 600;
22
+ --link: #e8c060;
23
+
24
+ /* ── accent ─────────────────────────────── */
25
+ --accent: #58d364;
26
+ --accent-contrast: #131313;
27
+
28
+ /* ── blocks ─────────────────────────────── */
29
+ --block-bg: #111c18;
30
+ --block-border: 1px solid #26302c;
31
+ --block-radius: 3px;
32
+ --shadow: 0 8px 26px rgba(0, 0, 0, 0.5);
33
+
34
+ /* ── code ───────────────────────────────── */
35
+ --code-bg: #0e1511;
36
+ --code-fg: #b8e8c8;
37
+ --hl-keyword: #8fe8b0;
38
+ --hl-string: #e8d080;
39
+ --hl-number: #e8a850;
40
+ --hl-comment: #557a64;
41
+ --hl-function: #7fd8d0;
42
+ --hl-type: #c8e890;
43
+ --hl-punct: #8fb89c;
44
+
45
+ /* ── diagram ────────────────────────────── */
46
+ --d-stroke: #6f9a80;
47
+ --d-text: #b8e0c8;
48
+ --d-muted: #6f9a80;
49
+ --d-accent: #e8b840;
50
+ --d-fill-1: #17201b;
51
+ --d-fill-2: #28251a;
52
+ --d-fill-3: #1b312a;
53
+ --d-fill-4: #172019;
54
+ --d-fill-5: #1a2827;
55
+ --d-fill-6: #22311b;
56
+
57
+ /* ── terminal ───────────────────────────── */
58
+ --term-bg: #080c0a;
59
+ --term-fg: #e6e6e2;
60
+ --term-prompt: #58d364;
61
+ --term-cursor: #58d364;
62
+ --term-selection: rgba(88, 211, 100, 0.28);
63
+ --ansi-black: #7a8a7a;
64
+ --ansi-red: #e08a6a;
65
+ --ansi-green: #6fd66f;
66
+ --ansi-yellow: #d6c258;
67
+ --ansi-blue: #7fb3d0;
68
+ --ansi-magenta: #c79ac0;
69
+ --ansi-cyan: #7fd0c0;
70
+ --ansi-white: #dfe8df;
71
+ --ansi-bright-black: #9ba79b;
72
+ --ansi-bright-red: #ebb29d;
73
+ --ansi-bright-green: #9fe49f;
74
+ --ansi-bright-yellow: #e2d489;
75
+ --ansi-bright-blue: #accee0;
76
+ --ansi-bright-magenta: #ddc1d9;
77
+ --ansi-bright-cyan: #ace0d6;
78
+ --ansi-bright-white: #f3f6f3;
79
+
80
+ /* ── builds ─────────────────────────────── */
81
+ --dim-opacity: 0.22;
82
+ }
83
+
84
+ .decklight h1, .decklight h2 { text-transform: uppercase; letter-spacing: 0.05em; }
@@ -0,0 +1,126 @@
1
+ /* ═══════════════════════════════════════════════════════════════
2
+ Decklight theme · apple2
3
+ dark · black glass, one green phosphor, mono display type
4
+ Inspired by the Apple ][ green phosphor CRT — palette kept canonical where possible,
5
+ every gated pair fitted to the WCAG contract.
6
+ rule-exception: R1 a single-phosphor monochrome display is the identity
7
+ rule-exception: R3 phosphor green burns bright by design
8
+ Token contract: SPEC.md §5 — validated by test/contrast.mjs
9
+ ═══════════════════════════════════════════════════════════════ */
10
+
11
+ .decklight {
12
+ /* ── canvas ─────────────────────────────── */
13
+ --bg: #0c0f0c;
14
+ --bg-accent: none;
15
+ --fg: #7fe87f;
16
+ --muted: #4f9f5b;
17
+
18
+ /* ── type ───────────────────────────────── */
19
+ --font-body: "SF Mono", SFMono-Regular, ui-monospace, "Cascadia Code", Menlo, Consolas, monospace;
20
+ --font-heading: "SF Mono", SFMono-Regular, ui-monospace, "Cascadia Code", Menlo, Consolas, monospace;
21
+ --font-mono: "SF Mono", SFMono-Regular, ui-monospace, "Cascadia Code", Menlo, Consolas, monospace;
22
+ --heading-color: #8ff98f;
23
+ --heading-weight: 600;
24
+ --link: #a8ff9f;
25
+
26
+ /* ── accent ─────────────────────────────── */
27
+ --accent: #37d63d;
28
+ --accent-contrast: #131313;
29
+
30
+ /* ── blocks ─────────────────────────────── */
31
+ --block-bg: #141b14;
32
+ --block-border: 1px solid #273127;
33
+ --block-radius: 2px;
34
+ --shadow: 0 8px 26px rgba(0, 0, 0, 0.5);
35
+
36
+ /* ── code ───────────────────────────────── */
37
+ --code-bg: #101510;
38
+ --code-fg: #8ff98f;
39
+ --hl-keyword: #a8ff9f;
40
+ --hl-string: #5fd68f;
41
+ --hl-number: #d6d65f;
42
+ --hl-comment: #3f7a4a;
43
+ --hl-function: #7fe8b0;
44
+ --hl-type: #c8e87f;
45
+ --hl-punct: #6fbf7f;
46
+
47
+ /* ── diagram ────────────────────────────── */
48
+ --d-stroke: #4f9f5b;
49
+ --d-text: #7fe87f;
50
+ --d-muted: #4f9f5b;
51
+ --d-accent: #37d63d;
52
+ --d-fill-1: #182119;
53
+ --d-fill-2: #1d291a;
54
+ --d-fill-3: #1c3223;
55
+ --d-fill-4: #1c2118;
56
+ --d-fill-5: #1a2923;
57
+ --d-fill-6: #2b321c;
58
+
59
+ /* ── terminal ───────────────────────────── */
60
+ --term-bg: #0a0d0a;
61
+ --term-fg: #e6e6e2;
62
+ --term-prompt: #37d63d;
63
+ --term-cursor: #37d63d;
64
+ --term-selection: rgba(55, 214, 61, 0.28);
65
+ --ansi-black: #7a8a7a;
66
+ --ansi-red: #e08a6a;
67
+ --ansi-green: #6fd66f;
68
+ --ansi-yellow: #d6c258;
69
+ --ansi-blue: #7fb3d0;
70
+ --ansi-magenta: #c79ac0;
71
+ --ansi-cyan: #7fd0c0;
72
+ --ansi-white: #dfe8df;
73
+ --ansi-bright-black: #9ba79b;
74
+ --ansi-bright-red: #ebb29d;
75
+ --ansi-bright-green: #9fe49f;
76
+ --ansi-bright-yellow: #e2d489;
77
+ --ansi-bright-blue: #accee0;
78
+ --ansi-bright-magenta: #ddc1d9;
79
+ --ansi-bright-cyan: #ace0d6;
80
+ --ansi-bright-white: #f3f6f3;
81
+
82
+ /* ── builds ─────────────────────────────── */
83
+ --dim-opacity: 0.22;
84
+ }
85
+
86
+ .decklight h1, .decklight h2 { text-transform: uppercase; letter-spacing: 0.04em; }
87
+
88
+ /* ── CRT character: the Monitor /// look ─────────────────────────────────────
89
+ Scanlines + phosphor bloom + a slow raster roll + the occasional horizontal
90
+ sync tear. Subtle by design; all motion sits out prefers-reduced-motion. */
91
+ .decklight .terminal-screen {
92
+ position: relative;
93
+ overflow: hidden;
94
+ text-shadow: 0 0 5px rgba(90, 240, 110, 0.4);
95
+ animation: a2-tear 7s steps(1) infinite;
96
+ }
97
+ .decklight .terminal-screen::after {
98
+ content: '';
99
+ position: absolute;
100
+ inset: 0;
101
+ pointer-events: none;
102
+ background: repeating-linear-gradient(0deg, rgba(0, 0, 0, 0.20) 0 1px, transparent 1px 3px);
103
+ }
104
+ .decklight .terminal-screen::before {
105
+ content: '';
106
+ position: absolute;
107
+ left: 0;
108
+ right: 0;
109
+ top: -25%;
110
+ height: 22%;
111
+ pointer-events: none;
112
+ background: linear-gradient(180deg, transparent, rgba(130, 255, 150, 0.055), transparent);
113
+ animation: a2-roll 8s linear infinite;
114
+ }
115
+ @keyframes a2-roll { to { transform: translateY(560%); } }
116
+ @keyframes a2-tear {
117
+ 0%, 93.9% { transform: none; }
118
+ 94% { transform: translateX(2px); }
119
+ 94.7% { transform: translateX(-3px) skewX(0.5deg); }
120
+ 95.4% { transform: translateX(1px); }
121
+ 96%, 100% { transform: none; }
122
+ }
123
+ @media (prefers-reduced-motion: reduce) {
124
+ .decklight .terminal-screen,
125
+ .decklight .terminal-screen::before { animation: none; }
126
+ }
@@ -0,0 +1,84 @@
1
+ /* ═══════════════════════════════════════════════════════════════
2
+ Decklight theme · aurora
3
+ dark · Northern-lights gradient — teal glow over deep arctic navy
4
+ Token contract: SPEC.md §5 — all values validated by test/contrast.mjs
5
+ ═══════════════════════════════════════════════════════════════ */
6
+
7
+ /* palette-rule exceptions (test/palette-rules.mjs):
8
+ rule-exception: R2 the borealis duotone canvas is the identity
9
+ ═══════════════════════════════════════════════════════════════ */
10
+
11
+ .decklight {
12
+ /* ── canvas ─────────────────────────────── */
13
+ --bg: linear-gradient(160deg, #0a0f24 0%, #0d1f3c 55%, #0b2b38 100%);
14
+ --bg-accent: linear-gradient(135deg, #10306b 0%, #0d4a54 100%);
15
+ --fg: #e8eefc;
16
+ --muted: #9fb1d1;
17
+
18
+ /* ── type ───────────────────────────────── */
19
+ --font-body: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
20
+ --font-heading: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
21
+ --font-mono: "SF Mono", SFMono-Regular, ui-monospace, "Cascadia Code", Menlo, Consolas, monospace;
22
+ --heading-color: #fafafa;
23
+ --heading-weight: 800;
24
+ --link: #7cc7ff;
25
+
26
+ /* ── accent ─────────────────────────────── */
27
+ --accent: #5ae4bb;
28
+ --accent-contrast: #04261c;
29
+
30
+ /* ── blocks ─────────────────────────────── */
31
+ --block-bg: rgba(16, 32, 68, 0.55);
32
+ --block-border: 1px solid rgba(110, 231, 208, 0.25);
33
+ --block-radius: 14px;
34
+ --shadow: 0 12px 40px rgba(2, 8, 26, 0.55);
35
+
36
+ /* ── code ───────────────────────────────── */
37
+ --code-bg: #0a1430;
38
+ --code-fg: #dbe6ff;
39
+ --hl-keyword: #82aaff;
40
+ --hl-string: #7ee2b8;
41
+ --hl-number: #ffcb8b;
42
+ --hl-comment: #7d90b5;
43
+ --hl-function: #c9a2f5;
44
+ --hl-type: #6fd7e8;
45
+ --hl-punct: #a6b8d8;
46
+
47
+ /* ── diagram ────────────────────────────── */
48
+ --d-stroke: #6ee7d0;
49
+ --d-text: #e8eefc;
50
+ --d-muted: #8ba0c4;
51
+ --d-accent: #4ef0c0;
52
+ --d-fill-1: #12305c;
53
+ --d-fill-2: #0e4d5c;
54
+ --d-fill-3: #274060;
55
+ --d-fill-4: #1b3b53;
56
+ --d-fill-5: #16344a;
57
+ --d-fill-6: #232a55;
58
+
59
+ /* ── terminal ───────────────────────────── */
60
+ --term-bg: #071021;
61
+ --term-fg: #d6e4ff;
62
+ --term-prompt: #4ef0c0;
63
+ --term-cursor: #4ef0c0;
64
+ --term-selection: rgba(78, 240, 192, 0.28);
65
+ --ansi-black: #8494ad;
66
+ --ansi-red: #ff7b8a;
67
+ --ansi-green: #5fe8b0;
68
+ --ansi-yellow: #ffd479;
69
+ --ansi-blue: #7cb7ff;
70
+ --ansi-magenta: #c99bff;
71
+ --ansi-cyan: #6fe0e8;
72
+ --ansi-white: #dfe8f5;
73
+ --ansi-bright-black: #9fb1cc;
74
+ --ansi-bright-red: #ffa3ad;
75
+ --ansi-bright-green: #8ff5c8;
76
+ --ansi-bright-yellow: #ffe3a1;
77
+ --ansi-bright-blue: #a3cdff;
78
+ --ansi-bright-magenta: #ddbcff;
79
+ --ansi-bright-cyan: #a1ecf2;
80
+ --ansi-bright-white: #fafafa;
81
+
82
+ /* ── builds ─────────────────────────────── */
83
+ --dim-opacity: 0.3;
84
+ }