Skip to main content
Glama
multi_track_showcase.py13.5 kB
#!/usr/bin/env python3 """ Multi-Track Timeline Showcase This example demonstrates the new track-based timeline system: - Multiple independent tracks (main, overlay, background, custom) - Auto-stacking components within tracks - Track alignment and synchronization - Parallel and sequential composition - No manual frame calculations needed! """ import asyncio import json import shutil import sys from pathlib import Path # Add parent directory to path for development sys.path.insert(0, str(Path(__file__).parent.parent / "src")) from chuk_motion.utils.project_manager import ProjectManager from chuk_motion.generator.composition_builder import ComponentInstance async def main(): """Generate a multi-track video showcasing the timeline system.""" print("\n" + "="*80) print("MULTI-TRACK TIMELINE SHOWCASE") print("="*80) print("\nDemonstrating:") print(" ✓ Multiple independent tracks") print(" ✓ Auto-stacking within tracks") print(" ✓ Track alignment and layering") print(" ✓ Parallel and sequential composition") # Initialize project manager manager = ProjectManager() project_name = "multi_track_showcase" # Clean up existing project project_path = manager.workspace_dir / project_name if project_path.exists(): print(f"\n🔄 Removing existing project: {project_name}") shutil.rmtree(project_path) # Create project print(f"\n📁 Creating project: {project_name}") project = manager.create_project( name=project_name, theme="tech", fps=30, width=1920, height=1080 ) print(f"✓ Project created at: {project['path']}") # Show default tracks print("\n🎯 Default Tracks:") tracks = manager.current_timeline.list_tracks() for track in tracks: print(f" • {track['name']:<12} (layer {track['layer']:>3}, gap {track['default_gap']}s)") # Add custom track for picture-in-picture print("\n➕ Adding custom 'pip' track (layer 20)...") manager.current_timeline.add_track( name="pip", layer=20, default_gap=0, description="Picture-in-picture overlays" ) print("✓ Custom track added") # ======================================================================== # MAIN TRACK: Sequential content # ======================================================================== print("\n" + "="*80) print("MAIN TRACK: Sequential auto-stacking content") print("="*80) # Title scene (auto-stacks at frame 0) print("\n🎬 Adding title scene...") title = ComponentInstance( component_type="TitleScene", start_frame=0, duration_frames=0, props={ "text": "Multi-Track Video System", "subtitle": "Powered by Remotion + Track-Based Timeline", "variant": "bold", "animation": "fade_zoom" }, layer=0 ) manager.current_timeline.add_component(title, duration=4.0, track="main") cursor = manager.current_timeline.get_track_cursor("main") print(f"✓ Title scene: 0.0s - 4.0s (main track cursor now at {cursor} frames)") # Code block (auto-stacks after title with 0.5s gap) print("\n💻 Adding code demonstration...") code = ComponentInstance( component_type="CodeBlock", start_frame=0, duration_frames=0, props={ "code": """# Track-based timeline example timeline = Timeline(fps=30) # Components auto-stack sequentially timeline.add_component(title, duration=4.0, track="main") timeline.add_component(code, duration=6.0, track="main") # Overlays layer on top timeline.add_component(caption, duration=3.0, track="overlay")""", "language": "python", "title": "timeline.py", "variant": "editor", "show_line_numbers": True }, layer=0 ) manager.current_timeline.add_component(code, duration=6.0, track="main", gap_before=0.5) cursor = manager.current_timeline.get_track_cursor("main") print(f"✓ Code block: 4.5s - 10.5s (main track cursor now at {cursor} frames)") # Bar chart (continues auto-stacking) print("\n📊 Adding bar chart...") chart = ComponentInstance( component_type="BarChart", start_frame=0, duration_frames=0, props={ "data": [ {"label": "Manual Timing", "value": 45, "color": "#ef4444"}, {"label": "Track-Based", "value": 95, "color": "#22c55e"} ], "title": "Developer Productivity", "ylabel": "Satisfaction %" }, layer=0 ) manager.current_timeline.add_component(chart, duration=5.0, track="main", gap_before=0.5) cursor = manager.current_timeline.get_track_cursor("main") print(f"✓ Bar chart: 11.0s - 16.0s (main track cursor now at {cursor} frames)") # ======================================================================== # OVERLAY TRACK: Text overlays that layer on top # ======================================================================== print("\n" + "="*80) print("OVERLAY TRACK: Layered on top of main content") print("="*80) # Lower third aligned to title start print("\n📋 Adding lower third (aligned to title)...") lower_third_1 = ComponentInstance( component_type="LowerThird", start_frame=0, duration_frames=0, props={ "name": "Track-Based System", "title": "No manual frame calculations!", "variant": "glass", "position": "bottom_left" }, layer=10 ) manager.current_timeline.add_component( lower_third_1, duration=3.5, track="overlay", align_to="main", offset=0.5 ) print(f"✓ Lower third #1: 0.5s - 4.0s (layer 10, over title)") # Text overlay aligned to code block print("\n💬 Adding text overlay (aligned to code)...") text_overlay = ComponentInstance( component_type="TextOverlay", start_frame=0, duration_frames=0, props={ "text": "Auto-stacking + Layering = 🚀", "style": "caption", "animation": "fade_in", "position": "top_right" }, layer=10 ) manager.current_timeline.add_component( text_overlay, duration=4.0, track="overlay", align_to="main", offset=5.0 ) print(f"✓ Text overlay: 5.0s - 9.0s (layer 10, over code)") # Another lower third aligned to chart print("\n📋 Adding lower third (aligned to chart)...") lower_third_2 = ComponentInstance( component_type="LowerThird", start_frame=0, duration_frames=0, props={ "name": "Parallel Tracks", "title": "Independent timelines working together", "variant": "bold", "position": "bottom_center" }, layer=10 ) manager.current_timeline.add_component( lower_third_2, duration=4.0, track="overlay", align_to="main", offset=11.5 ) print(f"✓ Lower third #2: 11.5s - 15.5s (layer 10, over chart)") # ======================================================================== # PIP TRACK: Picture-in-picture overlay at the top layer # ======================================================================== print("\n" + "="*80) print("PIP TRACK: High-level overlays (layer 20)") print("="*80) # Counter as PiP element print("\n🔢 Adding counter (top-right corner)...") counter = ComponentInstance( component_type="Counter", start_frame=0, duration_frames=0, props={ "start_value": 0, "end_value": 100, "suffix": "%", "decimals": 0, "animation": "count_up" }, layer=20 ) manager.current_timeline.add_component( counter, duration=8.0, track="pip", align_to="main", offset=4.0 ) print(f"✓ Counter: 4.0s - 12.0s (layer 20, highest layer)") # ======================================================================== # BACKGROUND TRACK: Behind everything # ======================================================================== print("\n" + "="*80) print("BACKGROUND TRACK: Sits behind all content (layer -10)") print("="*80) print("\n🎨 Adding background container...") # Note: Would typically add a solid color or video here # For now, adding a container as placeholder bg_container = ComponentInstance( component_type="Container", start_frame=0, duration_frames=0, props={ "position": "center", "width": "100%", "height": "100%", "padding": 0 }, layer=-10 ) manager.current_timeline.add_component( bg_container, duration=16.0, track="background", start_frame=0 # Explicit start from beginning ) print(f"✓ Background: 0.0s - 16.0s (layer -10, behind everything)") # ======================================================================== # Summary # ======================================================================== print("\n" + "="*80) print("TIMELINE SUMMARY") print("="*80) info = manager.get_project_info() composition = info['composition'] print(f"\n📊 Composition Stats:") print(f" Total duration: {composition['duration_seconds']:.1f} seconds") print(f" Total frames: {composition['duration_frames']}") print(f" Total components: {len(composition['components'])}") print(f"\n🎯 Track Summary:") all_tracks = manager.current_timeline.list_tracks() for track in all_tracks: print(f" • {track['name']:<12}: {track['component_count']} components, " f"cursor at {track['cursor_seconds']:.1f}s") print("\n📅 Timeline (sorted by start time):") sorted_components = sorted(composition['components'], key=lambda c: c['start_time']) for comp in sorted_components: layer_info = f"L{comp['layer']:>3}" time_info = f"{comp['start_time']:>5.1f}s - {comp['start_time'] + comp['duration']:>5.1f}s" print(f" {layer_info} │ {time_info} │ {comp['type']}") print("\n📚 Visual Timeline:") print(" ─────────────────────────────────────────────────") print(" Background (L-10): [████████████████████████████]") print(" Main (L0): [████][██████][███████] ") print(" Overlay (L10): [███] [████] [████] ") print(" PIP (L20): [████████] ") print(" ─────────────────────────────────────────────────") print(" Time (s): 0 5 10 15 ") # ======================================================================== # Generate files # ======================================================================== print("\n" + "="*80) print("GENERATING VIDEO FILES") print("="*80) print("\n⚙️ Generating TSX components...") component_types = {c.component_type for c in manager.current_timeline.get_all_components()} for comp_type in sorted(component_types): sample = next( c for c in manager.current_timeline.get_all_components() if c.component_type == comp_type ) file_path = manager.add_component_to_project( comp_type, sample.props, manager.current_timeline.theme ) print(f" ✓ {comp_type}.tsx") print("\n📝 Generating VideoComposition.tsx...") composition_file = manager.generate_composition() print(f" ✓ VideoComposition.tsx") # ======================================================================== # Next steps # ======================================================================== print("\n" + "="*80) print("🎉 MULTI-TRACK VIDEO GENERATED!") print("="*80) print(f"\n📁 Project: {project['path']}") print("\n🚀 Next steps:") print("\n1. Install dependencies:") print(f" cd {project['path']}") print(" npm install") print("\n2. Preview in Remotion Studio:") print(" npm start") print(" → Opens at http://localhost:3000") print("\n3. Render video:") print(" npm run build") print("\n" + "="*80) print("\n✨ Key Features Demonstrated:") print(" ✓ 4 tracks: main, overlay, pip, background") print(" ✓ Auto-stacking: components added sequentially within tracks") print(" ✓ Track alignment: overlays sync with main track") print(" ✓ Layering: z-index from tracks (background → main → overlay → pip)") print(" ✓ No manual frames: all timing calculated automatically") print("\n💡 This is much easier than calculating frames manually!\n") if __name__ == "__main__": asyncio.run(main())

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/chrishayuk/chuk-mcp-remotion'

If you have feedback or need assistance with the MCP directory API, please join our Discord server