Skip to main content
Glama

chuk-mcp-stage

3D Scene & Camera MCP Server - The director layer between physics simulation and motion rendering

Python MCP Async

🌐 Quick Install: uvx stage.chukai.io/mcp

chuk-mcp-stage is the orchestration layer that bridges:

  • chuk-mcp-physics (Rapier simulations) β†’ Scene animations

  • chuk-motion / Remotion (video rendering) β†’ Export targets

It's the "director + set designer" that defines what's in the 3D world, where the camera goes, and how physics drives motion.


🎯 What This Does

Core capabilities:

  1. Scene Graph - Define 3D worlds (objects, materials, lighting)

  2. Camera Paths - Cinematography (orbit, chase, dolly, static shots)

  3. Physics Bridge - Bind scene objects to physics bodies (uses public Rapier service by default)

  4. Animation Baking - Convert physics simulations β†’ keyframes

  5. Export - Generate R3F components, Remotion projects, glTF

The full pipeline:

Physics Simulation β†’ Stage β†’ Motion/Video (chuk-mcp-physics) β†’ (chuk-mcp-stage) β†’ (chuk-motion/Remotion)

πŸš€ Quick Start

Installation

Option 1: Install from public URL (Recommended)

# Install directly from public URL with uvx uvx stage.chukai.io/mcp

Option 2: Install from PyPI

pip install chuk-mcp-stage

Option 3: Install from source

cd chuk-mcp-stage pip install -e .

Physics ready out-of-the-box! Uses the public Rapier service at https://rapier.chukai.io by default. No additional setup required for physics simulations.

Run the Server

# STDIO mode (default - for MCP clients like Claude Desktop) uv run chuk-mcp-stage # HTTP mode (REST API on port 8000) uv run chuk-mcp-stage http # Streamable mode (Server-Sent Events for streaming responses) uv run chuk-mcp-stage streamable

Transport modes:

  • stdio: Standard MCP protocol via stdin/stdout (default for Claude Desktop)

  • http: HTTP REST API server on port 8000 (used by chuk-mcp-r3f-preview)

  • streamable: SSE (Server-Sent Events) transport for streaming responses

πŸ“– Complete Transport Modes Guide - Detailed documentation, examples, and troubleshooting

Configure in Claude Desktop

Add to ~/Library/Application Support/Claude/claude_desktop_config.json:

Option 1: Using public URL (Recommended)

{ "mcpServers": { "stage": { "command": "uvx", "args": ["stage.chukai.io/mcp"], "env": { "RAPIER_SERVICE_URL": "https://rapier.chukai.io" } } } }

Option 2: Using local installation

{ "mcpServers": { "stage": { "command": "chuk-mcp-stage", "env": { "RAPIER_SERVICE_URL": "https://rapier.chukai.io" } } } }

Physics Integration Configuration

chuk-mcp-stage integrates with physics simulations via chuk-mcp-physics and the Rapier physics engine.

Three Integration Methods:

  1. Direct Rapier HTTP (Default) - Fastest for simulations

    • Directly calls Rapier service HTTP API

    • Used by stage_bake_simulation tool

    • Defaults to public service: https://rapier.chukai.io

  2. Via MCP Tools - Most flexible

    • Use chuk-mcp-physics MCP server tools

    • Supports both analytic calculations and Rapier simulations

    • Requires chuk-mcp-physics server running

  3. Hybrid - Best of both worlds

    • Use MCP tools for simulation creation/setup

    • Use direct HTTP for baking trajectories

Environment Variables:

# Rapier service URL (default: https://rapier.chukai.io) RAPIER_SERVICE_URL=https://rapier.chukai.io # Public service # RAPIER_SERVICE_URL=http://localhost:9000 # Local development # Rapier timeout in seconds (default: 30.0) RAPIER_TIMEOUT=30.0 # Physics provider type (default: auto) PHYSICS_PROVIDER=auto # or 'rapier', 'mcp'

Claude Desktop with Custom Rapier Service:

{ "mcpServers": { "stage": { "command": "chuk-mcp-stage", "env": { "RAPIER_SERVICE_URL": "http://localhost:9000", "RAPIER_TIMEOUT": "60.0" } }, "physics": { "command": "uvx", "args": ["chuk-mcp-physics"], "env": { "RAPIER_SERVICE_URL": "http://localhost:9000" } } } }

Public Rapier Service:

  • URL: https://rapier.chukai.io

  • No authentication required

  • Rate limits may apply

  • Perfect for prototyping and demos

Local Rapier Service:

# Run locally with Docker docker run -p 9000:9000 chuk-rapier-service # Or from source cd rapier-service && cargo run --release

See chuk-mcp-physics README for complete physics integration guide.

What's New in chuk-mcp-physics v0.3.1:

  • 52 physics tools (expanded from 27) - Now covers ~50% of common physics use cases

  • Rotational dynamics: Torque, moment of inertia, angular momentum calculations

  • Springs & oscillations: Simple harmonic motion, damped oscillations, pendulums

  • Circular motion: Orbital mechanics, centripetal force, escape velocity

  • Advanced collisions: 3D elastic/inelastic collisions with coefficient of restitution

  • Conservation laws: Energy and momentum verification for simulations

  • Fluid dynamics: Drag, buoyancy, terminal velocity, underwater motion


Google Drive OAuth Storage (HTTP Mode)

Store your scenes in Google Drive with OAuth 2.1 authentication for secure, persistent, user-owned storage!

When running in HTTP mode, chuk-mcp-stage supports Google Drive OAuth integration. Users authenticate via their browser, and scenes are stored in their own Google Drive under /CHUK/stage/.

Benefits:

  • βœ… Secure OAuth 2.1 - Industry-standard authentication with PKCE

  • βœ… User Owns Data - Scenes stored in user's Google Drive, not your infrastructure

  • βœ… Auto Token Refresh - Seamless authentication with automatic refresh

  • βœ… Cross-Device Access - Access scenes from any device with Drive

  • βœ… Built-in Sharing - Share scenes using Google Drive's native sharing

  • βœ… Natural Discoverability - View/edit scene files directly in Drive UI

  • βœ… No Infrastructure Cost - Zero storage costs for the provider

Setup Steps

1. Create Google Cloud Project:

  • Go to https://console.cloud.google.com/

  • Create new project (or select existing)

  • Enable Google Drive API

  • Go to OAuth consent screen:

    • User Type: External

    • Add your email as test user

  • Go to Credentials β†’ Create OAuth 2.0 Client ID:

    • Application type: Web application

    • Authorized redirect URIs: http://localhost:8000/oauth/callback

  • Copy Client ID and Client Secret

2. Install with Google Drive Support:

pip install "chuk-mcp-stage[google_drive]"

3. Configure Environment:

# Copy example environment file cp .env.example .env # Edit .env and add your Google credentials: # GOOGLE_CLIENT_ID=your-client-id.apps.googleusercontent.com # GOOGLE_CLIENT_SECRET=your-client-secret

4. Verify OAuth Integration (Optional but Recommended):

# Verify that OAuth setup works python examples/verify_google_drive_oauth.py

This will verify:

  • OAuth provider initializes correctly

  • Credentials are valid

  • OAuth endpoints can be registered

  • Ready for Google Drive integration

5. Run Server in HTTP Mode:

# Load from .env file uv run chuk-mcp-stage http # Or set environment variables directly export GOOGLE_CLIENT_ID="your-client-id.apps.googleusercontent.com" export GOOGLE_CLIENT_SECRET="your-client-secret" uv run chuk-mcp-stage http

6. Authorize Access:

When Claude Desktop (or any MCP client) connects:

  1. OAuth flow automatically initiates

  2. Browser opens for Google authorization

  3. User grants access to Google Drive

  4. Tokens securely stored and auto-refreshed

OAuth Endpoints (automatically registered):

  • Authorization: http://localhost:8000/oauth/authorize

  • Token: http://localhost:8000/oauth/token

  • Discovery: http://localhost:8000/.well-known/oauth-authorization-server

  • Callback: http://localhost:8000/oauth/callback

Deployment to Fly.io

βœ… OAuth is now configured for

See OAUTH_SETUP_COMPLETE.md for details on the production OAuth setup.

For production deployments, set secrets instead of using .env:

# Set Google OAuth credentials as Fly secrets fly secrets set GOOGLE_CLIENT_ID="your-client-id.apps.googleusercontent.com" fly secrets set GOOGLE_CLIENT_SECRET="your-client-secret" # Set OAuth server URL (use your Fly.io app URL) fly secrets set OAUTH_SERVER_URL="https://your-app.fly.dev" fly secrets set GOOGLE_REDIRECT_URI="https://your-app.fly.dev/oauth/callback" # Optional: Configure session backend for production fly secrets set SESSION_PROVIDER="redis" fly secrets set SESSION_REDIS_URL="redis://your-redis-url:6379/0" # Deploy fly deploy

Important: Update Google Cloud Console with production redirect URI:

  • Add https://your-app.fly.dev/oauth/callback to authorized redirect URIs

Storage Providers

chuk-mcp-stage supports multiple storage backends - see STORAGE_CONFIGURATION.md for complete details.

Quick Comparison:

Provider

Persistence

Cloud Sync

OAuth Required

Setup

Best For

vfs-filesystem (default)

βœ… Local

❌

❌

Zero

Local dev

vfs-filesystem + OAuth

βœ… Persistent

βœ… Google Drive

βœ…

Medium

Production (small)

vfs-s3

βœ… Persistent

βœ… S3

❌

Medium

Production (large)

vfs-memory

❌ RAM only

❌

❌

Zero

Testing only

Environment Variables:

# Storage provider selection (default: vfs-filesystem) STORAGE_PROVIDER=vfs-filesystem # Session metadata storage (default: memory) SESSION_PROVIDER=memory # For Redis sessions (production) SESSION_PROVIDER=redis REDIS_URL=redis://localhost:6379/0 # For AWS S3 storage STORAGE_PROVIDER=vfs-s3 AWS_ACCESS_KEY_ID=xxx AWS_SECRET_ACCESS_KEY=xxx AWS_S3_BUCKET=chuk-artifacts AWS_REGION=us-east-1

See STORAGE_CONFIGURATION.md for:

  • Detailed provider comparison

  • Migration guides

  • Production best practices

  • Troubleshooting

Where Your Scenes Live

With vfs-filesystem (default):

~/.chuk-artifacts/ └── grid/ └── {sandbox_id}/ └── {session_id}/ └── {namespace_id}/ β”œβ”€β”€ scene.json β”œβ”€β”€ animations/ └── export/

With Google Drive (vfs-filesystem + OAuth):

Google Drive └── chuk-artifacts/ └── {user_id}/ └── {namespace_id}/ β”œβ”€β”€ scene.json β”œβ”€β”€ animations/ β”‚ └── cannonball.json └── export/ └── remotion/

With AWS S3 (vfs-s3):

s3://your-bucket/ └── grid/ └── {sandbox_id}/ └── {session_id}/ └── {namespace_id}/ β”œβ”€β”€ scene.json └── animations/

Storage Scope Behavior:

  • SESSION scope (unauthenticated) β†’ Local filesystem only, ephemeral

  • USER scope (authenticated) β†’ Google Drive (if OAuth enabled) or S3, persistent


πŸ“¦ Tool Surface

Scene Management

# Create a new scene stage_create_scene(name, author, description) # Add 3D objects stage_add_object( scene_id, object_id, object_type, # "box", "sphere", "cylinder", "plane" position_x, position_y, position_z, radius, size_x, size_y, size_z, material_preset, # "metal-dark", "glass-blue", "plastic-white" color_r, color_g, color_b ) # Set environment & lighting stage_set_environment( scene_id, environment_type, # "gradient", "solid", "hdri" lighting_preset # "three-point", "studio", "noon" )

Camera & Shots

# Add camera shot stage_add_shot( scene_id, shot_id, camera_mode, # "orbit", "static", "chase", "dolly" start_time, end_time, focus_object, # Object to orbit/chase orbit_radius, orbit_elevation, orbit_speed, easing # "ease-in-out-cubic", "spring", "linear" ) # Get shot details stage_get_shot(scene_id, shot_id)

Physics Integration

# Bind object to physics body stage_bind_physics( scene_id, object_id, physics_body_id # "rapier://sim-abc/body-ball" ) # Bake simulation to keyframes stage_bake_simulation( scene_id, simulation_id, fps=60, duration=10.0, physics_server_url=None # Optional: defaults to https://rapier.chukai.io )

Export

# Export to R3F/Remotion/glTF stage_export_scene( scene_id, format, # "r3f-component", "remotion-project", "gltf", "json" output_path ) # Get complete scene data stage_get_scene(scene_id)

🧩 Core Concepts

Stage Objects

A Stage Object is an entry in the scene graph that represents a 3D visual element. Every object has:

Property

Description

Example

id

Unique identifier

"ball", "ground", "car-chassis"

type

Primitive shape

"sphere", "box", "cylinder", "plane"

transform

Position, rotation, scale

{position: [0, 5, 0], rotation: [0, 0, 0], scale: [1, 1, 1]}

material

Visual appearance

"glass-blue", "metal-dark", custom PBR

physics_binding

Optional physics link

"rapier://sim-abc/body-ball"

Example scene JSON:

{ "id": "demo-scene", "name": "Falling Ball Demo", "objects": { "ground": { "id": "ground", "type": "plane", "transform": { "position": {"x": 0, "y": 0, "z": 0}, "rotation": {"x": 0, "y": 0, "z": 0}, "scale": {"x": 1, "y": 1, "z": 1} }, "size": {"x": 20, "y": 20, "z": 1}, "material": { "preset": "metal-dark" }, "physics_binding": null }, "ball": { "id": "ball", "type": "sphere", "transform": { "position": {"x": 0, "y": 5, "z": 0}, "rotation": {"x": 0, "y": 0, "z": 0}, "scale": {"x": 1, "y": 1, "z": 1} }, "radius": 1.0, "material": { "preset": "glass-blue", "color": {"r": 0.3, "g": 0.6, "b": 1.0} }, "physics_binding": "rapier://sim-falling/body-ball" } }, "shots": { "main": { "id": "main", "camera_path": { "mode": "orbit", "focus": "ball", "radius": 8.0, "elevation": 30.0 }, "start_time": 0.0, "end_time": 10.0 } } }

Why this matters for LLMs:

When you create an object with stage_add_object, you're modifying this scene graph. Later operations like stage_bind_physics or stage_add_shot reference the same object ID you created. This makes it easy to reason about: "I want to modify the ball I just created" β†’ just use object_id="ball".

Authoring vs Baking

chuk-mcp-stage has two distinct phases:

1️⃣ Authoring Phase (Define the World)

What you're doing: Planning and composing the scene

Operations:

  • Create scene structure

  • Place objects (primitives, positions, materials)

  • Define camera shots and movements

  • Bind object IDs to physics body IDs

  • Set environment and lighting

Output: Scene definition (metadata only, no animation yet)

Tools used:

  • stage_create_scene

  • stage_add_object

  • stage_add_shot

  • stage_bind_physics

  • stage_set_environment

2️⃣ Baking Phase (Generate Animation Data)

What you're doing: Converting physics simulation to renderable keyframes

Operations:

  • Connect to physics simulation (Rapier)

  • Sample physics state at desired FPS

  • Convert body positions/rotations β†’ keyframes

  • Store animation data in scene VFS

Output: Timestamped keyframe arrays (position, rotation, velocity per frame)

Tools used:

  • stage_bake_simulation (connects to physics, generates keyframes)

  • stage_export_scene (exports scene + baked animations)

Typical Flow

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ AUTHORING PHASE β”‚ β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ β”‚ 1. stage_create_scene(name="demo") β”‚ β”‚ β†’ Creates empty scene graph β”‚ β”‚ β”‚ β”‚ 2. stage_add_object(id="ground", type="plane", ...) β”‚ β”‚ stage_add_object(id="ball", type="sphere", y=10, ...) β”‚ β”‚ β†’ Defines visual objects (no motion yet) β”‚ β”‚ β”‚ β”‚ 3. stage_set_environment(lighting="three-point") β”‚ β”‚ β†’ Sets lights, background β”‚ β”‚ β”‚ β”‚ 4. Use physics MCP to create simulation β”‚ β”‚ create_simulation(gravity_y=-9.81) β”‚ β”‚ add_rigid_body(sim_id, body_id="ball", ...) β”‚ β”‚ β†’ Physics oracle creates simulation β”‚ β”‚ β”‚ β”‚ 5. stage_bind_physics(object_id="ball", β”‚ β”‚ body_id="rapier://sim-id/body-ball") β”‚ β”‚ β†’ Links visual object to physics body β”‚ β”‚ β”‚ β”‚ 6. step_simulation(sim_id, steps=600) # 10s @ 60 FPS β”‚ β”‚ β†’ Physics oracle runs simulation β”‚ β”‚ β”‚ β”‚ 7. stage_add_shot(mode="orbit", focus="ball", ...) β”‚ β”‚ β†’ Defines camera cinematography β”‚ β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ β”‚ BAKING PHASE β”‚ β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ β”‚ 8. stage_bake_simulation(scene_id, sim_id, fps=60, dur=10) β”‚ β”‚ β†’ Fetches physics data from Rapier β”‚ β”‚ β†’ Converts to keyframes β”‚ β”‚ β†’ Stores in /animations/ball.json β”‚ β”‚ β”‚ β”‚ 9. stage_export_scene(format="remotion-project") β”‚ β”‚ β†’ Generates R3F/Remotion code β”‚ β”‚ β†’ Includes baked animation data β”‚ β”‚ β†’ Returns artifact URIs β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ Authoring = "What should exist and where?" Baking = "What motion actually happened?"

Key Insight: Authoring is declarative (you define intent), baking is computational (physics oracle generates the motion).


🎬 Example Workflow

1. Simple Falling Ball Demo

# 1. Create scene scene = await stage_create_scene( name="falling-ball-demo", description="Ball falling under gravity" ) # 2. Add ground plane await stage_add_object( scene_id=scene.scene_id, object_id="ground", object_type="plane", size_x=20.0, size_y=20.0, material_preset="metal-dark" ) # 3. Add falling ball await stage_add_object( scene_id=scene.scene_id, object_id="ball", object_type="sphere", radius=1.0, position_y=5.0, material_preset="glass-blue", color_r=0.3, color_g=0.5, color_b=1.0 ) # 4. Add orbiting camera shot await stage_add_shot( scene_id=scene.scene_id, shot_id="orbit-shot", camera_mode="orbit", focus_object="ball", orbit_radius=8.0, orbit_elevation=30.0, orbit_speed=0.1, start_time=0.0, end_time=10.0 ) # 5. Export to Remotion result = await stage_export_scene( scene_id=scene.scene_id, format="remotion-project" )

2. Physics-Driven Animation

Note: This example uses the public Rapier service (https://rapier.chukai.io) by default. No configuration needed!

# 1. Create physics simulation (chuk-mcp-physics) sim = await create_simulation(gravity_y=-9.81) await add_rigid_body( sim_id=sim.sim_id, body_id="ball", body_type="dynamic", shape="sphere", radius=1.0, position=[0, 5, 0] ) # 2. Create scene scene = await stage_create_scene(name="physics-demo") await stage_add_object( scene_id=scene.scene_id, object_id="ball", object_type="sphere", radius=1.0, position_y=5.0 ) # 3. Bind physics to visual await stage_bind_physics( scene_id=scene.scene_id, object_id="ball", physics_body_id=f"rapier://{sim.sim_id}/body-ball" ) # 4. Run simulation (chuk-mcp-physics) await step_simulation(sim_id=sim.sim_id, steps=600) # 5. Bake physics β†’ keyframes await stage_bake_simulation( scene_id=scene.scene_id, simulation_id=sim.sim_id, fps=60, duration=10.0 ) # 6. Export with animation data await stage_export_scene( scene_id=scene.scene_id, format="r3f-component" )

πŸ“š Examples

The examples/ directory contains ready-to-run demonstrations of all features.

🌟 Start Here: Golden Path

The canonical example showing the complete pipeline:

uv run examples/00_golden_path_ball_throw.py

This example demonstrates:

  • βœ… Authoring phase - Scene creation, object placement, camera shots

  • βœ… Baking phase - Physics simulation β†’ keyframes (conceptual)

  • βœ… Export phase - Generate R3F/Remotion code

  • βœ… Artifact URIs - How chuk-mcp-stage integrates with chuk-artifacts

  • βœ… Two-phase model - Declarative β†’ Computational

  • βœ… Complete pipeline - Physics β†’ Stage β†’ Motion β†’ Video

This is the best example to understand the CHUK stack cohesion.

Getting Started

# Run any example uv run examples/00_golden_path_ball_throw.py # ⭐ Start here! uv run examples/01_simple_scene.py uv run examples/02_physics_integration_demo.py uv run examples/03_camera_shots_demo.py uv run examples/04_export_formats.py uv run examples/05_full_physics_workflow.py

Example Guide

Example

Purpose

What You'll Learn

00_golden_path_ball_throw.py ⭐

Complete pipeline

Full workflow, artifact URIs, two-phase model

01_simple_scene.py

Basic scene creation

Objects, transforms, materials, simple camera

02_physics_integration_demo.py

Physics binding concepts

Binding objects to physics bodies, metadata

03_camera_shots_demo.py

Camera cinematography

ORBIT, STATIC, DOLLY, CHASE modes, easing functions

04_export_formats.py

Export capabilities

JSON, R3F, Remotion, glTF formats and use cases

05_full_physics_workflow.py

Complete pipeline

Full physics-to-video workflow with public Rapier

Example Outputs

00_golden_path_ball_throw.py ⭐ - Complete pipeline demonstration

πŸ“‚ Artifact URIs (Not file contents!): Scene data: artifact://stage/golden-path-ball-throw/exports/scene.json R3F: artifact://stage/golden-path-ball-throw/exports/r3f/Scene.tsx Remotion: artifact://stage/golden-path-ball-throw/exports/remotion/ 🎬 Complete Pipeline: 1. Authoring - Define scene structure βœ“ 2. Physics - Create simulation (conceptual) 3. Binding - Link objects β†’ bodies βœ“ 4. Baking - Physics β†’ keyframes (conceptual) 5. Export - Scene β†’ R3F/Remotion βœ“ 6. Render - Remotion β†’ MP4 (external)

01_simple_scene.py - Creates falling ball scene

βœ“ Created scene: falling-ball βœ“ Added ground plane βœ“ Added ball at (0, 5, 0) βœ“ Added orbit camera shot (10s)

03_camera_shots_demo.py - 38-second multi-shot sequence

πŸ“Ή Shot Sequence: β€’ 0.0s - 10.0s ORBIT - Smooth orbit around center β€’ 10.0s - 15.0s STATIC - Static wide angle β€’ 15.0s - 22.0s DOLLY - Dolly tracking shot β€’ 22.0s - 28.0s CHASE - Chase with spring easing β€’ 28.0s - 33.0s ORBIT - Fast linear orbit β€’ 33.0s - 38.0s STATIC - Low angle hero shot

04_export_formats.py - Exports to all formats

βœ“ JSON: /exports/scene.json βœ“ R3F: /exports/r3f/Scene.tsx βœ“ Remotion: /exports/remotion/Root.tsx βœ“ glTF: /exports/scene.gltf Note: In production, these would be artifact URIs like: artifact://stage/{scene_id}/exports/scene.json

05_full_physics_workflow.py - Shows complete pipeline

🎬 Complete Pipeline: 1. Physics Simulation (chuk-mcp-physics) 2. Scene Composition (chuk-mcp-stage) βœ“ 3. Bind Physics βœ“ 4. Bake Simulation (Rapier service) 5. Export (R3F/Remotion) βœ“ 6. Render Video (Remotion)

Learning Path

Recommended order:

  1. Start with ⭐ - See the complete pipeline first

  2. Understand basics with 01_simple_scene.py

  3. Explore camera control with 03_camera_shots_demo.py

  4. Learn export options with 04_export_formats.py

  5. See physics concepts with 02_physics_integration_demo.py

  6. Complete workflow with 05_full_physics_workflow.py

Why start with golden path? It shows you the destination (full pipeline) before diving into individual pieces. You'll understand how all the tools work together in the CHUK stack.


πŸ—οΈ Architecture

Scene Storage

  • Backend: chuk-artifacts (VFS-backed workspaces)

  • Format: JSON scene definitions with nested objects

  • Scope: SESSION (ephemeral), USER (persistent), SANDBOX (shared)

Each scene is a workspace containing:

/scene.json # Scene definition /animations/ # Baked keyframe data ball.json car.json /export/ # Generated R3F/Remotion code r3f/ remotion/

Camera Path Modes

Mode

Use Case

Parameters

orbit

Product shots, inspection

radius, elevation, speed, focus

static

Fixed observation

position, look_at

chase

Follow moving objects

target, offset, damping

dolly

Linear reveals

from_position, to_position, look_at

flythrough

Scene tours

waypoints[]

crane

Cinematic sweeps

pivot, arc, height_range

Material Presets

  • metal-dark, metal-light

  • glass-clear, glass-blue, glass-green

  • plastic-red, plastic-blue, plastic-white

  • rubber-black

  • wood-oak

Export Formats

  • R3F Component - React Three Fiber .tsx files

  • Remotion Project - Full project with package.json

  • glTF - Static 3D scene file

  • JSON - Raw scene data

VFS & Artifacts Integration

chuk-mcp-stage is tightly integrated with chuk-artifacts and chuk-virtual-fs for storage and asset management.

Why This Matters

Unlike typical MCP servers that return large JSON blobs inline, chuk-mcp-stage returns artifact URIs:

# ❌ Traditional approach (bloated) { "scene_data": "...<10MB of JSON>...", "r3f_component": "...<5000 lines of TSX>...", "animations": "...<50MB of keyframes>..." } # βœ… CHUK approach (cohesive) { "scene": "artifact://stage/demo-scene/scene.json", "component": "artifact://stage/demo-scene/export/r3f/Scene.tsx", "animations": "artifact://stage/demo-scene/animations/ball.json" }

Benefits:

  1. No inline bloat - Tools return URIs, not massive data

  2. Persistent storage - Scenes survive across sessions (if using USER scope)

  3. VFS operations - Use vfs_ls, vfs_find, vfs_cp to manage scene files

  4. Cross-tool sharing - Other MCP servers can access same artifacts

  5. Checkpoint support - Version control for scene iterations

Storage Model

Each scene = one workspace in chuk-artifacts:

artifact://stage/{scene_id}/ β”œβ”€β”€ scene.json # Scene definition β”œβ”€β”€ animations/ # Baked physics keyframes β”‚ β”œβ”€β”€ ball.json # Per-object animation data β”‚ β”œβ”€β”€ car.json β”‚ └── character.json └── export/ # Generated code β”œβ”€β”€ r3f/ # React Three Fiber β”‚ β”œβ”€β”€ Scene.tsx β”‚ β”œβ”€β”€ Camera.tsx β”‚ └── animations.json β”œβ”€β”€ remotion/ # Remotion project β”‚ β”œβ”€β”€ Composition.tsx β”‚ β”œβ”€β”€ Root.tsx β”‚ └── package.json └── gltf/ # 3D model exports └── scene.gltf

Example: Working with Artifacts

# 1. Create scene (returns artifact URI) result = await stage_create_scene(name="demo") # β†’ {"scene_id": "demo-xyz", "workspace": "artifact://stage/demo-xyz"} # 2. Add objects and bake simulation # ... (authoring phase) # 3. Export to Remotion (returns artifact URIs) export_result = await stage_export_scene( scene_id="demo-xyz", format="remotion-project", output_path="/export/remotion" ) # β†’ { # "composition": "artifact://stage/demo-xyz/export/remotion/Composition.tsx", # "root": "artifact://stage/demo-xyz/export/remotion/Root.tsx", # "package": "artifact://stage/demo-xyz/export/remotion/package.json" # } # 4. Use VFS tools to explore (via chuk-virtual-fs MCP) await vfs_ls("artifact://stage/demo-xyz/export/remotion") # β†’ ["Composition.tsx", "Root.tsx", "package.json"] await vfs_read("artifact://stage/demo-xyz/export/remotion/package.json") # β†’ Returns package.json contents # 5. Copy to another location await vfs_cp( "artifact://stage/demo-xyz/export/remotion", "artifact://projects/my-video" )

Integration with Other CHUK Tools

chuk-mcp-r3f-preview can directly preview scenes:

# Stage creates scene scene_uri = "artifact://stage/demo-xyz/export/r3f/Scene.tsx" # R3F preview server loads it await r3f_preview_scene(scene_uri) # β†’ Opens interactive 3D preview in browser

chuk-motion can render baked animations:

# Stage bakes physics animation_uri = "artifact://stage/demo-xyz/animations/ball.json" # Motion applies spring physics to keyframes await motion_apply_spring(animation_uri, stiffness=100)

This is where the CHUK stack cohesion shines: Every tool speaks the same artifact URI language.


πŸ”— Integration with CHUK Stack

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ chuk-mcp-stage β”‚ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ β”‚ β”‚ Scene Graph β”‚ β”‚ Camera β”‚ β”‚ Physics Bridge β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ Paths β”‚ β”‚ β”‚ β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β”‚ β”‚ β–Ό β–Ό β–Ό β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ chuk-artifacts β”‚ β”‚ chuk-motion β”‚ β”‚ chuk-mcp-physics β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ (Rapier) β”‚ β”‚ β€’ scene.json β”‚ β”‚ β€’ easing β”‚ β”‚ β”‚ β”‚ β€’ assets/ β”‚ β”‚ β€’ springs β”‚ β”‚ β€’ rigid bodies β”‚ β”‚ β€’ animations/ β”‚ β”‚ β€’ keyframes β”‚ β”‚ β€’ constraints β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”˜ β”‚ β€’ sim state β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β–Ό β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ Remotion β”‚ β”‚ β”‚ β”‚ β€’ R3F render β”‚ β”‚ β€’ video export β”‚ β”‚ β€’ MP4 output β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

🎯 Use Cases

Immediate Wins

  1. Physics Explainer Videos - Auto-generate educational content

  2. Simulation-as-a-Service - LLMs can request visualizations

  3. Procedural B-Roll - Synthetic motion graphics

Vertical Plays

  1. Motorsport Visualization - Racing lines, braking zones, overtakes

  2. 3D Data Storytelling - Animated datasets with cinematography

  3. Science Journalism - Render model predictions visually

Weird & Powerful

  1. Explainable AI Animations - Show what models are thinking

  2. Virtual Physics Lab - Programmable experiments

  3. Agent Cinematography - AI chooses camera paths


πŸ“ Data Models

All models are Pydantic-native with no dictionary goop:

from chuk_mcp_stage.models import ( Scene, # Complete scene definition SceneObject, # 3D object (mesh, material, transform) Shot, # Camera path + time range CameraPath, # Camera movement definition Material, # PBR material properties Environment, # Lighting & background BakedAnimation, # Physics β†’ keyframes )

Enums everywhere:

ObjectType.SPHERE MaterialPreset.GLASS_BLUE CameraPathMode.ORBIT LightingPreset.THREE_POINT ExportFormat.R3F_COMPONENT

πŸ§ͺ Testing

# Run tests pytest # With coverage pytest --cov=chuk_mcp_stage

πŸ› οΈ Development

# Install dev dependencies pip install -e ".[dev]" # Format black src/ tests/ # Lint ruff check src/ # Type check mypy src/

πŸ“„ License

MIT License - see LICENSE for details


🌟 Why This Matters

Most people can: βœ… Run simulations βœ… Generate charts βœ… Animate text

Almost nobody can:

Simulate β†’ Direct β†’ Render β†’ Explain β†’ Export

chuk-mcp-stage gives you that pipeline.

You're not rendering things anymore. You're producing explainable simulations as media.


Built with ❀️ for the CHUK AI stack

-
security - not tested
A
license - permissive license
-
quality - not tested

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-stage'

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