@devinilabs/reelstack 1.2.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 (145) hide show
  1. package/LICENSE +128 -0
  2. package/README.md +125 -0
  3. package/cli/beats.js +124 -0
  4. package/cli/bootstrap.js +124 -0
  5. package/cli/capture.js +34 -0
  6. package/cli/direction.js +114 -0
  7. package/cli/icons.js +49 -0
  8. package/cli/index.js +101 -0
  9. package/cli/init.js +253 -0
  10. package/cli/license.js +168 -0
  11. package/cli/lint.js +865 -0
  12. package/cli/preview.js +59 -0
  13. package/cli/render.js +404 -0
  14. package/cli/scaffold.js +239 -0
  15. package/cli/smoke.js +76 -0
  16. package/cli/update.js +26 -0
  17. package/cli/utils.js +184 -0
  18. package/docs/buyers-guide.md +220 -0
  19. package/docs/design-discipline.md +130 -0
  20. package/docs/family-galleries/dark.md +95 -0
  21. package/docs/family-galleries/forbidden.md +78 -0
  22. package/docs/family-galleries/glass.md +98 -0
  23. package/docs/family-galleries/paper.md +82 -0
  24. package/docs/family-galleries/warm.md +86 -0
  25. package/docs/superpowers/plans/2026-05-09-reelstack-init-readiness-gate.md +1166 -0
  26. package/docs/superpowers/specs/2026-05-09-reelstack-init-readiness-gate-design.md +233 -0
  27. package/families/dark/components/DriftingSpotlights.tsx +59 -0
  28. package/families/dark/components/FilmGrain.tsx +44 -0
  29. package/families/dark/components/ForestCard.tsx +43 -0
  30. package/families/dark/components/GridBackground.tsx +29 -0
  31. package/families/dark/components/RadialVignette.tsx +21 -0
  32. package/families/dark/components/Scanlines.tsx +35 -0
  33. package/families/dark/components/SegmentOpacity.ts +37 -0
  34. package/families/dark/components/index.ts +13 -0
  35. package/families/dark/index.ts +31 -0
  36. package/families/dark/palette.ts +98 -0
  37. package/families/dark/presets/claudedispatch.ts +46 -0
  38. package/families/dark/presets/codedrop.ts +37 -0
  39. package/families/dark/presets/gpt55.ts +54 -0
  40. package/families/dark/presets/notebooklm.ts +50 -0
  41. package/families/dark/presets/resourcescta.ts +35 -0
  42. package/families/dark/presets/skills.ts +40 -0
  43. package/families/dark/presets/stitch.ts +46 -0
  44. package/families/dark/presets/stitch2.ts +43 -0
  45. package/families/dark/typography.ts +16 -0
  46. package/families/forbidden/components/ForbiddenCausticBlobs.tsx +52 -0
  47. package/families/forbidden/components/NewsprintTexture.tsx +28 -0
  48. package/families/forbidden/components/TintedShadow.tsx +36 -0
  49. package/families/forbidden/components/index.ts +38 -0
  50. package/families/forbidden/index.ts +17 -0
  51. package/families/forbidden/palette.ts +88 -0
  52. package/families/forbidden/presets/heretic.ts +44 -0
  53. package/families/forbidden/typography.ts +18 -0
  54. package/families/glass/components/BreakdownCard.tsx +158 -0
  55. package/families/glass/components/CausticBlobs.tsx +49 -0
  56. package/families/glass/components/Counter.tsx +72 -0
  57. package/families/glass/components/EyebrowPill.tsx +59 -0
  58. package/families/glass/components/FilmStrip.tsx +202 -0
  59. package/families/glass/components/FloatingGlyphs.tsx +78 -0
  60. package/families/glass/components/GlassCard.tsx +58 -0
  61. package/families/glass/components/GlassCardBezel.tsx +45 -0
  62. package/families/glass/components/HairlineGrid.tsx +30 -0
  63. package/families/glass/components/IridescentRing.tsx +114 -0
  64. package/families/glass/components/IridescentText.tsx +98 -0
  65. package/families/glass/components/LightBeam.tsx +46 -0
  66. package/families/glass/components/ParticleBurst.tsx +62 -0
  67. package/families/glass/components/SonarRings.tsx +81 -0
  68. package/families/glass/components/StaggeredWords.tsx +74 -0
  69. package/families/glass/components/index.ts +20 -0
  70. package/families/glass/index.ts +31 -0
  71. package/families/glass/palette.ts +93 -0
  72. package/families/glass/presets/claudewatch.ts +64 -0
  73. package/families/glass/presets/claudewatchcta.ts +43 -0
  74. package/families/glass/presets/graphify.ts +45 -0
  75. package/families/glass/presets/gstack.ts +48 -0
  76. package/families/glass/presets/jcode.ts +50 -0
  77. package/families/glass/presets/lilagents.ts +52 -0
  78. package/families/glass/presets/paperclip.ts +43 -0
  79. package/families/glass/typography.ts +15 -0
  80. package/families/index.ts +49 -0
  81. package/families/paper/components/CardSpring.tsx +42 -0
  82. package/families/paper/components/CreamGrid.tsx +26 -0
  83. package/families/paper/components/EditorialSerifText.tsx +51 -0
  84. package/families/paper/components/GreenAccentCard.tsx +10 -0
  85. package/families/paper/components/PaperShadow.tsx +30 -0
  86. package/families/paper/components/ScaleBlurText.tsx +40 -0
  87. package/families/paper/components/index.ts +11 -0
  88. package/families/paper/index.ts +23 -0
  89. package/families/paper/palette.ts +102 -0
  90. package/families/paper/presets/designreel.ts +32 -0
  91. package/families/paper/presets/devini3d.ts +45 -0
  92. package/families/paper/presets/justdrop.ts +39 -0
  93. package/families/paper/presets/opus.ts +48 -0
  94. package/families/paper/typography.ts +17 -0
  95. package/families/warm/components/AccentGlow.tsx +60 -0
  96. package/families/warm/components/BentoCell.tsx +56 -0
  97. package/families/warm/components/BentoGrid.tsx +30 -0
  98. package/families/warm/components/FilmGrain.tsx +36 -0
  99. package/families/warm/components/ScaleBlurCounter.tsx +71 -0
  100. package/families/warm/components/WarmSurface.tsx +35 -0
  101. package/families/warm/components/index.ts +11 -0
  102. package/families/warm/index.ts +19 -0
  103. package/families/warm/palette.ts +81 -0
  104. package/families/warm/presets/huashu.ts +49 -0
  105. package/families/warm/presets/mempalace.ts +51 -0
  106. package/families/warm/typography.ts +17 -0
  107. package/package.json +85 -0
  108. package/reference/dark/claudedispatch.tsx +2441 -0
  109. package/reference/dark/notebooklm.tsx +2316 -0
  110. package/reference/dark/stitch.tsx +3040 -0
  111. package/reference/forbidden/heretic.tsx +2636 -0
  112. package/reference/glass/claudewatch.tsx +3827 -0
  113. package/reference/glass/graphify.tsx +2418 -0
  114. package/reference/glass/paperclip.tsx +2218 -0
  115. package/reference/paper/designreel.tsx +883 -0
  116. package/reference/paper/justdrop.tsx +1898 -0
  117. package/reference/paper/opus.tsx +1770 -0
  118. package/reference/warm/huashu.tsx +3413 -0
  119. package/reference/warm/mempalace.tsx +2909 -0
  120. package/skill/SKILL.md +229 -0
  121. package/skill/commands/reelstack-beats.md +20 -0
  122. package/skill/commands/reelstack-capture.md +24 -0
  123. package/skill/commands/reelstack-critique.md +15 -0
  124. package/skill/commands/reelstack-dark.md +40 -0
  125. package/skill/commands/reelstack-direction.md +17 -0
  126. package/skill/commands/reelstack-forbidden.md +25 -0
  127. package/skill/commands/reelstack-glass.md +39 -0
  128. package/skill/commands/reelstack-icons.md +22 -0
  129. package/skill/commands/reelstack-init.md +17 -0
  130. package/skill/commands/reelstack-lint.md +22 -0
  131. package/skill/commands/reelstack-paper.md +36 -0
  132. package/skill/commands/reelstack-render.md +20 -0
  133. package/skill/commands/reelstack-warm.md +36 -0
  134. package/templates/dark/template.tsx +115 -0
  135. package/templates/forbidden/template.tsx +111 -0
  136. package/templates/glass/template.tsx +201 -0
  137. package/templates/paper/template.tsx +133 -0
  138. package/templates/warm/template.tsx +210 -0
  139. package/utils/ai-purple-blocklist.ts +13 -0
  140. package/utils/banned-fonts.ts +11 -0
  141. package/utils/cubic-bezier.ts +36 -0
  142. package/utils/easing.ts +84 -0
  143. package/utils/grid.ts +13 -0
  144. package/utils/render-presets.json +56 -0
  145. package/utils/safe-zones.tsx +57 -0
@@ -0,0 +1,93 @@
1
+ /**
2
+ * ReelStack — Glass Iridescent palette
3
+ *
4
+ * Verified against /Users/abhishekraj/my-video/src/GraphifyReel.tsx (the foundational
5
+ * preset). Other Glass presets (paperclip, gstack, lilagents, jcode) inherit this
6
+ * base and add accent variations in their own preset files.
7
+ *
8
+ * Mood: premium product reveal. Underwater-light caustics, glass surfaces,
9
+ * iridescent text shimmer.
10
+ */
11
+ export const palette = {
12
+ // Backgrounds
13
+ bg: "#EFEAF2",
14
+ bgWarm: "#E9E2EE",
15
+ bgCool: "#E4E9F2",
16
+
17
+ // Ink (light-mode text)
18
+ ink: "#0E0E12", // contrast 16.8:1 on bg #EFEAF2 — WCAG AAA
19
+ inkSoft: "#26242C", // contrast 12.4:1 on bg #EFEAF2 — WCAG AAA
20
+ inkMuted: "#5A5867", // contrast 6.4:1 on bg #EFEAF2 — WCAG AA
21
+ inkDim: "#86848F", // contrast 3.4:1 on bg #EFEAF2 — WCAG AA-Large
22
+
23
+ // Iridescent stops (used by CausticBlobs, FloatingGlyphs, ParticleBurst)
24
+ iriCyan: "#7FE8D4",
25
+ iriViolet: "#8B7FE8",
26
+ iriRose: "#E89BC4",
27
+ iriGold: "#F2D88F",
28
+
29
+ // Pills (eyebrow / contextual labels)
30
+ violetPill: "#9D8BF2",
31
+ tealPill: "#85DDC9",
32
+
33
+ // Glass-card surface tokens
34
+ glassFill: "rgba(255, 255, 255, 0.42)",
35
+ glassFillStrong: "rgba(255, 255, 255, 0.62)",
36
+ glassBorder: "rgba(255, 255, 255, 0.86)",
37
+
38
+ // Macro-window dots (for embedded UI screenshots)
39
+ macClose: "#FF5F57",
40
+ macMin: "#FEBC2E",
41
+ macMax: "#28C840",
42
+ } as const;
43
+
44
+ /**
45
+ * Safe-zone constants — every Glass scaffold reserves these.
46
+ * Top 280–290 px and bottom 1500–1640 px are off-limits for hero copy / CTAs.
47
+ */
48
+ export const safeZones = {
49
+ top: 290,
50
+ bottom: 1500, // y where the bottom 22% reserved band begins
51
+ canvas: { width: 1080, height: 1920 },
52
+ } as const;
53
+
54
+ /**
55
+ * Iridescent gradient strings derived from the palette — pre-computed so
56
+ * presets can drop them straight into CSS without re-mixing.
57
+ */
58
+ export const gradients = {
59
+ iridescent: `linear-gradient(135deg, ${palette.iriCyan} 0%, ${palette.iriViolet} 33%, ${palette.iriRose} 66%, ${palette.iriGold} 100%)`,
60
+ causticCyan: `radial-gradient(ellipse, ${palette.iriCyan}55 0%, transparent 60%)`,
61
+ causticViolet: `radial-gradient(ellipse, ${palette.iriViolet}55 0%, transparent 60%)`,
62
+ causticRose: `radial-gradient(ellipse, ${palette.iriRose}55 0%, transparent 60%)`,
63
+ causticGold: `radial-gradient(ellipse, ${palette.iriGold}55 0%, transparent 60%)`,
64
+ } as const;
65
+
66
+ /**
67
+ * Hard-coded "allowed accents" list. The lint command checks every fill /
68
+ * stroke / background color in a Glass Iridescent reel against this set
69
+ * (plus neutral ink shades). Anything off-list is flagged as a hue bleed.
70
+ */
71
+ export const ALLOWED_ACCENTS = [
72
+ palette.iriCyan,
73
+ palette.iriViolet,
74
+ palette.iriRose,
75
+ palette.iriGold,
76
+ palette.violetPill,
77
+ palette.tealPill,
78
+ palette.ink,
79
+ ] as const;
80
+
81
+ export type GlassPalette = typeof palette;
82
+
83
+ /** Re-export grid units so consumers can pull them from the family entrypoint. */
84
+ export {
85
+ GRID,
86
+ GRID_2,
87
+ GRID_4,
88
+ GRID_6,
89
+ GRID_8,
90
+ GRID_12,
91
+ GRID_16,
92
+ GRID_24,
93
+ } from "../../utils/grid";
@@ -0,0 +1,64 @@
1
+ /**
2
+ * Preset: claudewatch (Glass Iridescent)
3
+ * Source: ClaudeWatchReel.tsx
4
+ *
5
+ * The longest reel in the catalog (105.2s). Dual-narration structure (demo
6
+ * clip + technical explanation). Heavy use of frame-strip illustrations
7
+ * (film.mp4 sequences) for "video being watched" visuals.
8
+ */
9
+ export const preset = {
10
+ name: "claudewatch",
11
+ family: "glass",
12
+ source: "ClaudeWatchReel",
13
+ durationFrames: 3156,
14
+ fps: 30,
15
+ copy: {
16
+ hook: "This custom Claude skill literally watches video.",
17
+ sub: "YouTube, any length. Whisper, auto-chapters, searchable, second brain.",
18
+ cta: "Free skill — link below.",
19
+ },
20
+ accents: {
21
+ claude: "#FF7A4D", // coral
22
+ film: "#E89414", // marigold
23
+ vector: "#6E6EFF", // indigo
24
+ success: "#1FD891", // mint
25
+ crimson: "#FF5C7E",
26
+ plasma: "#B58CFF",
27
+ },
28
+ beats: {
29
+ hook: 0,
30
+ viral: 240,
31
+ demo: 540,
32
+ result: 1110,
33
+ decode: 1410,
34
+ brain: 1740,
35
+ ytCta: 1980,
36
+ hood: 2160,
37
+ ytdlp: 2310,
38
+ ffmpeg: 2460,
39
+ flipbook: 2640,
40
+ local: 2820,
41
+ comment: 2970,
42
+ end: 3120,
43
+ },
44
+ primitives: [
45
+ "CausticBlobs",
46
+ "HairlineGrid",
47
+ "GlassCard", // strong variant: glassFill 0.42 / glassFillStrong 0.62
48
+ "EyebrowPill",
49
+ "StaggeredWords",
50
+ "Counter",
51
+ "SonarRings",
52
+ "ParticleBurst",
53
+ "LightBeam",
54
+ "FloatingGlyphs",
55
+ "FilmStrip", // perforated 35mm strip — "Type. Paste. Watch." centerpiece
56
+ "IridescentRing", // multi-stop chromatic halo — alternative to SonarRings
57
+ "IridescentText", // hero-word gradient treatment ("Watch.")
58
+ "BreakdownCard", // BREAKDOWN.MD callout under the filmstrip
59
+ "FrameStrip", // preset-specific — film.mp4 sequences as flipbook
60
+ ],
61
+ glassVariant: "strong",
62
+ notes:
63
+ "ClaudeWatch's six accent colors are named scene-specific (claude, film, vector, success, crimson, plasma). Pick the accent per scene from the named set rather than mixing across scenes.",
64
+ } as const;
@@ -0,0 +1,43 @@
1
+ /**
2
+ * Preset: claudewatchcta (Glass Iridescent)
3
+ * Source: ClaudeWatchCTAReel.tsx
4
+ *
5
+ * 8-second standalone CTA cut. Uses ClaudeWatchReel's primitives but
6
+ * collapsed into a tight quick-hook + eyebrow + hero word + sub-line +
7
+ * description-pill structure. Use as an outro/sticker on other reels.
8
+ */
9
+ export const preset = {
10
+ name: "claudewatchcta",
11
+ family: "glass",
12
+ source: "ClaudeWatchCTAReel",
13
+ durationFrames: 240,
14
+ fps: 30,
15
+ copy: {
16
+ hook: "Claude Watches Video.",
17
+ sub: "Free skill, link below.",
18
+ },
19
+ accents: {
20
+ claude: "#FF7A4D",
21
+ },
22
+ beats: {
23
+ hook: 0,
24
+ eyebrow: 30,
25
+ heroWord: 60,
26
+ subLine: 120,
27
+ descriptionPill: 180,
28
+ end: 240,
29
+ },
30
+ primitives: [
31
+ "CausticBlobs",
32
+ "GlassCard",
33
+ "EyebrowPill",
34
+ "StaggeredWords",
35
+ "SonarRings",
36
+ "ParticleBurst",
37
+ "IridescentText", // hero-word gradient — fits inside the 8s budget
38
+ "BreakdownCard", // optional sub-line if the CTA needs structured rows
39
+ "IridescentRing", // chromatic halo behind the hero word
40
+ ],
41
+ notes:
42
+ "Designed to be appended to longer reels as a final 8s CTA. Frame budget is tight — keep motion floors satisfied with concurrent layers, not sequenced ones.",
43
+ } as const;
@@ -0,0 +1,45 @@
1
+ /**
2
+ * Preset: graphify (Glass Iridescent)
3
+ * Source: GraphifyReel.tsx — the foundational Glass reel.
4
+ *
5
+ * The reference build for the entire family. Multimodal product reveal,
6
+ * 65 seconds, full primitive vocabulary on display.
7
+ */
8
+ export const preset = {
9
+ name: "graphify",
10
+ family: "glass",
11
+ source: "GraphifyReel",
12
+ durationFrames: 1956,
13
+ fps: 30,
14
+ copy: {
15
+ hook: "Multimodal Claude understands the whole web. Graph everything.",
16
+ cta: "Hit my YouTube for the full walkthrough.",
17
+ },
18
+ accents: {},
19
+ beats: {
20
+ intro: 0,
21
+ hookEnd: 180,
22
+ problem: 540,
23
+ revealName: 720,
24
+ mechanism: 1020,
25
+ clip: 1320,
26
+ numbers: 1500,
27
+ multimodal: 1680,
28
+ compat: 1830,
29
+ cta: 1860,
30
+ },
31
+ primitives: [
32
+ "CausticBlobs",
33
+ "HairlineGrid",
34
+ "GlassCard",
35
+ "EyebrowPill",
36
+ "StaggeredWords",
37
+ "Counter",
38
+ "SonarRings",
39
+ "ParticleBurst",
40
+ "LightBeam",
41
+ "FloatingGlyphs",
42
+ ],
43
+ notes:
44
+ "Use this preset when in doubt — it carries the strongest motion-floor budget and the most polished primitive composition.",
45
+ } as const;
@@ -0,0 +1,48 @@
1
+ /**
2
+ * Preset: gstack (Glass Iridescent)
3
+ * Source: GstackReel.tsx
4
+ *
5
+ * Long-form (94s) feature-callout heavy reel. Heaviest GlassCard usage in
6
+ * the family — backdropFilter blur(32px) saturate(180%) for that frosted
7
+ * heavy feel.
8
+ */
9
+ export const preset = {
10
+ name: "gstack",
11
+ family: "glass",
12
+ source: "GstackReel",
13
+ durationFrames: 2820,
14
+ fps: 30,
15
+ copy: {
16
+ hook: "The president of YC just open-sourced his entire Claude Code setup. It's called gstack.",
17
+ cta: "Free, MIT, just clone.",
18
+ },
19
+ accents: {
20
+ ycOrange: "#F26625",
21
+ emerald: "#34D399",
22
+ rose: "#FB7185",
23
+ },
24
+ beats: {
25
+ hook: 0,
26
+ name: 240,
27
+ officeHours: 720,
28
+ qa: 1140,
29
+ cso: 1500,
30
+ parallel: 1860,
31
+ install: 2280,
32
+ cta: 2580,
33
+ end: 2820,
34
+ },
35
+ primitives: [
36
+ "CausticBlobs",
37
+ "HairlineGrid",
38
+ "GlassCard", // heavy variant — backdropFilter blur(32px) saturate(180%)
39
+ "EyebrowPill",
40
+ "StaggeredWords",
41
+ "SonarRings",
42
+ "ParticleBurst",
43
+ "FloatingGlyphs",
44
+ ],
45
+ glassVariant: "heavy",
46
+ notes:
47
+ "Use the heavy GlassCard variant — gstack's feature callouts need stronger glass to read against the iridescent caustics behind them.",
48
+ } as const;
@@ -0,0 +1,50 @@
1
+ /**
2
+ * Preset: jcode (Glass Iridescent)
3
+ * Source: JcodeReel.tsx
4
+ *
5
+ * Performance-claim reel with a single rust-orange accent on the iridescent
6
+ * base. ScrambleText (incremental char reveal) is the signature element.
7
+ * Film-grain overlay constant throughout.
8
+ */
9
+ export const preset = {
10
+ name: "jcode",
11
+ family: "glass",
12
+ source: "JcodeReel",
13
+ durationFrames: 2164,
14
+ fps: 30,
15
+ copy: {
16
+ hook: "63 times faster than Codex. Jcode rebuilt in Rust. Parallel swarms.",
17
+ cta: "GitHub link below.",
18
+ },
19
+ accents: {
20
+ rust: "#E55A1A",
21
+ rustSoft: "#F9C5A5",
22
+ rustDeep: "#9B3A0E",
23
+ },
24
+ beats: {
25
+ hook: 0,
26
+ nameDrop: 348,
27
+ benchmark: 554,
28
+ rustReveal: 907,
29
+ parallel: 1153,
30
+ swarms: 1463,
31
+ install: 1660,
32
+ cta: 1995,
33
+ end: 2164,
34
+ },
35
+ primitives: [
36
+ "CausticBlobs",
37
+ "HairlineGrid",
38
+ "GlassCard",
39
+ "EyebrowPill",
40
+ "StaggeredWords",
41
+ "Counter",
42
+ "SonarRings",
43
+ "ParticleBurst",
44
+ "FloatingGlyphs", // code symbols only — no emojis
45
+ "ScrambleText", // preset-specific
46
+ "FilmGrain", // constant overlay (SVG turbulence, opacity 0.06)
47
+ ],
48
+ notes:
49
+ "FloatingGlyphs use code-symbol set only (∑, ∫, ⟨⟩, ≠) — no emojis ever. Film grain stays on for the whole reel; do not toggle per scene.",
50
+ } as const;
@@ -0,0 +1,52 @@
1
+ /**
2
+ * Preset: lilagents (Glass Iridescent)
3
+ * Source: LilAgentsReel.tsx
4
+ *
5
+ * Character-driven (Bruce + Jazz). Dock dark background variant + ThoughtBubble
6
+ * components. Sits in Glass family because the iridescent glass primitives
7
+ * still drive scene composition, but uses a darker bg.
8
+ */
9
+ export const preset = {
10
+ name: "lilagents",
11
+ family: "glass",
12
+ source: "LilAgentsReel",
13
+ durationFrames: 2160,
14
+ fps: 30,
15
+ copy: {
16
+ hook: "Tiny Claude agents walk on your dock. Bruce and Jazz. Local, no signup.",
17
+ cta: "Free download below.",
18
+ },
19
+ accents: {
20
+ dockBg: "#1c162e", // overrides bg for the dock-style dark variant
21
+ peach: "#FFB088",
22
+ bruce: "#E89BC4",
23
+ jazz: "#7FE8D4",
24
+ terminalText: "#A8FFD9",
25
+ },
26
+ beats: {
27
+ hook: 0,
28
+ bruceIntro: 165,
29
+ jazzIntro: 268,
30
+ interaction: 448,
31
+ capability1: 542,
32
+ capability2: 711,
33
+ capability3: 837,
34
+ install: 1093,
35
+ privacy: 1391,
36
+ local: 1681,
37
+ cta: 2016,
38
+ },
39
+ primitives: [
40
+ "CausticBlobs",
41
+ "GlassCard",
42
+ "EyebrowPill",
43
+ "StaggeredWords",
44
+ "SonarRings",
45
+ "ParticleBurst",
46
+ "ThoughtBubble", // preset-specific
47
+ "DockSurface", // preset-specific (dark dock-style bg)
48
+ ],
49
+ bgOverride: "dockBg",
50
+ notes:
51
+ "Override the family bg with dockBg (#1c162e) for character scenes. ThoughtBubbles float on sine paths. Terminal-text accent (#A8FFD9) for code/install scenes.",
52
+ } as const;
@@ -0,0 +1,43 @@
1
+ /**
2
+ * Preset: paperclip (Glass Iridescent)
3
+ * Source: PaperclipReel.tsx
4
+ *
5
+ * Open-source reveal. 55 seconds. PaperclipGlyph (custom SVG paperclip with
6
+ * iridescent stroke draw-in via dash offset) is the signature element.
7
+ */
8
+ export const preset = {
9
+ name: "paperclip",
10
+ family: "glass",
11
+ source: "PaperclipReel",
12
+ durationFrames: 1650,
13
+ fps: 30,
14
+ copy: {
15
+ hook: "It's called Paperclip. It's not OpenAI, it's not Google. MIT licensed, open source.",
16
+ cta: "Link in description.",
17
+ },
18
+ accents: {},
19
+ beats: {
20
+ hook: 0,
21
+ reveal: 270,
22
+ demoIn: 594,
23
+ demoOut: 1410,
24
+ cta: 1560,
25
+ },
26
+ primitives: [
27
+ "CausticBlobs",
28
+ "HairlineGrid",
29
+ "GlassCard",
30
+ "EyebrowPill",
31
+ "StaggeredWords",
32
+ "SonarRings",
33
+ "ParticleBurst",
34
+ "PaperclipGlyph", // preset-specific: see family components/PaperclipGlyph.tsx
35
+ ],
36
+ embeddedClip: {
37
+ path: "captures/paperclip/demo.mp4",
38
+ sequenceStart: 594,
39
+ durationFrames: 816, // 27.17s
40
+ },
41
+ notes:
42
+ "PaperclipGlyph uses dash-offset animation on the inline SVG. Audio-locked beats are critical: demo cut points snap to whisper SRT segments.",
43
+ } as const;
@@ -0,0 +1,15 @@
1
+ /** Glass Iridescent typography scale. Geist Sans + Geist Mono only.
2
+ * Pulled from existing template usage; locks the implicit scale into named tokens.
3
+ * Letter-spacing follows leonxlnx/taste-skill: tighter at large sizes, looser for caption/mono.
4
+ */
5
+ export const typography = {
6
+ hero: { fontSize: 96, fontWeight: 700, letterSpacing: -2, lineHeight: 1.05, fontFamily: "Geist, system-ui" },
7
+ h1: { fontSize: 84, fontWeight: 700, letterSpacing: -1.5, lineHeight: 1.1, fontFamily: "Geist, system-ui" },
8
+ h2: { fontSize: 56, fontWeight: 700, letterSpacing: -1.5, lineHeight: 1.15, fontFamily: "Geist, system-ui" },
9
+ h3: { fontSize: 36, fontWeight: 600, letterSpacing: -1, lineHeight: 1.2, fontFamily: "Geist, system-ui" },
10
+ body: { fontSize: 24, fontWeight: 500, letterSpacing: -0.2, lineHeight: 1.5, fontFamily: "Geist, system-ui" },
11
+ caption: { fontSize: 18, fontWeight: 500, letterSpacing: 0.5, lineHeight: 1.4, fontFamily: "Geist, system-ui", textTransform: "uppercase" as const },
12
+ mono: { fontSize: 22, fontWeight: 500, letterSpacing: 0.3, lineHeight: 1.4, fontFamily: "Geist Mono, monospace" },
13
+ counter: { fontSize: 144, fontWeight: 700, letterSpacing: -2, lineHeight: 1, fontFamily: "Geist Mono, monospace" },
14
+ } as const;
15
+ export type Typography = typeof typography;
@@ -0,0 +1,49 @@
1
+ /**
2
+ * ReelStack — family registry.
3
+ *
4
+ * The CLI scaffolder reads this when handed `--family=<name> --preset=<name>`
5
+ * to validate inputs and to pull palette + preset metadata.
6
+ */
7
+ import * as glass from "./glass";
8
+ import * as paper from "./paper";
9
+ import * as dark from "./dark";
10
+ import * as warm from "./warm";
11
+ import * as forbidden from "./forbidden";
12
+
13
+ export const families = {
14
+ glass,
15
+ paper,
16
+ dark,
17
+ warm,
18
+ forbidden,
19
+ } as const;
20
+
21
+ export type FamilyName = keyof typeof families;
22
+
23
+ export const FAMILY_NAMES: FamilyName[] = ["glass", "paper", "dark", "warm", "forbidden"];
24
+
25
+ export function resolveFamily(name: string) {
26
+ if (!(name in families)) {
27
+ throw new Error(
28
+ `Unknown family "${name}". Valid families: ${FAMILY_NAMES.join(", ")}.`
29
+ );
30
+ }
31
+ return families[name as FamilyName];
32
+ }
33
+
34
+ export function resolvePreset(familyName: string, presetName: string) {
35
+ const fam = resolveFamily(familyName);
36
+ if (!(presetName in fam.presets)) {
37
+ const valid = Object.keys(fam.presets).join(", ");
38
+ throw new Error(
39
+ `Unknown preset "${presetName}" in family "${familyName}". Valid presets: ${valid}.`
40
+ );
41
+ }
42
+ // @ts-expect-error - dynamic key access; runtime narrowing happens above
43
+ return fam.presets[presetName];
44
+ }
45
+
46
+ export const TOTAL_PRESETS = Object.values(families).reduce(
47
+ (n, fam) => n + Object.keys(fam.presets).length,
48
+ 0,
49
+ ); // === 22
@@ -0,0 +1,42 @@
1
+ import React, { CSSProperties, ReactNode } from "react";
2
+ import { spring, useCurrentFrame, useVideoConfig } from "remotion";
3
+ import { palette, springConfig, paperShadow } from "../palette";
4
+
5
+ /**
6
+ * CardSpring — generic dark-green card revealed with the family's signature
7
+ * spring (damping 20 / stiffness 200).
8
+ *
9
+ * Animates from translateY(32px) + scale(0.96) + opacity(0) to identity over
10
+ * the spring curve. Background is `palette.cardForest` with the multi-layer
11
+ * `paperShadow.card` stack. Cream text on forest green is the Cream Paper
12
+ * family contract — never override `color` to a dark value.
13
+ */
14
+ export const CardSpring: React.FC<{
15
+ startFrame: number;
16
+ reduceMotion?: boolean;
17
+ style?: CSSProperties;
18
+ children?: ReactNode;
19
+ }> = ({ startFrame, reduceMotion = false, style, children }) => {
20
+ const frame = useCurrentFrame();
21
+ const { fps } = useVideoConfig();
22
+ const local = Math.max(0, frame - startFrame);
23
+ const t = reduceMotion ? 1 : spring({ frame: local, fps, config: springConfig });
24
+ return (
25
+ <div
26
+ style={{
27
+ background: palette.cardForest,
28
+ color: "#e9eee8",
29
+ borderRadius: 24,
30
+ padding: 36,
31
+ boxShadow: paperShadow.card,
32
+ opacity: t,
33
+ transform: reduceMotion
34
+ ? "none"
35
+ : `translateY(${(1 - t) * 32}px) scale(${0.96 + t * 0.04})`,
36
+ ...style,
37
+ }}
38
+ >
39
+ {children}
40
+ </div>
41
+ );
42
+ };
@@ -0,0 +1,26 @@
1
+ import React from "react";
2
+ import { AbsoluteFill } from "remotion";
3
+ import { palette } from "../palette";
4
+
5
+ /**
6
+ * CreamGrid — full-bleed 72×72 grid in `palette.paperGrid` (a quiet warm
7
+ * tone) with a radial mask fade from center.
8
+ *
9
+ * Provides "paper texture" — the document feel the buyer reads as editorial
10
+ * rather than digital. Pure CSS background, zero per-frame cost. Sits at the
11
+ * very bottom of the layer stack, just above `palette.bg`.
12
+ */
13
+ export const CreamGrid: React.FC = () => (
14
+ <AbsoluteFill
15
+ style={{
16
+ backgroundImage: `
17
+ linear-gradient(to right, ${palette.paperGrid} 1px, transparent 1px),
18
+ linear-gradient(to bottom, ${palette.paperGrid} 1px, transparent 1px)
19
+ `,
20
+ backgroundSize: "72px 72px",
21
+ WebkitMaskImage: "radial-gradient(ellipse at center, rgba(0,0,0,1) 35%, rgba(0,0,0,0) 80%)",
22
+ maskImage: "radial-gradient(ellipse at center, rgba(0,0,0,1) 35%, rgba(0,0,0,0) 80%)",
23
+ pointerEvents: "none",
24
+ }}
25
+ />
26
+ );
@@ -0,0 +1,51 @@
1
+ import React, { CSSProperties } from "react";
2
+ import { useCurrentFrame } from "remotion";
3
+ import { palette } from "../palette";
4
+ import { ease } from "../../../utils/easing";
5
+
6
+ /**
7
+ * Editorial-serif hero text for Cream Paper reels.
8
+ * Falls back through Lyon Text → Newsreader → Playfair Display → serif.
9
+ * Inspired by leonxlnx/taste-skill-minimalist's "serif fonts ONLY for hero".
10
+ */
11
+ export const EditorialSerifText: React.FC<{
12
+ startFrame: number;
13
+ text: string;
14
+ fontSize?: number;
15
+ color?: string;
16
+ italic?: boolean;
17
+ reduceMotion?: boolean;
18
+ style?: CSSProperties;
19
+ }> = ({
20
+ startFrame,
21
+ text,
22
+ fontSize = 96,
23
+ color = palette.heading,
24
+ italic = false,
25
+ reduceMotion = false,
26
+ style,
27
+ }) => {
28
+ const frame = useCurrentFrame();
29
+ const local = Math.max(0, frame - startFrame);
30
+ const tRaw = Math.min(1, local / 24);
31
+ const t = reduceMotion ? 1 : ease.power3Out(tRaw);
32
+ return (
33
+ <span
34
+ style={{
35
+ display: "inline-block",
36
+ fontFamily: "'Lyon Text', 'Newsreader', 'Playfair Display', Georgia, serif",
37
+ fontSize,
38
+ fontWeight: 500,
39
+ fontStyle: italic ? "italic" : "normal",
40
+ letterSpacing: -1,
41
+ lineHeight: 1.05,
42
+ color,
43
+ opacity: t,
44
+ transform: reduceMotion ? "none" : `translateY(${(1 - t) * 12}px) scale(${0.97 + t * 0.03})`,
45
+ ...style,
46
+ }}
47
+ >
48
+ {text}
49
+ </span>
50
+ );
51
+ };
@@ -0,0 +1,10 @@
1
+ import { CardSpring } from "./CardSpring";
2
+
3
+ /**
4
+ * GreenAccentCard — semantic alias of `CardSpring`.
5
+ *
6
+ * Some Cream Paper presets reference the spring-revealed forest-green card by
7
+ * the more descriptive `GreenAccentCard` name. Both names resolve to the same
8
+ * component so preset metadata can use whichever reads better in context.
9
+ */
10
+ export const GreenAccentCard = CardSpring;
@@ -0,0 +1,30 @@
1
+ import React, { CSSProperties, ReactNode } from "react";
2
+ import { paperShadow } from "../palette";
3
+
4
+ /**
5
+ * PaperShadow — wrapper that applies one of the family's three printed-shadow
6
+ * stacks to its children.
7
+ *
8
+ * Depths:
9
+ * - "soft" — page-level lift, used under inline thumbnails
10
+ * - "card" — default, matches `CardSpring`
11
+ * - "elevated" — anchor-scene cards that need a second layer of depth
12
+ *
13
+ * The shadow is applied via inline `boxShadow`, so the wrapped element should
14
+ * be the visual surface (a div with a background and borderRadius). Wrapping
15
+ * a transparent fragment will cast no shadow.
16
+ */
17
+ export const PaperShadow: React.FC<{
18
+ depth?: "soft" | "card" | "elevated";
19
+ style?: CSSProperties;
20
+ children?: ReactNode;
21
+ }> = ({ depth = "card", style, children }) => (
22
+ <div
23
+ style={{
24
+ boxShadow: paperShadow[depth],
25
+ ...style,
26
+ }}
27
+ >
28
+ {children}
29
+ </div>
30
+ );