Zenbu

Rendering Surfaces
Login

Rendering Surfaces

Choose the renderer by content

Content Entity type Native WebAssembly
Shapes, text, controls regular CANVAS_ENTITY_* Raylib Raylib/WASM
Lucide icons CANVAS_ENTITY_LUCIDE_GALLERY Raylib line segments Raylib/WASM line segments
Image URL or file CANVAS_ENTITY_IMAGE CEF off-screen pixels uploaded to a Raylib texture positioned <img> overlay
Live web page CANVAS_ENTITY_WEB_CONTENT CEF off-screen pixels uploaded to a Raylib texture positioned <iframe> overlay

Do not route vector icons or ordinary components through CEF. They belong in Canvas_Draw_Entity() so they inherit camera transforms, theme colors, selection, dragging, pinning, and context behavior without another rendering runtime.

Raylib entities

Canvas_Draw_World() opens one BeginMode2D() camera and draws every retained entity through Canvas_Draw_Entity(). Components such as buttons, dropdowns, cards, calendars, tables, and switches are immediate Raylib draw calls backed by state in Canvas_Entity.

The scene-array order is the z-order. The main frame interleaves each Raylib entity layer with its native CEF/image texture, so a later button can genuinely draw over and receive input ahead of an earlier browser surface. Picking and native browser input both resolve the same reverse scene order.

Dynamic text inside an entity must use the shared measured wrapping path rather than a raw DrawTextEx() call. The layout splits both words and long unbroken strings to the available width and draws only complete lines that fit the component's content height. Cards, accordions, buttons, text areas, notifications, conversations, search fields, and text chips therefore keep database, agent, and user-provided text inside their bounds.

The Lucide gallery follows the same path. The generator tools/generate_lucide_data.mjs downloads pinned Lucide 1.31.0 definitions, flattens SVG paths and primitives into line segments, and writes generated/lucide_data.h. The gallery virtualizes rows: only cards fully inside its visible body issue Raylib draw calls. Its Raylib search field filters icon names case-insensitively and resets the internal scroll offset when edited.

Regenerate after changing the pinned icon version:

node yuu/tools/generate_lucide_data.mjs

Native image and web surfaces

web_surface_native.cc maintains a pool of at most CANVAS_MAX_WEB_VIEWS off-screen CEF browsers. Visible image and web entities are reconciled by stable entity ID. CEF paint callbacks fill arena-owned RGBA buffers; Sync() creates or updates Raylib textures; Draw() composites those textures into the camera-derived screen bounds.

Resolution follows displayed size in stable buckets and is capped. Off-screen entities release their active pool slot, small background views receive lower frame rates, and the focused view receives the largest frame budget. Native and WebAssembly backends consume the same tested Canvas_Web_Surface_Should_Activate() camera policy: surfaces are inactive outside the viewport, while being removed, or below 0.30x zoom. Native CEF calls WasHidden(true) for inactive browsers; the web backend removes inactive DOM surfaces at frame end.

When a web entity is selected, C reserves a fixed-screen-height toolbar above the page viewport. The reserved height and toolbar clip animate together so selection pushes the page down like an opening accordion and deselection pulls it back up. Raylib draws the themed editable address field and Lucide navigation icons after that entity's CEF texture, preserving scene z-order. The URL editor retains its own draft, caret, selection, horizontal scroll, and clipboard focus; committing updates the entity URL, which triggers backend navigation. CEF reports main-frame address changes and history availability back to the toolbar. CEF emulates the canvas prefers-color-scheme value and updates the page color-scheme when the canvas theme changes.

Images use a bundled image-view.html wrapper for object-fit: contain. Filesystem paths are resolved to file://; URLs remain URLs.

WebAssembly image and web surfaces

web_surface_web.c cannot composite cross-origin page pixels into WebGL, so it positions DOM overlays over the Raylib canvas. It creates <img> elements for images and sandboxed <iframe> elements for live pages, converts Raylib screen coordinates to CSS coordinates, and removes overlays that are no longer visible.

Selected iframe entities use the same Raylib toolbar geometry and move the DOM viewport below it. The iframe element receives the canvas color-scheme. History navigation is best-effort because cross-origin iframe history and address inspection remain browser-controlled; the displayed URL falls back to the entity's configured URL.

This is intentionally different from native. Shared scene semantics live in C; the platform backend owns only presentation and input details.