stepupgaming/infinite-backlot

Local-first autonomous 3D content-production system (Bevy 0.19). Plans, executes, voices, and renders watchable episodes with an autonomous camera director and truthful LLM/fallback attribution.

0

stars

14

commits

Python

primary language

Jul 17, 2026

updated

README

Infinite Backlot

A local-first, autonomous 3D content world. A showrunner "director" (an OpenAI-compatible LLM, or a built-in deterministic fallback) continuously authors watchable, short-form narrative episodes from a persistent 3D world rendered in Bevy 0.19. Each episode is validated, rehearsed, rendered, and committed as a machine-readable package that can be replayed, inspected, or exported.

This repository is the runnable foundation described in the PRD's Content Proof (Phase 0) and the core of the Episode Engine (Phase 1):

  • An OpenAI-compatible LLM client (/v1/chat/completions, structured output).
  • A bounded, schema-validated protocol so the model can never emit an instruction the world cannot execute.
  • A deterministic director fallback so the product runs with zero external services.
  • A greybox Bevy world with 4 characters, a camera rig, and a watchability governor.
  • A committed episode package (JSONL events, dialogue, captions, camera plan, world deltas, diagnostics, a Gemmy-style manifest, and a human report).

Architecture

A Cargo workspace with three crates:

backlot-core/    protocol, world model, validation, deterministic director,
                 story application, episode packaging, seeded RNG, config
backlot-llm/     OpenAI-compatible async client + LLM-backed episode author
                 (graceful per-piece fallback to the deterministic director)
backlot-app/     Bevy 0.19 application: state machine, greybox scene,
                 navigation, beat execution, camera direction, captions,
                 watchability governor, operator HUD, commit + replay

Bounded agency (safety by construction)

The LLM decides narrative only. Every response is parsed, schema-validated, semantically validated, and capability-checked before a single byte reaches the world (backlot-core/src/validation.rs). The vocabulary of allowed actions (KNOWN_ACTIONS), camera intents (KNOWN_CAMERA_INTENTS), and entities is closed; invalid commands are rejected or deterministically repaired. The model never moves geometry, allocates memory, or performs I/O outside the protocol.

Episode pipeline

director.author(ctx)
   └─ structured EpisodePlan (beats) + per-beat BeatCommand
validate_plan(world, plan)  → ValidatedPlan
validate_beat_command(...)  → ResolvedBeat (ResolvedAction[])
   └─ committed to the Bevy player, which:
        • navigates characters (kinematic)
        • fires actions on a deterministic schedule
        • eases the camera rig toward per-beat intents
        • emits captions + logs events/dialogue
        • runs the watchability governor (forces a beat end on > max_dead_air)
apply_persistent_changes(world, plan.persistent_changes)  → world delta
EpisodePackage::write(output_dir)  → episodes/<id>/...

State machine (backlot-app/src/state.rs)

Boot → AssetLoading → Idle → EpisodeSelecting → EpisodePlanning → PlanValidation → Rehearsing → EpisodeReady → Rendering → Committing → Reviewing → (loop). The LLM request runs on a dedicated worker thread so the Bevy main thread never blocks.


Running

# build
cargo build --release

# run (open the operator window; press keys at the review screen)
cargo run -p backlot-app

Configuration lives in data/config.toml (auto-created defaults if missing).

Operator controls (at the Review screen)

KeyAction
Nnext episode (auto-advances if episodes_to_run > 0)
Rreplay the render pass of the last episode (no new LLM, no commit)
Qquit

Set episodes_to_run in data/config.toml to a positive number for an unattended demo run (it auto-advances and exits when the count is reached).


Configuring the LLM (OpenAI-compatible)

The LLM section is intentionally an OpenAI-compatible shape — point it at any server that speaks /v1/chat/completions:

[llm]
base_url = "http://localhost:1234/v1"   # LM Studio / llama.cpp default
model    = "gemma-4-26b-a3b"            # or any chat model
api_key  = ""                           # local servers usually accept empty
timeout_secs = 120
temperature   = 0.4
max_tokens    = 2048
max_retries   = 2
stream        = false

Examples of compatible endpoints:

  • LM Studiohttp://localhost:1234/v1, model = the loaded model id.
  • Ollamahttp://localhost:11434/v1.
  • vLLM / OpenAI / OpenRouter / Together — set base_url, model, and a real api_key.

Structured output is requested via response_format JSON schema (strict, with a json_object retry). On any malformed, slow, or unavailable response the author falls back per piece to the deterministic director, so the product is always runnable.

  • force_fallback = true → never touch the network; always deterministic.
  • force_fallback = false → attempt the real LLM first, fall back on failure.

The deterministic fallback is also the safety net if no model is loaded.


Committed episode package

Each episode is written to <output_dir>/episodes/<id>/:

FilePurpose
episode.jsonid / title / logline / duration
plan.jsonthe full structured EpisodePlan
world_before.json, world_after.jsoncanonical world before/after
events.jsonltimed, typed events (move, speak, flicker, …)
dialogue.jsonspoken lines with voice ids + timings
captions.jsoncaption cues for burn-in / subtitles
camera_plan.jsonper-shot camera intent + transform
render_manifest.jsonoutput asset paths (mp4 / thumbnail)
diagnostics.jsonmetrics, LLM request/failure counts, repairs
gemmy_manifest.jsondownstream export manifest
report.mdhuman-readable quality report

Production pipeline

Production replays an accepted whole-episode Gemma artifact without making new LLM requests, generates every dialogue line through one gepard_batch worker invocation, rebuilds the timeline from measured WAV durations, renders the Blender-authored semantic set through Bevy's GPU renderer, and packages native 1080×1920 H.264/AAC outputs with FFmpeg diagnostics and external-review frames.

Espeak remains available only as an explicit diagnostic/quick-preview backend. A Gepard production failure is fatal and never falls back to espeak or estimated audio.

Architecture documents

Tests

cargo test

backlot-core includes tests for the deterministic director (valid, executable, reproducible) and a headless end-to-end pipeline test that authors, validates, applies persistent changes, and writes a full episode package to disk.

Contributors

stepupgaming

14 commits

stepupgaming/infinite-backlot

Local-first autonomous 3D content-production system (Bevy 0.19). Plans, executes, voices, and renders watchable episodes with an autonomous camera director and truthful LLM/fallback attribution.

0

stars

14

commits

Python

primary language

Jul 17, 2026

updated

README

Infinite Backlot

A local-first, autonomous 3D content world. A showrunner "director" (an OpenAI-compatible LLM, or a built-in deterministic fallback) continuously authors watchable, short-form narrative episodes from a persistent 3D world rendered in Bevy 0.19. Each episode is validated, rehearsed, rendered, and committed as a machine-readable package that can be replayed, inspected, or exported.

This repository is the runnable foundation described in the PRD's Content Proof (Phase 0) and the core of the Episode Engine (Phase 1):

  • An OpenAI-compatible LLM client (/v1/chat/completions, structured output).
  • A bounded, schema-validated protocol so the model can never emit an instruction the world cannot execute.
  • A deterministic director fallback so the product runs with zero external services.
  • A greybox Bevy world with 4 characters, a camera rig, and a watchability governor.
  • A committed episode package (JSONL events, dialogue, captions, camera plan, world deltas, diagnostics, a Gemmy-style manifest, and a human report).

Architecture

A Cargo workspace with three crates:

backlot-core/    protocol, world model, validation, deterministic director,
                 story application, episode packaging, seeded RNG, config
backlot-llm/     OpenAI-compatible async client + LLM-backed episode author
                 (graceful per-piece fallback to the deterministic director)
backlot-app/     Bevy 0.19 application: state machine, greybox scene,
                 navigation, beat execution, camera direction, captions,
                 watchability governor, operator HUD, commit + replay

Bounded agency (safety by construction)

The LLM decides narrative only. Every response is parsed, schema-validated, semantically validated, and capability-checked before a single byte reaches the world (backlot-core/src/validation.rs). The vocabulary of allowed actions (KNOWN_ACTIONS), camera intents (KNOWN_CAMERA_INTENTS), and entities is closed; invalid commands are rejected or deterministically repaired. The model never moves geometry, allocates memory, or performs I/O outside the protocol.

Episode pipeline

director.author(ctx)
   └─ structured EpisodePlan (beats) + per-beat BeatCommand
validate_plan(world, plan)  → ValidatedPlan
validate_beat_command(...)  → ResolvedBeat (ResolvedAction[])
   └─ committed to the Bevy player, which:
        • navigates characters (kinematic)
        • fires actions on a deterministic schedule
        • eases the camera rig toward per-beat intents
        • emits captions + logs events/dialogue
        • runs the watchability governor (forces a beat end on > max_dead_air)
apply_persistent_changes(world, plan.persistent_changes)  → world delta
EpisodePackage::write(output_dir)  → episodes/<id>/...

State machine (backlot-app/src/state.rs)

Boot → AssetLoading → Idle → EpisodeSelecting → EpisodePlanning → PlanValidation → Rehearsing → EpisodeReady → Rendering → Committing → Reviewing → (loop). The LLM request runs on a dedicated worker thread so the Bevy main thread never blocks.


Running

# build
cargo build --release

# run (open the operator window; press keys at the review screen)
cargo run -p backlot-app

Configuration lives in data/config.toml (auto-created defaults if missing).

Operator controls (at the Review screen)

KeyAction
Nnext episode (auto-advances if episodes_to_run > 0)
Rreplay the render pass of the last episode (no new LLM, no commit)
Qquit

Set episodes_to_run in data/config.toml to a positive number for an unattended demo run (it auto-advances and exits when the count is reached).


Configuring the LLM (OpenAI-compatible)

The LLM section is intentionally an OpenAI-compatible shape — point it at any server that speaks /v1/chat/completions:

[llm]
base_url = "http://localhost:1234/v1"   # LM Studio / llama.cpp default
model    = "gemma-4-26b-a3b"            # or any chat model
api_key  = ""                           # local servers usually accept empty
timeout_secs = 120
temperature   = 0.4
max_tokens    = 2048
max_retries   = 2
stream        = false

Examples of compatible endpoints:

  • LM Studiohttp://localhost:1234/v1, model = the loaded model id.
  • Ollamahttp://localhost:11434/v1.
  • vLLM / OpenAI / OpenRouter / Together — set base_url, model, and a real api_key.

Structured output is requested via response_format JSON schema (strict, with a json_object retry). On any malformed, slow, or unavailable response the author falls back per piece to the deterministic director, so the product is always runnable.

  • force_fallback = true → never touch the network; always deterministic.
  • force_fallback = false → attempt the real LLM first, fall back on failure.

The deterministic fallback is also the safety net if no model is loaded.


Committed episode package

Each episode is written to <output_dir>/episodes/<id>/:

FilePurpose
episode.jsonid / title / logline / duration
plan.jsonthe full structured EpisodePlan
world_before.json, world_after.jsoncanonical world before/after
events.jsonltimed, typed events (move, speak, flicker, …)
dialogue.jsonspoken lines with voice ids + timings
captions.jsoncaption cues for burn-in / subtitles
camera_plan.jsonper-shot camera intent + transform
render_manifest.jsonoutput asset paths (mp4 / thumbnail)
diagnostics.jsonmetrics, LLM request/failure counts, repairs
gemmy_manifest.jsondownstream export manifest
report.mdhuman-readable quality report

Production pipeline

Production replays an accepted whole-episode Gemma artifact without making new LLM requests, generates every dialogue line through one gepard_batch worker invocation, rebuilds the timeline from measured WAV durations, renders the Blender-authored semantic set through Bevy's GPU renderer, and packages native 1080×1920 H.264/AAC outputs with FFmpeg diagnostics and external-review frames.

Espeak remains available only as an explicit diagnostic/quick-preview backend. A Gepard production failure is fatal and never falls back to espeak or estimated audio.

Architecture documents

Tests

cargo test

backlot-core includes tests for the deterministic director (valid, executable, reproducible) and a headless end-to-end pipeline test that authors, validates, applies persistent changes, and writes a full episode package to disk.

Contributors

stepupgaming

14 commits

Languages

Python

48.3%

Rust

40.1%

C++

10.9%