🚧 Glyx is pre-release software. APIs may change before v1.0. Get started →
Documentation
Roadmap
3D Rendering — Phase 2

3D Rendering — Phase 2

Canvas3D and @glyx-dev/three cover the foundation. Phase 2 is about closing the gap to Three.js parity.

Status: Phase 1 stable, Phase 2 in active design. The Canvas3D scene format is experimental — the API may change before v1.0.


What's shipped (Phase 1)

FeatureStatus
Box / sphere / plane primitives
GLTF model loading — multi-mesh, multi-primitive
GLTF textures (base-color, UVs)
32-bit indices (large models, >65k vertices)
Phong shading
Ambient + directional lights
Point lights (range falloff)
Spot lights (cone + falloff)
Up to 8 dynamic lights
@glyx-dev/three — Three.js-shaped JS API
Same-frame composite with 2D Vello scene
Per-canvas dirty tracking (skip GPU pass when static)
Scene-graph hierarchy (<Group> / parenting)
Raycasting / picking (click/select 3D objects)
Per-primitive material color (GLTF baseColorFactor)
GLTF animations — keyframe + skeletal (CPU skinning)

GLTF animation playback is keyed by model path, not mesh instance — two <Model>s pointing at the same GLTF file share one animation pose per frame (the last-applied {clip, time} that frame wins). This is fine for the common case of one animated character/prop per model file; per-instance independently-animated clones of a single model is a possible future refinement, not currently planned work.


Phase 2 — what's planned

Materials — PBR

Priority: High

Replace (or augment) Phong with a physically-based metallic/roughness model. GLTF files already carry PBR material data (metallicRoughnessFactor, baseColorTexture, normalTexture, occlusionTexture, emissiveTexture) — the loader reads them but the shader currently ignores everything except baseColorTexture.

Phase 2 adds a PBR shader path alongside the existing Phong path. Meshes with PBR material data use it automatically; plain-color meshes stay on Phong.

Shadows

Priority: High

Shadow maps for directional and spot lights. Planned approach: a single depth-pass per shadow-casting light into a shadow atlas, sampled in the main fragment pass with PCF filtering. Point light shadows (cube maps) are lower priority.

Triangle-precision GLTF raycasting

Priority: Low

Raycasting against GLTF models currently tests the model's AABB (axis-aligned bounding box), not individual triangles — good enough for "click to select a model," but a click inside a model's bounding box that misses its actual geometry (e.g. an L-shaped mesh) still registers as a hit. Built-in primitives (box/sphere/plane) already get exact analytic intersection.

Instanced rendering

Priority: Medium

Draw many copies of one mesh in a single GPU draw call — essential for particles, crowds, foliage, and repeated UI elements like icon grids. API target:

ctx.updateScene({
  meshes: [
    {
      geometry: { type: 'sphere', radius: 0.1 },
      instances: [
        { transform: [...], color: [1, 0.3, 0.3, 1] },
        { transform: [...], color: [0.3, 1, 0.3, 1] },
        // ...thousands
      ],
    }
  ]
})

Environment maps / IBL

Priority: Low

Image-based lighting from an HDR cubemap or equirectangular panorama. Pairs with PBR for realistic reflections. Likely ships alongside or after PBR.

Post-processing

Priority: Low

A lightweight post-processing pass after the 3D scene but before 2D composite. Initial targets: bloom, tone mapping, FXAA. Implemented as a screen-space wgpu compute pass inserted between the 3D render and the Vello composite.


@glyx-dev/three API alignment

As each Phase 2 feature lands, @glyx-dev/three gets the matching Three.js-shaped API so migration paths from Three.js are straightforward:

// Today
new PointLight({ color: [1,1,1,1], intensity: 2, range: 10 })
 
// Shipped: GLTF animation — a prop-driven API, not a Three.js-shaped
// SkinnedMesh/AnimationMixer class pair. JS owns the clock (same
// "JS drives state, Rust is a dumb renderer" model as the rest of Glyx) and
// sends {clip, time} every frame; Rust does CPU skinning.
<Model src="rig.glb" animationClip="walk" animationTime={elapsed} />
 
// Phase 2 additions
new MeshStandardMaterial({ metalness: 0.8, roughness: 0.2 })
new InstancedMesh(geometry, material, count)

Phase 2 order may shift based on what the community is building. Open an issue or start a discussion on GitHub (opens in a new tab) if a specific feature is blocking your project.