paprika3d

Three.js MCP server and Claude Code plugin paprika3d turns your coding agent into a game studio.

It pulls references from the web, writes a look and character sheets and a design doc with the creative calls left to you, builds the game, then runs loops that keep improving it, all in one lean package of tools.

$ claude plugin marketplace add paprika3d/paprika3d
$ claude plugin install paprika3d@paprika3d
$ npx -y paprika3d serve

As an MCP server in the client's settings (.cursor/mcp.json, Windsurf, VS Code): the JSON entry.

$ codex mcp add paprika -- npx -y paprika3d serve

Needs Google Chrome and Node 20.11 or later; the Claude Code plugin needs Claude Code 2.1.118 or later.

Or hand this to your coding agent

Install paprika3d (https://paprika3d.com/docs/install) and make me a small three.js game: <one line about it>. In Claude Code, run /paprika3d:paprika-make with that line and answer its questions with me. Before you say it’s done, play its controls with paprika3d, look for objects that never appear, and time a frame against the desktop budget.

01 · Research references paprika-make · reference · sheet

Research references.

paprika3d searches the web and YouTube for art styles, game mechanics and sound design to draw from. Keep what you like, and the game gets built from it.

How it works

In Claude Code, /paprika3d:paprika-make asks first whether to search the web. On a yes, subagents read trailers, gameplay and the makers' own posts into refs/study/ and its notes (they stay on your machine and are never published), and look for free CC0 and CC BY models whose licence they read on the model's own page. When you bring no pictures, another one finds some on Wikimedia Commons and Openverse and you keep the ones you want, each as refs/01.jpg, refs/02.jpg, … with its role and whether to match it.

A hypothetical example: the references for a toy race, if the scene behind this page were your game. The pictures and links are real, pulled from the web for this page on 2026-11-01; the brief around them is made up.
## References
refs/01.png · style (low-poly canyons, warm light) · inspiration · github.com/pmndrs/racing-game (MIT)
refs/02.png · style (toy car, one soft colour) · inspiration · github.com/brunosimon/folio-2019 (MIT)
refs/03.png · style (saturated dusk, chunky car) · inspiration · github.com/brunosimon/folio-2025 (MIT)
refs/04.png · style (matcap cars, graphic floor) · inspiration · github.com/victorgalvez56/redline (MIT)
refs/05.png · camera (high chase, track kerbs) · inspiration · github.com/KenneyNL/Starter-Kit-Racing (CC0)
refs/06.png · layout (a whole circuit in one view) · inspiration · kenney.nl/assets/racing-kit (CC0)

sheet {"pictures": [refs/01.png, refs/02.png, refs/03.png, refs/04.png, refs/05.png, refs/06.png], "title": "Toy race · references", "out": "refs/sheets/refs.png"}

Saved refs/sheets/refs.png (1248 × 744): 6 pictures, numbered as given, and 0 swatches. Made here, free; nothing was sent anywhere.
A hypothetical reference sheet titled Toy race · references: six numbered pictures from other racing projects: a road through low-poly orange canyons, a small red toy truck on an orange floor, a chunky red truck in a purple dusk, matcap cars on a dark grid with red lines, a yellow car passing under a striped arch among green pines, and a whole isometric circuit with grandstands. Each is labelled with its file, role, project and licence.
A hypothetical reference sheet for a toy race: real pictures from the web, composed by sheet for free. 1 racing-game by pmndrs; 2 folio-2019 and 3 folio-2025 by Bruno Simon; 4 REDLINE by Victor Galvez; all three.js, MIT. 5 Starter Kit Racing and 6 Racing Kit by Kenney, CC0, free kits rather than three.js games. 2 to 6 are cropped.

02 · Design spec sheet · reference · asset_search

Write the design spec.

Your references become style sheets, character sheets and a design doc covering the mechanics. You make the creative calls.

A hypothetical look board titled Look: Toy race: the car, the duck and the track in a row, then nine colour swatches with their hex codes (ink #24211d, red #d93a1e, paper #f1e8d8, asphalt #3d3a36, wood #c99358, gold #e9b632, leaf #5d8c4c, water #86bccc, mat #2f8a5b) and one line of notes.
A hypothetical LOOK.png, from sheet, free: the look this page's scene settled on, in its own car, duck and track, with its palette. Duck: “Rubber duck” by Ikki_3d, CC BY 4.0.
How it works

From the tagged pictures and your answers it writes LOOK.md (palette, light, materials, shapes, camera, UI, sound, and three to five checks a look can verify), CHARACTERS.md for characters and key props, and for a game DESIGN.md, which asks you up to two calls that change what the game is (tone, how it progresses, how it is won) and leaves the rest to the builder with a recommendation. Every line names the picture behind it. sheet composes refs/sheets/LOOK.png for free; with your own fal, OpenAI or Gemini key it also draws a look board and character turnarounds, and with a fal, Meshy or Tripo key it can make a model. Then one question per key item: the library, a free model from the web, your key, or code. A one-line request takes a quick path of about four questions, and nothing paid is used unasked.

A hypothetical example: the calls for this part's two sheets, on the toy race
sheet {"pictures": [refs/car.png, refs/duck.png, refs/track.png], "palette": [9 colours], "title": "Look: Toy race"}

Saved refs/sheets/LOOK.png (1248 × 538): 3 pictures, numbered as given, and 9 swatches. Made here, free; nothing was sent anywhere.

sheet {"pictures": [refs/07.jpg, refs/08.jpg, refs/09.png, refs/10.png, refs/11.png, refs/12.png], "title": "Duck · character references", "out": "refs/sheets/duck-refs.png"}

Saved refs/sheets/duck-refs.png (1248 × 744): 6 pictures, numbered as given, and 0 swatches. Made here, free; nothing was sent anywhere.
A hypothetical example of LOOK.md and CHARACTERS.md (formats in skills/paprika-make/sheets.md), written for the toy race
# Look: Toy race
Board: refs/sheets/LOOK.png
## Palette
ink #24211d · red #d93a1e · paper #f1e8d8 · asphalt #3d3a36 · mat #2f8a5b · accents #e9b632 #86bccc   (the toy level's own colours)
## Camera
high three-quarter over the mat, the whole lap in frame   (refs/06.png, layout, inspiration)
## Checks
1. The car is the warmest object on screen (look's Subject line names it).
2. The mat sampled at the board's centre within 30/255 of #2f8a5b.

# Characters: Toy race
## Rubber duck (trackside)
Role: the mascot; watches the lap from the pond in its middle.
Silhouette: round body, big head, flat orange beak; 0.8 units tall.
Colours: body #e9b632 (palette accent), beak #d93a1e.
Source: library f1de4fc3… · "Rubber duck" by Ikki_3d · CC BY 4.0.
Refs: refs/07.jpg (photo, match), refs/09.png (low poly, inspiration), refs/10.png (voxel, inspiration); all six styles on refs/sheets/duck-refs.png.
A hypothetical character reference sheet titled Duck · character references: six ducks in six styles: a photo of a yellow rubber duck floating in a glass bowl, Audubon's print of mallards among reeds, a low-poly yellow duck, a green voxel duck with striped legs, a realistic mallard model and a white toon duck on a green disc. Each is labelled with its file, style, maker and licence.
Hypothetical character references for the duck: six real pictures from the web in six styles, composed by sheet for free. 1 photo by Nanda93 and 2 Mallard Duck by John J. Audubon, Brooklyn Museum, both public domain. Rendered here from models, CC BY 4.0: 3 “Hubs Duck” by sagefreeman, 4 “Duck (Coin)” by Gundy, 5 “Duck” by AIUM2, 6 “QUACK ANIMATED” by Diversas Plumas. With your own fal, OpenAI or Gemini key it can also draw a turnaround from them.

03 · Build paprika-make · asset_search · model_run · geo.js · fx.js

Build it, with a critic.

paprika-make builds from the brief and the sheets. Then a critic reads the pictures and lists what is broken or falls short of the look.

How it works

The first version is written from BRIEF.md and the sheets: LOOK.md's palette and camera as written, each key item from the source you picked, and DESIGN.md's controls and core loop as what gets played. Once the page runs, a critic subagent reads the newest look pictures and lists glitches (z-fighting, objects through each other, floating or clipped things), each LOOK.md check the pictures fail and what a viewer would notice first; they are closed one at a time. open also puts two helper files in the project, geo.js (procedural geometry) and fx.js (sound, textures, particles, a lighting setup). asset_search (preview) finds a ready-made model, PBR texture or HDRI sky in a hosted library of 57,732 models, 3,545 textures and 1,430 skies, and model_run builds a model in code and saves it as a .glb. The board behind this text pulls apart into what made it: the gates are geo.js booleans, the pebbles fx.js placement, the duck one asset_search pick.

Real replies that put the duck in this page, 2026-10-28; cut to the lines shown. model_audit's shrink then capped its textures at 256 px (74 KB to 46 KB).
asset_search {"query": "rubber duck", "maxTris": 6000}

2. f1de4fc390db4266a509b9739350512a · Rubber duck · stylized · 3458 tris · 0.075 MB · about 0.1 m tall · CC-BY-4.0 · …

asset_search {"pick": "f1de4fc3", "height": 1.2}

Picked f1de4fc390db4266a509b9739350512a, the one shown id that starts with "f1de4fc3".
Saved assets/rubber-duck-f1de4f.glb (Rubber duck, CC-BY-4.0); credited in assets/CREDITS.md
If the import map has no `three/addons/`, map it to three's `examples/jsm/` folder.

04 · Iterate paprika-loop

Keep improving it for hours.

paprika-loop runs a builder and a judge session each round, scores the game against the brief and commits it, until the time you gave it is up.

How it works

/paprika3d:paprika-loop <request> for <time> writes the brief with you, then starts fresh claude -p sessions: a builder makes as many improvements as fit, a read-only judge scores the page against the brief's Must have list and writes the next three improvements, and each round is committed, with the best tagged paprika-loop/best. You can edit paprika-loop/PROMPT.md while it runs. It starts only when you type it, each round is two Claude Code sessions billed as such, and it needs claude and git on PATH. The bars behind this text are the six rounds below, each car lap one round.

Real report from a paprika-loop run on Night Shift Toss, 2026-10-28 (the run's second hour; its rounds are numbered on from the first)
# paprika-loop report

6 iterations in 57 minutes, $11.90.

| n | min | turns | tokens | commit | score |
|---|---|---|---|---|---|
| 18 | 8.3 | 45 | 3699609 | b6a2ba6 | 7.3 |
| 19 | 7.5 | 38 | 2951642 | 789479e | 7.4 |
| 20 | 3.4 | 16 | 931095 | 07e4879 | 7.4 |
| 21 | 30 | 20 | 1060576 | 61f2ff4 | 7.6 |
| 22 | 4.5 | 14 | 786807 | 246cab0 | 7.8 |
| 23 | 3.7 | 18 | 750452 | 4529600 | 7.8 |

Best: iteration 22 at 246cab0 (score 7.8), tagged paprika-loop/best; the latest is 4529600.

05 · See and play open · look · interact · observe · eval · feel

See it and play it, frame by frame.

Every object gets a box, and anything missing gets a reason. Keys, clicks and touches land on exact frames, so every run comes out the same.

How it works

Your agent sees what is on screen, what never appears and why (behind the camera, outside the view, too small), which files failed to load, and which lighting and surface faults show. In the scene behind this text, every named object gets its box in page pixels, the way look lists them, and the screw on the mat is too small to see. Then it presses keys, clicks, touches and scrolls on exact frames of a paused, seeded clock and reads the state after each input: scroll on and the car drives one lap, frame by frame, its trace drawn behind it.

Real replies from the guides Find out why a three.js model is not visible, 2026-10-14, and Test a three.js game with Claude Code, 2026-10-16
look {}

Picture: <project>/paprika3d/runs/2026-10-14T07-50-50-163Z/look-1.png
ID image: <project>/paprika3d/runs/2026-10-14T07-50-50-163Z/look-1-ids.png
On screen (2):
ground 68.0% [0, 241, 1279, 799]
car 0.0% [638, 346, 641, 347]
Never visible: lamp (3 units, behind the camera)

eval {"code": "return stats(\"car\")"}

total  1 meshes  24 v  12 tri
car  24 v  12 tri  closed  vol 0  genus 0  size 0.04×0.014×0.02  [position, normal, uv]

interact {"steps": [{"key": "ArrowRight", "frames": 30}, {"key": "ArrowRight", "down": false}]}

{"changed":{"x":1.5}}

interact {"steps": [{"key": " "}, {"key": " ", "down": false}, {"wait": 18}], "look": true}

{"changed":{"y":0.95,"jumps":1}}
Picture: <project>/paprika3d/runs/2026-10-16T23-20-52-829Z/look-2.png
Pixels: brightness 14%, colour saturation 50%, 0% near black, 0% blown out; 2% of the picture changed since the last look.
Hues: blue 90%, green 9%.
On screen (2):
floor 8.8% [0, 614, 1279, 689]
ball 0.71% [735, 452, 831, 547]
Never visible: none

06 · Test and measure interact save · test · perf

Turn a play into a test, and time every frame.

Saved plays rerun after every edit. Each frame is timed against a desktop or phone budget, with the objects that cost the most.

This page, measured in your browser: the numbers appear once the scene runs.

How it works

A play your agent saves reruns from a fresh reload with test, and the after-edit hook reruns every saved check after each edit, speaking only when one starts or stops failing: on the second lap each gate turns green as the car passes it. perf times the frame against a desktop, mobile or site budget, finds what costs it, and with optimize: true keeps only the speed-ups that leave the picture unchanged. The bars that rise next are this scene's own named groups, counted in your browser the way perf's cost table counts them (the height is the square root of the triangles); the line above is this page's frame time.

Real replies from the guides Unit test a three.js app in a real browser, 2026-10-28 (the second test ran after a refactor broke the wall rule), and Measure three.js draw calls and FPS, 2026-10-28, on a server with no GPU (the reply says so); cut to the lines shown
interact {"steps": [{"state": {"player": {"x": 3, "z": 0}}}, {"key": "ArrowRight"}], "expect": {"player.x": 4, "score": 10, "coins.0.x": 1}, "save": "far-coin"}

{"changed":{"player":{"x":4},"coins":[{"x":1,"z":1}],"score":10,"moves":1}}
Expect: player.x 4 ✓ · score 10 ✓ · coins.0.x 1 ✓
Saved check "far-coin" in game-tests.json (3 checks now); `test` reruns them all, each from a fresh reload.

test {}

✓ coin-pickup
✗ wall-blocks: player.x 2, expected 1; moves 2, expected 1
✓ far-coin
2 of 3 saved checks passed in 0.5 s

perf {"costs": true}

248.3 ms median frame (p95 273 ms, 4 fps on average), 1797 draw calls, 54298 triangles, 0 MB assets; over budget: frameMs 248.3 of 16.7 ms; desktop budget; software renderer (no GPU): frame time is no budget signal, do not optimize for it
…
  statue: 16384 triangles, 16384 casting shadows, 1 draw calls, 0 MB of textures
  crates: 10800 triangles, 10800 casting shadows, 900 draw calls, 0 MB of textures
  floor: 2 triangles, 0 casting shadows, 1 draw calls, 0 MB of textures

07 · Tools 16 MCP tools, in any MCP client

The 16 tools, by stage.

paprika-make and paprika-loop are Claude Code skills; the tools work in any MCP client.

References and spec

reference
Reads a picture at full resolution: a crop with a pixel grid, colours at points; with the page open, compares the two.
sheet
Names the image and 3D keys set, composes a free LOOK.png, and with your key draws boards and turnarounds or starts a model job.

Build

asset_search
Finds a model, PBR texture or HDRI sky in the hosted CC BY and CC0 library, and downloads the pick with its loading code and credit.
model_run
Builds a model in code with three.js and Manifold, and saves a .glb the page loads.
model_look
Shows that model from four sides against a grid, with each object's size and triangles.
model_audit
Checks .glb, .gltf and USD files: size, triangles, textures, compression; shrink makes one smaller.

See

open
Runs the page in headless Chrome on a paused, seeded clock and lists what loaded and what failed.
look
A screenshot, every object on screen with its box, and what never appears and why.
observe
Reads the game state as JSON, with renderer counts and new console errors.
eval
Runs JavaScript in the page, with the scene, camera and mesh stats in scope.

Play and test

interact
Plays keys, mouse, touch and scroll on exact frames and reports what changed; save keeps the play as a check.
feel
Measures whether a hit, pickup or win shows on screen: shake, pops, flashes, particles, sounds.
test
Reruns every saved check from a fresh reload, one pass or fail line each.

Measure

perf
Times the frame against a budget with what costs it; optimize: true keeps only the speed-ups that leave the picture the same.

Share

publish
Puts the game on https://<name>.paprika3d.app when you ask (preview, invite-only).
send_feedback
Sends the paprika3d team a bug or criticism, with the last tool call.

How it works, stage by stage · Every tool, skill and hook

Built with paprika3d

From the intro reel

Watch the 46-second reel ↗

Results

paprika3d vs Playwright MCP and Blender MCP

Featurepaprika3dPlaywright MCPBlender MCP
Sees the scene: named objects, sizes, what never appearsYesNoNo
Same inputs give the same frames (paused, seeded clock)YesNot built inNo
Input on an exact frame, with the game state backYesNoNo
Frame time against a budget, plus an optimizerYesNoNo
Names lighting and z-fighting faultsYesNoNo
Flickering faces found in 133 finished objects (Sonnet 5.5)
75% vs 44% paprika3d vs Playwright MCP with a QA skill and a measuring script.
Clean objects correctly passed (Sonnet 5.5)
80% vs 66% Same 133 objects, paprika3d vs Playwright MCP.

3JSBench

3JSBench by General Context Labs checks the 3D objects a model builds from one-line requests. In our run of its checks, more objects pass with paprika3d:

Sonnet 5.5: objects that pass every check
66% → 86% +20 points (95% interval +11 to +29), 150 runs per arm
Opus 5.5: objects that pass every check
63% → 78% +15 points (95% interval +4 to +26), 150 runs per arm
Sonnet 5.5: objects with no flickering faces
68% → 88% +20 points (95% interval +11 to +29), 150 runs per arm
Opus 5.5: objects with no flickering faces
69% → 89% +21 points (95% interval +11 to +31), 150 runs per arm

More results

Imported glTF model loaded and shown at the right size (Sonnet 5.5)
1 → 9 of 11 runs Without vs with paprika3d.
Draco-compressed model loaded (Sonnet 5.5)
0 → 3 of 3 runs Without vs with paprika3d.
Main-thread time per frame, ~2,000 physics crates (Opus 5.5)
7–11 → 1.3–2.0 ms With game-state, which runs physics in a worker. 18 of 18 game checks pass.

All results

This page was built and checked with paprika3d

We tested it with paprika3d at desktop and phone sizes.

Desktop frame
4.8 ms
Phone frame (390 × 844, JS 4× slower)
7.5 ms
Draw calls
79
First scene frame, fast 4G
1.6 s
Bytes to first frame
0.28 MB