Inside figgy / technical guide

Small details.
Large datasets.
One chart engine.

Crisp labels on the CPU. Data geometry on the GPU. Original values kept intact. A closer look at the architecture behind your figures, with diagrams and real chart outputs from the figgy README.

Studio engine: figgy 0.10.0 · renderer 0.12.0
Based on the source README · Updated 8 October 2026

A coloured heatmap with labelled contour lines, exported by the figgy native renderer.
RENDERED BY FIGGYA continuous field, two ways to read it.Interpolated heatmap and labelled contours on the same matrix lattice. Synthetic data from the README gallery.
01 / INPUT

A local data pipeline

Opening a CSV, TSV, or Excel file gives the browser access to the file you selected. Chart data is parsed and plotted locally; it is not uploaded to a figgy plotting service.

  1. 01 →Read & parse

    Delimited text is read incrementally in a Worker, keeping parsing work off the interface thread.

  2. 02 →Store & map

    Columns hold the table. You choose X, Y, and optional error or style columns.

  3. 03Render & inspect

    Numeric arrays reach the renderer as registered columns or replayable stream sources.

The sheet uses a virtual viewport, so a large table does not create an HTML cell for every stored value. Numeric chart extraction writes into typed arrays. These choices reduce interface overhead, but the source data still occupies browser memory: streaming the GPU work does not make tab memory unlimited.

Incremental text import and bounded GPU submission are separate mechanisms. An Excel workbook follows its workbook parser's path and does not inherit every CSV streaming property.

02 / ENGINE

Rust, WebAssembly, and WebGPU

The chart engine is written in Rust and compiled to WebAssembly. JavaScript manages the studio interface and supplies data; the engine owns chart configuration, range fitting, ticks, layout, hit testing, and drawing.

The renderer combines GPU work for data geometry with CPU raster work for text and chart decoration. WebGPU is accessed through wgpu. Keeping chart decisions in one engine helps the displayed figure and its exported rendering follow the same configuration.

  1. MODELDeclare the chart

    Config, series, rich text, layout and interaction policy. This layer owns no GPU resources.

  2. RENDERERPrepare & draw

    The chart registry, columns, GPU pipelines and CPU raster work. It owns the authoritative rendering state.

  3. WEBConnect the browser

    Canvas, input, resize and scheduling. The studio uses the raw WASM API; a Custom Element facade is also available.

Three layers, in a deliberate order

tiny-skia and swash rasterize the grid, axes and rich text. The GPU draws data geometry between the background grid and foreground decoration, keeping the data readable.

  1. 01Grid

    CPU-rasterized background reference lines.

  2. 02Data

    GPU lines, points, error bars, histograms and matrix fields.

  3. 03Decoration

    Axes, tick labels, titles and the legend above the data.

These are native renderer outputs with synthetic data, reproduced from the README gallery guide.

Configuration is the source of truth

Axes, series, labels, styles, and selected-data references belong to the renderer's configuration. After an asynchronous operation changes that configuration, the studio reads the committed result. A method returning successfully does not always mean that the GPU has finished drawing.

Redraw only what changed

The renderer issues revisions for chart state and raster changes. The browser compares them with the last successfully presented frame: an idle frame can skip drawing, a label change can refresh decoration, and a view change can request new data work. Queued resource cleanup still needs to progress while the picture is unchanged.

Explore the full architecture diagram
Nine areas of the figgy architecture: crate responsibilities, column upload, state ownership, frame invalidation, prepared frames, GPU calculations, output, fidelity and memory retirement.
README / INTERNAL MEMORY DATA FLOWThe numbered areas describe ownership boundaries, not one sequential pipeline. Open full-size diagram ↗

WebGPU support depends on the browser, device, driver, and adapter limits. Data editing can remain available when GPU rendering is unavailable. A successful file import alone does not prove a chart can be rendered.

03 / VISUAL LANGUAGE

One dataset. Four visual treatments.

The README uses growth-response curves to show the engine’s Precise, Sketch, Milkyway and Constellation styles. Each mode changes how the chart is drawn; the original data coordinates remain the source.

Original native renders from the README. Style and series support vary; these previews are not a claim that all four modes support streaming in the studio.

04 / LARGE CHARTS

Bounded work, renderer-owned fitting

For a large chart, the renderer requests and processes bounded chunks while the browser keeps replayable source arrays. It controls draw order, temporary GPU allocations, and backpressure. The host supplies the requested data and gives the browser opportunities to process input between steps.

This path draws the source primitives without a JavaScript downsampling pass. It is a way to bound GPU work and memory, not a promise that every dataset will render instantly.

Replayable source data supplies a renderer with two paths: resident columns draw directly; bounded streamed chunks build an accumulation surface, optionally with an exact packed-view cache. Engine export replays source ranges separately.
README / EXACT STREAMING & RESIDENCYTwo rendering paths, the same original data.The dashed branch is an optional cache for a supported view, not automatic upload of every source column. The export lane describes the engine; see the studio export boundary. Open full-size diagram ↗

Resident drawing reads GPU columns directly. Nonresident streaming builds an accumulation surface from original chunks. An unchanged completed revision can reuse that result; changing the view or output resolution may require replaying the source. Neither path introduces LOD or decimation.

New charts and manual views have different intent

When the studio requests automatic fitting
ActionRange behavior
Create a chartLet the engine collect complete source statistics, request fit, then render the fitted view.
Open a saved chartRestore its saved ranges. Rendering does not implicitly turn fitting on.
Zoom or panKeep the range you chose and render that view.
Fit to all dataExplicitly request a new fit using the currently connected series and padding.

The current release collects source statistics before fitting to avoid repeated prefix redraws. The renderer computes the range and draws the fitted view. “All submitted” means the chunks have been submitted; it does not by itself mean the final image or range is ready.

The current studio streaming path accepts supported Precise line, scatter, error-bar, and histogram configurations. Other styles and field charts have separate support constraints; importing a table does not imply that every render mode can stream it.

05 / MEMORY

A large source can have a resident view

Where the complete source is stored and where the visible view is stored are different questions. The source can stay streamed while the renderer packs the rows needed for the current view into a GPU cache.

Zooming into a smaller region can make that view fit. The renderer includes dependencies such as a line crossing the viewport even when its endpoints lie outside it. Original source indices are preserved.

Reading the current-view state
StateWhat it means
PreparingThe renderer is building the current view's packed GPU data.
GPU residentThe current view is packed on the GPU and can support picking. This does not mean every source column is uploaded.
StreamedThe view remains streamed when packing is unsupported or exceeds a resource limit. Rendering can still complete.

The studio currently requests a 4,000,000,000-byte overall GPU budget and a 500,000,000-byte view-cache limit. These are application limits, not measurements of free VRAM or guarantees of available memory. Device limits and allocation failures can impose tighter bounds.

Precision and lifetime have a cost

Resident logical values use two f32 lanes. Uploading f64 values splits them into high and low components, preserving large offsets such as timestamps. The shared column pool can relocate allocations during defragmentation without changing the source identity.

Live resourceAwaiting retirementQueue completion

Releasing a chart reference does not make in-flight GPU work disappear. Live and retired allocations both remain in the renderer’s tracked total until the relevant owners and submitted work are finished. The report measures tracked requested bytes, not physical VRAM; driver allocations and some lazy Milkyway/Constellation textures are outside that total.

Whole-column admission counts unique logical values using the renderer's eight-byte resident representation. CSV file size and typed-array byte length are therefore not direct measures of the GPU allocation. Narrowing the view reduces its working set without discarding the original table.

06 / INTERACTION

Picking and displaying a selection

With a completed packed view, the GPU picker identifies a visible primitive and returns its original series and row reference. A view that is still preparing, or could not be packed, may not support picking yet.

Finding a hit and drawing its highlight are separate operations. Selection has its own renderer-controlled requests for the selected source rows. The studio supplies those small ranges even after the data stream has completed.

Changing or clearing a selection updates that display without restarting the entire data scan. Keeping a selection does not block zooming; view changes still pass through the renderer's normal cache and resource checks.

07 / OUTPUT

Editable projects and rendered figures

A .figgy project stores tables and chart configuration in a local file. Large tables use bounded binary grid blocks so the file codec can handle them in pieces. The project format belongs to the studio and is separate from the rendering engine.

Export is a new rendering target

The engine scales chart dimensions and styles, draws to an offscreen texture in the same grid → data → decoration order, and reads back aligned row chunks. It then converts premultiplied colour to straight-alpha RGBA and encodes the PNG. Chunked readback bounds the temporary buffer; the final image still needs memory.

PNG export uses an explicit scale factor. A project file preserves editable data and settings; a PNG preserves a rendered image. Save a project when you need to continue editing later.

The current public studio still restricts PNG export for raw streamed charts. A view becoming GPU resident does not automatically remove that host-side export restriction. Renderer-level capabilities and the operations exposed by the studio can differ.

08 / NETWORK

Local plotting does not mean an offline website

Chart files are processed in the browser. Hosting delivers the application, fonts, and engine assets; it does not perform the chart computation.

The site can load external resources, advertising, and analytics. Sending feedback is an explicit network submission. Theme and style preferences use browser storage, while saving a project writes a file to your device. See the privacy policy for the site's data and third-party resource details.

09 / REFERENCES

Explore the implementation

This guide describes the public studio and its pinned renderer release. The engine's source and API documentation define the underlying contracts.

The nine illustrations on this page are unmodified documentation assets from the pinned figgy source revision. © figgy contributors, used under the MIT license. The page layout and explanatory summaries are adapted for this guide. Source releases and the online studio can run different versions.

Try it in the studio →