Render tools¶
Environment, effects, hair, shaders, render layers, impostors, benchmarks and the movie renderer.
27 tools in the render category. Badges: read-only tools never change the project; mutating tools are undoable and attributed; open-world tools reach outside the engine and MCP clients ask before running them.
| Tool | Summary |
|---|---|
environment_get |
Current sun, sky, ambient, fog, exposure and grid settings. |
environment_update |
Edit scene lighting/atmosphere: sun (azimuth, elevation, color, intensity), sky colors, ambient, fog, exposure, grid. |
shader_get |
The renderer's current shader source (Metal Shading Language). |
shader_set |
Replace the renderer's shader source at runtime. |
perf_stats |
Frame cost and scene complexity: GPU and CPU frame time, draw calls, lights, terrain nodes, foliage instances, entities, behaviors and assets. |
fx_create |
Create an effect or a body of water from a preset, ready to tweak. |
fx_burst |
Emit particles from an emitter right now (explosions, muzzle flashes, impacts). |
groom_create |
Grow strand hair or fur on an entity's mesh (a head, a bust, an animal body) from a preset, ready to tweak. |
groom_update |
Change a groom's fields (or switch to another preset and then apply fields). |
groom_info |
Strand, guide and point counts, memory (CPU and GPU), generation time and the measured GPU cost (simulation and drawing) of a groom, or of every groom in the scene when entity is omitted. |
fx_benchmark |
Render frames real-time frames back to back (no readback, effects time advancing 1/60 s per frame, so GPU particles and hair simulate) and report the GPU time per frame and per effects pass, plus the wall-clock time. |
fx_stats |
Measured GPU cost of the last rendered frames: whole-frame GPU time, the GPU simulation pass (particles + hair), per-emitter live particle counts (read back asynchronously, a few frames old) and per-groom sizes. |
impostor_bake |
Bake the octahedral impostors of foliage layers now: each heavy model (an imported tree, bush, rock or grass clump; one mesh or every part of a prefab) is captured from up to 32x32 directions into an atlas of albedo, normal and depth, and instances beyond the layer's transition distance render as impostors (lit, shadowed and depth-correct like real geometry). |
movie_render |
Render a cinematic to video or a PNG sequence, offline and deterministically (the movie renderer). |
render_layers |
Render layers (20): MeshRenderer.layers says which layers a mesh is on; Camera.cullMask and Light.cullMask say which layers a camera draws and a light illuminates (a mesh is drawn / lit when they share a layer). |
shadow_atlas_info |
Which point and spot lights cast shadows this frame and how: projection (spot view, cube = 6 views, dual_paraboloid = 2 views), atlas slot and resolution, whether it was re-rendered this frame or reused from the static cache, and why a light has no shadow (disabled, out_of_view, beyond_max_distance, over_light_budget, atlas_full, pending). |
light_shadows |
Turn shadows of point/spot lights on or off and tune them, for one light, a list, or every light ("all", optionally only one kind). |
probe_add |
Add a reflection probe: a captured cubemap that glossy floors, metal and glass inside its volume reflect instead of the sky (box-projected, so reflections line up with the walls), and that gives them their ambient light. |
probe_bake |
Re-capture reflection probes now (after moving furniture, changing lights or the sky): renders one still frame of view, which captures every invalidated probe in full regardless of the per-frame face budget, and returns their state (slot, captures, GPU time) plus warnings. |
probe_info |
Reflection probes and their atlas: the budget (Environment.probeBudget probes, probeUpdates faces per frame), atlas resolution / slots / memory, and per probe: slot and debug color (the reflection_probes debug view draws it), whether it is captured, lighting this view, waiting for the face budget, over budget or out of view, captures so far, last capture GPU time, stale (something in range changed since a once probe was captured: run probe_bake), size, update mode. |
particles2d_create |
Create pixel-art particles for a 2D game from a preset, ready to tweak: rain (streaks over the whole view), drizzle, snow (drifting flakes), leaves and petals (falling, swaying), fireflies (glowing, twinkling, wandering), smoke (chimney puffs), ripples (puddle rings while it rains), dust (motes in sunlight), sparkle (water glints). |
particles2d_info |
Live state of particles2d emitters: particles alive, cap, rate, box, wrap, and the bounds the live particles cover (world units). |
locale_list |
Lists the game's locales: the current one and its fallback chain (pt-BR -> pt -> source), the source language, every locale with strings (count, coverage, files under locale/), game.json localization settings, strings requested at run time that no table has, and table file problems. |
locale_set |
Switches the language the game shows: texts written as "@key" (ui.text, ui.placeholder, text.text), tr() calls and #line dialogue lines follow at once. |
locale_check |
Audits localization and returns findings an agent can fix one by one: per locale the keys with no translation (and coverage); keys the project uses ("@key" fields, tr("key") in scripts, #line dialogue ids) that no table defines; unused keys; placeholder mismatches between a translation and the source ({name} missing or extra); invalid messages; plurals missing forms the language needs (ru: one/few/many, ar: zero..many); strings longer than their budget (the table's max column, or source length x budget, default game.json maxLengthRatio); characters no font covers (CJK, Arabic...: add a font); keys requested at run time but missing. |
locale_extract |
Scans the open scene, scenes, prefabs, dialogue scripts and Wander code for hard-coded player-facing texts (ui.text, ui.placeholder, text.text, dialogue lines and choices without a #line id, .text = "..." in scripts) and proposes a key for each ("main_menu.play", "dlg.intro.start.003"); a text whose source string already exists reuses its key. |
locale_pseudo |
Writes a pseudo-locale for layout testing: every string accented and about 30% longer inside brackets ("Play" -> "[Ƥļáý~~]"), placeholders, plurals and rich-text tags intact, so truncation, overflow and hard-coded texts (they stay plain) jump out. |
environment_get¶
Get lighting & environment read-only
Current sun, sky, ambient, fog, exposure and grid settings.
Takes no arguments.
environment_update¶
Lighting & environment mutating
Edit scene lighting/atmosphere: sun (azimuth, elevation, color, intensity), sky colors, ambient, fog, exposure, grid. Optional preset: noon, sunset, night, overcast, studio (applied first).
| Argument | Type | Required | Description | Values |
|---|---|---|---|---|
skyTop |
color | Sky color at the zenith — hex string "#rrggbb[aa]" or [r,g,b(,a)] in 0..1 | ||
skyHorizon |
color | Sky color at the horizon — hex string "#rrggbb[aa]" or [r,g,b(,a)] in 0..1 | ||
ground |
color | Ambient bounce color from below — hex string "#rrggbb[aa]" or [r,g,b(,a)] in 0..1 | ||
ambient |
number | Ambient light strength | 0 .. 10 | |
sunAzimuth |
number | Sun compass direction in degrees (0 = +Z) | ||
sunElevation |
number | Sun height above horizon in degrees | -90 .. 90 | |
sunColor |
color | Sun light color — hex string "#rrggbb[aa]" or [r,g,b(,a)] in 0..1 | ||
sunIntensity |
number | Sun brightness | 0 .. 100 | |
fogColor |
color | Distance fog color — hex string "#rrggbb[aa]" or [r,g,b(,a)] in 0..1 | ||
fogDensity |
number | Exponential fog density (0 = off) | 0 .. 1 | |
exposure |
number | Camera exposure multiplier | 0.01 .. 20 | |
autoExposure |
boolean | Adapt exposure to scene brightness (eye adaptation) | ||
exposureCompensation |
number | Exposure compensation in EV stops | -6 .. 6 | |
adaptationSpeed |
number | Auto exposure adaptation speed | 0.05 .. 20 | |
showGrid |
boolean | Draw the editor ground grid | ||
bloomIntensity |
number | Glow around bright/emissive things (0 = off) | 0 .. 5 | |
bloomThreshold |
number | Brightness where glow starts (lower = more glow) | 0 .. 10 | |
bloomClamp |
number | Brightest (exposed) value that feeds the glow: 2-8 keeps sun glints, chrome and LED lights crisp instead of blown-out halos; 64 = effectively unlimited | 0.1 .. 64 | |
saturation |
number | Color saturation (1 = neutral) | 0 .. 2 | |
contrast |
number | Contrast (1 = neutral) | 0.5 .. 2 | |
vignette |
number | Darken the image corners | 0 .. 1 | |
grain |
number | Film grain | 0 .. 1 | |
chromaticAberration |
number | Lens color fringing toward the frame edges | 0 .. 1 | |
look |
string | Color grading look | none warm cool teal_orange golden_hour bleach noir vivid moonlight vintage |
|
lut |
string | Optional .cube 3D LUT file (project-relative); when set it replaces the look (lookStrength blends it) | ||
lookStrength |
number | Strength of the look / LUT | 0 .. 1 | |
skyMode |
string | gradient = two artist colors; atmosphere = physically inspired sky from the sun; hdri = a photographed .hdr panorama lights and backs the scene (set hdri) |
gradient atmosphere hdri |
|
hdri |
string | Equirectangular .hdr panorama, project-relative (skyMode hdri) | ||
hdriRotation |
number | Panorama rotation in degrees (line its sun up with sunAzimuth) | ||
hdriIntensity |
number | Panorama brightness | 0 .. 20 | |
clouds |
number | Procedural cloud cover | 0 .. 1 | |
cloudMode |
string | Clouds: volumetric (ray-marched, lit, shadows) or flat (cheap) | volumetric flat |
|
cloudHeight |
number | Cloud layer base height in meters | 100 .. 12000 | |
cloudThickness |
number | Cloud layer thickness in meters | 100 .. 10000 | |
cloudDensity |
number | Cloud density: 0.3 wispy .. 2 stormy | 0 .. 4 | |
cloudScale |
number | Cloud feature size (0.5 small puffs .. 3 huge banks) | 0.1 .. 8 | |
cloudSpeed |
number | Cloud drift speed in m/s (along windDirection) | 0 .. 100 | |
stars |
number | Stars in the night sky | 0 .. 1 | |
sunSize |
number | Sun / moon disc size | 0.1 .. 8 | |
fogHeight |
number | Fog pools near the ground as this grows (0 = uniform) | 0 .. 2 | |
reflections |
number | Sky reflections / image-based lighting strength | 0 .. 3 | |
ao |
number | Ambient occlusion (contact shadows in corners and creases) | 0 .. 2 | |
aoRadius |
number | Ambient occlusion radius in meters | 0.05 .. 5 | |
gi |
number | Screen-space global illumination: bounce and emissive light (0 = sky light only) | 0 .. 1 | |
giDistance |
number | Global illumination ray length in meters | 0.5 .. 50 | |
ssr |
number | Screen-space reflections on glossy surfaces (wet streets, floors, metal) | 0 .. 1 | |
taa |
boolean | Temporal anti-aliasing (smooth edges, stable shimmer-free detail) | ||
renderScale |
number | Real-time internal resolution: 0.5-0.77 renders fewer pixels and MetalFX temporal upscaling reconstructs full resolution (faster); 1 = native. Stills and captures with samples > 1 render native. | 0.33 .. 1 | |
sharpen |
number | Sharpening after temporal anti-aliasing | 0 .. 1 | |
shadowSoftness |
number | Sun shadow penumbra size | 0 .. 6 | |
tonemap |
string | HDR to display curve | aces agx neutral filmic none |
|
temperature |
number | White balance: -1 cool .. +1 warm | -1 .. 1 | |
tint |
number | White balance: -1 green .. +1 magenta | -1 .. 1 | |
shadowDistance |
number | Sun shadow range in meters (0 = automatic) | 0 .. 5000 | |
godRays |
number | Volumetric light: sun shafts through trees and windows, cones under lamps (0 = off, 1 = natural) | 0 .. 8 | |
haze |
number | Air density for volumetric light, extinction per meter: 0.0003 clear landscape, 0.002 hazy valley, 0.01-0.03 misty alley or interior | 0 .. 1 | |
windSpeed |
number | Wind (m/s) that carries smoke, rain, snow and particles | 0 .. 60 | |
windDirection |
number | Direction the wind blows toward (degrees, 0 = +Z) | ||
localShadowAtlas |
integer | Point/spot shadow atlas size in px: 2048 (16 MB), 4096 (64 MB, default), 8192 (256 MB) | ||
localShadowLights |
integer | Most point/spot lights with shadows per frame (the most important on screen); the rest light without shadows. 0 = no local shadows | ||
localShadowUpdates |
integer | Point/spot shadow views re-rendered per frame when lights or casters move (cube light = 6, spot = 1); later updates wait a frame. Stills render all | ||
probeBudget |
integer | Reflection probes with a slot in the probe atlas (the most important in view first; the rest fall back to the sky). Max 32; 0 = probes off | ||
probeUpdates |
integer | Reflection probe cube faces captured per frame (a whole probe = 6); later captures wait a frame. Stills capture everything | ||
preset |
string | Lighting preset | noon sunset night overcast studio |
|
align_sun_to_hdri |
boolean | Point the sun (direction of light and shadows) at the brightest spot of the hdri panorama |
environment_update {"preset": "overcast", "skyMode": "atmosphere", "clouds": 0.85, "cloudMode": "volumetric", "cloudDensity": 1.3, "sunIntensity": 1.2, "shadowSoftness": 4, "ao": 1.2, "aoRadius": 1.0, "gi": 0.5, "fogColor": "#9aa6b2", "fogDensity": 0.006, "fogHeight": 0.5, "saturation": 0.85, "look": "bleach", "lookStrength": 0.25, "tonemap": "agx", "autoExposure": true}
skywalker call environment_update '{"preset": "overcast", "skyMode": "atmosphere", "clouds": 0.85, "cloudMode": "volumetric", "cloudDensity": 1.3, "sunIntensity": 1.2, "shadowSoftness": 4, "ao": 1.2, "aoRadius": 1.0, "gi": 0.5, "fogColor": "#9aa6b2", "fogDensity": 0.006, "fogHeight": 0.5, "saturation": 0.85, "look": "bleach", "lookStrength": 0.25, "tonemap": "agx", "autoExposure": true}' --project my_game
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "environment_update",
"arguments": {
"preset": "overcast",
"skyMode": "atmosphere",
"clouds": 0.85,
"cloudMode": "volumetric",
"cloudDensity": 1.3,
"sunIntensity": 1.2,
"shadowSoftness": 4,
"ao": 1.2,
"aoRadius": 1.0,
"gi": 0.5,
"fogColor": "#9aa6b2",
"fogDensity": 0.006,
"fogHeight": 0.5,
"saturation": 0.85,
"look": "bleach",
"lookStrength": 0.25,
"tonemap": "agx",
"autoExposure": true
}
}
}
shader_get¶
Get shader source read-only
The renderer's current shader source (Metal Shading Language). Edit it with shader_set.
Takes no arguments.
shader_set¶
Hot-reload shaders mutating
Replace the renderer's shader source at runtime. On a compile error nothing changes and the compiler diagnostics are returned. Function names and struct layouts must be kept.
| Argument | Type | Required | Description | Values |
|---|---|---|---|---|
source |
string | yes | Complete shader source |
perf_stats¶
Performance stats read-only
Frame cost and scene complexity: GPU and CPU frame time, draw calls, lights, terrain nodes, foliage instances, entities, behaviors and assets. Pass frames (e.g. 30) to benchmark real-time rendering of the current view at width x height (temporal AA, no supersampling) and get average/min/max GPU ms. Check after big scatters, generators or look changes; 16.6 ms = 60 fps. view is "editor", "scene" or a custom camera {eye, target, fov}; quality benchmarks an editor viewport tier. The gpu section includes foliage impostor stats (impostorInstances, meshInstances, impostorsBaked, impostorBakeMs). passes=true adds where the frame time goes: profile.passes = GPU time per render pass (Main, Shadow cascades, SSGI, SSR, Lighting resolve, TAA, Bloom, Composite, Foliage cull, GPU particles, Hair ...; rolling 60-frame avg/min/max), profile.groups = the same summed by area (shadows, main, ao, ssgi, ssr, resolve, effects, volumetrics, clouds, temporal, post, foliage, particles, hair, ui ...) and profile.cpu = CPU scopes (frame.build, scene.buildFrame, world.gather, render.encode ...). With frames > 0 the profile covers exactly the benchmark frames. Example: {"frames":30,"passes":true,"view":{"eye":[0,300,-600],"target":[0,80,0]}}.
| Argument | Type | Required | Description | Values |
|---|---|---|---|---|
frames |
integer | Benchmark this many real-time frames first (default 0 = just report) | ||
width |
integer | Benchmark width (default 1920) | ||
height |
integer | Benchmark height (default 1080) | ||
view |
any | Camera for the benchmark: "editor" (default), "scene", or | ||
quality |
string | Viewport quality tier to benchmark (default full, as in play mode and captures) | full balanced fast |
|
passes |
boolean | Add the per-pass GPU timeline and CPU scopes (profile: passes, groups, cpu) | ||
characters |
boolean | With frames: also benchmark with hair and fur hidden to measure what grooms cost to draw (characters.groomRenderGpuMs) |
fx_create¶
Create effect mutating
Create an effect or a body of water from a preset, ready to tweak. Volumetric fluid simulations (GPU, ray-marched, film-quality fire and smoke): volume_fire, volume_torch, volume_smoke, steam_vent, explosion_volume. Particles: fire (sprite), embers, smoke, steam, sparks, rain, snow, mist, spray, dust, fireflies, magic, fireball, debris_smoke, shrapnel. GPU particles (millions, depth collisions, sub-emitters, ribbons, mesh particles; visuals only): sparks_shower, fireworks, rain_heavy, waterfall_mist (composites), ember_storm, magic_vortex, dust_storm, falling_leaves (~6 m up), snow_heavy (~12 m up), smoke_column_gpu. Composites (volumetric fire + embers + light): campfire, torch, burning_barrel, explosion; sprite_campfire is the cheap particle version. Water (FFT ocean simulation): ocean, calm_sea, storm, lake, pool, puddle — the entity's y is the water level. overrides patches the particles/water fields (e.g. {"rate": 80, "colorStart": "#7af"}). Fires light the scene by themselves; rain/snow cover a box around the entity (place it ~12 m up), set floorHeight to the ground.
| Argument | Type | Required | Description | Values |
|---|---|---|---|---|
effect |
string | yes | Preset | fire embers smoke steam sparks rain snow mist spray dust fireflies magic fireball debris_smoke shrapnel ember_storm magic_vortex dust_storm falling_leaves snow_heavy smoke_column_gpu sparks_gpu embers_gpu rain_gpu splashes_gpu rockets_gpu firework_burst_gpu mist_gpu droplets_gpu volume_fire volume_torch volume_smoke steam_vent explosion_volume campfire torch explosion burning_barrel sparks_shower fireworks rain_heavy waterfall_mist sprite_campfire ocean calm_sea storm lake puddle pool |
name |
string | Entity name (default: the preset's name) | ||
position |
number[3] | World position | ||
parent |
integer | string | Parent entity | ||
overrides |
object | Fields to change on the particles/water component (composites: applied to every emitter) |
fx_burst¶
Burst particles read-only
Emit particles from an emitter right now (explosions, muzzle flashes, impacts). Works while editing (preview) and playing. In Wander use burst(n).
| Argument | Type | Required | Description | Values |
|---|---|---|---|---|
entity |
integer | string | yes | Entity with a particles component (or a composite whose children have one) | |
count |
integer | Particles to emit (default: the emitter's burst field, else 50) |
groom_create¶
Create hair or fur mutating
Grow strand hair or fur on an entity's mesh (a head, a bust, an animal body) from a preset, ready to tweak. Presets: hair_straight, hair_wavy, hair_curly, hair_ponytail, hair_short (heads: they grow on the upper back of the mesh; set maskDirection/maskAngle or a vertex-color mask for your model), fur_short, fur_long (cover the whole mesh); for rigged characters: hair_scalp (dense scalp hair on the Head bone's vertices), beard, eyebrows (regions in the head's bounds, mirrored brows), fur_dense (a creature's coat). On a rigged mesh the roots ride the animated skin (attach auto: rooted on triangles, follow, maxSpeed, capsules fitted to the skeleton as colliders); maskBone / maskCenter / maskRadius / maskSpace limit growth to a region. overrides patches groom fields, e.g. {"melanin": 0.2, "length": 0.5, "strands": 100000}. Color is physically based: melanin 0 white .. 0.3 blond .. 0.8 brown .. 1 black, redness for auburn/ginger, dye for unnatural tints. Hair is simulated (gravity, wind, collisions with the mesh) and rendered as real strands with Marschner shading and self-shadowing. Example: {"entity": "Head", "preset": "hair_wavy", "overrides": {"melanin": 0.25}}. Grooms stack: the first groom goes on the mesh entity itself, every further one (a beard and eyebrows on a scalp) on a new child entity named after the preset (or name) that grows on the same mesh and skin; replace: true replaces the existing groom instead. On a character root without a mesh, hair grows on its largest skinned part (the body). The result's entity is the groom's entity (edit it with groom_update, remove it with entity_delete). Example: {"entity": "Hero", "preset": "beard", "overrides": {"melanin": 0.6}}.
| Argument | Type | Required | Description | Values |
|---|---|---|---|---|
entity |
integer | string | yes | Entity with the mesh to grow on, or a character root (its body mesh) | |
preset |
string | Starting style | hair_straight hair_wavy hair_curly hair_ponytail hair_short fur_short fur_long beard eyebrows hair_scalp fur_dense |
|
overrides |
object | Groom fields to change | ||
name |
string | Name of the groom's own entity when it is added beside other grooms (default: the preset, e.g. "Beard") | ||
replace |
boolean | Replace the groom already on entity instead of adding another one |
groom_update¶
Update hair or fur mutating
Change a groom's fields (or switch to another preset and then apply fields). Geometry fields (strands, length, curls, clumps, mask...) regenerate the strands; color, shading and motion fields apply instantly. Example: {"entity": "Head", "fields": {"curlRadius": 0.01, "curlFrequency": 18, "melanin": 0.9}}.
| Argument | Type | Required | Description | Values |
|---|---|---|---|---|
entity |
integer | string | yes | Entity with a groom | |
preset |
string | Reset to this preset first | hair_straight hair_wavy hair_curly hair_ponytail hair_short fur_short fur_long beard eyebrows hair_scalp fur_dense |
|
fields |
object | Groom fields to change |
groom_info¶
Hair or fur info read-only
Strand, guide and point counts, memory (CPU and GPU), generation time and the measured GPU cost (simulation and drawing) of a groom, or of every groom in the scene when entity is omitted. Use it to budget hair (e.g. keep a hero head under ~2 ms at 1080p). On a character (or a mesh with several grooms) it lists every groom growing on it (grooms).
| Argument | Type | Required | Description | Values |
|---|---|---|---|---|
entity |
integer | string | Entity with a groom (omit for all) |
fx_benchmark¶
Benchmark GPU frame time read-only
Render frames real-time frames back to back (no readback, effects time advancing 1/60 s per frame, so GPU particles and hair simulate) and report the GPU time per frame and per effects pass, plus the wall-clock time. Use it to budget effects: e.g. {"width":1920,"height":1080,"frames":120}. The view is the editor camera unless eye/target are given.
| Argument | Type | Required | Description | Values |
|---|---|---|---|---|
width |
integer | Width (default 1920) | ||
height |
integer | Height (default 1080) | ||
frames |
integer | Frames to render (default 120, max 2000) | ||
eye |
number[3] | Camera position | ||
target |
number[3] | Look-at point | ||
serial |
boolean | Wait for each frame (default true): exact per-pass GPU times; false = frames overlap like a game loop (throughput) |
fx_stats¶
GPU effects stats read-only
Measured GPU cost of the last rendered frames: whole-frame GPU time, the GPU simulation pass (particles + hair), per-emitter live particle counts (read back asynchronously, a few frames old) and per-groom sizes. Render a few frames (viewport_capture) first; values are 0 on renderers without GPU effects.
Takes no arguments.
impostor_bake¶
Bake foliage impostors read-only
Bake the octahedral impostors of foliage layers now: each heavy model (an imported tree, bush, rock or grass clump; one mesh or every part of a prefab) is captured from up to 32x32 directions into an atlas of albedo, normal and depth, and instances beyond the layer's transition distance render as impostors (lit, shadowed and depth-correct like real geometry). The renderer bakes on first use and caches in .skywalker/cache/impostors/, so this is for baking ahead of time, rebaking after editing a mesh or material (rebake:true), or checking the atlases (preview:true returns the first atlas as an image). Tune per layer with impostorDistance (m; 0 auto from on-screen size, -1 off), impostorResolution (atlas px) and impostorFrames (views per side); see the transition distance in the result. Example: {"entity":"Forest","layer":0,"rebake":true,"preview":true}.
| Argument | Type | Required | Description | Values |
|---|---|---|---|---|
entity |
integer | string | Foliage entity (default: every foliage entity in the scene) | ||
layer |
any | Layer index or name (default: every layer) | ||
rebake |
boolean | Bake again even when a cached atlas exists (default false) | ||
preview |
boolean | Return the first atlas as an image (default false) | ||
save_preview |
string | Also write that preview PNG to this project-relative path |
movie_render¶
Render movie read-only
Render a cinematic to video or a PNG sequence, offline and deterministically (the movie renderer). Renders a sequence (sequence: its entity or .sequence.json, whole length or start/end), an inline camera move (camera: {keys: [{t, eye, target, fov?, roll?}]} splined, or {shots: [{shot: orbit|dolly|crane|track|pan|static|path|flyover, duration, target, ...sequence_camera_shot fields}]} where each shot is a cut), or the scene camera for duration seconds. Always starts from the scene state and restores it after. simulate=true runs the game (scripts, physics); false (default) runs only sequences, animators and particles. Motion blur: shutter 0..1 of the frame (0.5 = 180 degrees; default the camera's motionBlur) accumulates sub-frames at fractional times; samples (default 8) is the per-frame budget. Outputs by extension: .mp4 = H.264 (codec hevc = 10-bit HEVC), .mov = ProRes 422 HQ, a folder or name_####.png = PNG sequence (resume=true continues an interrupted one). clay=true / debug_view="sketch" render the same move as clay or pencil sketch. Blocks until done and returns frames, timings and paths; background=true returns at once (progress: movie_progress events, action="status"; action="cancel" stops). Example: {"sequence": "Intro", "output": "renders/intro.mp4", "resolution": "1080p", "fps": 24, "shutter": 0.5, "samples": 16}.
| Argument | Type | Required | Description | Values |
|---|---|---|---|---|
action |
string | render (default), status of the current/last render, or cancel it | render status cancel |
|
sequence |
any | Sequence to render: entity with a sequencer, or a .sequence.json path | ||
camera |
any | Inline camera move: {keys: [{t, eye, target, fov?, roll?, ease?}]} or {shots: [{shot, duration, target, t?, ...}]}, plus aperture, focus_distance, tilt_shift | ||
camera_entity |
integer | string | Look through this camera instead of the scene's primary one | ||
simulate |
boolean | Run the full game simulation (scripts, physics) while rendering (default false) | ||
start |
number | Start time in seconds (default 0; the simulation pre-rolls to it) | ||
end |
number | End time in seconds (default: the sequence / camera path length) | ||
duration |
number | Seconds to render from start (instead of end) | ||
fps |
integer | Frames per second: 24 (default), 25, 30, 48, 50, 60 | ||
resolution |
string | Size preset (default 1080p) | 720p 1080p 1440p 4k |
|
width |
integer | Width in pixels (up to 3840) | ||
height |
integer | Height in pixels (up to 2160) | ||
samples |
integer | Samples per frame (default 8; 16-32 for finals): anti-aliasing, noise-free GI, motion blur | ||
shutter |
number | Motion blur: open shutter as a fraction of the frame (0.5 = 180-degree film look, 0 = off) | ||
shutter_samples |
integer | Sub-frames across the shutter (default: one per sample) | ||
shutter_timing |
string | Shutter interval relative to the frame time (default center) | center open close |
|
quality |
string | Render quality tier (default full; fast for previews) | full balanced fast |
|
clay |
boolean | Matte clay look (same move, for sketch -> clay -> final transitions) | ||
debug_view |
string | Buffer visualization, shading debug view (wireframe, lod, unshaded, ...) or the pencil sketch look; see viewport_capture | final albedo normals material gi reflections ao depth lighting sketch impostors wireframe overdraw unshaded lighting_only shadow_cascades light_complexity lod emission specular uv_checker texel_density motion shadow_atlas reflection_probes vehicles skeleton ik_targets groom_roots sss_mask |
|
warmup |
integer | Frames rendered before the first one so temporal effects settle (default 4) | ||
output |
string | Output path: .mp4 (H.264), .mov (ProRes 422 HQ), or a folder / name_####.png (PNG sequence); default renders/<name>.mp4 | ||
outputs |
any[] | Several outputs from one render, e.g. ["renders/a.mp4", {"path": "renders/a.mov", "codec": "prores"}] | ||
codec |
string | Codec for output: h264, hevc (10-bit), prores (422 HQ), prores4444, png |
png h264 hevc prores prores4444 |
|
bitrate_mbps |
number | H.264 / HEVC average bitrate (default: chosen from size and fps) | ||
resume |
boolean | PNG sequences: continue from the first missing frame of an interrupted render | ||
name |
string | Name for reports and the default output path | ||
background |
boolean | Return immediately; the editor keeps rendering frame by frame (default false) |
render_layers¶
Render layers and cull masks mutating
Render layers (20): MeshRenderer.layers says which layers a mesh is on; Camera.cullMask and Light.cullMask say which layers a camera draws and a light illuminates (a mesh is drawn / lit when they share a layer). Name layers in game.json and use the names everywhere. action get (default): named layers, meshes per layer, cameras and lights with restricted masks, plus warnings (meshes no camera sees, lights that light nothing). action name: {layer: 2, name: "player"} (name "" clears). action set: {entities, layers} puts meshes on layers and/or {entities, cull_mask} sets cameras' and lights' masks; masks accept a number (raw bits), a layer name, "3", "all", "none" or a list; mode add/remove edits the existing mask instead of replacing it. Uses: a rim light only on the hero ({entities:["RimLight"], cull_mask:"hero"}), first-person arms hidden from a mirror camera, editor-only helpers on layer 20 hidden from the game camera. Example: {"action":"set","entities":["Hero"],"layers":["world","hero"]}
| Argument | Type | Required | Description | Values |
|---|---|---|---|---|
action |
string | get (default), name a layer, or set masks | get name set |
|
layer |
integer | name: layer number 1..20 | ||
name |
string | name: the layer's name ("" removes it) | ||
entities |
integer | string[] | set: entities to change | ||
layers |
any | set: the meshes' layers (number, name, "all", or a list of names / layer numbers) | ||
cull_mask |
any | set: the cameras' / lights' cull mask (same forms as layers) | ||
mode |
string | set: replace the mask (default), add layers to it, or remove them | replace add remove |
shadow_atlas_info¶
Inspect point/spot light shadows read-only
Which point and spot lights cast shadows this frame and how: projection (spot view, cube = 6 views, dual_paraboloid = 2 views), atlas slot and resolution, whether it was re-rendered this frame or reused from the static cache, and why a light has no shadow (disabled, out_of_view, beyond_max_distance, over_light_budget, atlas_full, pending). Also the atlas size and memory, slots used per quadrant, the per-frame budgets (Environment.localShadowLights / localShadowUpdates) and warnings. Renders one real-time frame of view first (default: the editor camera). Use it when light leaks through walls, a shadow is missing or blocky, or to check the cost of many lamps; see the atlas itself with viewport_capture debug_view "shadow_atlas". With entity, also lists the meshes that block that light (casters, first 40) and the small fixtures right at the light that are ignored (lamp heads, bulbs). invalidate=true re-renders every cached shadow on the next frame. Example: {"view": "scene"} or {"entity": "Street Lamp 3"}.
| Argument | Type | Required | Description | Values |
|---|---|---|---|---|
view |
any | Camera of the frame to inspect: "editor" (default), "scene", or | ||
entity |
integer | string | Only report this light entity | ||
render |
boolean | Render a frame of view first (default true; false = the last frame rendered) |
||
invalidate |
boolean | Force every cached shadow to re-render (after editing meshes outside the engine, or to measure the full cost) |
light_shadows¶
Configure light shadows mutating
Turn shadows of point/spot lights on or off and tune them, for one light, a list, or every light ("all", optionally only one kind). Shadows stop light leaking through walls and floors; they cost an atlas slot (cube point light = 6 views, spot = 1) but are cached while nothing in range moves. Tuning: resolution (slot px hint: 256 small, 1024 hero light; 0 = automatic), mode (cube | dual_paraboloid for cheaper point lights), bias (m; raise against speckled self-shadowing, lower if shadows float), normal_bias (texels), max_distance (m from the camera beyond which the shadow fades out). One undo step. Example: {"lights": "all", "kind": "point", "enabled": true, "max_distance": 40}.
| Argument | Type | Required | Description | Values |
|---|---|---|---|---|
lights |
any | yes | A light entity (id or name), a list of them, or "all" | |
kind |
string | With "all": only lights of this kind | point spot |
|
enabled |
boolean | Cast shadows (Light.castShadows) | ||
resolution |
integer | Atlas slot hint in px (0 = automatic, 128..2048) | ||
mode |
string | Point light projection | cube dual_paraboloid |
|
bias |
number | Depth bias in meters (default 0.02) | ||
normal_bias |
number | Normal offset in shadow-map texels (default 1) | ||
max_distance |
number | Camera distance (m) where the shadow fades out (0 = no limit) |
probe_add¶
Add a reflection probe mutating
Add a reflection probe: a captured cubemap that glossy floors, metal and glass inside its volume reflect instead of the sky (box-projected, so reflections line up with the walls), and that gives them their ambient light. Put one per room, corridor or street section, with the capture point in open space at about eye height. size "auto" (default) casts rays from position to the nearest meshes in the six axis directions and fits the box to the room (open directions get 8 m): the volume reaches blend_distance past the walls and the reflections project onto the room (projectionSize); or give [x, y, z] in meters. interior=true for closed rooms: no sky light leaks in (the probe replaces it; windows still show the sky). update: once (default, cached until it moves or probe_bake), on_change (re-captures when something in range changes), realtime (every interval frames, within Environment.probeUpdates faces per frame). The new probe is captured right away and its state returned (see probe_info). Example: {"name": "Hall Probe", "position": [0, 1.6, 0], "interior": true}.
| Argument | Type | Required | Description | Values |
|---|---|---|---|---|
name |
string | Entity name (default "Reflection Probe") | ||
position |
number[3] | yes | Capture point in meters (the room's open space, ~1.5 m up) | |
parent |
integer | string | Parent entity | ||
size |
any | Box size [x, y, z] in meters, or "auto" (default): fit the room around position |
||
shape |
string | Influence volume (default box) | box sphere |
|
radius |
number | Sphere radius in meters | ||
interior |
boolean | Closed room: no sky light inside (default false) | ||
update |
string | When to capture (default once) | once on_change realtime |
|
interval |
integer | realtime: frames between captures (default 1) | ||
resolution |
integer | Face size in px: 64, 128, 256 (default), 512 | ||
priority |
integer | Higher wins where volumes overlap (default 0) | ||
blend_distance |
number | Meters over which the probe fades at its edges (default 1) | ||
box_projection |
boolean | Parallax-correct reflections against the box (default true) | ||
intensity |
number | Brightness multiplier (default 1) | ||
ambient |
string | Diffuse ambient inside the volume (default probe) | probe sky color |
|
ambient_color |
string | Interior / color ambient "#rrggbb" | ||
cull_mask |
any | Render layers the capture draws: names, numbers, "all" (default) or a list | ||
render |
boolean | Capture it now and return its state (default true) |
probe_bake¶
Re-capture reflection probes read-only
Re-capture reflection probes now (after moving furniture, changing lights or the sky): renders one still frame of view, which captures every invalidated probe in full regardless of the per-frame face budget, and returns their state (slot, captures, GPU time) plus warnings. probes: one entity, a list or "all" (default). render=false only marks them; they re-capture over the next frames (Wander: probe_bake()). Example: {"probes": ["Hall Probe"]}.
| Argument | Type | Required | Description | Values |
|---|---|---|---|---|
probes |
any | A probe entity, a list of them, or "all" (default) | ||
view |
any | Camera of the frame: "editor" (default), "scene", or | ||
render |
boolean | Render the frame that captures them now (default true) |
probe_info¶
Inspect reflection probes read-only
Reflection probes and their atlas: the budget (Environment.probeBudget probes, probeUpdates faces per frame), atlas resolution / slots / memory, and per probe: slot and debug color (the reflection_probes debug view draws it), whether it is captured, lighting this view, waiting for the face budget, over budget or out of view, captures so far, last capture GPU time, stale (something in range changed since a once probe was captured: run probe_bake), size, update mode. Warnings: overlapping volumes with equal priority, probes with no geometry in them, capture points inside a mesh, atlas exhaustion. Renders one real-time frame of view first. See the volumes with viewport_capture {debug_view: "reflection_probes"} and a probe's cubemap with viewport_capture {probe: "Hall Probe"}. Example: {"entity": "Hall Probe"}.
| Argument | Type | Required | Description | Values |
|---|---|---|---|---|
view |
any | Camera of the frame: "editor" (default), "scene", or | ||
entity |
integer | string | Only report this probe | ||
render |
boolean | Render a frame of view first (default true; false = the last frame) |
particles2d_create¶
Create 2D particles mutating
Create pixel-art particles for a 2D game from a preset, ready to tweak: rain (streaks over the whole view), drizzle, snow (drifting flakes), leaves and petals (falling, swaying), fireflies (glowing, twinkling, wandering), smoke (chimney puffs), ripples (puddle rings while it rains), dust (motes in sunlight), sparkle (water glints). Weather presets (rain, drizzle, snow, ripples) wrap: their box tiles endlessly so they fill whatever the camera shows, wherever the entity is. Untextured particles are solid pixel rectangles (pixelSize texels); give a texture sheet (with columns/rows, frames, animate random|life|loop) for leaves, flakes or ripple rings. overrides patches fields, e.g. {"rate": 400, "color": "#9fc4ff", "pixelsPerUnit": 16}. Simulated on fixed ticks while playing (deterministic, reset on stop). Example: particles2d_create {"preset": "fireflies", "position": [12, 4, 0], "overrides": {"area": [14, 6]}}.
| Argument | Type | Required | Description | Values |
|---|---|---|---|---|
preset |
string | yes | Preset | rain drizzle snow leaves petals fireflies smoke ripples dust sparkle |
name |
string | Entity name (default: the preset's name) | ||
position |
number[3] | World position (center of the emission box) | ||
parent |
integer | string | Parent entity (e.g. a chimney) | ||
overrides |
object | particles2d fields to change |
particles2d_info¶
2D particle stats read-only
Live state of particles2d emitters: particles alive, cap, rate, box, wrap, and the bounds the live particles cover (world units). Use it to check that weather is running while playing, or to find emitters that hit their maxParticles cap. Without entity lists every emitter in the scene.
| Argument | Type | Required | Description | Values |
|---|---|---|---|---|
entity |
integer | string | Emitter (default: all) |
locale_list¶
List locales read-only
Lists the game's locales: the current one and its fallback chain (pt-BR -> pt -> source), the source language, every locale with strings (count, coverage, files under locale/), game.json localization settings, strings requested at run time that no table has, and table file problems. Start here before translating or checking.
Takes no arguments.
locale_set¶
Set the locale read-only
Switches the language the game shows: texts written as "@key" (ui.text, ui.placeholder, text.text), tr() calls and #line dialogue lines follow at once. While playing it acts like Wander's set_locale (undone when play stops); while editing it previews a language in the editor until changed. "" returns to the default (game.json localization.locale, else the source language). Then viewport_capture / ui_inspect to look for overflow. Example: {"locale": "fr"}.
| Argument | Type | Required | Description | Values |
|---|---|---|---|---|
locale |
string | yes | Locale code ("fr", "pt-BR", "en-XA" for the pseudo-locale); "" = default |
locale_check¶
Check the string tables read-only
Audits localization and returns findings an agent can fix one by one: per locale the keys with no translation (and coverage); keys the project uses ("@key" fields, tr("key") in scripts, #line dialogue ids) that no table defines; unused keys; placeholder mismatches between a translation and the source ({name} missing or extra); invalid messages; plurals missing forms the language needs (ru: one/few/many, ar: zero..many); strings longer than their budget (the table's max column, or source length x budget, default game.json maxLengthRatio); characters no font covers (CJK, Arabic...: add a font); keys requested at run time but missing. Example: {"locale": "de", "budget": 1.3}.
| Argument | Type | Required | Description | Values |
|---|---|---|---|---|
locale |
string | Only this locale (default: all) | ||
budget |
number | Max length ratio translation / source, e.g. 1.3 (default game.json localization.maxLengthRatio) | ||
max_findings |
integer | Most findings listed per category (default 200) |
locale_extract¶
Extract hard-coded texts mutating
Scans the open scene, scenes, prefabs, dialogue scripts and Wander code for hard-coded player-facing texts (ui.text, ui.placeholder, text.text, dialogue lines and choices without a #line id, .text = "..." in scripts) and proposes a key for each ("main_menu.play", "dlg.intro.start.003"); a text whose source string already exists reuses its key. With apply: true it writes the source strings to a CSV table (default locale/strings.csv), replaces the open scene's fields with "@key" (one undoable edit) and tags dialogue lines with #line:
| Argument | Type | Required | Description | Values |
|---|---|---|---|---|
apply |
boolean | Write the table, update the open scene and tag dialogue lines (default false: proposals only) | ||
file |
string | CSV table to write (default locale/strings.csv) | ||
max |
integer | Most proposals returned (default 300) |
locale_pseudo¶
Generate a pseudo-locale mutating
Writes a pseudo-locale for layout testing: every string accented and about 30% longer inside brackets ("Play" -> "[Ƥļáý~~]"), placeholders, plurals and rich-text tags intact, so truncation, overflow and hard-coded texts (they stay plain) jump out. Writes locale/pseudo.csv with the locale en-XA and, by default, switches to it (like locale_set). Then viewport_capture and ui_inspect each menu; locale_set {"locale": ""} goes back. Example: {"expand": 0.4}.
| Argument | Type | Required | Description | Values |
|---|---|---|---|---|
expand |
number | Extra length, 0..2 (default 0.3 = 30% longer) | ||
locale |
string | Pseudo-locale code (default en-XA) | ||
activate |
boolean | Switch to it afterwards (default true) |