A golf hole should be a typed object before it is a mesh. courseforge/unreal-playground is a Python-first learning environment for AI-assisted course design. Agents write a validated CourseDesign. Unreal evaluates it in a game-engine world. Blender realizes it as a portable hole.glb. Then Python scores, critiques, and revises.
Python owns orchestration, schemas, scoring, storage, and the learning loop. Unreal and Blender are interchangeable backends — including a pure-Python fake so the whole loop runs without Docker or an editor.
The loop
prompt
│
▼
DesignerAgent ──► CourseDesign JSON
│ (tee, green, fairway spline, hazards)
├──────────────► Unreal evaluate ──► metrics + camera PNGs
└──────────────► Blender realize ──► hole.glb + preview
│
▼
PlayabilityAgent ──► score / critique ──► revise ──► next iteration
They are not two copies of the same renderer. Unreal answers “is this hole measurable as built?” Blender answers “what does this hole look like as geometry?” Both consume the same design object.
# Offline — no Unreal, no Docker
python python_env/orchestration/run_iteration.py \
--prompt "short risk-reward par 4 in a Pine Barrens style" --fake
python python_env/orchestration/run_experiment.py \
--prompt "links par 5 for a scratch golfer" --iterations 3 --fake
Each run lands under python_env/datasets/generated/<job_id>/: prompt, design JSON, job JSON, metrics, score, critique, screenshots, logs.
Where the engines actually are
Phase 1 is done. Pydantic schemas, deterministic designer/routing/critic agents, fake Unreal, run_iteration / run_experiment / run_batch, and dataset archival. The MVP hole is a short Pine Barrens par 4 you can generate on a laptop.
Phase 2 wired the CourseForge worker standard. A persistent unreal-worker runs the versioned unreal-golf-build job package. Backends swap without changing the agent graph: FakeUnrealRunner, WorkerUnrealRunner, one-shot Docker, or a host LocalUnrealRunner gated by COURSEFORGE_REAL_UNREAL=1.
Dual-engine graphics (FEAT-003) is the recent ship. Host Blender 4.x exports a real hole.glb plus Cycles preview. Host Unreal now goes past placeholder boxes:
- fairway
SplineComponent, rough and tree-line proxies - heightmap
.r16+ realALandscapeimport through a thinGolfCourseC++ bridge - PCG graphs + volume ISM fill when the commandlet cannot tick a StaticMeshSpawner
- InstancedFoliage tree line from a saved foliage type
End-to-end Embabel iterations have run with both host binaries in the same job (Landscape + PCG on Unreal, glb/preview on Blender). Kind blender-worker already runs the same package over HTTP. Full in-pod Unreal golf jobs are still the open edge — the 35–49 GB worker image is a local/Kind concern, not CI.
Embabel on top of the same contracts
A Python mirror of Embabel’s nested-agent (Matryoshka) pattern lives in python_env/embabel_explore/. CourseDesignAgent nests design → evaluate → realize_blender → critique. Placement (fake / host binary / Kind worker) swaps underneath without rewriting the graph.
golf-embabel-web on port 8765) is chat + before/after, validation gates, and inline revise/redo. The same GUI can deploy into the CourseForge Kind suite. Cookbook recipes — type chaining, conditions, stuck recovery, RepeatUntil, thinking, streaming — are mapped onto this golf loop, not a second travel-agent demo.
Process sits on SDLC-SPDD canvases (FEAT-001 MVP hole, FEAT-002 worker integration, FEAT-003 dual-engine). The interesting remaining work is richer artist-authored PCG assets and a clean Kind Unreal worker run — not another schema rewrite.
Source: github.com/courseforge/unreal-playground
Related: embabel-v1-learning · SDLC-SPDD
No comments:
Post a Comment