Skip to main content
Glama
safe_margins_demo.pyβ€’12.5 kB
#!/usr/bin/env python3 """ Example: Safe Margins Demo Demonstrates platform-specific safe margins for: - LinkedIn Feed - Instagram Stories (9:16) - TikTok - YouTube - Mobile formats Shows how to ensure your content isn't cropped by platform UIs. """ import asyncio 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.generator.composition_builder import ComponentInstance from chuk_motion.tokens.spacing import SPACING_TOKENS async def create_safe_margins_demo(): """Create a video demonstrating safe margins for different platforms.""" from chuk_motion.utils.project_manager import ProjectManager import shutil manager = ProjectManager() project_name = "safe_margins_demo" # Clean up existing project project_path = manager.workspace_dir / project_name if project_path.exists(): shutil.rmtree(project_path) # Create project (standard YouTube 16:9) print(f"\nπŸ“ Creating project: {project_name}") project = manager.create_project( name=project_name, theme="tech", fps=30, width=1920, height=1080 ) print("\n🎬 Creating Safe Margins Demo Video...") print("=" * 70) # ======================================================================== # SECTION 1: Title Card (0-5s) # ======================================================================== print("\nπŸ“ Section 1: Introduction") title = ComponentInstance( component_type="TitleScene", start_frame=0, duration_frames=0, props={ "text": "Safe Margins", "subtitle": "Platform-Specific Cropping Zones", "variant": "bold", "animation": "fade_zoom" }, layer=0 ) manager.current_timeline.add_component(title, duration=5.0, track="main") # ======================================================================== # SECTION 2: LinkedIn Safe Margins (5-15s) # ======================================================================== print("πŸ“ Section 2: LinkedIn Feed Margins") linkedin_margins = SPACING_TOKENS.safe_area['linkedin'] linkedin_lower = ComponentInstance( component_type="LowerThird", start_frame=0, duration_frames=0, props={ "name": "LinkedIn Feed", "title": f"Safe Zone: {linkedin_margins.left} horizontal, {linkedin_margins.top} vertical", "variant": "glass", "position": "bottom_left" }, layer=10 ) manager.current_timeline.add_component(linkedin_lower, duration=8.0, track="main") linkedin_text = ComponentInstance( component_type="TextOverlay", start_frame=0, duration_frames=0, props={ "text": "⚠️ LinkedIn crops 8-24px from edges\nKeep text & graphics inside safe zone!", "position": "center", "style": "standard", "animation": "slide_up" }, layer=15 ) manager.current_timeline.add_component( linkedin_text, duration=6.0, track="overlay", align_to="main", offset=7.0 # Start 2s after previous component (5s + 2s) ) # ======================================================================== # SECTION 3: Instagram Stories (15-25s) # ======================================================================== print("πŸ“ Section 3: Instagram Stories (9:16)") instagram_margins = SPACING_TOKENS.safe_area['instagram_story'] instagram_lower = ComponentInstance( component_type="LowerThird", start_frame=0, duration_frames=0, props={ "name": "Instagram Stories", "title": f"Top: {instagram_margins.top} | Bottom: {instagram_margins.bottom}", "variant": "animated", "position": "bottom_center" }, layer=10 ) manager.current_timeline.add_component(instagram_lower, duration=8.0, track="main", gap_before=2.0) instagram_text = ComponentInstance( component_type="TextOverlay", start_frame=0, duration_frames=0, props={ "text": "πŸ“± Stories overlay at top (100px) and bottom (120px)\nAvoid placing important content in these areas", "position": "center", "style": "glass", "animation": "fade_in" }, layer=15 ) manager.current_timeline.add_component( instagram_text, duration=6.0, track="overlay", align_to="main", offset=17.0 # 15s + 2s ) # ======================================================================== # SECTION 4: TikTok Margins (25-35s) # ======================================================================== print("πŸ“ Section 4: TikTok Margins") tiktok_margins = SPACING_TOKENS.safe_area['tiktok'] tiktok_lower = ComponentInstance( component_type="LowerThird", start_frame=0, duration_frames=0, props={ "name": "TikTok", "title": f"Right side: {tiktok_margins.right} (buttons!) | Top: {tiktok_margins.top}", "variant": "bold", "position": "top_left" }, layer=10 ) manager.current_timeline.add_component(tiktok_lower, duration=8.0, track="main", gap_before=2.0) tiktok_text = ComponentInstance( component_type="TextOverlay", start_frame=0, duration_frames=0, props={ "text": "🎡 TikTok has UI buttons on the right side\n80px right margin prevents overlap", "position": "center", "style": "standard", "animation": "scale_in" }, layer=15 ) manager.current_timeline.add_component( tiktok_text, duration=6.0, track="overlay", align_to="main", offset=27.0 # 25s + 2s ) # ======================================================================== # SECTION 5: YouTube Long Form (35-45s) # ======================================================================== print("πŸ“ Section 5: YouTube Long Form") youtube_margins = SPACING_TOKENS.safe_area['youtube_long_form'] youtube_lower = ComponentInstance( component_type="LowerThird", start_frame=0, duration_frames=0, props={ "name": "YouTube", "title": f"Standard Safe Area: {youtube_margins.top} all around", "variant": "glass", "position": "bottom_right" }, layer=10 ) manager.current_timeline.add_component(youtube_lower, duration=8.0, track="main", gap_before=2.0) youtube_text = ComponentInstance( component_type="TextOverlay", start_frame=0, duration_frames=0, props={ "text": "πŸ“Ί YouTube: Simple 20px margins\nClean and professional", "position": "center", "style": "minimal", "animation": "blur_in" }, layer=15 ) manager.current_timeline.add_component( youtube_text, duration=6.0, track="overlay", align_to="main", offset=37.0 # 35s + 2s ) # ======================================================================== # SECTION 6: All Platforms Summary (45-55s) # ======================================================================== print("πŸ“ Section 6: Platform Summary") summary_title = ComponentInstance( component_type="TitleScene", start_frame=0, duration_frames=0, props={ "text": "Platform Comparison", "subtitle": "7 Platform Presets Available", "variant": "kinetic", "animation": "slide_up" }, layer=0 ) manager.current_timeline.add_component(summary_title, duration=5.0, track="main", gap_before=2.0) # Show stats - counter overlapping with text counter = ComponentInstance( component_type="Counter", start_frame=0, duration_frames=0, props={ "start_value": 0, "end_value": 7, "prefix": "", "suffix": " Platforms", "decimals": 0, "animation": "count_up" }, layer=10 ) manager.current_timeline.add_component(counter, duration=3.0, track="main") platform_list = ComponentInstance( component_type="TextOverlay", start_frame=0, duration_frames=0, props={ "text": "LinkedIn β€’ Instagram Stories β€’ TikTok β€’ YouTube\nMobile Vertical β€’ Mobile Horizontal β€’ Instagram Square", "position": "center", "style": "glass", "animation": "fade_in" }, layer=15 ) manager.current_timeline.add_component( platform_list, duration=4.5, track="overlay", align_to="main", offset=50.5 # Start 0.5s into the counter ) # ======================================================================== # SECTION 7: End Card (55-60s) # ======================================================================== print("πŸ“ Section 7: End Card") end_screen = ComponentInstance( component_type="EndScreen", start_frame=0, duration_frames=0, props={ "cta_text": "Use Design System β€’ Safe Margins", "variant": "gradient" }, layer=0 ) manager.current_timeline.add_component(end_screen, duration=5.0, track="main") # ======================================================================== # Generate the video # ======================================================================== print("\n" + "=" * 70) print("πŸ“¦ Generating Remotion Project...") print("=" * 70) # Generate TSX files for each component type component_types = {c.component_type for c in manager.current_timeline.get_all_components()} for comp_type in component_types: sample = next( c for c in manager.current_timeline.get_all_components() if c.component_type == comp_type ) manager.add_component_to_project(comp_type, sample.props, manager.current_timeline.theme) print(f" βœ“ {comp_type}.tsx") manager.generate_composition() print(f" βœ“ VideoComposition.tsx") # Get project info info = manager.get_project_info() composition = info['composition'] print("\nβœ… Safe Margins Demo Created!") print("=" * 70) print(f"πŸ“ Project: {project_path}") print(f"🎬 Duration: {composition['duration_seconds']:.1f} seconds") print(f"πŸ“ Resolution: 1920x1080 @ 30fps") print("\nπŸ“± Platform Safe Margins Covered:") for platform, margins in SPACING_TOKENS.safe_area.items(): print(f" β€’ {platform.replace('_', ' ').title()}") if hasattr(margins, 'all'): print(f" β†’ {margins.all} all sides") else: top = getattr(margins, 'top', 'N/A') bottom = getattr(margins, 'bottom', 'N/A') left = getattr(margins, 'left', 'N/A') right = getattr(margins, 'right', 'N/A') print(f" β†’ Top: {top}, Bottom: {bottom}") print(f" β†’ Left: {left}, Right: {right}") print("\nπŸš€ To render:") print(f" cd {project_path}") print(" npm install") print(" npm start") print("\n" + "=" * 70) return project_path async def main(): """Main example function.""" print("\n" + "=" * 70) print("SAFE MARGINS DEMO") print("=" * 70) print("\nDemonstrates platform-specific safe margins:") print(" β€’ LinkedIn Feed (8-24px crop zones)") print(" β€’ Instagram Stories (9:16 with UI overlays)") print(" β€’ TikTok (side button considerations)") print(" β€’ YouTube (standard margins)") print(" β€’ Mobile formats (vertical & horizontal)") print("\nEnsures your content is never cropped by platform UIs!") print("\n" + "=" * 70) result = await create_safe_margins_demo() if result: print("\n✨ Success! Your safe margins demo is ready to render.\n") else: print("\n❌ Something went wrong. Check the logs above.\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