paprika3d
OfficialServer Configuration
Describes the environment variables required to run the server.
| Name | Required | Description | Default |
|---|---|---|---|
| PAPRIKA3D_CHROME | No | Path to Chrome or Chromium. Optional: found automatically on PATH (chromium, google-chrome) or at the usual install path. |
Instructions
Guidance the server publishes about itself, which clients place ahead of the tool catalog so the model reads it before choosing anything.
This server publishes no instructions, or was last inspected before Glama recorded them.
Capabilities
Features and capabilities supported by this server
Protocol revision2025-11-25
| Capability | Details |
|---|---|
| tools | {} |
Tools
Functions exposed to the LLM to take actions
| Name | Description |
|---|---|
| openA | Opens a three.js, React Three Fiber or WebGL page (a game, viewer, configurator, simulation or shader demo) in headless Chrome (or the |
| observeA | Reads the open page's state as JSON (window.__game.observe(), or its named three.js objects), renderer counts, new console errors and what changed since the last observe. |
| evalA | Runs JavaScript in the open page and returns what it returns, as JSON, then up to 5 lines it logged (console.log, warn, info) and up to 5 console errors. In scope: scene, camera, renderer, find(name), stats(target) (vertices, triangles, bounds, closed, volume, genus per mesh), realNow(), window, and THREE on a page that loads three through an import map. performance.now, Date and timers run on the harness's paused clock (code that awaits a timer or frame steps it until done), so to time code here use realNow() (real milliseconds), and end GPU work before reading it (a 1-pixel gl.readPixels; on WebGPU, await renderer.backend.device.queue.onSubmittedWorkDone()). Use it to inspect the scene, try a change before writing it into the source, measure an imported model, or check procedural geometry with stats after each step; changes vanish on reload. A thrown error names where it threw: a line of this code or of the page's own files. Code that keeps the page busy for 30 s (longer on a busy host) is stopped and the page kept: split long work across calls, or await a 0 ms timer every few hundred iterations. |
| interactA | Plays the open page: keyboard, mouse, touch, wheel, scroll, resize and clock steps sent frame by frame ( |
| lookA | Screenshot of the open page, returned in the reply (no file to read), with an ID image saved beside it (one colour per object, the picture's path with -ids before .png), and a list of what is on screen and the named objects no look has seen, with their size and where they are: it catches a model at the wrong scale, out of view or never loaded, which a screenshot alone misses. One mode per field: |
| feelA | Measures game feel, how the page reacts to an event: on a fresh reload, sends the steps, then watches the next frames for camera shake or one camera move out and back (a hit's lurch), scale pops, smooth moves versus teleports, colour flashes, particles (a Points pool's or an InstancedMesh's count), spawned objects, HUD text ticks and sounds, each with the watched frame it came on. Leading { state } steps set the scene up (the player next to the coin), and nothing is measured until they and one frame have run; what moved during the other steps is listed as a fact on its own line, and teleports are jumps between two watched frames, so a setup or a walk in the steps is never one. It shows whether each event a feel brief names (hits, clears, explosions, pickups, deaths, wins) reacts on screen, and whether anything teleports. It measures and saves nothing: to keep the play as a check, send the same steps to |
| perfA | Measures the open page's frame time (fps), draw calls, triangles and asset size against a budget (desktop by default): it is for a frame a reply reports over budget, or a user who asks about performance (stutter, low fps). To find what costs the frame, give |
| optimizeA | Speeds up the open page: measures the frame time (no |
| model_auditA | Inspects 3D model files (.glb, .gltf, and USD: .usd, .usda, .usdc, .usdz): megabytes, triangles, materials, each texture's size and format, and whether it uses Draco, meshopt and KTX2, for one file or every one under a folder ( |
| model_runA | Runs JavaScript against the modelling scene: a three.js scene this server keeps between calls, apart from any page, for building a model in code as in Blender, then saving it as a .glb the page loads. The code is an async function body with THREE, scene, geo (Manifold, started: geo.Manifold, geo.CrossSection, geo.toGeometry(manifold), geo.toManifold(geometry), geo.boolean(op, a, ...b)), scatter, find(name), stats(target) (vertices, triangles, bounds, closed, volume, genus per mesh), load(path) (a .glb from the project, an asset_search pick included, added to the scene and returned), save(path, object = scene) (a GLB under cwd; replies with its size and the line that loads it) and clear() in scope, and returns what it returns, as JSON, with up to 5 lines it logged. What it adds to scene stays for the next call and is saved to paprika3d/model/scene.glb after each run that changed it, so a restart loads it back; variables (a Manifold) do not last between calls. Manifold works in metres with Z up and angles in degrees; three is Y up. Name every object you make: model_look lists them by name. |
| model_lookA | Shows the modelling scene that |
| testA | Reruns every check saved with |
| referenceA | Reads a reference picture the page should match (a photo, artwork, mockup or screenshot in the project, e.g. refs/01.jpg) at full resolution, in one call and with no page open: |
| asset_searchA | Searches the hosted paprika3d asset library over the network (assets.keeno.dev) for a ready-made model (57k, CC BY or CC0, as GLB and some as USD), PBR texture or HDRI sky, and puts the one you pick in the project with its loading code. A search answers one numbered line per hit (id, name, size, licence, preview image) and a contact sheet: the hits' thumbnails in one row, numbered as the lines are. |
| publishA | Publishes the project at https://.paprika3d.app (public; preview, invite-only), only when the person asks; never for another host. Never read or print ~/.config/paprika3d/credentials.json: this tool reads the key. |
| send_feedbackA | Sends the paprika3d team a bug, feedback or criticism about the harness itself (not about the user's page): a reply that was wrong or unclear, a tool that hung, errored or got in your way, a check you disagree with, or something you needed and no tool gave. It attaches the last tool call's name, options and error, never the page's code or files. One line back; carry on with the task after it. |
Prompts
Interactive templates invoked by user choice
| Name | Description |
|---|---|
No prompts | |
Resources
Contextual data attached and managed by the client
| Name | Description |
|---|---|
No resources | |
TDQS
Scored across 16 tools
Several tools have overlapping boundaries: perf and optimize both target performance, interact and feel both replay input steps, and look and reference compare both handle visual comparison. The descriptions explain the distinctions, but an agent could still misselect when deciding whether to measure or optimize, or whether to use interact versus feel.
Names are all lowercase snake_case, but the conventions are mixed: single verbs or nouns such as open, look, feel, eval, perf, and test sit alongside compound names like model_audit, asset_search, and send_feedback. The names remain readable, but there is no predictable verb_noun pattern throughout.
Sixteen tools is slightly above the typical 3-15 range, but the server covers a broad 3D game-development harness from opening pages to modelling, testing, asset search, and publishing. Each tool mostly earns its place, though a few overlaps make the surface feel larger than necessary.
The set covers a strong lifecycle: opening pages, inspecting and interacting, visual checks, performance measurement and optimization, model creation and audit, tests, reference comparison, asset search, and publishing. Minor gaps exist, such as no explicit close/list management for open pages, but core workflows are well covered.