Skip to content
kevinroastPublic

About

Small, friendly 3D for the web - Phoria2 graphics boogaloo!

Topics

Resources

Stars

74 stars

Watchers

0 watching

Forks

Latest commit

 

History

132 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

phoria2

Small, friendly 3D for the web. A WebGL 2 renderer with PBR materials, shadows, instancing, points, lines, labels, picking, glTF models and particles, behind an API small enough to learn in an afternoon - aimed at business apps: charts, labelled scenes, diagrams, dashboards, floor plans and product viewers. The demo gallery.

  • Small: about 70 KB gzipped for a lit, interactive scene, and about 116 KB for everything; charts, particles, glTF, motion and editing are separate imports, and the heavier parts (shadows, HDR environments, GPU picking) load only when used.
  • Interaction built in: tooltips, hover highlights, click and drag handlers, and HTML labels that hide when they overlap or go behind something - each an option or a line of code, not a layer to build.
  • Idle when nothing changes: a view draws only when something in it changed, so a dashboard of many views only updates when needed.
  • Any number of views on a page: browsers allow about 16 WebGL contexts per page, so most libraries need one big canvas and scissoring for a dashboard of tiles. phoria2 gives the first four views their own context and draws the rest with one shared context, each still an ordinary canvas in your layout. The chart lab demo runs over 100 live chart views.
  • Tells you what to write: every option is checked, and a mistake throws an error that names the fix - pass colour and you get Material: use 'color'. Written to be easy for coding agents too.
  • Accessible: keyboard: true lets people step through bars, points and parts with the arrow keys while a screen reader says what each one is; motion follows the system's reduced-motion setting.
  • Integrates well: physics, solid modelling and path finding can be added using libraries made for them - the gallery shows phoria2 rendering with Rapier, Manifold and recast-navigation.
  • No runtime dependencies. ES modules, with TypeScript types.

New to phoria2? The getting started tutorial builds a first 3D scene and then a live dashboard of 3D charts, step by step - each step running beside its code, ready to copy as one HTML file.

Using a coding agent? Point it at llms-full.txt - the whole API in one page (llms.txt is the short index). Both ship in the package too, at node_modules/phoria2/llms-full.txt.

Claude Code: install the phoria2 plugin, and Claude reaches for phoria2 when asked for 3D charts, diagrams, explainers or dashboards - with the reference to hand and a check that loads the page in Chrome and reports what's wrong:

/plugin marketplace add kevinroast/phoria2
/plugin install phoria2@phoria2

The skill inside it (claude-plugin/skills/phoria2) follows the Agent Skills standard, so other agents that read skills can use the folder as it is.

Install

npm install phoria2

Or straight from a CDN, with no build step:

<script type="module">
  import { View, Mesh, box } from 'https://cdn.jsdelivr.net/npm/phoria2/+esm'
</script>

To use more than the core - charts, particles, glTF, motion or editing - map each import to the package's own files, so they share one copy of the core (the CDN's ready-made +esm builds each bundle their own). Pin the version so a new release can't change your page:

<script type="importmap">
{
  "imports": {
    "phoria2": "https://cdn.jsdelivr.net/npm/phoria2@1.2.0/dist/phoria2.js",
    "phoria2/charts": "https://cdn.jsdelivr.net/npm/phoria2@1.2.0/dist/charts.js",
    "phoria2/particles": "https://cdn.jsdelivr.net/npm/phoria2@1.2.0/dist/particles.js",
    "phoria2/gltf": "https://cdn.jsdelivr.net/npm/phoria2@1.2.0/dist/gltf.js",
    "phoria2/motion": "https://cdn.jsdelivr.net/npm/phoria2@1.2.0/dist/motion.js",
    "phoria2/edit": "https://cdn.jsdelivr.net/npm/phoria2@1.2.0/dist/edit.js"
  }
}
</script>
<script type="module">
  import { View } from 'phoria2'
  import { chart } from 'phoria2/charts'
</script>

A first scene

<canvas id="c" style="width: 100%; height: 100vh; display: block"></canvas>
<script type="module" src="./main.js"></script>
import { View, Mesh, box, DirectionalLight } from 'phoria2'

const view = new View({ canvas: '#c', orbit: true, background: '#1c1c20' })
const cube = view.scene.add(new Mesh({ geometry: box(2), material: { color: 'orange' } }))
view.scene.add(new DirectionalLight({ direction: [-1, -2, -1] }))
view.start((dt) => cube.rotateY(0.6 * dt))

The canvas takes its size from CSS; the view matches its drawing buffer to it and follows resizes. The camera starts fitted to the scene, and orbit: true lets the user turn, pan and zoom it. The tutorial takes it on from here: materials, shadows, labels, hover and click.

Interaction

const view = new View({ canvas: '#c', orbit: true, highlight: '#ffffff',
  tooltip: (hit) => ({ title: hit.datum.name, rows: { Sales: hit.datum.sales } }) })
view.on('click', (hit) => hit && select(hit.datum))             // hit is null for empty space
chair.onDrag = (drag) => drag.point && chair.position.copy(drag.point)

A hit carries the node, the instance and its row of data, so a chart of 10,000 bars is one mesh with one handler. Labels are HTML, styled with your CSS.

Charts

import { View } from 'phoria2'
import { chart } from 'phoria2/charts'

const view = new View({ canvas: '#c', orbit: true })
view.scene.add(chart({
  mark: 'bar',
  data: rows,                         // [{ month: 'Jan', region: 'North', sales: 41 }, ...]
  x: 'month', z: 'region', y: 'sales',
  color: 'region',
  tooltip: true,
}))

Marks: bar, point, line, area, surface and network, with axes, legends, labels, tooltips and animated updates (chart.update(newRows)). A JSON schema for specs ships as phoria2/charts/schema.json.

Models

import { loadGLTF } from 'phoria2/gltf'

const model = await loadGLTF('models/chair.glb')   // .glb or .gltf
view.scene.add(model)
view.frame(model)
model.play()                                        // its first animation

With other libraries

phoria2 draws; a library built for the job does the rest. Physics engines hand back positions and { x, y, z, w } rotations, which instances take as they are:

// each frame: Rapier moves the bricks, phoria2 draws them - one mesh, one draw call
world.step()
bodies.forEach((body, i) => bricks.setInstance(i, { position: body.translation(), quaternion: body.rotation() }))

The gallery's Integrations section has four, each with its source: a brick tower knocked down with Rapier, a tablecloth simulated by Rapier's soft bodies, a block cut and joined with Manifold, and people finding their way round an office with recast-navigation.

Accessibility (1.2)

const view = new View({ canvas: '#c', keyboard: true })

The canvas joins the page's tab order. The arrow keys step through whatever can be hovered or clicked - each bar, point, link or part - showing its highlight and tooltip, and Enter clicks it. A screen reader hears each one ("North, Sales: 26. 1 of 48") and a description of the view, which charts write for themselves. Glides, auto-rotation and chart transitions follow the system's reduced-motion setting (reducedMotion to choose).

With React

React owns the canvas; phoria2 draws on it. Make the view once, dispose of it on unmount, and change the scene in place when props change:

import { useEffect, useRef } from 'react'
import { View, Mesh, box } from 'phoria2'

export function SpinningBox({ color }) {
  const canvas = useRef(null)
  const mesh = useRef(null)

  useEffect(() => {
    const view = new View({ canvas: canvas.current, orbit: true })
    mesh.current = view.scene.add(new Mesh({ geometry: box(2) }))
    view.start((dt) => mesh.current.rotateY(0.6 * dt))
    return () => view.dispose()
  }, [])

  useEffect(() => {
    mesh.current.material.color.set(color)
  }, [color])

  return <canvas ref={canvas} style={{ width: '100%', height: 320 }} />
}

A full example, with a chart that follows its data, is in examples/react.

What's in the package

Import
phoria2 the view, scene graph, cameras, lights, materials, geometry, curves, textures, picking, labels, bloom, create() from JSON
phoria2/charts chart() - charts from a spec of mark, data and channels, and the scales they use
phoria2/particles Emitter and Body
phoria2/gltf loadGLTF() - glTF 2.0 models with their materials and animations
phoria2/motion Timeline - named steps played in order, follow() along a curve, reveal() a path as it's travelled - for explainers and guided tours
phoria2/edit TransformHandle - a move and turn handle with grid and angle snapping - and History for undo, for planners and layout editors
phoria2/schema.json, phoria2/charts/schema.json JSON Schemas for scene descriptions (create()) and chart specs

Versioning

phoria2 follows semver from 1.0: no 1.x release breaks code written against what is documented.

  • Covered: what the entry points above export, as the reference and the published types describe it - names, options and their defaults, and what they do. The formats create() reads and toJSON() writes, and chart specs, as their JSON Schemas describe them. The conventions: +Y up, metres, radians, sRGB colour in, and light intensities - a scene keeps its colours and its brightness from one 1.x release to the next.
  • Not covered: exact pixels, since drawing can get better (smoother edges, softer shadows); the wording of errors and warnings (catch PhoriaError, not its message); modules imported from phoria2/src/... directly, members left out of the types, and the shape of NullRenderer.lastFrame; the demos.
  • Minor releases add: options, methods, node types, chart marks. A new option's default keeps what happened before.
  • Nothing is removed or renamed in 1.x. What 2.0 will drop is deprecated first: a 1.x release keeps it working and warns once in the console, saying exactly what to write instead.

Browsers

Any browser with WebGL 2: current Chrome, Edge, Firefox and Safari (desktop and iOS 15+).

Examples

The getting started tutorial walks through a first scene and a chart dashboard. The demo gallery has charts and diagrams, a demo for each feature, showcase scenes and integrations with other libraries; its source, and the tutorial's, is in demos/.

Licence

MIT - see LICENSE. phoria2 is a rewrite of phoria, a 2013 library that drew 3D on the canvas 2D context.

About

Small, friendly 3D for the web - Phoria2 graphics boogaloo!

Topics

Resources

Stars

74 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages