2D and 3D plot


The @use-gpu/plot package provides the ability to make graphs. <Plot> comes with a set of matching components that go inside, such as views, axes, grids, points, lines, etc.

You can make both 2D and 3D plots, depending on the surrounding camera component (e.g. <Flat> or <OrbitCamera>). Plots must be placed inside a drawing pass, so the generated geometry can be rendered.

A basic chart frame looks like:

return (
    <Cartesian range={[[min, max], [min, max]]}>
      <Axis axis="x" {...} />
      <Axis axis="y" {...} />
      <Grid axes="xy" />
      <Scale axis="x" {...}>
        <Label {...} />

Plot components are designed for maximum convenience. This allows you to build diagrams through simple nesting.

The Plot geometry mainly consists of wrappers around the basic geometry layers. e.g. A Point wraps PointLayer, but hooks it up automatically to a local DataContext.

Plot views provide a RangeContext, used by axes, grids and scales to place themselves automatically in the view.







The default 3D coordinate system matches WebGPU. X goes left to right, Y goes bottom to top, Z goes in-to-out. The axis order may be changed using the axes prop on a view.

The projection is normalized to -1..1 on the Y axis, and -aspect..aspect on the X axis, where aspect = width / height.

3D viewports are relative to world-space and always show the same view regardless of resolution.


<Flat> will instead set up "normal" 2D pixel-sized viewport, with the origin in the top-left and Y going down. This is ideal for classic 2D layout and works well with @use-gpu/layout.

  • To keep the origin in the center, use <PanControls centered>.
  • For a normalized flat viewport (-1...1), use <Flat relative>.


Point sizes and line widths are in (logical) pixels by default. Regardless of canvas size, perspective or device DPI, the apparent size remains the same.

You can control this in several ways:


  • depth: number - Value 0...1 - How strongly to apply perspective scaling. i.e. 0 = 2D, 0.5 = 2.5D, 1 = 3D. Default 0.

View / Perspective

  • focus?: number - Distance from camera at which the scaling factor is 1 if depth = 1. Default 1
  • scale?: number | null - Fixed reference size. If viewport is larger/smaller than this, scale everything up/down to compensate. Default null.

Note that changing the fov of the camera will not affect the on-screen size of lines.

When scale is not null, everything will be scaled proportionally, as height / scale.

If scale is 1080 and the canvas is 1440 pixels tall, the scale factor will be 1440/1080.

Views and ranges

To anchor a plot, you place a view such as Cartesian. You give it a range to define a mapping from its domain to world space.

It can be placed, rotated and sized like any 3D object:

  range={[[-1, 1], [-1, 1], [-1, 1]]}
  position={[0, 0, 0]}
  rotation={[0, 0, 0]}
  scale={[1, 1, 1]}
  // ...

Place an <Axis> or <Grid> inside to align and size it automatically.

Nest views inside other views to combine their transforms.

Non-linear transforms like Polar have a bend prop 0..1. This interpolates smoothly between e.g. cartesian (0) and polar (1). This uses custom designed shaders that preserve conformality, scale and aspect ratio as appropriate, to provide a natural and intuitive transition.

Data and geometry

Use <Sampled> to automatically sample data for the entire view range, on one or more axes.

This can then be used as position data for e.g. <Point>, <Line> or <Surface>, provided through the local DataContext.

For more advanced uses, you can embed the underlying geometry layers directly into the plot. They will respect the coordinate transform of the surrounding view.