11import {
22 AbsoluteFill ,
33 useCurrentFrame ,
4+ interpolate ,
5+ Sequence ,
46} from "remotion" ;
57import { theme , fonts } from "./theme" ;
68import {
@@ -13,6 +15,83 @@ import {
1315import { CrumbLine } from "./CrumbLine" ;
1416import { SyntaxLine , lineLength , type Token } from "./SyntaxLine" ;
1517
18+ // ── Intro card ──────────────────────────────────────────────────────
19+ const INTRO_FRAMES = 74 ; // ~2.5s
20+
21+ const Intro : React . FC = ( ) => {
22+ const frame = useCurrentFrame ( ) ;
23+
24+ const prefix = "Debug mode for " ;
25+ const accent = "any agent" ;
26+ const full = prefix + accent ;
27+ const charsToShow = Math . min ( Math . floor ( frame * 1.2 ) , full . length ) ;
28+ const visiblePrefix = full . slice ( 0 , Math . min ( charsToShow , prefix . length ) ) ;
29+ const visibleAccent = charsToShow > prefix . length ? accent . slice ( 0 , charsToShow - prefix . length ) : "" ;
30+
31+ return (
32+ < AbsoluteFill
33+ style = { {
34+ backgroundColor : "#1a1b1f" ,
35+ fontFamily : "'Inter', 'SF Pro Display', -apple-system, sans-serif" ,
36+ display : "flex" ,
37+ flexDirection : "column" ,
38+ alignItems : "center" ,
39+ justifyContent : "center" ,
40+ } }
41+ >
42+ { /* Fixed position container so logo doesn't move */ }
43+ < div
44+ style = { {
45+ display : "flex" ,
46+ flexDirection : "column" ,
47+ alignItems : "center" ,
48+ position : "absolute" ,
49+ top : "50%" ,
50+ left : "50%" ,
51+ transform : "translate(-50%, -50%)" ,
52+ } }
53+ >
54+ { /* Logo */ }
55+ < div
56+ style = { {
57+ display : "flex" ,
58+ alignItems : "center" ,
59+ gap : 24 ,
60+ marginBottom : 56 ,
61+ fontFamily : fonts . mono ,
62+ } }
63+ >
64+ < span style = { { fontSize : 80 , fontWeight : "bold" } } >
65+ < span style = { { color : theme . fgBright } } > agent</ span >
66+ < span style = { { color : theme . green , textShadow : `0 0 40px ${ theme . green } 50, 0 0 80px ${ theme . green } 25` } } > crumbs</ span >
67+ </ span >
68+ < span style = { { fontSize : 42 , color : theme . comment } } > by</ span >
69+ < span style = { { fontSize : 42 , color : theme . comment , display : "flex" , alignItems : "center" , gap : 12 } } >
70+ < svg width = "36" height = "36" viewBox = "0 0 120 120" fill = "none" xmlns = "http://www.w3.org/2000/svg" >
71+ < path fillRule = "evenodd" clipRule = "evenodd" d = "M41.6889 52.2795L60.4195 20L106.839 100H14L32.7305 67.7195L45.9801 75.3312L40.5003 84.7756H80.3387L60.4195 50.4478L54.9396 59.8922L41.6889 52.2795Z" fill = "#A8FF53" />
72+ </ svg >
73+ Trigger.dev
74+ </ span >
75+ </ div >
76+
77+ { /* Headline — fixed height so it doesn't push logo when typing */ }
78+ < div
79+ style = { {
80+ fontSize : 72 ,
81+ fontWeight : 800 ,
82+ color : theme . fgBright ,
83+ textAlign : "center" ,
84+ whiteSpace : "nowrap" ,
85+ height : 86 ,
86+ } }
87+ >
88+ { visiblePrefix } < span style = { { color : theme . green , textShadow : `0 0 30px ${ theme . green } 60, 0 0 60px ${ theme . green } 30` } } > { visibleAccent } </ span >
89+ </ div >
90+ </ div >
91+ </ AbsoluteFill >
92+ ) ;
93+ } ;
94+
1695// ── Spinner component ───────────────────────────────────────────────
1796const Spinner : React . FC < { frame : number ; startFrame : number ; verb : string } > = ( { frame, startFrame, verb } ) => {
1897 const elapsed = frame - startFrame ;
@@ -128,7 +207,7 @@ const AllContent: React.FC = () => {
128207 const inputText = isTyping ? userMessage . slice ( 0 , typedChars ) : "" ;
129208
130209 return (
131- < ClaudeCodeShell scrollY = { scrollY } showInput inputText = { inputText } >
210+ < ClaudeCodeShell scrollY = { scrollY } showInput inputText = { inputText } frame = { frame } >
132211 { /* ── User prompt (appears after submit) ── */ }
133212 { frame >= T . userSubmit && (
134213 < div style = { { marginBottom : 16 } } >
@@ -246,11 +325,16 @@ const AllContent: React.FC = () => {
246325 const lineFrame = T . crumbStart + i * T . crumbInterval ;
247326 if ( frame < lineFrame ) return null ;
248327 const isError = line . type === "scope:error" ;
328+ // Error lines flash bright red for 4 frames then settle
329+ const framesShown = frame - lineFrame ;
330+ const errorBg = isError
331+ ? framesShown < 2 ? "#F8514940" : framesShown < 4 ? "#F8514928" : "#F8514915"
332+ : "transparent" ;
249333 return (
250334 < div
251335 key = { i }
252336 style = { {
253- backgroundColor : isError ? "#F8514915" : "transparent" ,
337+ backgroundColor : errorBg ,
254338 borderRadius : 2 ,
255339 padding : isError ? "0 4px" : 0 ,
256340 } }
@@ -342,6 +426,37 @@ const AllContent: React.FC = () => {
342426 ) ;
343427} ;
344428
429+ // ── Fade through black transition ────────────────────────────────────
430+ const FADE_FRAMES = 12 ;
431+
432+ const FadeOut : React . FC = ( ) => {
433+ const frame = useCurrentFrame ( ) ;
434+ const opacity = interpolate ( frame , [ 0 , FADE_FRAMES ] , [ 0 , 1 ] , { extrapolateRight : "clamp" } ) ;
435+ return (
436+ < AbsoluteFill style = { { backgroundColor : `rgba(0, 0, 0, ${ opacity } )` , zIndex : 100 } } />
437+ ) ;
438+ } ;
439+
440+ const FadeIn : React . FC = ( ) => {
441+ const frame = useCurrentFrame ( ) ;
442+ const opacity = interpolate ( frame , [ 0 , FADE_FRAMES ] , [ 1 , 0 ] , { extrapolateRight : "clamp" } ) ;
443+ if ( opacity <= 0 ) return null ;
444+ return (
445+ < AbsoluteFill style = { { backgroundColor : `rgba(0, 0, 0, ${ opacity } )` , zIndex : 100 } } />
446+ ) ;
447+ } ;
448+
449+ // ── Vignette overlay ────────────────────────────────────────────────
450+ const Vignette : React . FC = ( ) => (
451+ < AbsoluteFill
452+ style = { {
453+ background : "radial-gradient(ellipse at center, transparent 50%, rgba(0,0,0,0.4) 100%)" ,
454+ zIndex : 50 ,
455+ pointerEvents : "none" ,
456+ } }
457+ />
458+ ) ;
459+
345460export const AgentCrumbsDemo : React . FC = ( ) => {
346461 return (
347462 < AbsoluteFill
@@ -350,7 +465,30 @@ export const AgentCrumbsDemo: React.FC = () => {
350465 fontFamily : fonts . mono ,
351466 } }
352467 >
353- < AllContent />
468+ { /* Intro card */ }
469+ < Sequence durationInFrames = { INTRO_FRAMES } >
470+ < Intro />
471+ </ Sequence >
472+
473+ { /* Fade out end of intro */ }
474+ < Sequence from = { INTRO_FRAMES - FADE_FRAMES } durationInFrames = { FADE_FRAMES } >
475+ < FadeOut />
476+ </ Sequence >
477+
478+ { /* Fade in start of terminal */ }
479+ < Sequence from = { INTRO_FRAMES } durationInFrames = { FADE_FRAMES } >
480+ < FadeIn />
481+ </ Sequence >
482+
483+ { /* Terminal session */ }
484+ < Sequence from = { INTRO_FRAMES } >
485+ < AllContent />
486+ </ Sequence >
487+
488+ { /* Vignette over everything in terminal session */ }
489+ < Sequence from = { INTRO_FRAMES } >
490+ < Vignette />
491+ </ Sequence >
354492 </ AbsoluteFill >
355493 ) ;
356494} ;
0 commit comments