WVY-3D by Starpower: a 23M-parameter transformer that writes 3D art as code

WVY-3D-23m

A tiny language model that writes 3D art as code.

WVY, designed by Starpower.

WVY-3D is a 23.1-million-parameter transformer trained from scratch. Give it a short prompt like "a pixel car" and pick a format. It writes the code that draws it:

  • three.js: JavaScript that builds and returns a THREE.Group
  • SVG: a complete standalone vector image
  • SDF shader: a GLSL ES 3.0 fragment shader that raymarches the object as signed distance fields

23.1M parameters · 92 MB safetensors · ~275 tokens/s on CPU · three output formats

▶ Try it in the browser

WVY-3D is the successor to WVY-Blender-5m. That model made selections: it picked tokens from a fixed scene language, and a procedural builder supplied the geometry. WVY-3D writes the geometry itself, as code, and learns to compose a style transformation with an object it has never seen in that style.

See it in motion

Every clip in the video is the model's first answer (seed 0, temperature 0.45). The code streams at the speed it was actually generated on an Apple M4 CPU, and the demo runs it exactly as written. The only change is a turntable spin on three.js objects. The prompts, seeds and the exact code for every clip are in demo_manifest.json.

The test: pairs it has never seen

The training data covers 25 objects × 6 styles × 3 formats. Five object + style pairs were held out completely: they never appear in training, in any format.

Held-out pair What the model has seen
pixel car cars in 5 other styles; pixel art on 24 other objects
wireframe frog frogs in 5 other styles; wireframes of 24 other objects
neon house houses in 5 other styles; neon on 24 other objects
clay rocket rockets in 5 other styles; clay on 24 other objects
low-poly bus buses in 5 other styles; low poly on 24 other objects

To draw a pixel car, the model has to apply the pixel transformation, learned on other objects, to the parts of a car it learned in other styles. Here is every held-out pair in every format, uncurated: seed 0, first try.

Five held-out pairs × three formats, seed 0, uncurated

Two of the 15 fail an automated check, and they are marked. The pixel-car SVG passes the checks but only draws the wheels, a stripe and a taillight, which shows the checks don't catch everything.

Gallery

These are trained pairs across the vocabulary, one prompt each. Seed 0, first try, nothing re-rolled; we chose the prompts.

Gallery: 24 samples across objects, styles and formats

Every image is also in media/gallery/ at 640×640. The prompt, check results and full code for each one are in gallery_manifest.json.

Benchmark

All numbers come from the same checkpoint. A sample passes only if it does all of these:

  • Runs: three.js executes in Node, the SDF compiles and links in WebGL2, and the SVG parses.
  • Uses the style: it contains the style's signature idiom (voxel grid, flatShading, glow, edges…).
  • Draws the object: its parts overlap the object's reference part list (Jaccard ≥ 0.6).
  • Matches the palette: it uses the style's colours.
  • Has the right plan line: its first-line comment names the object and style.
Suite Result
Held-out pairs, all formats (temp 0.45, 16 samples per pair × format) 218 / 240 pass (91%)
· three.js 74 / 80
· SVG 64 / 80
· SDF shader 80 / 80
Trained sibling pairs (share an object or a style with a held-out pair) 216 / 216 pass (100%)
Held-out pairs with phrasings never used in training ("show me a frog done in wireframe") 54 / 75
SDF shaders that compile and link across every suite 326 / 327

Temperature. Held-out pass rates by sampling temperature:

Temperature Pass rate Distinct outputs
0 (greedy) 85 / 90 38%
0.3 81 / 90 96%
0.45 (default) 218 / 240 99%
0.7 82 / 90 100%
1.0 71 / 90 100%

Loss. Teacher-forced loss on gold code is 0.055 nats/token for trained pairs and 0.141 for held-out pairs (perplexity 1.06 vs 1.15). The gap is largest for SVG and smallest for SDF.

Speed. On an Apple M4 CPU (4 threads, batch 1), decoding runs at about 275 tokens/s and the first token arrives in about 6 ms. A three.js object (200 tokens) takes under a second; an SDF shader (540 tokens) about 2 s. Peak memory is about 535 MB.

The full results, per pair and per check, are in benchmark.json.

Known limitations

  • Fixed vocabulary. It knows 25 objects (car, truck, bus, boat, plane, rocket, frog, cat, duck, pig, fish, robot, snowman, mushroom, tree, pine, cactus, flower, house, bench, chair, table, lamp, fountain, castle) and 6 styles (smooth, pixel, low poly, clay, neon, wireframe). Other words are not reliably understood.
  • Colour and size words slip in the plan line. With prompts like "a big red pixel car", the code usually applies the colour (70 / 90) and the size (45 / 45) correctly. But the first-line plan comment often names the wrong object (correct in 3 / 90). This is the main thing the next version fixes.
  • Pixel cars in three.js sometimes stop before the voxel-mesh block (10 / 16 pass). This was the cause of every three.js runtime failure in the benchmark.
  • SVG is the weakest format on held-out pairs. The low-poly bus SVG sometimes draws car parts (6 / 16 pass), and the neon house SVG sometimes uses off-palette colours (11 / 16).
  • Neon in three.js is lit like everything else in the viewer's daylight scene, so it reads as bright colour rather than glow.
  • The training data is procedural. All 200,000 training samples were generated by our own builders, so outputs share that visual language. It does not make arbitrary meshes.

What it was trained on

WVY-3D was trained from scratch on 200,000 prompt → code pairs that we generated locally. No scraped code, images or pretrained models were used.

Each sample is built from three factors: an object (a list of named parts with shapes, sizes and colours), a style (a transformation applied to those parts, such as voxelizing, faceting, glow or edges), and a format (the emitter that writes three.js, SVG or GLSL). The five held-out pairs are removed from training entirely. Prompts vary their wording ("8-bit", "voxel", "blocky" for pixel; "sedan", "auto" for car), and may add colour and size words.

Each sample starts with a plan line, e.g. // wvy-3d: car, pixel, so the model commits to what it is drawing before it writes code.

Model details

Property Value
Published name WVY-3D-23m
Author Starpower
Parameters 23,120,640
Architecture Decoder-only causal transformer (GPT-style), pre-LayerNorm, GELU MLP, tied input/output embeddings
Layers 12
Hidden size 384
Attention heads 6
Feed-forward width 1,536
Context window 768 tokens
Vocabulary 4,096 (BPE learned on the corpus; numbers and hex colours kept whole as single tokens)
Training 3,000 steps, batch 16 × 768 tokens, AdamW (β 0.9/0.95, weight decay 0.1), lr 6e-4 with warmup and cosine decay, Apple-silicon GPU
Final validation loss 0.072
Default decoding temperature 0.45, top-k 40, top-p 0.95, KV cache
Weight format safetensors, FP32
Pretrained base model None; trained from scratch

Run it locally

pip install torch safetensors huggingface_hub
hf download StarpowerTechnology/WVY-3D-23m --local-dir WVY-3D-23m
cd WVY-3D-23m
python generate.py "a pixel car"                          # three.js
python generate.py "a neon house" --format sdf            # GLSL fragment shader
python generate.py "a clay rocket" --format svg --out rocket.svg

From Python:

import wvy3d

model, tok = wvy3d.load("StarpowerTechnology/WVY-3D-23m")   # or a local folder
code = wvy3d.generate(model, tok, "a wireframe frog", "threejs", seed=0)

Running what it writes

  • three.js: the code is a function body that receives THREE and returns the object.
    const obj = new Function('THREE', code)(THREE);
    scene.add(obj);
    
  • SVG: save it as a .svg file and open it. It's a complete document.
  • SDF: a GLSL ES 3.0 fragment shader. Draw a full-screen triangle and set uniform vec2 R (resolution in pixels) and uniform float T (time in seconds). It writes to out vec4 O.

The Space does all of this in the browser, and can also export three.js output as GLB.

Files

File What it is
model.safetensors Weights (the output head is tied to the token embedding)
config.json Architecture, plus the object/style/format vocabulary and the held-out pairs
tokenizer.json BPE tokenizer
wvy3d/ Model, tokenizer and loader (about 370 lines of PyTorch)
generate.py Command-line generator
benchmark.json Full benchmark results
demo_manifest.json Prompt, seed and exact code for every clip in the video
gallery_manifest.json Prompt, checks and exact code for every gallery image
media/ Video, cover, gallery sheets and individual renders

License

Apache-2.0.

Downloads last month
-
Safetensors
Model size
23.1M params
Tensor type
F32
·
Inference Providers NEW
This model isn't deployed by any Inference Provider. 🙋 Ask for provider support

Space using StarpowerTechnology/WVY-3D-23m 1