AutoEnv should generate and evaluate environments that share one core game logic while supporting multiple presentation modalities:
- Text environments for LLM policy learning.
- 2D visual environments for image-based interaction.
- 3D visual environments for richer embodied interaction.
This document defines the current architecture, explains how 3D is built in PR #8, and sets the abstraction contract to align text/2D/3D under one model.
Core runtime is split into three layers.
- Environment semantics (
base/env)
BaseEnv: true state, transition, reward.ObsEnv: semantic observation extraction (observe_semantic).SkinEnv: skin rendering over semantic observations.
- Solver/runtime (
base/agent,benchmarks/base)
- Solver consumes skin output as agent observation.
- Benchmark runner dynamically loads each env and executes solver loop.
- Generation pipelines (
autoenv/pipeline)
GeneratorPipeline: environment code/config/levels.VisualPipeline: visual assets and runnable visual scene.
VisualPipeline.create_default(dimension="3d") builds the DAG:
Analyzer -> Strategist -> AssetGenerator -> BackgroundRemoval -> Image3DConvert -> ThreeJSAssembly
Node responsibilities:
AnalyzerNode: parse benchmark/instruction and writeanalysis.json.StrategistNode: producestrategy.jsonwith asset plan.AssetGeneratorNode: generate style-consistent 2D assets.BackgroundRemovalNode: remove background/crop for cleaner conversion.Image3DConvertNode: call Meshy image-to-3D, poll progress, download.glbtomodels_3d/.ThreeJSAssemblyNode: buildgame/index.html, copy models togame/models/, optionally ask agent to enhance JS logic.
Current 3D output is a scene runtime (index.html + models/*.glb) and not yet a canonical environment runtime with the same authority as transition/reward in Python env classes.
Without a shared contract, text/2D/3D can diverge:
- Agent input format differs by modality.
- Human display and agent display are not explicitly separated.
- Visual pipeline artifacts are not normalized for upstream orchestrators.
- 3D scene logic can drift away from canonical state transition rules.
base/env/skin_output.py introduces SkinRenderOutput:
agent_view: what solver receives.human_view: optional richer UI view.modality:text | 2d | 3d | multi.artifacts: paths/handles for render assets.metadata: auxiliary render metadata.
SkinEnv.render() now normalizes output to this contract while keeping backward compatibility with existing render_skin() implementations.
Both solver implementations (base/agent/base_solver.py, benchmarks/base/agent.py) now:
- Prefer
env.render(...)when present. - Fallback to legacy
render_skin(...)behavior. - Read observation from
info["agent_obs"]first, then fallback toinfo["skinned"].
This keeps all existing benchmark envs runnable while enabling richer modality outputs.
AutoEnvContext now carries skin_manifest.
- 2D
AssemblyNodesets manifest with game entrypoint and assets dir. - 3D
ThreeJSAssemblyNodesets manifest with HTML entrypoint and models dir.
This gives upper layers a single way to consume generated skins regardless of modality.
transition()andreward()remain the only source of environment truth.- All modalities are projections of semantic state, not separate game authorities.
- Visual code (pygame/three.js) should be treated as view/runtime adapters unless intentionally promoted to core env logic.
- Add a
TextAssemblyNodethat emits the sameskin_manifestcontract for text-only runs. - Add consistency tests:
- same action sequence over same seed,
- text/2D/3D should produce identical semantic state traces and reward traces.
- Move three.js enhancement prompts toward generated view adapters, not independent game rule engines.
- Define versioned schema for
skin_manifestto stabilize downstream tooling.
When adding a new modality:
- Keep semantic env unchanged (
BaseEnv/ObsEnv). - Implement renderer adapter that returns
SkinRenderOutput. - Ensure generation pipeline writes
skin_manifestwith a valid entrypoint. - Validate semantic consistency against text baseline.
This keeps AutoEnv extensible without modality-specific logic forks.