Spawn
spawn / swhat we're building

pinned

start herewhat spawn isfaqfrequently asked questionsthe betthe spawn bet

updates

engine v5.1Connection1 weekengine v5.0For Real3 weeksengine v4.6AtelierJune 1, 2026engine v4.5Surface TensionMay 22, 2026engine v4.4SolidMay 15, 2026engine v4.3GroovyMay 13, 2026engine v4.2ContinuumMay 9, 2026engine v4.1FoundationsMay 4, 2026engine v0.1GenesisApril 29, 2026

pinned

what spawn isstart herefrequently asked questionsfaqthe spawn betthe bet

updates

Connectionengine v5.11 weekFor Realengine v5.03 weeksAtelierengine v4.6June 1, 2026Surface Tensionengine v4.5May 22, 2026Solidengine v4.4May 15, 2026Groovyengine v4.3May 13, 2026Continuumengine v4.2May 9, 2026Foundationsengine v4.1May 4, 2026Genesisengine v0.1April 29, 2026
← All posts
← All posts

engine v5.1.8

Engine v5.1.8

July 2, 2026

A patch in the Connection line.

what's new

  • Side-scroller levels with visual-only heightmaps no longer get fake ground snaps or repeated collider rebuild warnings.
  • Color-grading looks that adjust saturation build correctly again instead of failing with a shader error.
  • A broken or still-compiling look can no longer darken your world: the screen always shows your plain, correctly-lit scene until the look is healthy, and Savi still gets told what failed.
  • Games can now author their render resolution: api.patchEngine({ graphics: { renderResolution: [480, 270] } }) renders the whole game at 480×270 and upscales to fill the screen — retro/PS1 looks, pixel-perfect low-res, or a performance cap for heavy scenes. It applies live (no reload), acts as a ceiling (players' devices can still auto-reduce under it when struggling, and it never exceeds their native resolution), and renderResolution: null removes it.
  • Player progress now saves when a stuck world update forces a room restart — players rejoin the fresh room with their latest progress instead of losing everything since their last save.
  • A model can now sit offset from its physics body: model: { id, offset: [x, y, z] } slides the rendered mesh in meters along the entity's local axes — no more child-entity workarounds when a model's art doesn't line up with its hitbox (e.g. an avatar mesh 1m behind its capsule).
  • Paint parts of a model: model: { id, materials: { PartName: { ... } } } layers color, metalness/roughness, opacity, and glow onto one named part of a GLB while the rest keeps its built-in look — make the blade glow without touching the grip, light the brake lights, tint one building's windows. Typos in part names warn in logs with the names that would match.
  • Switching a game into a different built-in camera style now changes both its framing and movement behavior.
  • Blueprint placement is more reliable across larger multi-area games.
  • God-mode labels and status text (like "Generating…") stay readable while the UI is still loading.
  • Switching in and out of god mode keeps player placement more consistent.
  • Games built from many scripted shapes load smoothly when you join — no more lag spiral or briefly vanishing objects in scripted-geometry-heavy worlds.
  • God mode gets its 10x pass: pressure-feathered brushes with a two-ring cursor, snapping, slider widgets, an fx shelf (seeded firework shows, rain that streaks along its fall, layered mist), spline and spotlight feel, emitter shape wireframes when selected, and a library plus genre pages.
  • Screen effects no longer flash the whole screen when they turn on.
  • Blur and desaturate effects actually work now — and looks with saturation (noir, underwater, vhs) stop washing toward white.
  • Re-triggering a timed effect no longer cuts it short.
  • Regenerating scripted shapes stop blinking (and their shadows stop flickering).
  • Plug in a controller and the right stick looks around in every game.
  • Music that leaves the screen actually stops: no more invisible ghost copies stacking up behind your soundtrack.
  • The new anti-aliasing path is stepping back to opt-in while we fix sprite ghosting and material fade — visuals return to the previous default
  • Brushes got a feel upgrade: a new Feather control (hard edge → soft airbrush), and the brush cursor now shows two rings — solid where you're painting at full strength, dotted where the effect fades out.
  • The brush remembers your radius, strength, and feather per tool now — no more re-dialing every time you pick a brush back up.
  • Sliders! Brightness and volume (and anything Savi builds for you) can now be dragged smoothly instead of picking from presets.
  • Buttons Savi makes for you are more reliable: broken ones can't take down the rest of your editing tools anymore, and missing icons show a letter instead of nothing.
  • God-mode icons are getting a fresh, consistent look (they regenerate as you play — a few may take a moment to appear the first time).
›technical notes
  • Terrain rescue and client collider parity checks now stand down for visual-only heightmaps in 2D places instead of creating fall/snap and impossible rebuild loops; supported voxel-slice and 3D terrain behavior is unchanged.
  • Color-grading looks using grade() with a saturation key build correctly again (ledger #661). The TypeError: getNodeType is not a function TSL build crash lived in the r0.184 three fork that engines 5.1.5/5.1.6 shipped; the r185 re-vendor replaced those TSL internals, and the creator's exact repro and bisect matrix (exposure+saturation, saturation-only, the full grade→vignette→grain chain, the script+vocabulary composite, and a two-builder rebuild) are now pinned through the real WGSLNodeBuilder so the documented grade surface cannot silently regress.
  • A look whose final full-screen draw cannot land no longer darkens the world (ledger #662). Nonblocking shader compilation silently skips draws with cold or never-compiling pipelines; the look pass now detects its own skipped present via the fork's compilationSkipCount (the same guard the engine chain's presenter uses) and presents the plain un-graded frame that same frame, and it pre-warms the copy material's pipeline at construction so the fallback is never itself cold. Any look build failure now presents the scene exactly as if no look were authored, alongside the existing diagnostics.
  • New spec vocabulary engine.graphics.renderResolution: [width, height] — an authored drawing-buffer ceiling. The client syncs it into a forwarded draw/render-resolution singleton (spec-sync → render channel), and the renderer folds it into effectivePixelRatio as a cap on the existing DPR plumb: the buffer renders at the largest size that fits inside the authored pair at the viewport's aspect (exact on matching-aspect displays), the browser upscales to fill the canvas, and the quality ladder's renderScale multiplies after the cap so the governor reduces under the authored ceiling and can never exceed it. Never raises above the device's native/tier-clamped resolution. Live on patch; unauthored specs are byte-identical to before.
  • The wedged-apply container recycle (tome.update RPC timeout, ledger 649) now runs a bounded graceful dispose before exitContainer(1): the container posts dispose to the still-healthy sim worker and waits up to 5s for disposeComplete, so saveAndDispose → firePlayerDisconnectedHooksForShutdown lands connected players' saves like a SIGTERM shutdown would; past the bound it exits hard exactly as before.
  • The mount-fallback roomReady flip in room-runtime.ts now clears the 45s boot-liveness deadline, so no dead timer stays armed after the room becomes ready.
  • Primitive batch lanes reuse freed geometry arena ranges (#7518): regenerating scripted primitives (params ticking every second) no longer grow the merged arena monotonically — the wholesale buffer reallocation at every capacity crossing, the per-revision geometry-id churn (indirect draw buffer replacement), and the stream-reset feedback loop all stop. 40-revision regression pin.
  • The look-activation flash is dead by invariant (#7525): every frame presents through warm pipelines — cross-target topology flips (vignette/effect/slowMo on) re-present the last warm path until the look's pipelines land; LookPass reports landed draws; prewarm overlaps compiles with covered frames. The r185 luma-dot white-wash is fixed (dot promoted vec3 weights to vec4 with alpha=1.0, so every authored-saturation look mixed toward super-white — WGSL-shape pins prevent recurrence); blur and desaturate join the look vocabulary (separable gaussian, radius rides a uniform so fades never rebuild the graph); effect(duration) re-press is anchor-guarded.
  • Right-stick camera look works in every game (#7458): the stick writes the same 120Hz camera-orientation channel as mouse and touch, so authored sensitivity/clamps govern identically; the pad poll ignites on gamepadconnected and parks at zero pads — zero per-frame cost until a controller exists.
  • Media elements removed by tome-UI morphs or teardowns are unloaded (#7515): a discarded playing <audio>/<video> is paused and released instead of playing forever detached (Chrome GC-protects playing media) — the ghost-chorus bug class (stacked invisible music copies) is dead; persistent same-id players survive re-renders untouched.
  • Bespoke scripted geometry and its textures are content-addressed resources now (#7412): join-time no longer re-normalizes and re-hashes every byte of every scripted mesh on every encode/decode, and a stream reset no longer disposes and cold-rebuilds every bespoke visual — killing the self-sustaining join lag-loop in scripted-primitive-heavy games (and the disappearing-mesh reports that were the same loop from the other side).
  • model object form gains offset?: [x, y, z] (ledger 672): a render-only translate of the mesh relative to the entity's transform, composed as entity · T(offset) — after rotation (including any pivot fold) and entity scale, before the geometry-fit scale. Plumbed through the spec types, zod schema, curated property validator, DrawModel component + wire codec (new flag bit; absent offset is byte-identical to the pre-offset stream), and all three renderer representations (static batch, horde batch, skinned clone — including bone-pose bases, so bone-attached children follow the offset mesh).
  • Offsets quantize to f32 at the source (quantize.ts contract) so client-side setProperty('model') writes match the decoded authoritative value bit-exactly — no phantom prediction drift rows.
  • Physics, colliders, culling/LOD, nameplates, cameras, and everything else anchored to the ENTITY deliberately keep the entity origin; the offset moves only the rendered mesh (pick/outline follow the mesh since they derive from it).
  • ObjectProperties.model object form gains materials?: Record<string, StandardMaterialSpec> — the writer half of per-submesh material overrides (structural-gap audit #3, ledger 678). Entries normalize through normalizeMaterialSpec into the already-shipped DrawModel.subOverrides field (wire codec + model-batch consumption existed with zero producers; derive-appearance.ts now carries the map instead of never writing it), keyed by the GLB's material names with node name / primitive id as the consumer's fallbacks. Per property the renderer resolves subOverride ?? whole-model override ?? GLB value.
  • A model written without materials keeps the exact legacy component value (no subOverrides key), so existing specs replicate byte-identically.
  • Part names that match nothing are gracefully inert and now report model-part-material-unknown (once per entity+key-set, listing the model's real material names); a materials map on a rigged model reports model-part-materials-skinned — the static render path is the consumer.
  • The dormant inert-scatter instanced path carries the map too: InertScatterTemplateSource.subOverrides → DrawModelInstances.subOverrides (the instanced draws feed the same ModelVisual pipeline), so a scatter template painting parts keeps them if/when INERT_SCATTER_INSTANCED_PATH flips back on.
  • Runtime setCamera() now resolves behavior from the final camera config: built-in kinds activate their matching behavior, optional script overlays remain composed in order, and replacement cameras stay replacement-rooted through later cursor/FOV patches.
  • Fixed TAAU motion vectors for all positionNode-driven content (heightmap terrain, voxel buckets, decorations, water): the previous-frame basis is now the same deformed position reprojected through previous matrices, instead of the raw geometry attribute that made terrain velocity garbage and rejected history every frame.
  • Skinned characters carry real previous-frame bone data for their motion vectors (per-object useVelocity opt-in; vendor patch 0009 exports three's object-data registry), so animated characters stay sharp under TAAU instead of smearing.
  • Deformation-aware blend boost: pixels whose motion disagrees with a static-scene camera reprojection (limbs, movers) converge toward the current frame in a few frames instead of smearing across the full accumulation window; camera-only motion is unaffected.
  • Persisted the TAAU thin-feature lock channel across frames (two-attachment resolve target; lock read follows the reprojected history UV).
  • RCAS sharpening now runs in reversibly compressed space with the noise limiter enabled, so HDR highlights and residual instability are no longer amplified.
  • Replaced fixed nonlinear-depth disocclusion thresholds with FSR2-style view-space, depth-proportional tests (Akeley separation bound).
  • Jitter sequence length now follows the upscale ratio (8 × area ratio, FSR2/DLSS prescription) instead of a fixed 31-phase cycle.
  • History resampling upgraded from bilinear to 5-tap Catmull-Rom.
  • Added a Velocity debug view to the renderer inspector (Debug view → Velocity) presenting the motion-vector MRT directly.
  • Fixed god-mode blueprint toolbar values in src/engine/ui/tome/toolbar-overlay.ts and src/tome/api/object-api.ts so object choices stay scoped to their source place.
  • Fixed blueprint subtree collection so scoped object IDs and authored object IDs both resolve during placement.
  • Added an inherited color + text-shadow base rule for #tome-creator-ui-container in src/engine/ui/tome/tailwind-cdn.ts so god-mode text is readable in the boot window before the lazy Tailwind runtime compiles utility classes; compiled utilities still win via inheritance.
  • Fixed god-mode exit/re-entry in src/engine/runtime/server/commands/god-mode.ts by clearing stale BodyPosition state when restoring the parked god-mode entity.
  • SMAA is the default renderer anti-aliasing path again (DEFAULT_RENDERER_ANTI_ALIASING_MODE = "smaa-1x"); the mode union is widened back to "msaa" | "smaa-1x" | "taau" so TAAU stays built and selectable (SessionParametersInput.antiAliasingMode) instead of being the only representable value. Reverted because live tasting failed the TAAU default: heavy temporal ghosting on moving pixel-art sprites and material fade at distance.
  • Every desktop session — discrete and Apple-silicon — resolves the pre-TAAU defaults: native scene scale, the class shadow baseline (no integrated→medium shadow-floor demotion), SMAA at the encode seam. The "integrated desktop" heuristic classed M-series Max machines as weak silicon; an honest Apple-aware tiering pass will re-introduce scaling where it belongs.
  • The scene pass is a plain native-scale single-target pass outside TAAU; under opt-in TAAU it keeps the velocity MRT + sub-native sceneResolutionScale (TAAU remains the one shipped upscaler, so a sub-native scale without it is ignored). All #7422 velocity/lock/RCAS fixes stay in the tree.
  • Restored the Retina MSAA suppression and the msaa-mode boot fact (displayPixelRatio input), and the vendored SMAA node deleted with the TAAU default.
  • The "medium" device shadow tier and its inspector label stay as vocabulary; no class baseline resolves to it today.
  • Brushes: new optional feather (0–1, fraction of radius that fades at the rim) on BrushDef, armBrush, and the brush session; ctx.falloff now shapes by feather (feather 1 ≡ legacy full-radius smoothstep — terrain sculpt brushes unchanged). Material brushes default feather 0.25 (Crisp), scatter 0.5 — every family default sits on the Feather chip's option list so the strip highlights on arm. Feather chip (Hard/Crisp/Soft/Softer/Airbrush) in the brush action panel.
  • Brush cursor is now two rings: solid at the half-strength contour, dotted at the true rim. Tile brushes keep the single hard ring.
  • Brush defaults snapped onto the chip option lists (material 4.5→5, paint-with-prop 6→5); scroll steps are proportional (radius ±max(0.5, r·0.12), strength ±max(0.05, s·0.12)); per-creator brush tuning (radius/strength/feather) now persists across re-arms on TomeGodMode.
  • Action chips: new optional icon slug (normalized via the shared moodboard convention, letter fallback on 404 — no more invisible chips), disabled, active, and persistProperties on click verbs (non-envelope property writes now persist + undo).
  • New slider chip: slider: { min, max, step?, value, apply, format?, persistProperties? } on ActionHandleSpec — chip opens a slider drawer (desktop) / expanding sheet row (touch); replicated god:slider action with drag/commit/cancel phases riding the standard gesture undo bracket (pointercancel reverts the preview; a reaped or orphaned drag commits its last previewed value, so no abandonment path leaves the bracket open). Declared ranges are validated at publish — non-finite/inverted ranges render as a plain chip. Light Brightness and audio Volume default editors converted from preset menus to sliders.
  • Editor fault isolation: a throwing creator editor() layer no longer strips the whole authoring surface — the faulted layer is script-scope parked (DM rail intact), default handles keep composing.
  • Menu option pre-rendering memoized (was re-rendered per option per sim tick); one-UI-frame TTL + commit-funnel invalidation.
  • God-mode icon moodboard consolidated to one exported constant (MCDN_ICON_BASE) and bumped to moodboard-solid-flat-ui-icons-v2, forcing every icon to regenerate under the current tight-crop pipeline; the renderer insets the glyph to 78% of the icon box for assets from that board ONLY — pass-through URLs (legacy v1 icons pinned in specs/recents, foreign art) keep the old 100% contain, since they carry their own margins and would double-pad.