rive_gl_player · architecture

RIV — Project Structure

A Rive player and from-scratch vector editor built on the official Rive runtime for parsing, scene and animation — but rendering through our own ground-up GL pipeline that implements every Rive render interface.

121 source files ~40k lines 2 renderers · ours ∥ official 5 GL-free test suites CMake · OpenGL · Dear ImGui

01Official vs Ours — the central idea

The official runtime in external/rive-runtime/ owns the file format, the object model and animation. Drawing happens through an abstract interface seam — and we provide a second, independent implementation of that seam. Same .riv, two renderers.

rive-runtime · official (external/rive-runtime)

Everything above the renderer is shared and unmodified.

.riv parser — rive::File::import Core model — Artboard · Shape · Path · Fill · Gradient · Text · Image Animation + State machines — advanceAndApply
▼ draws through ▼

rive render interface — the API contract

FactoryRenderer RenderPathRenderPaint RenderShaderRenderBuffer RenderImage
▼ two independent implementations ▼

official renderer — Rive Renderer (PLS)

rive::RiveRenderer over rive::gpu::RenderContextGLImpl (Pixel Local Storage GPU renderer, linked as rive_pls_renderer). Wrapped by gl_backend.cpp. Fast, analytic edges, flattens splines.

not cg_renderer — that is Rive's Apple CoreGraphics path, unused here

ours — GL stencil-then-cover

GlStencilShapeRenderer + SimpleShapeFactory + the Simple* render objects. A from-scratch GL pipeline: MSAA edges, analytic erf feather, exact spline primitives, in-shader gradients.

render/ · gl_shape_renderer · gl_stencil_renderer · shape_geometry

Import a .riv with SimpleShapeFactory → the artboard builds our render objects → artboard->draw(ours) runs our GL pipeline. The same scene also imports with the official factory for the live A/B compare.

02The interface seam — what "ours" implements

We reimplement rendering ground-up. We do not reimplement parsing, the Core model, or animation — those stay official and call into our objects.

rive interface (the API)our implementationrole
rive::FactorySimpleShapeFactorybuilds the render objects the runtime needs
rive::RendererGlStencilShapeRenderersave/clip/drawPath/drawImage — the GL pipeline
rive::RenderPathSimpleRenderPathgeometry: contours, fill rule, exact curves
rive::RenderPaintSimpleRenderPaintfill/stroke, gradients, feather, blend
rive::RenderShaderSimpleRenderShaderlinear/radial gradient stops
rive::RenderBufferSimpleRenderBuffervertex/index data for meshes
rive::RenderImageSimpleRenderImagedecoded bitmaps → GL textures

03Module map

Code is organised by domain folder; CMake assigns each file to a target. The PlayerApp-free leaves are static libraries; the app layer compiles into the rive_gl_player executable.

base lib (riv_backend) module lib (riv_*) app layer (exe)

backend/

riv_backend

Rive integration base: wraps RenderContextGLImpl + RiveRenderer (official), runtime probe, param matcher.

native_backend · gl_backend

render/

riv_render

The ours GL stencil-then-cover renderer + Simple* render objects + geometry.

gl_shape_renderer · gl_stencil_renderer · shape_geometry · simple_shape_factory

io/

riv_io

Binary .riv reader/writer + registry fallback; image loading.

riv_binary_reader · riv_binary_writer · image_target

curve/

riv_curve

Spline evaluation (Bezier/B-spline/Yuksel), contour vectorizer, nested box-tree queries.

curve_eval · contour_trace · box_tree

splat/

riv_splat

Gaussian-splat lab: field math, greedy fitter, gradients, GPU optimizers. (ParamMatcher stays in riv_backend — it is part of that lib's public API.)

splat_field · splat_fitter · gl_splat_* · training_metrics

npr/

riv_npr

Non-photorealistic post-process effect registry + GL executor + aux buffers.

npr_effects · npr_pipeline · ours_aux_producer

spacetime/

riv_spacetime

Space-time volume raymarcher (a stack of recent frames; z = time).

spacetime_volume · spacetime_params

beam/

riv_beam

Vector beam — an XY oscilloscope trace of the scene's contours.

vector_beam

scene/

exe

Loaded-scene introspection: hierarchy, inspector, per-object bounds.

scene_loader · scene_inspector · scene_hierarchy · scene_bounds

editor/

exe

From-scratch shape + curve editor, gradient handles, undo, .rivx export.

shape_editor

ui/

exe

Dear ImGui chrome: panels, headers, node graph, auto-layout, theme.

ui_* · panel_routing · viewport_panel · node_graph

core/

exe

App lifecycle + the PlayerApp state, frame loop, input, feature routing.

gl_player · player_app · player_frame · input_* · feature_*

dedup

exe

The P3 audit found the backend already DRY — the GL shader-compile helper is shared in render/gl_util, .riv (de)serialization in riv_io. The one genuine cross-file duplication (dashed-line draw) was hoisted into ui/ui_common; no separate riv_util lib was warranted.

ui_common · gl_util

04Library graph

Targets link upward. The base lib is shared by every module lib; the executable and the GL-free test suites link the libs instead of recompiling sources.

riv_backend←
riv_ioriv_curveriv_renderriv_splatriv_nprriv_spacetimeriv_beam
rive_gl_player→
riv_backendall riv_* libsimguiglfw3
rive_*_tests (5)→
riv_curveriv_splatriv_nprriv_renderriv_backend

05The ours-only container — .rivx

Our editor and effect stacks can express things official .riv cannot (exact splines, anisotropic splats, a serialized effect/beam/space-time pipeline). Those persist in our experimental .rivx format, read and written only by the ours path.

06By the numbers

121
source files
~40k
lines of code
7
module libraries
7
rive interfaces reimplemented
5
GL-free test suites