import React from 'react'; import {AbsoluteFill,Audio,Sequence,staticFile,useCurrentFrame} from 'remotion'; import {Background,Zone} from '../components/Stage'; import {Headline,words} from '../components/Headline'; import {Card,Callout,CheckItem,Frames} from '../components/UI'; import {C,FONT} from '../lib/tokens'; import {FormatCtx,Format,Platform} from '../lib/format-context'; import {geometry} from '../lib/format.mjs'; import {DebugCtx} from '../lib/debug'; import {beatAccent, nearestBeatFrame} from '../lib/beat'; export type TimelineScene={id:string;role:string;headline?:string;fromFrame:number;toFrame:number;start:number;end:number}; export type TimelineBoard={fps:number;duration:number;scenes:TimelineScene[]}; export type TimelineProps={timeline?:TimelineBoard;beats?:number[];format?:Format;platform?:Platform;audio?:string;mcDebug?:boolean;handle?:string;product?:string;problem?:string;feature1?:string;feature2?:string;cta?:string;demoDir?:string;demoCount?:number;demoCredit?:string;title?:string;captureDir?:string;captureCount?:number;sourceCredit?:string}; const defaultLaunch:TimelineBoard={fps:30,duration:45,scenes:[ {id:'problem',role:'problem',headline:'A real problem',fromFrame:0,toFrame:240,start:0,end:8}, {id:'demo',role:'demo',headline:'Product in action',fromFrame:240,toFrame:810,start:8,end:27}, {id:'features',role:'features',headline:'What changes',fromFrame:810,toFrame:1170,start:27,end:39}, {id:'cta',role:'cta',headline:'Try it yourself',fromFrame:1170,toFrame:1350,start:39,end:45}]}; const defaultTutorial:TimelineBoard={fps:30,duration:30,scenes:[ {id:'intro',role:'intro',headline:'A clear tutorial',fromFrame:0,toFrame:150,start:0,end:5}, {id:'step-1',role:'step',headline:'Open',fromFrame:150,toFrame:450,start:5,end:15}, {id:'step-2',role:'step',headline:'Choose',fromFrame:450,toFrame:750,start:15,end:25}, {id:'outro',role:'outro',headline:'Review',fromFrame:750,toFrame:900,start:25,end:30}]}; export const timelineDefaults={launch:defaultLaunch,tutorial:defaultTutorial}; const Beat:React.FC<{beats:number[];start:number;fps:number}>=({beats,start,fps})=>{const f=useCurrentFrame();const hit=beats.some(b=>{const d=f-Math.round((b-start)*fps);return d>=0&&d<5});return
}; const SceneBody:React.FC<{s:TimelineScene;p:TimelineProps;kind:'launch'|'tutorial';beats:number[];fps:number}>=({s,p,kind,beats,fps})=>{ const f=useCurrentFrame(),g=geometry(p.format,p.platform),duration=s.toFrame-s.fromFrame; const name=s.headline || (s.role==='problem'?p.problem:s.role==='demo'?`${p.product||'Product'} in action`:s.role==='intro'?p.title:s.role==='cta'?p.cta:s.role); const demo=kind==='launch'?p.demoDir:p.captureDir,count=kind==='launch'?p.demoCount:p.captureCount,credit=kind==='launch'?p.demoCredit:p.sourceCredit; const ready=!!demo&&!!count&&!!credit; return {(s.role==='demo'||s.role==='step')? {ready?:
REAL FOOTAGE REQUIRED - DO NOT PUBLISH
}
:s.role==='features'?
:s.role==='cta'||s.role==='outro'?:
{kind==='tutorial'?'Watch the steps':'A problem worth solving'}
}
{ready&&['demo','step'].includes(s.role)?`Source: ${credit}`:p.handle||''}
; }; export const TimelineVideo:React.FC=p=>{ const {kind,timeline,beats=[],mcDebug=false,format=kind==='launch'?'16:9':'9:16',platform=kind==='launch'?'wide':'tiktok'}=p; const board=timeline||timelineDefaults[kind]; return {!mcDebug?:} {board.scenes.map(s=>)} {p.audio&&!mcDebug&&; };