@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.
- package/LICENSE +128 -0
- package/README.md +125 -0
- package/cli/beats.js +124 -0
- package/cli/bootstrap.js +124 -0
- package/cli/capture.js +34 -0
- package/cli/direction.js +114 -0
- package/cli/icons.js +49 -0
- package/cli/index.js +101 -0
- package/cli/init.js +253 -0
- package/cli/license.js +168 -0
- package/cli/lint.js +865 -0
- package/cli/preview.js +59 -0
- package/cli/render.js +404 -0
- package/cli/scaffold.js +239 -0
- package/cli/smoke.js +76 -0
- package/cli/update.js +26 -0
- package/cli/utils.js +184 -0
- package/docs/buyers-guide.md +220 -0
- package/docs/design-discipline.md +130 -0
- package/docs/family-galleries/dark.md +95 -0
- package/docs/family-galleries/forbidden.md +78 -0
- package/docs/family-galleries/glass.md +98 -0
- package/docs/family-galleries/paper.md +82 -0
- package/docs/family-galleries/warm.md +86 -0
- package/docs/superpowers/plans/2026-05-09-reelstack-init-readiness-gate.md +1166 -0
- package/docs/superpowers/specs/2026-05-09-reelstack-init-readiness-gate-design.md +233 -0
- package/families/dark/components/DriftingSpotlights.tsx +59 -0
- package/families/dark/components/FilmGrain.tsx +44 -0
- package/families/dark/components/ForestCard.tsx +43 -0
- package/families/dark/components/GridBackground.tsx +29 -0
- package/families/dark/components/RadialVignette.tsx +21 -0
- package/families/dark/components/Scanlines.tsx +35 -0
- package/families/dark/components/SegmentOpacity.ts +37 -0
- package/families/dark/components/index.ts +13 -0
- package/families/dark/index.ts +31 -0
- package/families/dark/palette.ts +98 -0
- package/families/dark/presets/claudedispatch.ts +46 -0
- package/families/dark/presets/codedrop.ts +37 -0
- package/families/dark/presets/gpt55.ts +54 -0
- package/families/dark/presets/notebooklm.ts +50 -0
- package/families/dark/presets/resourcescta.ts +35 -0
- package/families/dark/presets/skills.ts +40 -0
- package/families/dark/presets/stitch.ts +46 -0
- package/families/dark/presets/stitch2.ts +43 -0
- package/families/dark/typography.ts +16 -0
- package/families/forbidden/components/ForbiddenCausticBlobs.tsx +52 -0
- package/families/forbidden/components/NewsprintTexture.tsx +28 -0
- package/families/forbidden/components/TintedShadow.tsx +36 -0
- package/families/forbidden/components/index.ts +38 -0
- package/families/forbidden/index.ts +17 -0
- package/families/forbidden/palette.ts +88 -0
- package/families/forbidden/presets/heretic.ts +44 -0
- package/families/forbidden/typography.ts +18 -0
- package/families/glass/components/BreakdownCard.tsx +158 -0
- package/families/glass/components/CausticBlobs.tsx +49 -0
- package/families/glass/components/Counter.tsx +72 -0
- package/families/glass/components/EyebrowPill.tsx +59 -0
- package/families/glass/components/FilmStrip.tsx +202 -0
- package/families/glass/components/FloatingGlyphs.tsx +78 -0
- package/families/glass/components/GlassCard.tsx +58 -0
- package/families/glass/components/GlassCardBezel.tsx +45 -0
- package/families/glass/components/HairlineGrid.tsx +30 -0
- package/families/glass/components/IridescentRing.tsx +114 -0
- package/families/glass/components/IridescentText.tsx +98 -0
- package/families/glass/components/LightBeam.tsx +46 -0
- package/families/glass/components/ParticleBurst.tsx +62 -0
- package/families/glass/components/SonarRings.tsx +81 -0
- package/families/glass/components/StaggeredWords.tsx +74 -0
- package/families/glass/components/index.ts +20 -0
- package/families/glass/index.ts +31 -0
- package/families/glass/palette.ts +93 -0
- package/families/glass/presets/claudewatch.ts +64 -0
- package/families/glass/presets/claudewatchcta.ts +43 -0
- package/families/glass/presets/graphify.ts +45 -0
- package/families/glass/presets/gstack.ts +48 -0
- package/families/glass/presets/jcode.ts +50 -0
- package/families/glass/presets/lilagents.ts +52 -0
- package/families/glass/presets/paperclip.ts +43 -0
- package/families/glass/typography.ts +15 -0
- package/families/index.ts +49 -0
- package/families/paper/components/CardSpring.tsx +42 -0
- package/families/paper/components/CreamGrid.tsx +26 -0
- package/families/paper/components/EditorialSerifText.tsx +51 -0
- package/families/paper/components/GreenAccentCard.tsx +10 -0
- package/families/paper/components/PaperShadow.tsx +30 -0
- package/families/paper/components/ScaleBlurText.tsx +40 -0
- package/families/paper/components/index.ts +11 -0
- package/families/paper/index.ts +23 -0
- package/families/paper/palette.ts +102 -0
- package/families/paper/presets/designreel.ts +32 -0
- package/families/paper/presets/devini3d.ts +45 -0
- package/families/paper/presets/justdrop.ts +39 -0
- package/families/paper/presets/opus.ts +48 -0
- package/families/paper/typography.ts +17 -0
- package/families/warm/components/AccentGlow.tsx +60 -0
- package/families/warm/components/BentoCell.tsx +56 -0
- package/families/warm/components/BentoGrid.tsx +30 -0
- package/families/warm/components/FilmGrain.tsx +36 -0
- package/families/warm/components/ScaleBlurCounter.tsx +71 -0
- package/families/warm/components/WarmSurface.tsx +35 -0
- package/families/warm/components/index.ts +11 -0
- package/families/warm/index.ts +19 -0
- package/families/warm/palette.ts +81 -0
- package/families/warm/presets/huashu.ts +49 -0
- package/families/warm/presets/mempalace.ts +51 -0
- package/families/warm/typography.ts +17 -0
- package/package.json +85 -0
- package/reference/dark/claudedispatch.tsx +2441 -0
- package/reference/dark/notebooklm.tsx +2316 -0
- package/reference/dark/stitch.tsx +3040 -0
- package/reference/forbidden/heretic.tsx +2636 -0
- package/reference/glass/claudewatch.tsx +3827 -0
- package/reference/glass/graphify.tsx +2418 -0
- package/reference/glass/paperclip.tsx +2218 -0
- package/reference/paper/designreel.tsx +883 -0
- package/reference/paper/justdrop.tsx +1898 -0
- package/reference/paper/opus.tsx +1770 -0
- package/reference/warm/huashu.tsx +3413 -0
- package/reference/warm/mempalace.tsx +2909 -0
- package/skill/SKILL.md +229 -0
- package/skill/commands/reelstack-beats.md +20 -0
- package/skill/commands/reelstack-capture.md +24 -0
- package/skill/commands/reelstack-critique.md +15 -0
- package/skill/commands/reelstack-dark.md +40 -0
- package/skill/commands/reelstack-direction.md +17 -0
- package/skill/commands/reelstack-forbidden.md +25 -0
- package/skill/commands/reelstack-glass.md +39 -0
- package/skill/commands/reelstack-icons.md +22 -0
- package/skill/commands/reelstack-init.md +17 -0
- package/skill/commands/reelstack-lint.md +22 -0
- package/skill/commands/reelstack-paper.md +36 -0
- package/skill/commands/reelstack-render.md +20 -0
- package/skill/commands/reelstack-warm.md +36 -0
- package/templates/dark/template.tsx +115 -0
- package/templates/forbidden/template.tsx +111 -0
- package/templates/glass/template.tsx +201 -0
- package/templates/paper/template.tsx +133 -0
- package/templates/warm/template.tsx +210 -0
- package/utils/ai-purple-blocklist.ts +13 -0
- package/utils/banned-fonts.ts +11 -0
- package/utils/cubic-bezier.ts +36 -0
- package/utils/easing.ts +84 -0
- package/utils/grid.ts +13 -0
- package/utils/render-presets.json +56 -0
- package/utils/safe-zones.tsx +57 -0
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { useCurrentFrame } from "remotion";
|
|
3
|
+
import { palette } from "../palette";
|
|
4
|
+
import { ease } from "../../../utils/easing";
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* ScaleBlurText — hero text with a power4Out scale + blur entrance.
|
|
8
|
+
*
|
|
9
|
+
* Over 30 frames the glyphs scale 0.94 → 1.0 and blur 10px → 0 while opacity
|
|
10
|
+
* runs the eased curve. This is the Cream Paper family's signature title
|
|
11
|
+
* reveal — pair it with `CardSpring` body cards downstream.
|
|
12
|
+
*/
|
|
13
|
+
export const ScaleBlurText: React.FC<{
|
|
14
|
+
startFrame: number;
|
|
15
|
+
text: string;
|
|
16
|
+
size?: number;
|
|
17
|
+
color?: string;
|
|
18
|
+
reduceMotion?: boolean;
|
|
19
|
+
}> = ({ startFrame, text, size = 84, color = palette.heading, reduceMotion = false }) => {
|
|
20
|
+
const frame = useCurrentFrame();
|
|
21
|
+
const local = Math.max(0, frame - startFrame);
|
|
22
|
+
const t = reduceMotion ? 1 : ease.power4Out(Math.min(1, local / 30));
|
|
23
|
+
return (
|
|
24
|
+
<span
|
|
25
|
+
style={{
|
|
26
|
+
display: "inline-block",
|
|
27
|
+
fontFamily: "Geist, system-ui",
|
|
28
|
+
fontSize: size,
|
|
29
|
+
fontWeight: 700,
|
|
30
|
+
letterSpacing: -1.5,
|
|
31
|
+
color,
|
|
32
|
+
opacity: t,
|
|
33
|
+
transform: reduceMotion ? "none" : `scale(${0.94 + t * 0.06})`,
|
|
34
|
+
filter: reduceMotion ? "none" : `blur(${(1 - t) * 10}px)`,
|
|
35
|
+
}}
|
|
36
|
+
>
|
|
37
|
+
{text}
|
|
38
|
+
</span>
|
|
39
|
+
);
|
|
40
|
+
};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cream Paper — primitive components index.
|
|
3
|
+
* Scaffold templates import from here:
|
|
4
|
+
* import { CardSpring, ScaleBlurText, ... } from "@devinilabs/reelstack/families/paper/components";
|
|
5
|
+
*/
|
|
6
|
+
export { CardSpring } from "./CardSpring";
|
|
7
|
+
export { ScaleBlurText } from "./ScaleBlurText";
|
|
8
|
+
export { CreamGrid } from "./CreamGrid";
|
|
9
|
+
export { GreenAccentCard } from "./GreenAccentCard";
|
|
10
|
+
export { PaperShadow } from "./PaperShadow";
|
|
11
|
+
export { EditorialSerifText } from "./EditorialSerifText";
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cream Paper — family index.
|
|
3
|
+
*/
|
|
4
|
+
export { palette, safeZones, springConfig, paperShadow } from "./palette";
|
|
5
|
+
export type { PaperPalette } from "./palette";
|
|
6
|
+
|
|
7
|
+
import { preset as justdrop } from "./presets/justdrop";
|
|
8
|
+
import { preset as opus } from "./presets/opus";
|
|
9
|
+
import { preset as designreel } from "./presets/designreel";
|
|
10
|
+
import { preset as devini3d } from "./presets/devini3d";
|
|
11
|
+
|
|
12
|
+
export const presets = {
|
|
13
|
+
justdrop,
|
|
14
|
+
opus,
|
|
15
|
+
designreel,
|
|
16
|
+
devini3d,
|
|
17
|
+
} as const;
|
|
18
|
+
|
|
19
|
+
export const family = {
|
|
20
|
+
name: "paper",
|
|
21
|
+
label: "Cream Paper",
|
|
22
|
+
presets: Object.keys(presets) as Array<keyof typeof presets>,
|
|
23
|
+
} as const;
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ReelStack — Cream Paper palette
|
|
3
|
+
*
|
|
4
|
+
* Verified against /Users/abhishekraj/my-video/src/JustDropReel.tsx and
|
|
5
|
+
* OpusReel.tsx.
|
|
6
|
+
*
|
|
7
|
+
* Mood: editorial print. Warm, document-like, with depth in the dark-green
|
|
8
|
+
* card stack.
|
|
9
|
+
*/
|
|
10
|
+
export const palette = {
|
|
11
|
+
// Backgrounds — warm cream paper
|
|
12
|
+
bg: "#f0ede8",
|
|
13
|
+
bgWarm: "#e8e4de",
|
|
14
|
+
bgLight: "#edeae4",
|
|
15
|
+
paperGrid: "#e5e2dd",
|
|
16
|
+
|
|
17
|
+
// Light-mode text
|
|
18
|
+
heading: "#1a1a1a", // contrast 15.6:1 on bg #f0ede8 — WCAG AAA
|
|
19
|
+
body: "#2d2d2d", // contrast 11.6:1 on bg #f0ede8 — WCAG AAA
|
|
20
|
+
muted: "#6b6b6b", // contrast 4.8:1 on bg #f0ede8 — WCAG AA
|
|
21
|
+
|
|
22
|
+
// Dark-green card stack — the family's depth move
|
|
23
|
+
cardForest: "#1e3a27",
|
|
24
|
+
cardForestLift: "#2d4433",
|
|
25
|
+
cardForestDeep: "#142318",
|
|
26
|
+
cardForestBody: "#c9d1c5", // muted body text on cardForest (~8:1 contrast — WCAG AA)
|
|
27
|
+
|
|
28
|
+
// Accents
|
|
29
|
+
accent: "#D4663A", // Claude terracotta
|
|
30
|
+
accentDark: "#1e3a27",
|
|
31
|
+
danger: "#c0392b",
|
|
32
|
+
success: "#1e7a45",
|
|
33
|
+
|
|
34
|
+
// Terminal / code embeds (used in OpusReel / Devini3DReel)
|
|
35
|
+
terminalGreen: "#5be8a0",
|
|
36
|
+
terminalCaret: "#9B6B4F",
|
|
37
|
+
|
|
38
|
+
// Macro-window dots (for UI screenshots embedded in cards)
|
|
39
|
+
macClose: "#ff5f57",
|
|
40
|
+
macMin: "#febb2e",
|
|
41
|
+
macMax: "#28c840",
|
|
42
|
+
} as const;
|
|
43
|
+
|
|
44
|
+
export const safeZones = {
|
|
45
|
+
top: 290,
|
|
46
|
+
bottom: 1500,
|
|
47
|
+
canvas: { width: 1080, height: 1920 },
|
|
48
|
+
} as const;
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Spring config used by every Cream Paper card reveal. Different from Glass
|
|
52
|
+
* (gentler, more editorial) — never override these in a paper preset without
|
|
53
|
+
* a deliberate reason.
|
|
54
|
+
*/
|
|
55
|
+
export const springConfig = {
|
|
56
|
+
damping: 20,
|
|
57
|
+
stiffness: 200,
|
|
58
|
+
mass: 1,
|
|
59
|
+
} as const;
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Paper-shadow stack — multi-layer to feel printed, not digital.
|
|
63
|
+
*/
|
|
64
|
+
export const paperShadow = {
|
|
65
|
+
soft: "0 1px 2px rgba(26,26,26,0.04), 0 4px 12px rgba(26,26,26,0.06)",
|
|
66
|
+
card: "0 2px 4px rgba(26,26,26,0.06), 0 12px 28px rgba(26,26,26,0.10)",
|
|
67
|
+
elevated: "0 8px 16px rgba(26,26,26,0.08), 0 32px 60px rgba(26,26,26,0.14)",
|
|
68
|
+
} as const;
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Hard-coded "allowed accents" list. The lint command checks every fill /
|
|
72
|
+
* stroke / background color in a Cream Paper reel against this set.
|
|
73
|
+
* Includes neutral text colors + the dark-green card stack + the terracotta
|
|
74
|
+
* accent + semantic success/danger + terminal green for embedded code.
|
|
75
|
+
*/
|
|
76
|
+
export const ALLOWED_ACCENTS = [
|
|
77
|
+
palette.heading,
|
|
78
|
+
palette.body,
|
|
79
|
+
palette.muted,
|
|
80
|
+
palette.cardForest,
|
|
81
|
+
palette.cardForestLift,
|
|
82
|
+
palette.cardForestBody,
|
|
83
|
+
palette.accent,
|
|
84
|
+
palette.accentDark,
|
|
85
|
+
palette.success,
|
|
86
|
+
palette.danger,
|
|
87
|
+
palette.terminalGreen,
|
|
88
|
+
] as const;
|
|
89
|
+
|
|
90
|
+
export type PaperPalette = typeof palette;
|
|
91
|
+
|
|
92
|
+
/** Re-export grid units so consumers can pull them from the family entrypoint. */
|
|
93
|
+
export {
|
|
94
|
+
GRID,
|
|
95
|
+
GRID_2,
|
|
96
|
+
GRID_4,
|
|
97
|
+
GRID_6,
|
|
98
|
+
GRID_8,
|
|
99
|
+
GRID_12,
|
|
100
|
+
GRID_16,
|
|
101
|
+
GRID_24,
|
|
102
|
+
} from "../../utils/grid";
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Preset: designreel (Cream Paper)
|
|
3
|
+
* Source: DesignReel.tsx
|
|
4
|
+
*
|
|
5
|
+
* Ultra-short 10-second teaser. Compressed beats. Designed as a promotional
|
|
6
|
+
* clip — high-energy, single message, fast in/out.
|
|
7
|
+
*/
|
|
8
|
+
export const preset = {
|
|
9
|
+
name: "designreel",
|
|
10
|
+
family: "paper",
|
|
11
|
+
source: "DesignReel",
|
|
12
|
+
durationFrames: 300,
|
|
13
|
+
fps: 30,
|
|
14
|
+
copy: {
|
|
15
|
+
hook: "Describe it. Get it.",
|
|
16
|
+
sub: "Design at the speed of thought.",
|
|
17
|
+
},
|
|
18
|
+
accents: {},
|
|
19
|
+
beats: {
|
|
20
|
+
hook: 0,
|
|
21
|
+
tagline: 120,
|
|
22
|
+
cta: 210,
|
|
23
|
+
end: 300,
|
|
24
|
+
},
|
|
25
|
+
primitives: [
|
|
26
|
+
"CardSpring",
|
|
27
|
+
"ScaleBlurText",
|
|
28
|
+
"CreamGrid",
|
|
29
|
+
],
|
|
30
|
+
notes:
|
|
31
|
+
"Frame budget is tight (300f total). Use the compressed-beat structure: 4s hook, 3s tagline, 3s CTA. Anchor scenes still need 3+ motion layers — do not let the tight budget cut energy.",
|
|
32
|
+
} as const;
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Preset: devini3d (Cream Paper)
|
|
3
|
+
* Source: Devini3DReel.tsx
|
|
4
|
+
*
|
|
5
|
+
* Showcase reel for a 3D-website-in-an-hour build. Hero clip plays full-frame
|
|
6
|
+
* for 31 seconds, then motion graphics take over for the closing 8 seconds.
|
|
7
|
+
*/
|
|
8
|
+
export const preset = {
|
|
9
|
+
name: "devini3d",
|
|
10
|
+
family: "paper",
|
|
11
|
+
source: "Devini3DReel",
|
|
12
|
+
durationFrames: 1170,
|
|
13
|
+
fps: 30,
|
|
14
|
+
copy: {
|
|
15
|
+
hook: "Built a 3D website in an hour.",
|
|
16
|
+
sub: "Custom Claude skill end-to-end.",
|
|
17
|
+
cta: "Skill link below.",
|
|
18
|
+
},
|
|
19
|
+
accents: {},
|
|
20
|
+
beats: {
|
|
21
|
+
clipIn: 0,
|
|
22
|
+
clipOut: 915, // hero.mp4 fade-out crossfade starts at 30.5s
|
|
23
|
+
motionGraphics: 930,
|
|
24
|
+
pipelineViz: 990,
|
|
25
|
+
breadthCallout: 1080,
|
|
26
|
+
cta: 1140,
|
|
27
|
+
end: 1170,
|
|
28
|
+
},
|
|
29
|
+
primitives: [
|
|
30
|
+
"CardSpring",
|
|
31
|
+
"ScaleBlurText",
|
|
32
|
+
"CreamGrid",
|
|
33
|
+
"GreenAccentCard",
|
|
34
|
+
"PaperShadow",
|
|
35
|
+
"OffthreadVideoLetterbox", // preset-specific — letterbox 2304×1440 → 1080×675
|
|
36
|
+
],
|
|
37
|
+
embeddedClip: {
|
|
38
|
+
path: "captures/devini3d/hero.mp4",
|
|
39
|
+
sequenceStart: 0,
|
|
40
|
+
durationFrames: 915,
|
|
41
|
+
aspect: "letterbox", // 2304×1440 source → centered 1080×675 in 1080×1920 frame
|
|
42
|
+
},
|
|
43
|
+
notes:
|
|
44
|
+
"Clip plays first, motion graphics close out. Crossfade clip→motion at frame 915 (15-frame overlap). Pipeline visualization in the closing 8s should mirror the family's GreenAccentCard stack.",
|
|
45
|
+
} as const;
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Preset: justdrop (Cream Paper)
|
|
3
|
+
* Source: JustDropReel.tsx
|
|
4
|
+
*
|
|
5
|
+
* Skill-ecosystem launch reel. Cream paper background with dark-green card
|
|
6
|
+
* stack. Card-spring reveals carry the family's signature.
|
|
7
|
+
*/
|
|
8
|
+
export const preset = {
|
|
9
|
+
name: "justdrop",
|
|
10
|
+
family: "paper",
|
|
11
|
+
source: "JustDropReel",
|
|
12
|
+
durationFrames: 1760,
|
|
13
|
+
fps: 30,
|
|
14
|
+
copy: {
|
|
15
|
+
hook: "Using Claude Code and missing the point.",
|
|
16
|
+
sub: "JustDrop — 1000+ free skills. Works everywhere.",
|
|
17
|
+
cta: "npm install, free.",
|
|
18
|
+
},
|
|
19
|
+
accents: {},
|
|
20
|
+
beats: {
|
|
21
|
+
hook: 0,
|
|
22
|
+
problem: 225,
|
|
23
|
+
nameDrop: 555,
|
|
24
|
+
skills: 885,
|
|
25
|
+
everywhere: 1125,
|
|
26
|
+
install: 1395,
|
|
27
|
+
cta: 1605,
|
|
28
|
+
end: 1755,
|
|
29
|
+
},
|
|
30
|
+
primitives: [
|
|
31
|
+
"CardSpring",
|
|
32
|
+
"ScaleBlurText",
|
|
33
|
+
"CreamGrid",
|
|
34
|
+
"GreenAccentCard",
|
|
35
|
+
"PaperShadow",
|
|
36
|
+
],
|
|
37
|
+
notes:
|
|
38
|
+
"Card springs use the family's default damping 20 / stiffness 200. Cream-paper bg is non-negotiable — light text on cream is the family contract.",
|
|
39
|
+
} as const;
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Preset: opus (Cream Paper)
|
|
3
|
+
* Source: OpusReel.tsx
|
|
4
|
+
*
|
|
5
|
+
* Thesis-driven 111-second reel — the longest in the catalog. Embedded
|
|
6
|
+
* benchmark screenshots, agents.md card integrations, half-step theory
|
|
7
|
+
* narrative. Cream paper aesthetic with screenshot fade sequences.
|
|
8
|
+
*/
|
|
9
|
+
export const preset = {
|
|
10
|
+
name: "opus",
|
|
11
|
+
family: "paper",
|
|
12
|
+
source: "OpusReel",
|
|
13
|
+
durationFrames: 3330,
|
|
14
|
+
fps: 30,
|
|
15
|
+
copy: {
|
|
16
|
+
hook: "Opus 4.7 just dropped.",
|
|
17
|
+
sub: "The half-step theory. Stop switching models and ship.",
|
|
18
|
+
cta: "Read the thesis below.",
|
|
19
|
+
},
|
|
20
|
+
accents: {
|
|
21
|
+
danger: "#c0392b",
|
|
22
|
+
success: "#1e7a45",
|
|
23
|
+
},
|
|
24
|
+
beats: {
|
|
25
|
+
hook: 0,
|
|
26
|
+
drop: 240,
|
|
27
|
+
benchmarks: 540,
|
|
28
|
+
halfStep: 840,
|
|
29
|
+
zeroToOne: 1140,
|
|
30
|
+
thesis: 1560,
|
|
31
|
+
agentsMd: 1800,
|
|
32
|
+
workflow: 2160,
|
|
33
|
+
ship: 2460,
|
|
34
|
+
cta: 2760,
|
|
35
|
+
end: 3060,
|
|
36
|
+
},
|
|
37
|
+
primitives: [
|
|
38
|
+
"CardSpring",
|
|
39
|
+
"ScaleBlurText",
|
|
40
|
+
"CreamGrid",
|
|
41
|
+
"GreenAccentCard",
|
|
42
|
+
"PaperShadow",
|
|
43
|
+
"ScreenshotFade", // preset-specific — screenshot fade-in/fade-out sequences
|
|
44
|
+
],
|
|
45
|
+
embeddedScreenshots: 5,
|
|
46
|
+
notes:
|
|
47
|
+
"Five screenshot sequences (benchmarks, agents.md, workflow examples). Each fades in over 12 frames, holds, fades out 18 frames. Don't replace screenshots with hand-drawn UI — buyer should /reelstack-capture them.",
|
|
48
|
+
} as const;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/** Cream Paper typography scale. Geist Sans + Geist Mono primary; editorial serif
|
|
2
|
+
* (Lyon Text / Newsreader) is allowed via variant overlays for headings only.
|
|
3
|
+
* Pulled from existing template usage (BodyScene uses h1 88, h2 48); locks the
|
|
4
|
+
* implicit scale into named tokens. Text colors come from palette
|
|
5
|
+
* (heading/body/muted) — never embed colors in typography tokens.
|
|
6
|
+
*/
|
|
7
|
+
export const typography = {
|
|
8
|
+
hero: { fontSize: 96, fontWeight: 700, letterSpacing: -2, lineHeight: 1.05, fontFamily: "Geist, system-ui" },
|
|
9
|
+
h1: { fontSize: 88, fontWeight: 700, letterSpacing: -1.5, lineHeight: 1.1, fontFamily: "Geist, system-ui" },
|
|
10
|
+
h2: { fontSize: 48, fontWeight: 700, letterSpacing: -1.2, lineHeight: 1.15, fontFamily: "Geist, system-ui" },
|
|
11
|
+
h3: { fontSize: 36, fontWeight: 600, letterSpacing: -1, lineHeight: 1.2, fontFamily: "Geist, system-ui" },
|
|
12
|
+
body: { fontSize: 24, fontWeight: 500, letterSpacing: -0.2, lineHeight: 1.5, fontFamily: "Geist, system-ui" },
|
|
13
|
+
caption: { fontSize: 18, fontWeight: 500, letterSpacing: 0.5, lineHeight: 1.4, fontFamily: "Geist, system-ui", textTransform: "uppercase" as const },
|
|
14
|
+
mono: { fontSize: 22, fontWeight: 500, letterSpacing: 0.3, lineHeight: 1.4, fontFamily: "Geist Mono, monospace" },
|
|
15
|
+
counter: { fontSize: 144, fontWeight: 700, letterSpacing: -2, lineHeight: 1, fontFamily: "Geist Mono, monospace" },
|
|
16
|
+
} as const;
|
|
17
|
+
export type Typography = typeof typography;
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { AbsoluteFill, useCurrentFrame } from "remotion";
|
|
3
|
+
import { palette } from "../palette";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* AccentGlow — amber radial glow that breathes.
|
|
7
|
+
*
|
|
8
|
+
* Background ambient layer for every Warm Signature scene. Sine-wave on
|
|
9
|
+
* opacity drives a slow ~5s respiration (period = 2π / 0.04 ≈ 157 frames
|
|
10
|
+
* @ 30fps). Mix-blend `screen` lifts the scene without flattening the
|
|
11
|
+
* warm zinc base; 60px blur keeps it diffuse.
|
|
12
|
+
*
|
|
13
|
+
* Frame-budget: cheap. One absolutely-positioned radial-gradient div.
|
|
14
|
+
*
|
|
15
|
+
* Pair with `<FilmGrain />` immediately after to dirty up the highlight
|
|
16
|
+
* before any foreground content is drawn.
|
|
17
|
+
*/
|
|
18
|
+
export const AccentGlow: React.FC<{
|
|
19
|
+
cx?: string;
|
|
20
|
+
cy?: string;
|
|
21
|
+
size?: number;
|
|
22
|
+
baseOpacity?: number; // mid-point of the breathing wave
|
|
23
|
+
swing?: number; // amplitude — total opacity range = 2 × swing
|
|
24
|
+
period?: number; // radians per frame; default 0.04 ≈ 5s cycle
|
|
25
|
+
color?: string;
|
|
26
|
+
glowAlpha?: string; // 2-char hex for radial-gradient inner stop
|
|
27
|
+
reduceMotion?: boolean;
|
|
28
|
+
}> = ({
|
|
29
|
+
cx = "50%",
|
|
30
|
+
cy = "30%",
|
|
31
|
+
size = 1400,
|
|
32
|
+
baseOpacity = 0.4,
|
|
33
|
+
swing = 0.15,
|
|
34
|
+
period = 0.04,
|
|
35
|
+
color = palette.amber,
|
|
36
|
+
glowAlpha = "33", // 20% — matches palette.amberGlow rgba alpha
|
|
37
|
+
reduceMotion = false,
|
|
38
|
+
}) => {
|
|
39
|
+
const frame = useCurrentFrame();
|
|
40
|
+
const intensity = reduceMotion ? baseOpacity : baseOpacity + Math.sin(frame * period) * swing;
|
|
41
|
+
return (
|
|
42
|
+
<AbsoluteFill style={{ pointerEvents: "none" }}>
|
|
43
|
+
<div
|
|
44
|
+
style={{
|
|
45
|
+
position: "absolute",
|
|
46
|
+
left: cx,
|
|
47
|
+
top: cy,
|
|
48
|
+
width: size,
|
|
49
|
+
height: size,
|
|
50
|
+
marginLeft: -size / 2,
|
|
51
|
+
marginTop: -size / 2,
|
|
52
|
+
background: `radial-gradient(circle, ${color}${glowAlpha} 0%, transparent 55%)`,
|
|
53
|
+
filter: "blur(60px)",
|
|
54
|
+
mixBlendMode: "screen",
|
|
55
|
+
opacity: intensity,
|
|
56
|
+
}}
|
|
57
|
+
/>
|
|
58
|
+
</AbsoluteFill>
|
|
59
|
+
);
|
|
60
|
+
};
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import React, { CSSProperties, ReactNode } from "react";
|
|
2
|
+
import { spring, useCurrentFrame, useVideoConfig } from "remotion";
|
|
3
|
+
import { palette } from "../palette";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* BentoCell — single cell with snappy spring entrance + amber-deep border.
|
|
7
|
+
*
|
|
8
|
+
* Spring config: damping 20, stiffness 200 — the "snappy" preset from
|
|
9
|
+
* utils/easing. Drives a translateY(20px) → 0, scale 0.96 → 1.0,
|
|
10
|
+
* opacity 0 → 1 entrance.
|
|
11
|
+
*
|
|
12
|
+
* Stagger cells by passing different `startFrame` values (e.g.
|
|
13
|
+
* `startFrame={i * 6}` to fire one cell every ~200ms).
|
|
14
|
+
*/
|
|
15
|
+
export const BentoCell: React.FC<{
|
|
16
|
+
startFrame: number;
|
|
17
|
+
idx?: number;
|
|
18
|
+
reduceMotion?: boolean;
|
|
19
|
+
style?: CSSProperties;
|
|
20
|
+
children?: ReactNode;
|
|
21
|
+
}> = ({ startFrame, idx, reduceMotion = false, style, children }) => {
|
|
22
|
+
const frame = useCurrentFrame();
|
|
23
|
+
const { fps } = useVideoConfig();
|
|
24
|
+
const local = Math.max(0, frame - startFrame);
|
|
25
|
+
const t = reduceMotion
|
|
26
|
+
? 1
|
|
27
|
+
: spring({ frame: local, fps, config: { damping: 20, stiffness: 200 } });
|
|
28
|
+
|
|
29
|
+
return (
|
|
30
|
+
<div
|
|
31
|
+
style={{
|
|
32
|
+
background: palette.surface,
|
|
33
|
+
color: palette.fg,
|
|
34
|
+
border: `1px solid ${palette.amberDeep}`,
|
|
35
|
+
borderRadius: 18,
|
|
36
|
+
padding: 24,
|
|
37
|
+
opacity: t,
|
|
38
|
+
transform: reduceMotion
|
|
39
|
+
? "none"
|
|
40
|
+
: `translateY(${(1 - t) * 20}px) scale(${0.96 + t * 0.04})`,
|
|
41
|
+
...style,
|
|
42
|
+
}}
|
|
43
|
+
>
|
|
44
|
+
{children ?? (
|
|
45
|
+
<>
|
|
46
|
+
<span style={{ fontSize: 22, fontWeight: 600, color: palette.amber }}>
|
|
47
|
+
FEATURE {idx ?? ""}
|
|
48
|
+
</span>
|
|
49
|
+
<p style={{ fontSize: 20, color: palette.fgSoft, marginTop: 8 }}>
|
|
50
|
+
Bento cell — replace with your callout.
|
|
51
|
+
</p>
|
|
52
|
+
</>
|
|
53
|
+
)}
|
|
54
|
+
</div>
|
|
55
|
+
);
|
|
56
|
+
};
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import React, { CSSProperties, ReactNode } from "react";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* BentoGrid — container for the Warm family's signature bento layout.
|
|
5
|
+
*
|
|
6
|
+
* Plain CSS grid, equal-fraction columns, tight 18px gutter. Drop any
|
|
7
|
+
* number of `<BentoCell />` children inside; each cell handles its own
|
|
8
|
+
* spring entrance.
|
|
9
|
+
*
|
|
10
|
+
* Default 2 columns, 18px gap. Override `cols` to 3 for tighter feature
|
|
11
|
+
* matrices, or 1 to stack callouts vertically.
|
|
12
|
+
*/
|
|
13
|
+
export const BentoGrid: React.FC<{
|
|
14
|
+
cols?: number;
|
|
15
|
+
gap?: number;
|
|
16
|
+
style?: CSSProperties;
|
|
17
|
+
children?: ReactNode;
|
|
18
|
+
}> = ({ cols = 2, gap = 18, style, children }) => (
|
|
19
|
+
<div
|
|
20
|
+
style={{
|
|
21
|
+
display: "grid",
|
|
22
|
+
gridTemplateColumns: `repeat(${cols}, 1fr)`,
|
|
23
|
+
gap,
|
|
24
|
+
alignContent: "start",
|
|
25
|
+
...style,
|
|
26
|
+
}}
|
|
27
|
+
>
|
|
28
|
+
{children}
|
|
29
|
+
</div>
|
|
30
|
+
);
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { AbsoluteFill } from "remotion";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* FilmGrain — SVG turbulence noise overlay at 6% opacity, multiply blend.
|
|
6
|
+
*
|
|
7
|
+
* Stamps subtle film-stock texture across the canvas so digital gradients
|
|
8
|
+
* never read as flat. The Warm Signature family runs warm-zinc surfaces
|
|
9
|
+
* that look plastic without grain — this is non-optional ambient.
|
|
10
|
+
*
|
|
11
|
+
* Frame-budget: zero per-frame cost. The turbulence pattern is deterministic
|
|
12
|
+
* and rendered once by the SVG filter; only the static `<rect>` is composited.
|
|
13
|
+
*
|
|
14
|
+
* Always render this AFTER `<AccentGlow />` and BEFORE any foreground scene
|
|
15
|
+
* so the multiply blend tints the glow rather than punching through it.
|
|
16
|
+
*/
|
|
17
|
+
export const FilmGrain: React.FC<{
|
|
18
|
+
opacity?: number;
|
|
19
|
+
baseFrequency?: number;
|
|
20
|
+
numOctaves?: number;
|
|
21
|
+
}> = ({ opacity = 0.06, baseFrequency = 0.9, numOctaves = 2 }) => (
|
|
22
|
+
<AbsoluteFill
|
|
23
|
+
style={{
|
|
24
|
+
pointerEvents: "none",
|
|
25
|
+
opacity,
|
|
26
|
+
mixBlendMode: "multiply",
|
|
27
|
+
}}
|
|
28
|
+
>
|
|
29
|
+
<svg width="100%" height="100%">
|
|
30
|
+
<filter id="reelstack-warm-grain">
|
|
31
|
+
<feTurbulence baseFrequency={baseFrequency} numOctaves={numOctaves} />
|
|
32
|
+
</filter>
|
|
33
|
+
<rect width="100%" height="100%" filter="url(#reelstack-warm-grain)" />
|
|
34
|
+
</svg>
|
|
35
|
+
</AbsoluteFill>
|
|
36
|
+
);
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import React, { CSSProperties } from "react";
|
|
2
|
+
import { useCurrentFrame } from "remotion";
|
|
3
|
+
import { palette } from "../palette";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* ScaleBlurCounter — numeric ticker tuned for the Warm family.
|
|
7
|
+
*
|
|
8
|
+
* Mirrors Glass's `Counter` component but defaults to the amber accent and
|
|
9
|
+
* the 96–168 px size band that Warm hero shots prefer. Same power4Out
|
|
10
|
+
* easing curve so motion timing reads identical across families.
|
|
11
|
+
*
|
|
12
|
+
* House rule: 5-digit MONO counters cap at ~256px width. If you need 5
|
|
13
|
+
* digits, drop `fontSize` to 96 or pair the counter with a separate label
|
|
14
|
+
* block on its own vertical band.
|
|
15
|
+
*/
|
|
16
|
+
export const ScaleBlurCounter: React.FC<{
|
|
17
|
+
startFrame: number;
|
|
18
|
+
durationFrames?: number;
|
|
19
|
+
fromValue?: number;
|
|
20
|
+
toValue: number;
|
|
21
|
+
prefix?: string;
|
|
22
|
+
suffix?: string;
|
|
23
|
+
fontSize?: number;
|
|
24
|
+
color?: string;
|
|
25
|
+
fontFamily?: string;
|
|
26
|
+
reduceMotion?: boolean;
|
|
27
|
+
style?: CSSProperties;
|
|
28
|
+
}> = ({
|
|
29
|
+
startFrame,
|
|
30
|
+
durationFrames = 36,
|
|
31
|
+
fromValue = 0,
|
|
32
|
+
toValue,
|
|
33
|
+
prefix = "",
|
|
34
|
+
suffix = "",
|
|
35
|
+
fontSize = 144,
|
|
36
|
+
color = palette.amber,
|
|
37
|
+
fontFamily = "Geist Mono, monospace",
|
|
38
|
+
reduceMotion = false,
|
|
39
|
+
style,
|
|
40
|
+
}) => {
|
|
41
|
+
const frame = useCurrentFrame();
|
|
42
|
+
const local = Math.max(0, frame - startFrame);
|
|
43
|
+
const tRaw = Math.min(1, local / durationFrames);
|
|
44
|
+
// power4Out — matches utils/easing.ts ease.power4Out
|
|
45
|
+
const t = reduceMotion ? 1 : 1 - Math.pow(1 - tRaw, 4);
|
|
46
|
+
const value = reduceMotion ? toValue : Math.round(fromValue + (toValue - fromValue) * t);
|
|
47
|
+
const blur = reduceMotion ? 0 : (1 - t) * 12; // px
|
|
48
|
+
const scale = reduceMotion ? 1 : 0.92 + t * 0.08;
|
|
49
|
+
|
|
50
|
+
return (
|
|
51
|
+
<span
|
|
52
|
+
style={{
|
|
53
|
+
display: "inline-block",
|
|
54
|
+
fontFamily,
|
|
55
|
+
fontSize,
|
|
56
|
+
fontWeight: 700,
|
|
57
|
+
letterSpacing: -2,
|
|
58
|
+
color,
|
|
59
|
+
textShadow: `0 0 60px ${palette.amberGlow}`,
|
|
60
|
+
filter: `blur(${blur}px)`,
|
|
61
|
+
transform: `scale(${scale})`,
|
|
62
|
+
transformOrigin: "center",
|
|
63
|
+
...style,
|
|
64
|
+
}}
|
|
65
|
+
>
|
|
66
|
+
{prefix}
|
|
67
|
+
{value.toLocaleString()}
|
|
68
|
+
{suffix}
|
|
69
|
+
</span>
|
|
70
|
+
);
|
|
71
|
+
};
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import React, { CSSProperties, ReactNode } from "react";
|
|
2
|
+
import { AbsoluteFill } from "remotion";
|
|
3
|
+
import { palette } from "../palette";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* WarmSurface — full-bleed `AbsoluteFill` painted with `palette.surfaceWarm`.
|
|
7
|
+
*
|
|
8
|
+
* The family's "stage". Wraps every Warm Signature scene as the bottom-most
|
|
9
|
+
* layer. Use this instead of inlining
|
|
10
|
+
* `<AbsoluteFill style={{ background: palette.surfaceWarm }}>` so future
|
|
11
|
+
* palette tweaks (e.g. adjusting the warm-zinc base) propagate everywhere.
|
|
12
|
+
*
|
|
13
|
+
* Stack order (bottom → top):
|
|
14
|
+
* <WarmSurface>
|
|
15
|
+
* <FilmGrain /> ← multiply
|
|
16
|
+
* <AccentGlow /> ← screen
|
|
17
|
+
* <Sequence>...scenes... ← foreground
|
|
18
|
+
* <SafeZones visible={false} />
|
|
19
|
+
* </WarmSurface>
|
|
20
|
+
*/
|
|
21
|
+
export const WarmSurface: React.FC<{
|
|
22
|
+
style?: CSSProperties;
|
|
23
|
+
children?: ReactNode;
|
|
24
|
+
}> = ({ style, children }) => (
|
|
25
|
+
<AbsoluteFill
|
|
26
|
+
style={{
|
|
27
|
+
background: palette.surfaceWarm,
|
|
28
|
+
fontFamily: "Geist, system-ui",
|
|
29
|
+
color: palette.fg,
|
|
30
|
+
...style,
|
|
31
|
+
}}
|
|
32
|
+
>
|
|
33
|
+
{children}
|
|
34
|
+
</AbsoluteFill>
|
|
35
|
+
);
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Warm Signature — primitive components index.
|
|
3
|
+
* Scaffold templates import from here:
|
|
4
|
+
* import { AccentGlow, FilmGrain, ... } from "@devinilabs/reelstack/families/warm/components";
|
|
5
|
+
*/
|
|
6
|
+
export { AccentGlow } from "./AccentGlow";
|
|
7
|
+
export { FilmGrain } from "./FilmGrain";
|
|
8
|
+
export { BentoGrid } from "./BentoGrid";
|
|
9
|
+
export { BentoCell } from "./BentoCell";
|
|
10
|
+
export { WarmSurface } from "./WarmSurface";
|
|
11
|
+
export { ScaleBlurCounter } from "./ScaleBlurCounter";
|