Sprites.Scene

A small three dimensional engine, built on the same reactive model as Sprites.Image. A point starts in the local space of the transform around it; Translate and the three Rotate commands nest to build that transform. A command maps its points to world space, the camera projects them to the drawing plane, and the shape draws through the Sprites.Image commands, so a scene is just lines and polygons projected onto an image. Draw inside a Sprites.Ui.Scene.Vector.

Sprites.Scene

Sprites.Scene.Line Void

Sprites.Scene.Line(x1, y1, z1, x2, y2, z2)

Draw a line between two points, in the current line style. The points are in the space of the transform around the command; each coordinate may be a constant or a reactive value. The example is a hollow cube, twelve edges drawn with lines from -1 to 1 and no transforms at all.

InputTypeDescription
x1, y1, z1Number or Sprites.Reactive.ValueThe first point.
x2, y2, z2Number or Sprites.Reactive.ValueThe second point.

Returns nothing.

Sprites.Ui.Dom.Tag('div', () => {
  Sprites.Ui.Dom.Class('image-frame');
  Sprites.Ui.Dom.Style('width', '100%');
  Sprites.Ui.Dom.Style('height', '220px');
  Sprites.Ui.Scene.Vector(() => {
    Sprites.Scene.RotateAndZoom();
    Sprites.Scene.LineStyle(0.02, '#0f172a', () => {
      Sprites.Scene.Line(-1, -1, -1, 1, -1, -1);
      Sprites.Scene.Line(1, -1, -1, 1, -1, 1);
      Sprites.Scene.Line(1, -1, 1, -1, -1, 1);
      Sprites.Scene.Line(-1, -1, 1, -1, -1, -1);
      Sprites.Scene.Line(-1, 1, -1, 1, 1, -1);
      Sprites.Scene.Line(1, 1, -1, 1, 1, 1);
      Sprites.Scene.Line(1, 1, 1, -1, 1, 1);
      Sprites.Scene.Line(-1, 1, 1, -1, 1, -1);
      Sprites.Scene.Line(-1, -1, -1, -1, 1, -1);
      Sprites.Scene.Line(1, -1, -1, 1, 1, -1);
      Sprites.Scene.Line(1, -1, 1, 1, 1, 1);
      Sprites.Scene.Line(-1, -1, 1, -1, 1, 1);
    });
  });
});
A hollow cube of twelve edges. Drag to orbit the camera and use the wheel to zoom.

Sprites.Scene.Square Void

Sprites.Scene.Square(x1, y1, x2, y2)

Draw a filled square in the Z = 0 plane of the current transform, its corners at (x1, y1), (x2, y1), (x2, y2) and (x1, y2). It is filled when a FillStyle is in scope and stroked when a LineStyle is. Its local normal is +Z; when the transform turns that away from the camera the square is culled, so only faces turned toward you draw. The example is a cube: six squares, each moved and turned into place by a small tree of transforms, and each a different colour.

InputTypeDescription
x1, y1Number or Sprites.Reactive.ValueOne corner in the Z = 0 plane.
x2, y2Number or Sprites.Reactive.ValueThe opposite corner.

Returns nothing.

Sprites.Ui.Dom.Tag('div', () => {
  Sprites.Ui.Dom.Class('image-frame');
  Sprites.Ui.Dom.Style('width', '100%');
  Sprites.Ui.Dom.Style('height', '220px');
  Sprites.Ui.Scene.Vector(() => {
    Sprites.Scene.RotateAndZoom();
    Sprites.Scene.LineStyle(0.02, '#0f172a', () => {
      Sprites.Scene.FillStyle('#ef4444', () => {
        Sprites.Scene.Translate(0, 0, 1, () => {
          Sprites.Scene.Square(-1, -1, 1, 1);
        });
      });
      Sprites.Scene.FillStyle('#f97316', () => {
        Sprites.Scene.Translate(0, 0, -1, () => {
          Sprites.Scene.RotateY(Math.PI, () => {
            Sprites.Scene.Square(-1, -1, 1, 1);
          });
        });
      });
      Sprites.Scene.FillStyle('#22c55e', () => {
        Sprites.Scene.Translate(1, 0, 0, () => {
          Sprites.Scene.RotateY(Math.PI / 2, () => {
            Sprites.Scene.Square(-1, -1, 1, 1);
          });
        });
      });
      Sprites.Scene.FillStyle('#3b82f6', () => {
        Sprites.Scene.Translate(-1, 0, 0, () => {
          Sprites.Scene.RotateY(-Math.PI / 2, () => {
            Sprites.Scene.Square(-1, -1, 1, 1);
          });
        });
      });
      Sprites.Scene.FillStyle('#eab308', () => {
        Sprites.Scene.Translate(0, 1, 0, () => {
          Sprites.Scene.RotateX(-Math.PI / 2, () => {
            Sprites.Scene.Square(-1, -1, 1, 1);
          });
        });
      });
      Sprites.Scene.FillStyle('#a855f7', () => {
        Sprites.Scene.Translate(0, -1, 0, () => {
          Sprites.Scene.RotateX(Math.PI / 2, () => {
            Sprites.Scene.Square(-1, -1, 1, 1);
          });
        });
      });
    });
  });
});
A cube of six coloured square faces, each placed by a translate and a rotate. Only the three faces turned toward you draw; the back three are culled. Drag to orbit.

Sprites.Scene.LineStyle Void

Sprites.Scene.LineStyle(thickness, colour, build)

Set the line style for the build subtree. A scene draws through the image commands, so this is Sprites.Image.LineStyle: everything drawn inside strokes with this thickness and colour until a nearer LineStyle overrides it. The example draws the three axes as lines, each in its own style.

InputTypeDescription
thicknessNumber or Sprites.Reactive.ValueThe stroke width, in drawing units.
colourString or Sprites.Reactive.ValueThe stroke colour.
buildFunctionThe scene subtree that draws in this style.

Returns nothing.

Sprites.Ui.Dom.Tag('div', () => {
  Sprites.Ui.Dom.Class('image-frame');
  Sprites.Ui.Dom.Style('width', '100%');
  Sprites.Ui.Dom.Style('height', '220px');
  Sprites.Ui.Scene.Vector(() => {
    Sprites.Scene.RotateAndZoom();
    Sprites.Scene.LineStyle(0.05, '#dc2626', () => {
      Sprites.Scene.Line(-1.4, 0, 0, 1.4, 0, 0);
    });
    Sprites.Scene.LineStyle(0.025, '#2563eb', () => {
      Sprites.Scene.Line(0, -1.4, 0, 0, 1.4, 0);
    });
    Sprites.Scene.LineStyle(0.01, '#16a34a', () => {
      Sprites.Scene.Line(0, 0, -1.4, 0, 0, 1.4);
    });
  });
});
The three axes, each a line in its own thickness and colour: a thick red X, a medium blue Y, a thin green Z. Drag to orbit.

Sprites.Scene.FillStyle Void

Sprites.Scene.FillStyle(colour, build)

Set the fill colour for the build subtree. A scene draws through the image commands, so this is Sprites.Image.FillStyle: a Square drawn inside fills with this colour until a nearer FillStyle overrides it. The example draws two squares, one in each fill.

InputTypeDescription
colourString or Sprites.Reactive.ValueThe fill colour.
buildFunctionThe scene subtree that fills in this colour.

Returns nothing.

Sprites.Ui.Dom.Tag('div', () => {
  Sprites.Ui.Dom.Class('image-frame');
  Sprites.Ui.Dom.Style('width', '100%');
  Sprites.Ui.Dom.Style('height', '220px');
  Sprites.Ui.Scene.Vector(() => {
    Sprites.Scene.RotateAndZoom();
    Sprites.Scene.LineStyle(0.02, '#1e293b', () => {
      Sprites.Scene.FillStyle('#f472b6', () => {
        Sprites.Scene.Translate(-0.55, 0, 0.35, () => {
          Sprites.Scene.Square(-0.7, -0.7, 0.7, 0.7);
        });
      });
      Sprites.Scene.FillStyle('#38bdf8', () => {
        Sprites.Scene.Translate(0.55, 0, -0.35, () => {
          Sprites.Scene.Square(-0.7, -0.7, 0.7, 0.7);
        });
      });
    });
  });
});
Two squares set at an angle to each other, one pink and one blue, each in its own fill. Drag to orbit.

Sprites.Scene.Translate Void

Sprites.Scene.Translate(x, y, z, build)

Move the build subtree by (x, y, z) in the directions of the current transform, then draw it. Translates and Rotates nest to place a shape. The offsets may be reactive, so a slider moves the subtree live. The example is a square you slide along each axis.

InputTypeDescription
x, y, zNumber or Sprites.Reactive.ValueThe offset, in the current transform.
buildFunctionThe scene subtree that is moved.

Returns nothing.

const tx = Sprites.Reactive.Value(0);
const ty = Sprites.Reactive.Value(0.5);
const tz = Sprites.Reactive.Value(0);
Sprites.Ui.Dom.Tag('div', () => {
  Sprites.Ui.Dom.Class('image-frame');
  Sprites.Ui.Dom.Style('width', '100%');
  Sprites.Ui.Dom.Style('height', '220px');
  Sprites.Ui.Scene.Vector(() => {
    Sprites.Scene.RotateAndZoom();
    Sprites.Scene.LineStyle(0.02, '#065f46', () => {
      Sprites.Scene.FillStyle('#34d399', () => {
        Sprites.Scene.Translate(tx, ty, tz, () => {
          Sprites.Scene.Square(-0.7, -0.7, 0.7, 0.7);
        });
      });
    });
  });
});
Sprites.Ui.Layout.Row(() => {
  Sprites.Ui.Content.Text('x');
  Sprites.Ui.Input.Slider(tx, -2, 2, 0.05);
  Sprites.Ui.Content.Text('y');
  Sprites.Ui.Input.Slider(ty, -2, 2, 0.05);
  Sprites.Ui.Content.Text('z');
  Sprites.Ui.Input.Slider(tz, -2, 2, 0.05);
});
A square moved by the x, y and z sliders. Drag the view to orbit; move the sliders to slide the square through space.

Sprites.Scene.RotateX Void

Sprites.Scene.RotateX(angle, build)

Turn the build subtree by angle radians about the X axis of the current transform, then draw it. The angle may be reactive, so a slider turns the subtree live. The example is a square you tilt about X; turn it past edge-on and its back face is culled until it comes round to face you again.

InputTypeDescription
angleNumber or Sprites.Reactive.ValueThe turn about X, in radians.
buildFunctionThe scene subtree that is turned.

Returns nothing.

const angle = Sprites.Reactive.Value(0.6);
Sprites.Ui.Dom.Tag('div', () => {
  Sprites.Ui.Dom.Class('image-frame');
  Sprites.Ui.Dom.Style('width', '100%');
  Sprites.Ui.Dom.Style('height', '220px');
  Sprites.Ui.Scene.Vector(() => {
    Sprites.Scene.RotateAndZoom();
    Sprites.Scene.LineStyle(0.02, '#7c2d12', () => {
      Sprites.Scene.FillStyle('#fb923c', () => {
        Sprites.Scene.RotateX(angle, () => {
          Sprites.Scene.Square(-1, -1, 1, 1);
        });
      });
    });
  });
});
Sprites.Ui.Layout.Row(() => {
  Sprites.Ui.Content.Text('angle');
  Sprites.Ui.Input.Slider(angle, -3.14, 3.14, 0.01);
});
A square turned about the X axis by the slider. Past edge-on its back face is culled, so it disappears until it turns back toward you. Drag the view to orbit.

Sprites.Scene.RotateY Void

Sprites.Scene.RotateY(angle, build)

Turn the build subtree by angle radians about the Y axis of the current transform, then draw it. The angle may be reactive. The example is a square you swing about Y.

InputTypeDescription
angleNumber or Sprites.Reactive.ValueThe turn about Y, in radians.
buildFunctionThe scene subtree that is turned.

Returns nothing.

const angle = Sprites.Reactive.Value(0.6);
Sprites.Ui.Dom.Tag('div', () => {
  Sprites.Ui.Dom.Class('image-frame');
  Sprites.Ui.Dom.Style('width', '100%');
  Sprites.Ui.Dom.Style('height', '220px');
  Sprites.Ui.Scene.Vector(() => {
    Sprites.Scene.RotateAndZoom();
    Sprites.Scene.LineStyle(0.02, '#155e75', () => {
      Sprites.Scene.FillStyle('#22d3ee', () => {
        Sprites.Scene.RotateY(angle, () => {
          Sprites.Scene.Square(-1, -1, 1, 1);
        });
      });
    });
  });
});
Sprites.Ui.Layout.Row(() => {
  Sprites.Ui.Content.Text('angle');
  Sprites.Ui.Input.Slider(angle, -3.14, 3.14, 0.01);
});
A square swung about the Y axis by the slider. Past edge-on its back face is culled. Drag the view to orbit.

Sprites.Scene.RotateZ Void

Sprites.Scene.RotateZ(angle, build)

Turn the build subtree by angle radians about the Z axis of the current transform, then draw it. The angle may be reactive. The example is a square you spin about Z. Because Z is the square’s own normal, it spins in place and never turns away, so it is never culled.

InputTypeDescription
angleNumber or Sprites.Reactive.ValueThe turn about Z, in radians.
buildFunctionThe scene subtree that is turned.

Returns nothing.

const angle = Sprites.Reactive.Value(0.6);
Sprites.Ui.Dom.Tag('div', () => {
  Sprites.Ui.Dom.Class('image-frame');
  Sprites.Ui.Dom.Style('width', '100%');
  Sprites.Ui.Dom.Style('height', '220px');
  Sprites.Ui.Scene.Vector(() => {
    Sprites.Scene.RotateAndZoom();
    Sprites.Scene.LineStyle(0.02, '#4c1d95', () => {
      Sprites.Scene.FillStyle('#a78bfa', () => {
        Sprites.Scene.RotateZ(angle, () => {
          Sprites.Scene.Square(-1, -1, 1, 1);
        });
      });
    });
  });
});
Sprites.Ui.Layout.Row(() => {
  Sprites.Ui.Content.Text('angle');
  Sprites.Ui.Input.Slider(angle, -3.14, 3.14, 0.01);
});
A square spun about the Z axis by the slider. Z is the square’s own normal, so it spins in place and stays facing you. Drag the view to orbit.

Sprites.Scene.RotateAndZoom Void

Sprites.Scene.RotateAndZoom()

Capture the pointer over the surface: a drag orbits the camera about the origin, and the wheel moves it in and out. It reads the camera from the scene in scope and writes it, so a look-around tool is just this one command placed in the scene. The example is a single square you can orbit; being in the Z = 0 plane, it turns edge-on and culls as you go round the back.

Takes no arguments.

Returns nothing.

Sprites.Ui.Dom.Tag('div', () => {
  Sprites.Ui.Dom.Class('image-frame');
  Sprites.Ui.Dom.Style('width', '100%');
  Sprites.Ui.Dom.Style('height', '220px');
  Sprites.Ui.Scene.Vector(() => {
    Sprites.Scene.RotateAndZoom();
    Sprites.Scene.LineStyle(0.02, '#0f172a', () => {
      Sprites.Scene.FillStyle('#38bdf8', () => {
        Sprites.Scene.Square(-1, -1, 1, 1);
      });
    });
  });
});
A filled square you orbit by dragging; the wheel zooms. Go round the back and the square, facing away, is culled.