# Text To 3d Scene

> Turn plain-English scene descriptions into walkable 3D environments rendered as standalone HTML files. Use this skill whenever the user asks to "build", "create", "generate", or "render" a 3D scene, environment, level, room, interior, village, compound, or any spatial composition they want to see and walk through — even if they don't say "3D" explicitly (e.g. "make me a medieval tavern", "design…

- **Type:** Skill
- **Install:** `agentstack add skill-steveonw-text-to-3d-text-to-3d`
- **Verified:** Yes — security-reviewed for prompt injection and unsafe behavior
- **Seller:** [steveonw](https://agentstack.voostack.com/s/steveonw)
- **Installs:** 0
- **Category:** [Agent Skills](https://agentstack.voostack.com/c/agent-skills)
- **Latest version:** 0.1.0
- **License:** MIT
- **Upstream author:** [steveonw](https://github.com/steveonw)
- **Source:** https://github.com/steveonw/text-to-3d

## Install

```sh
agentstack add skill-steveonw-text-to-3d-text-to-3d
```

Requires the [AgentStack CLI](https://agentstack.voostack.com/docs/cli). Works with Claude Code, Cursor, and any MCP-compatible agent.

## About

# Text-to-3D Scene Skill

Build walkable 3D scenes from text descriptions. The solver handles *where* things go. You handle *what things look like* — fresh, every scene, every piece.

---

## The core philosophy

**You are a toddler with blocks.**

A toddler building a house doesn't look up "house" in a catalog. They grab blocks, stand them up, and declare *"this is a house."* Next time, different blocks, different arrangement, still a house. The identity comes from the act of making, not from a template.

That is the shape of this skill. **Do not build a template library.** Do not define a canonical "tree" and reuse it 50 times. Each piece is improvised in the moment, for this specific scene, considering what's around it.

Why this matters:

- **Variation is the point.** A scene where every chair is identical feels dead. A scene where each chair is hand-made, slightly different, feels alive.
- **Context should shape appearance.** A tree next to the path looks different from a tree in deep forest. The third chair in a row can be slightly scruffier than the first two. These micro-decisions are what make a scene feel handcrafted.
- **Your attention goes to appearance, not coordinates.** The solver places pieces. You don't have to track coordinates or avoid overlaps. Your whole creative budget goes to "what should this specific thing look like, here, next to these neighbors."

If you catch yourself thinking *"I defined a tree earlier, I'll reuse the same geometry,"* stop. Author a new tree. The variety is deliberate.

---

## The division of labor

| Responsibility | Who owns it |
|----------------|-------------|
| What does the user want? (decomposition) | You |
| Where does each piece go? (placement) | Solver |
| How does the solver know where to put things? (DSL) | You write it |
| What does piece #7 look like, specifically? | You (improvised) |
| Did the scene come out coherent? (verification) | Verifiers + you reading output |
| Final HTML assembly | Scaffold |

Notice: you do not own placement. If a placement feels wrong, **change the DSL and re-solve**. Do not try to override the solver's coordinates.

---

## The workflow

### 1. Decompose the request

User says: *"Build me a forest shrine."*

Think: what's in a forest shrine? A central altar or fountain. Trees around it in some arrangement. A path approaching it. Maybe lanterns along the path. Maybe stones or rubble as atmosphere.

Don't skip this step. A bad decomposition produces a bad DSL produces a bad scene.

### 2. Write the DSL

Compact, declarative. See `references/dsl_reference.md` for full syntax. Example:

```
anchor fountain shrine_center
ma hard radius 3

object tree label forest count 12 shape circle radius 7 clusters 4 spread 1
object road label path count 10 from shrine_center heading south steps 10 wobble 0.1
object lantern label lanterns count 5 target road side any distance 1 spacing 2
object rubble label clutter count 3 radius 10
```

The DSL is intentionally small. You can write a 46-piece scene in ~35 tokens of intent.

### 3. Run the solver

```python
import sys; sys.path.insert(0, "scripts")
from dropgrid.api import solve_object_scene

result = solve_object_scene(DSL, seed=42, debug=False)
print(result.to_ascii(include_legend=True))
```

The solver returns a `SceneResult` with every placed piece. `.to_ascii()` prints the grid so you can see the layout before committing to geometry authoring.

### 4. Read the ASCII. Decide.

Look at the output before writing a single primitive. The ASCII catches layout problems that authoring cannot fix.

**ASCII review checklist — check these before proceeding:**

- [ ] **Paths terminate where intended.** An L-shaped path that ends mid-grid means the DSL path parameters are wrong. Fix the DSL, re-solve.
- [ ] **Clusters cluster around something.** Objects scattered with `radius N` are placed relative to the grid center unless anchored. If a cluster of objects looks orphaned or far from the focal piece, add an anchor relation in the DSL.
- [ ] **No isolated outliers.** A single piece alone in empty space usually means it landed outside the cluster by chance. Tighten the radius or reduce count.
- [ ] **Object counts feel right.** The ASCII makes it easy to count — six trees should read as six, not four with two hiding behind the focal piece.
- [ ] **Orientation makes sense.** Lanterns beside a path should appear adjacent to the path symbol, not behind the tree ring.

If anything is wrong → **change the DSL and re-solve**. The solver is cheap (~2ms). Two of the six most common naturalness failures are visible in the ASCII before any geometry is written — catching them here is free.

If yes → go to step 5.

### 5. Verify

Run cheap sanity checks before committing to a full render:

Easiest path — one call gets all three views with the adapter wired in:

```python
from verification.run_all import verify, format_report
print(format_report(verify(result)))
```

Or run the verifiers individually:

- **Braille view** (`scripts/verification/braille_view.py`) — a silhouette of the scene. Good for catching "wait, nothing should be over *there*."
- **Path walk** (`scripts/verification/path_walk.py`) — simulates walking through the scene as text. Catches dead zones, awkward spacing, unreachable areas.
- **Spatial validator** (`scripts/verification/spatial_validate.py`) — overlaps, out-of-bounds pieces, floating geometry.

The verifiers expect their own input formats (`parts` for braille, `items` for spatial); use `result.to_layout('parts')` or `result.to_layout('items')` to get them. `run_all.py` does this conversion for you.

See `references/checklists.md` for what to look for in verification output.

### 6. Author geometry per piece

First, get the context packet for every piece:

```python
from authoring.context_exporter import export_all_contexts
contexts = export_all_contexts(result)
```

Each context packet tells you: is this piece on the edge or interior? Is it near a path? Which way is "outward"? Who are its nearest neighbors? Use this to shape the geometry.

For each piece, produce a geometry packet — a list of Three.js-style primitives in the piece's local coordinate space (y = 0 is the floor):

```python
packet = {
    "piece_id": 7,
    "primitives": [
        {
            "shape": "cylinder",
            "dimensions": [0.14, 0.18, 1.1],
            "position": [0.0, 0.55, 0.0],
            "rotation": [0.0, 0.0, 4.0],   # degrees
            "material": {"color": "#4a3218", "roughness": 0.9}
        },
        {
            "shape": "cone",
            "dimensions": [0.5, 1.1],
            "position": [-0.06, 1.65, 0.06],
            "rotation": [0.0, 0.0, 5.0],
            "material": {"color": "#2a5022", "roughness": 0.85}
        }
    ]
}
```

Then validate all packets at once:

```python
from authoring.geometry_receiver import receive_all
packets = receive_all([packet_1, packet_2, ...])   # raises GeometryError if any are invalid
```

Not "here is *the* tree." Here is *this tree, in this spot, with these neighbors.*

Read `references/authoring_guide.md` for the full context-aware authoring approach and `scripts/authoring/schema.md` for the packet format reference.

### 7. Assemble the HTML

```python
from scaffold.scaffold_v4_walkmode import generate_scene_html

html = generate_scene_html(result, packets, title="Forest Shrine")
with open("forest_shrine.html", "w") as f:
    f.write(html)
```

Produces a standalone `.html` file with:
- Orbit camera auto-framed to the scene
- First-person walk mode (WASD + mouse, press **F** to toggle)
- HUD with position and compass
- No build step, no dependencies — opens in any browser

Pieces without a geometry packet get a grey placeholder box, so partial authoring sessions still render.

### 8. Iterate with the user

The user walks through it. They say "the lanterns are too close to the path" or "the trees feel sparse on the east side." You change the DSL and re-solve, or re-author specific pieces. Commit to nothing.

---

## When things go wrong

**The ASCII looks wrong.** Read `references/checklists.md`. Usually the DSL needs adjusting — wrong mode, wrong count, wrong relation. The solver doesn't invent; it does what you told it.

**Pieces overlap or float.** Spatial validator will catch this. Usually means the DSL asked for something impossible (e.g. too many objects inside a small region). Rethink counts or radii.

**The scene renders but feels "dead" or "AI-shaped."** You probably reused geometry across pieces. Each piece should be its own small authoring decision. If all your trees are the same three cylinders stacked, that's the warning sign.

**You want to add more of the same thing.** Fine — but *more* doesn't mean *identical*. Five market stalls should be five different arrangements of similar parts, not five copies of one arrangement.

---

## Two authoring paths

Choose based on what you're building:

### Path A — Protocol path (for complex, multi-piece scenes)

Use the context exporter and geometry receiver (steps 6–7 above). Best when:
- You want validated, structured geometry packets
- You're authoring 20+ distinct piece types with careful context reactions
- You need the scaffold's fallback placeholder boxes for pieces you haven't authored yet

### Path B — Direct Three.js authoring (for demos, quick renders, custom scenes)

Skip the packet protocol. Solve the DSL, get the `SceneResult`, then write a complete Three.js HTML directly — reading `result.pieces`, their `p.gx`/`p.gz` coordinates, and `p.meta['wall_sym']` for wall orientation. This is how `examples/campsite_3d.html`, `examples/tavern_interior.html`, `examples/fishing_dock.html`, and `examples/workshop_interior.html` were built.

```python
result = solve_object_scene(DSL, seed=42, debug=False)
from dropgrid.exporters import annotate_wall_symbols
annotate_wall_symbols(result)  # populates p.meta['wall_sym'] for fence/wall pieces

# Then build your Three.js HTML directly, iterating result.pieces
# Each piece: p.type, p.gx, p.gz, p.cells, p.meta
```

Wall/fence pieces get a box-drawing char in `p.meta['wall_sym']` (e.g. `─`, `│`, `┌`, `┼`).
Use it to choose E/W vs. N/S panel geometry instead of re-deriving orientation in JS.

**Also available:** `try_now.py` is a local HTTP server (port 8000) for testing the pipeline interactively without writing code. Run `python try_now.py` and open `http://localhost:8000`.

---

## The example scenes

`examples/` contains both old-style scenes (baked-in per-type geometry — **don't extract from these**) and new-style direct-authored scenes (study these for approach):

| File | Style | Study for |
|------|-------|-----------|
| `forest_shrine_v2.html`, `village_scene.html` | Old — per-type baked geometry | Spatial composition only |
| `campsite_3d.html` | New — direct Three.js | Outdoor scene, per-channel color variation, PointLights |
| `tavern_interior.html` | New — direct Three.js | Indoor walls, wall_sym orientation, box-drawing borders |
| `fishing_dock.html` | New — direct Three.js | Water/shore split, custom props (rowboat, crab traps, reeds) |
| `workshop_interior.html` | New — direct Three.js | Stove, workbench, tool pegs, dusk window, shavings |

New-style scenes author geometry **fresh per piece, per scene**. Study the approach, not the specific geometry.

---

## What's built

The full pipeline is operational:

| Module | Location | Status |
|--------|----------|--------|
| Placement solver | `scripts/dropgrid/api.py` | ✅ working |
| DSL parser | `scripts/dropgrid/parser.py` | ✅ working |
| ASCII exporter + wall box-drawing | `scripts/dropgrid/exporters.py` | ✅ working |
| Wall orientation (single source of truth) | `annotate_wall_symbols()` in exporters | ✅ working |
| Per-piece context exporter | `scripts/authoring/context_exporter.py` | ✅ working |
| Geometry packet receiver | `scripts/authoring/geometry_receiver.py` | ✅ working |
| HTML scaffold + walk mode | `scripts/scaffold/scaffold_v4_walkmode.py` | ✅ working |
| Scene HTML from packets | `generate_scene_html()` in scaffold | ✅ working |
| Verifiers (braille, path walk, spatial) | `scripts/verification/` | ✅ working |
| Local demo server | `try_now.py` | ✅ working |

Read `CHECKLIST.md` for tier 2/3 items and known gaps.

---

## Key references

Load these when needed — don't try to read them all upfront.

| File | When to read it |
|------|-----------------|
| `references/philosophy.md` | Full writeup of the toddler-with-blocks principle |
| `references/authoring_guide.md` | How to author context-aware geometry — the craft guide |
| `references/dsl_reference.md` | Writing the scene description |
| `references/threejs-conventions.md` | Composing geometry from primitives |
| `scripts/authoring/schema.md` | Geometry packet JSON schema |
| `references/braille-spatial.md` | Reading braille verifier output |
| `references/checklists.md` | Verification passes — what to look for |
| `references/narrative-decomposition.md` | Turning a user's description into a DSL |
| `references/script-recipes.md` | Common Three.js patterns |
| `references/worked_examples/full_loop_example.md` | Full end-to-end trace: DSL → solver → context → authored geometry → HTML |
| `references/cross_piece_narrative.md` | Making a finished scene feel inhabited — kettles, ropes, worn paths, shared mats |
| `examples/campsite_3d.html` (and other new-style examples) | Live demonstrations of Path B (direct Three.js authoring) — open in browser |

---

## Anti-patterns — things this skill explicitly rejects

- **Template libraries.** No canonical "chair," "tree," "house." Author each piece fresh.
- **Re-using geometry across pieces.** Even in the same scene, each piece is its own authoring decision.
- **Overriding the solver's coordinates.** If placement is wrong, change the DSL — don't patch positions after the fact.
- **Asking the LLM to hold a large spatial layout in its head.** That's the solver's job. The LLM's job is small, local, in-context authoring decisions.
- **Treating the DSL as final art.** It's the spec, not the scene. The scene emerges from solver + authoring + verification.

## Source & license

This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.

- **Author:** [steveonw](https://github.com/steveonw)
- **Source:** [steveonw/text-to-3d](https://github.com/steveonw/text-to-3d)
- **License:** MIT

Install and usage instructions live in the source repository linked above.

## Pricing

- **Free** — Free

## Security capabilities

Automated source analysis of v0.1.0 — what this tool can access:

- **Network access:** no
- **Filesystem access:** no
- **Shell / process execution:** no
- **Environment & secrets:** no
- **Dynamic code execution:** no

*"Yes" means the capability is present in the source — more access means more to trust, not that it is unsafe.*


## Versions

- **0.1.0** — security scan: passed — Imported from the upstream source.

## Links

- Listing page: https://agentstack.voostack.com/l/skill-steveonw-text-to-3d-text-to-3d
- Seller: https://agentstack.voostack.com/s/steveonw
- Browse the marketplace: https://agentstack.voostack.com/browse

---
Listed on AgentStack — the marketplace for AI agent skills and MCP servers. Every listing is security-reviewed. Creators keep 70%.
