CranberryClock.Ideas / Systems / Design
← Back to work

Rendering / R&D / Research prototype

FrameBridge

A browser-to-native rendering experiment, built to test where the connection works and what it costs.

FrameBridge — illustrated project design map
IDEAS / SYSTEMS / DESIGNIllustrated project study

Can a web experience reach beyond the browser renderer?

FrameBridge began with an ambitious question: could a browser-controlled scene use a native graphics process, eventually opening a path to rendering features outside the browser’s usual reach?

I approached it as a sequence of experiments. Before investigating advanced upscaling, the system needed to prove something more fundamental: that the browser and native renderer agreed on the scene, that frames crossed the boundary correctly, and that the result could make its way back to the page.

FrameBridge is the system. The Cube Works is its first demo. A deliberately small scene made discrepancies visible and kept the investigation focused on the connection itself.

One scene, one source of truth

The browser owns simulation time, camera state, object transforms, and viewport changes. It sends an explicit scene description over an authenticated local WebSocket connection to a C++ process, where Dawn renders through D3D12.

That ownership rule matters. If the native side independently animated its own cube, two similar-looking windows could hide a broken connection. Instead, the native renderer consumes the browser’s state. Projection checks compare the native math against an independent Three.js reference, down to the projected corners of the cube.

The experiment progressed from native-window presentation to a complete return path: native rendering, a reference upscaling pass, CPU image readback, and presentation on a browser canvas.

Making the boundary testable

The difficult work lives between the visible frames. Resizing changes resource dimensions. Queues can fall behind. GPU work needs clear ownership and synchronization. A dropped frame changes which previous state should be used for motion.

The implementation addresses those problems with bounded queues, correlated frame identifiers, explicit resize generations, and reusable render targets. Temporal resources include GPU-written depth and motion targets; motion history follows the previous successfully submitted native frame, rather than assuming every browser frame was rendered.

These choices made the prototype inspectable. A picture on screen was one check; resource readbacks, projection comparisons, and protocol validation explained whether that picture had arrived through the intended path.

What the experiment demonstrated

The documented closeout run returned a browser-controlled textured cube through the full native-to-browser path. It rendered at 320 × 180, applied reference upscaling to 640 × 360, and displayed 107 images during a ten-second run, with no recorded page or protocol errors.

The same measurement exposed the limits. Median returned cadence was 11 FPS, with a median submission-to-browser frame age of 21.5 ms. Those are measurements of the diagnostic return path, not a benchmark of native rendering throughput. CPU readback and image transport added overhead, and the result did not demonstrate a performance advantage over browser rendering.

Where I drew the line

Genuine DLSS Super Resolution was not initialized or evaluated. The closeout environment lacked the configured vendor SDK and application identity needed for that probe. The working path is explicitly reference upscaling, and its results cannot establish DLSS quality or performance.

FrameBridge also mirrors a defined scene; it is not a drop-in backend for arbitrary Three.js applications.

The useful outcome is a working browser/native experiment with measured boundaries. It separates what the architecture demonstrated from what would require another integration effort—and gives that next decision a concrete technical basis.

UNDER THE HOOD

Architecture & loops

Implemented path

The browser → native → browser round trip

The browser owns the scene. The native process renders a defined mirror and returns pixels.

  1. Browser scene state

    Camera, transforms, simulation time, viewport, and texture revision originate in the webpage.

  2. Authenticated local bridge

    A binary WebSocket protocol sends scene state to the installed C++ process. A bounded queue limits backlog.

  3. Native Dawn / D3D12 rendering

    The renderer consumes that state and produces color, depth, and motion resources on its graphics device.

  4. Reference upscaling

    A native GPU pass scales the rendered color into an explicit output texture. This pass is not DLSS.

  5. CPU readback + image transport

    The output becomes RGBA8 pixel data and travels back over the local connection.

  6. Browser canvas presentation

    The page displays the returned image and correlates it with its submitted frame.

Camera movement or a new frame starts the same round trip again.

The return path includes CPU copies. It proves connectivity, not zero-copy presentation or a performance advantage.

Implemented path

Keeping motion history honest

A skipped browser frame must not become a fictional previous native frame.

  1. Receive complete scene state

    Each submission carries frame identity and resize generation.

  2. Handle queue pressure

    Drop old queued work when necessary; retain the state of the last successfully submitted native frame.

  3. Produce temporal inputs

    Compute motion from the previous submitted state to the current state, including camera movement.

  4. Update history after submission

    New sessions, dimensions, scale, and explicit reinitialization reset history; ordinary queue drops do not.