Skip to content
vishruthbPublic

About

text-to-2d worlds with verifiable rewards

Resources

Stars

1 star

Watchers

0 watching

Forks

Latest commit

 

History

4 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

infin

(demo, offline) key opens the door, can goes in the bin, avoid the spill (gpt-5.4) button opens the gate, grab the sample, dodge the moving hazard

infin turns a text command into a small 2d world that you can run, watch, and check. each world essentially becomes a program.

the same world can be played in a physics engine, drawn to image frames (what a vision model would see), and read directly by code to decide whether the goal was met. from one prompt it can make an endless stream of worlds that are checked to be solvable and labeled by difficulty. every step it runs produces a (frame, action, reward) record, which you would use to train a reward model.

the rules, goals, checking, and curation don't care about dimensions. only the renderer and the navigation policy would change if we wanted to transition to 3d. further, the action space is the same controller layout a 3d vision policy would use.

there are three key files here:

  • infin/objectives.py - goals as code-level checks
  • infin/napoleon.py - the solver that proves each world is solvable and records an expert's run-through
  • infin/compiler.py - compiles text into a world, offline templates or gpt-5.4

quicklinks

run offline

no api key is needed. we just run one command that in turn runs the whole offline showcase:

pip install -r requirements.txt
python run.py demo

this builds the three sample prompts offline, checks and solves each one, and writes:

  • outputs/demo_{kitchen,storage,lab}/replay.gif and .mp4, the solved run
  • outputs/demo_*/transitions.jsonl and episode.npz, the reward-model data
  • outputs/report/index.html, a simple page with one card per world

it finishes with a summary table and a pass/fail line.

run with an llm

to build worlds with a model instead of templates, you'll need an openai api key. then you can run:

export OPENAI_API_KEY=sk-...
python run.py generate --prompt "a lab with a button-gated room and a moving saw" --model openai

this uses the openai responses api with strict structured output aimed at the GenSpec schema, checks the result, and retries with the error fed back up to 3 times. if it still fails it falls back to templates, so the run never breaks. the model id in use is printed at the start of the run. model worlds are checked, not merely assumed, to be solvable, so generate resamples seeds with --tries N (default 4) and keeps the first solvable world.

commands

# build and check one world from a prompt (offline templates)
python run.py generate --prompt "find a key, unlock the door, reach the exit" \
                       --model offline --seed 1 --name myworld

# print a world: entities, goal, check report, difficulty
python run.py inspect --spec outputs/myworld/world.json

# solve a world and record a replay plus the dataset
python run.py solve --spec outputs/myworld/world.json --name myworld

# make N checked, difficulty-banded variants from one prompt
python run.py batch --prompt "kitchen can into recycling bin" --num 16 \
        --mutations layout,distractors,hazards,friction,mass \
        --min-difficulty 16 --max-difficulty 22 --name stream1

# optional human play with WASD and space, skipped cleanly if no display
python run.py play --prompt "reach the goal"

generate builds and checks the world and writes a single preview.png. it does not run a simulation, so it does not make a video. to get a replay video you run solve or demo, which play the world and record every frame.

how the goal check works

the goal of each world is checked by plain code that reads the true positions of objects every step. it does not use a model looking at pixels. the checks are simple geometry like "is the agent inside this box" or "did these two boxes overlap".

the basic checks are:

check true when
reach the agent is inside the target area
pickup the target has been held at some point
place the target is inside its container and not being held
unlock the door is open
press the button or pressure plate is pressed
avoid the hazard was never touched

these combine with all, any, or sequence (in order). because the answer is plain code reading real state, it is reliable in a way that a model reading pixels is not.

the dataset and the reward model

every step is logged as (frame, action, reward, done, satisfied_clauses). the frame is what a vision model would see. the reward is the code-level answer. that pairing is exactly what you need to train a reward model that reads frames and predicts the reward, so a policy can be scored from pixels alone without access to the engine. napoleon supplies the expert runs and mutations supply the variety.

going from 2d to 3d

the parts that define a task do not assume 2d. the world format, the goal checks, and the curation all carry over. the action space is already the controller layout a vision policy uses: move forward / back / left / right, mouse dx, mouse dy, and an interact button. in 2d we use the movement part. a 3d navigation policy plugs into the same interface. only two things change for 3d, the renderer and the navigation policy. everything around them stays.

napoleon

napoleon is our programmatic solver. it is plain code, not a model. it builds a grid of free space, runs A* to plan paths, fetches keys to open doors, moves blocking crates aside, presses buttons, times its way past moving hazards, and reaches the goal. it runs the real environment, so a success is confirmed by the same checks that define the reward. this is what lets infin promise that every world it keeps is actually solvable.

there is also an optional model-driven solver, solve --agent pixel, which sends each frame and the goal text to a vision model and asks for the next action. it turns on only when OPENAI_API_KEY is set, and falls back to napoleon otherwise. it shows that a real vision policy would plug into the same loop.

high-level architecture

flowchart TD
    P[text prompt] --> C{compiler}
    C -->|offline templates| G[GenSpec<br/>flat strict schema]
    C -->|openai structured output<br/>+ repair loop| G
    G --> V[validator<br/>refs, bounds, reachability,<br/>solvability, difficulty, caps]
    V --> W[WorldSpec<br/>+ compiled objective checker]
    W --> E[engine<br/>pymunk physics]
    W --> R[renderer<br/>image frames, gif, mp4]
    W --> O[objectives<br/>code-level goal checks]
    E --> ENV[WorldEnv<br/>gym env: obs=frame, reward=code]
    R --> ENV
    O --> ENV
    ENV --> N[napoleon<br/>A* planner, proves solvable,<br/>records expert run]
    ENV --> D[dataset<br/>frame, action, reward logs]
    ENV --> M[mutations<br/>curated batch of variants]
Loading

About

text-to-2d worlds with verifiable rewards

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages