Spark On-Demand Rendering: Keep Async Splat Updates Visible

Wire Spark onDirty and scene edits into demand rendering. Use an offline scheduling lab to catch lost updates without claiming unmeasured GPU savings.

colinkoko6 min read

Key takeaways

  • Wire asynchronous work and application edits into the same frame-request path.
  • Coalesce bursts but preserve requests raised during drawing.
  • An idle queue is not proof that a scene has finished loading.

Wake for new data, not just camera movement

For a mostly static Spark splat viewer, connect SparkRenderer.onDirty to a coalesced frame request, and request a frame after your own visible changes. Rendering only when the camera moves can leave asynchronous results unseen. Keep an ongoing frame source while something is genuinely animating; idle rendering is not a replacement for animation updates.[4][6]

A miniature stone observatory formed from teal and gold dots, with separate clusters beside it on a dark background.
Concept illustration of a scene receiving new pieces. Not a Spark render, screenshot or performance test.

Spark announced its 2.3.0 on-demand-rendering improvements on X on September 30, 2026. The release notes carry a September 29 heading; 2.3.1 followed on October 1 with a build fix. This guide turns that change into a review workflow rather than a promise of faster rendering.[1][2][3]

Choose a viewer that can actually become still

An asset-review page, scene inspector or product configurator often spends time waiting for the next edit. That makes it a candidate for demand rendering. A game with moving characters, a running simulation or an animated camera has different needs. Three.js documents this distinction and shows why a continuous loop is appropriate for continuous motion.[6]

Start with one specific acceptance question: after the user stops interacting, can the page finish showing newly available content and then stop requesting frames? Make that question part of the handoff. Do not start with an arbitrary target frame count or battery-saving percentage.

Use a reproducible dependency baseline. The Spark quick-start page inspected on October 12, 2026 pairs Spark 2.3.1 with Three.js 0.180.0. That is a documented example pairing, not a claim that every other version is incompatible. Record the versions in your own project before changing its render loop.[5]

Give every visible change a route to the next frame

Spark starts and advances work during rendering. Sorting, level-of-detail selection, loading and paged data can finish later. Its onDirty callback requests another opportunity to render those results. Your application must also request frames for changes it makes itself.[4]

ChangeFrame request routeWhat to inspect
Spark asynchronous workSparkRenderer onDirtyNew data becomes visible without moving the camera.
Camera or canvas sizeControl change / resize handlerCamera and projection updates are shown.
Object or material editApplication edit handlerA stationary view reflects the new value.
AnimationAn active animation update sourceFrames continue while motion needs them.
A compact wiring plan. The downloadable checklist maps additional events to sources.[4][6]

Treat an idle queue as a scheduling observation, not a loading-complete signal. Network requests, failed resources and pending application jobs need their own status and error handling. A quiet viewer can be correct, unfinished or broken; the frame counter alone cannot distinguish them.

Coalesce requests without losing the next one

The supplied scheduler is a small original teaching adapter. It accepts a draw callback plus scheduling and cancellation callbacks. Multiple requests made before a scheduled callback runs share one pending slot. It clears that slot before drawing, so a request raised inside draw can reserve the following frame. Its dispose operation cancels the pending callback and rejects later work.

That ordering matters. Clearing the pending flag after draw can erase a request made while drawing. Calling draw immediately from a change event can also create recursive calls when updating controls emits another change. Three.js illustrates this problem with damped controls and recommends scheduled, coalesced requests.[6]

Use the official Spark example to wire the real renderer; use this lab to reason about scheduling. Do not paste a second independent loop alongside an existing one and assume both are harmless. Identify which component owns the frame request and which components only notify it.

Run the offline frame-request lab

Download the files linked in the lab README, then run its Node test and report commands. No packages, network access, WebGL context or 3D assets are required. A controlled queue advances only when the fixture asks it to, making each requested and drawn frame inspectable. These are tests of the supplied helper, not tests of Spark or a browser.

  • Burst requests: several changes before one queue step should cause one draw.
  • A later completion: after the queue rests, a new request should cause another draw.
  • A request during draw: the subsequent frame must remain pending.
  • No new work: advancing an empty queue should not draw.
  • Teardown: disposing with a callback pending must prevent later drawing.

The downloadable report records the results of ten actual Node tests on authored scenarios. Their event sequences are deliberately synthetic: they control when notifications arrive, not how long splat decoding, network traffic or GPU work takes. Run the tests before adapting the helper. These results are not FPS, power or loading-time measurements.

In React Three Fiber, use the existing invalidation system

For React Three Fiber, set Canvas frameloop to demand and route Spark onDirty to invalidate. Do not add the lab scheduler as a second frame owner. R3F coalesces invalidation requests; an invalidate call schedules work rather than drawing immediately.[4][7]

React prop changes can trigger demand frames, but imperative mutations can escape that mechanism. If an event handler changes an object directly, request invalidation after the change. Drei controls already integrate camera changes. R3F also documents a timing caveat for immediately starting animations: request the first frame before starting the synchronous animation on the next frame.[7]

Review the real scene before calling the change finished

  • Load a scene, stop touching the controls and check that incoming content still appears.
  • Change a material or object transform while the camera stays still; verify the change is visible.
  • Resize the canvas and check its aspect and framing.
  • Start and stop any animation; verify both motion and the return to idle.
  • Navigate away during loading; check cleanup and console errors.
  • Repeat with a slow connection and the browsers and devices you actually support.

This checklist is a proposed acceptance procedure, not a record of tests performed here. We did not run Spark, measure a renderer or compare devices for this article. Demand rendering does not reduce the cost of an individual draw, shrink an asset or establish correct transparency and sorting in your scene.

Spark v2.3.1 uses the MIT license, including notice-retention conditions. Check the rights to each scene and any redistributed dependencies separately; a renderer license does not establish permission to publish your input assets.[8]

Keep asset creation and viewer behavior separate

For a mesh-based prop workflow, Goblin3D offers Image to 3D and paid-plan GLB, OBJ and FBX exports. Review your chosen export before putting it into a viewer. This is a separate mesh workflow; these public features do not establish a Spark splat export or integration.[9]

The useful outcome is a viewer whose update paths you can explain: what changed, who requested the next frame and why it can stop again. Validate that behavior with your actual scene before discussing any performance benefit.

Evidence used

Sources

  1. 1.SparkJS 2.3.0 announcement — Spark. Accessed 2026-10-12.
  2. 2.Spark 2.3.0 release notes — Spark. Accessed 2026-10-12.
  3. 3.Spark 2.3.1 build fix — Spark. Accessed 2026-10-12.
  4. 4.Spark on-demand rendering — Spark. Accessed 2026-10-12.
  5. 5.Spark getting started — Spark. Accessed 2026-10-12.
  6. 6.Three.js rendering on demand — Three.js. Accessed 2026-10-12.
  7. 7.React Three Fiber scaling performance — Poimandres. Accessed 2026-10-12.
  8. 8.Spark v2.3.1 license — Spark. Accessed 2026-10-12.
  9. 9.Goblin3D public features — Goblin3D. Accessed 2026-10-12.

Create a mesh prop from a visual reference

Explore Goblin3D Image to 3D, then inspect the exported model in the viewer you choose.

Explore Image to 3D

Sources, product facts, and original evidence were checked before publication.

Share your feedback

Sign in to share feedback with the Goblin3D team.

Sign in

support@goblin3d.ai