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

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