Appearance
@carrot/engine ​
ts
Umbrella orchestrator for the Carrot WebGL2 engine - owns the game loop, timing, input, renderer, and shader registry.
Installation ​
bash
npm install @carrot/engineArchitecture / How It Works ​
Engine is deliberately thin. It creates and wires up the core subsystems, then runs a requestAnimationFrame loop that dispatches signals at each phase:
- Timing -
EngineTime.update()computes delta, smoothed delta, FPS, and advances the fixed-timestep accumulator. - Input -
Input.update(delta)polls keyboard/mouse/touch state. - Update - The game's update callback runs with the current delta.
- Render - Post-render signal fires (the game submits draw calls during its update).
Signals (onLoopStart, onPreInput, onPostInput, onPreUpdate, onPostUpdate, onPostRender, onResize) let systems hook into the loop without subclassing.
DisplayInfo handles DPI-aware coordinate conversion - logical (CSS pixels) vs physical (device pixels), plus real-world unit conversion (cm, inches).
DPR-Transparent Coordinate System ​
The engine provides a DPR-transparent coordinate system. engine.width and engine.height always return logical CSS pixels - game code never needs to think about device pixel ratio. Under the hood, resizeCanvas() scales the canvas backing store by devicePixelRatio for sharp rendering on HiDPI displays, and rebuilds a DisplayInfo on each resize. The initial resize happens during construction so width, height, and display are valid immediately after new Engine(canvas).
EngineTime._last and _now initialise to performance.now() (not 0), which prevents a spurious large delta on the first frame.
Dependencies ​
| Package | Used For |
|---|---|
@carrot/signals | Event signals for game loop phases |
@carrot/logging | Optional structured logging |
@carrot/input | Keyboard, mouse, touch input |
@carrot/engine-renderer | WebGL2 renderer |
@carrot/engine-renderer-shaders | Shader program registry |
@carrot/maths-geometry | Size2, Vector2 used by DisplayInfo |
Build ​
bash
npm run build # runs tscUsing @carrot/engine ​
Umbrella orchestrator for the Carrot WebGL2 engine - initialise, start the loop, hook into signals.
Import ​
ts
import { Engine, EngineTime, DisplayInfo } from '@carrot/engine';Common Patterns ​
1. Basic game loop ​
ts
const canvas = document.getElementById('game') as HTMLCanvasElement;
const engine = new Engine(canvas);
engine.start((delta) => {
// game logic
// submit draw calls via engine.renderer
});2. Hooking into loop phases ​
ts
engine.onPreUpdate.add(() => {
// runs before the game update callback every frame
});
engine.onPostRender.add(() => {
// runs after all rendering - good for debug overlays
});
engine.onResize.add(() => {
// canvas resized - update cameras, UI layout, etc.
});3. Fixed-timestep physics ​
ts
engine.start((delta) => {
while (engine.time.shouldStepPhysics) {
physicsWorld.step(1 / 60);
engine.time.stepPhysics();
}
renderScene();
});4. Reading frame stats ​
ts
engine.onPostRender.add(() => {
hud.setText(`FPS: ${engine.time.fps}`);
hud.setText(`Delta: ${engine.time.smoothedDelta.toFixed(4)}s`);
hud.setText(`Total: ${engine.time.totalTime.toFixed(1)}s`);
});5. Using logical canvas dimensions ​
ts
// engine.width and engine.height are always in logical CSS pixels -
// you never need to care about DPR when positioning game objects.
const halfW = engine.width / 2;
const halfH = engine.height / 2;
// The full DisplayInfo is available if you need physical pixels or DPI:
const physicalPos = engine.display.toPhysical(mousePosition);
const borderPx = engine.display.cmToPixels(0.5);6. Stopping the engine ​
ts
engine.stop();
// The loop stops after the current frame completesPackage Contents ​
@carrot/engine-buffers ​
Import: import { FloatBuffer, IndexBuffer } from '@carrot/engine-buffers';
Classes ​
| Class | Description |
|---|---|
FloatBuffer | CPU-side Float32Array wrapper for vertex attribute data |
IndexBuffer | CPU-side index buffer - auto-selects Uint16Array or Uint32Array |
FloatBuffer ​
Constructor: new FloatBuffer(sizeOrData: number | number[] | Float32Array)
| Member | Type | Description |
|---|---|---|
data | Float32Array | Raw typed array |
length | number | Element count |
byteLength | number | Size in bytes |
Methods: get(index) · set(index, value) · set(values) · setAt(offset, values) · fill(value, start?, end?) · slice(start?, end?) · clone() · toArray() · copyFrom(source, srcOffset?, destOffset?, length?)
Iteration: Implements [Symbol.iterator] for for...of loops.
IndexBuffer ​
Constructor: new IndexBuffer(data: number[] | Uint16Array | Uint32Array)
| Member | Type | Description |
|---|---|---|
data | Uint16Array | Uint32Array | Raw typed array (auto-selected) |
length | number | Element count |
byteLength | number | Size in bytes |
is32Bit | boolean | Whether using Uint32Array (max index > 65535) |
Methods: get(index) · set(index, value) · slice(start?, end?) · clone() · toArray()
Iteration: Implements [Symbol.iterator] for for...of loops.
@carrot/engine-textures ​
Import: import { Texture2D, DataTexture, Texture3D, TextureCube, RenderTexture, ... } from '@carrot/engine-textures';
Classes ​
| Class | Description |
|---|---|
Texture | Abstract GPU texture base - handle, descriptor, bind/unbind/dispose lifecycle |
Texture2D | 2D texture loaded from an AssetImage |
DataTexture | 2D texture from raw typed array data (noise, LUTs, SDF atlases) |
Texture3D | 3D volumetric texture (voxel grids, 3D LUTs) |
TextureCube | Cubemap texture - 6 faces (skyboxes, environment reflections) |
RenderTexture | Framebuffer-backed render target with optional depth |
TextureBuilder2D | Fluent builder for procedural 2D data textures |
TextureBuilder3D | Fluent builder for procedural 3D data textures |
Enums / Constants ​
| Name | Values |
|---|---|
TextureTarget | Texture2D · Texture3D · TextureCube |
TextureFormat | RGBA8 · RGB8 · RG8 · R8 · RGBA16F · RGB16F · RG16F · R16F · RGBA32F · RGB32F · RG32F · R32F · Depth16 · Depth24 · Depth32F · Depth24Stencil8 |
TextureFilter | Nearest · Linear · NearestMipmapNearest · LinearMipmapNearest · NearestMipmapLinear · LinearMipmapLinear |
TextureWrap | Clamp · Repeat · Mirror |
CubeFace | PositiveX · NegativeX · PositiveY · NegativeY · PositiveZ · NegativeZ |
Types ​
| Type | Description |
|---|---|
TextureDescriptor | Immutable config - format, filtering, wrapping, mipmaps |
TextureDataSource | Float32Array | Uint8Array | Uint16Array | null |
Texture3DDataSource | Float32Array | Uint8Array | null |
TexelFn2D | (x: number, y: number) => number - per-texel callback |
TexelFn3D | (x: number, y: number, z: number) => number - per-texel callback |
Descriptor Presets ​
defaultTextureDescriptor · defaultRenderTextureDescriptor · pixelArtTextureDescriptor
Factory Functions ​
| Function | Returns | Description |
|---|---|---|
noiseTexture2D(gl, w, h, noise, scale?, offsetX?, offsetY?, desc?) | DataTexture | Generate a 2D R32F noise texture |
noiseTexture3D(gl, w, h, d, noise, scale?, desc?) | Texture3D | Generate a 3D R32F noise texture |
Texture (abstract base) ​
| Member | Type |
|---|---|
gl | WebGL2RenderingContext |
descriptor | TextureDescriptor |
target | TextureTarget |
handle | WebGLTexture | null |
isUploaded | boolean |
width · height · depth | number |
Methods: bind(unit?) · unbind(unit?) · dispose() · upload() (abstract)
RenderTexture (additional) ​
| Member | Type |
|---|---|
framebuffer | WebGLFramebuffer | null |
Methods: resize(width, height) · bindAsTarget() · unbindTarget() · dispose()
TextureBuilder2D ​
Factory: TextureBuilder2D.create(gl, width, height)
Methods (fluent): set(fn) · add(fn, weight?) · multiply(fn) · curve(fn) · remap(inMin, inMax, outMin, outMax) · clamp(min?, max?) · normalise() · descriptor(desc) · build()
TextureBuilder3D ​
Factory: TextureBuilder3D.create(gl, width, height, depth)
Methods (fluent): set(fn) · add(fn, weight?) · multiply(fn) · curve(fn) · remap(inMin, inMax, outMin, outMax) · clamp(min?, max?) · normalise() · descriptor(desc) · build()
@carrot/engine-shaders ​
Import: import { ShaderSource, ShaderFile, ShaderUniform, ShaderUniformType } from '@carrot/engine-shaders';
Classes ​
| Class | Description |
|---|---|
ShaderSource | Complete shader description - id, GLSL version, precision, vertex/fragment source, includes, uniforms |
ShaderFile | Parses a .shader XML file into a ShaderSource |
ShaderUniform | Metadata for a single shader uniform - name, GLSL type, optional default |
Enums / Constants ​
| Name | Values |
|---|---|
ShaderUniformType | Float · Int · Bool · Vec2 · Vec3 · Vec4 · Mat3 · Mat4 · Sampler2D · SamplerCube |
ShaderSource ​
Constructor: new ShaderSource(id, version, precision, vertexRaw, fragmentRaw, includes?, uniforms?)
| Member | Type |
|---|---|
id | string |
version | string |
precision | string |
vertexRaw | string |
fragmentRaw | string |
includes | readonly string[] |
uniforms | readonly ShaderUniform[] |
uniformNames | ReadonlySet<string> |
Methods: renderVertex() · renderFragment() · getUniform(name) · toString()
ShaderFile ​
Constructor: new ShaderFile(rawXml: string)
| Member | Type |
|---|---|
source | ShaderSource |
id / key | string |
version | string |
precision | string |
vertexRaw · fragmentRaw | string |
includes | readonly string[] |
uniforms | readonly ShaderUniform[] |
Methods: renderVertex() · renderFragment()
ShaderUniform ​
Constructor: new ShaderUniform(name, type, defaultValue?)
| Member | Type |
|---|---|
name | string |
type | ShaderUniformType |
defaultValue | string | undefined |
Methods: fromXml(xml) (static) · toString()
@carrot/engine-materials ​
Import: import { Material, MaterialInstance, MaterialSchema, ... } from '@carrot/engine-materials';
Classes ​
| Class | Description |
|---|---|
Material | Abstract typed property bag - references a shader by key, defines properties via schema |
MaterialInstance | Per-object runtime copy with property overrides and dirty tracking |
MaterialSchema | Ordered collection of property definitions for a material |
MaterialPropertyDef<T> | Typed property definition - key, label, type, default, constraints |
Material2DSprite | Standard 2D sprite material (unlit, textured + tint) |
Material2DUnlitColor | Flat colour material (unlit, no texture) |
Material2DUnlitTextured | General-purpose unlit textured material (texture + colour) |
Enums / Constants ​
| Name | Values |
|---|---|
MaterialPropertyType | Color · Texture · Number · Boolean · Vector2 · Vector3 · Vector4 · Enum |
MaterialType | Unlit · Simple · Pbr |
Factory Functions ​
| Function | Description |
|---|---|
defineProperty<T>(key, label, propertyType, config?) | Create a MaterialPropertyDef<T> |
Material (abstract base) ​
| Member | Type |
|---|---|
name | string |
shaderKey | string |
schema | MaterialSchema |
type | MaterialType (abstract) |
transparent | boolean (get/set) |
Methods: getProperty(def) · setProperty(def, value) · getPropertyByKey(key) · setPropertyByKey(key, value) · getPropertyEntries()
MaterialInstance ​
| Member | Type |
|---|---|
material | TMaterial |
name | string (get/set) |
type | MaterialType |
schema | MaterialSchema |
shaderKey | string (get/set, overrideable) |
transparent | boolean |
isDirty | boolean |
Methods: getProperty(def) · setProperty(def, value) · clearProperty(def) · hasOverride(def) · getPropertyByKey(key) · setPropertyByKey(key, value) · resetOverrides() · markDirty() · clearDirty()
MaterialSchema ​
Methods: define(def) · get(key) · has(key) · getAll() · size
Iteration: Implements [Symbol.iterator].
MaterialPropertyDef<T> ​
| Member | Type |
|---|---|
key | string |
label | string |
propertyType | MaterialPropertyType |
defaultValue | T | undefined |
options | readonly T[] | undefined |
min · max · step | number | undefined |
Built-in Materials ​
| Material | Shader Key | Properties |
|---|---|---|
Material2DSprite | core.sprite.default | mainTexture (Texture) · tintColor (Color) |
Material2DUnlitColor | core.unlit.color | color (Color) |
Material2DUnlitTextured | core.unlit.textured | mainTexture (Texture) · color (Color) |
@carrot/engine-meshes ​
Import: import { Mesh, VertexView, meshFromQuad, meshFromCircle, ... } from '@carrot/engine-meshes';
Classes ​
| Class | Description |
|---|---|
Mesh | CPU-side mesh - named bag of vertex attribute buffers and triangle indices |
VertexView | Zero-allocation view into a single vertex's attributes (used by forEachVertex) |
Types ​
| Type | Description |
|---|---|
MeshData | Construction data - all attribute buffers optional |
Primitive Generators ​
| Function | Description |
|---|---|
meshFromQuad(width, height?, name?) | 2D quad in XY plane, centered at origin |
meshFromTriangle(a, b, c, name?) | 2D triangle in XY plane from 3 points |
meshFromCircle(radius, segments?, name?) | Circle/disc in XY plane, triangle fan |
meshFromPlane(width, depth, subdivisionsX?, subdivisionsZ?, name?) | Subdivided plane in XZ plane (Y up) |
meshFromCube(size?, name?) | Unit cube, 24 verts (hard edges), 12 tris |
Path-to-Mesh Generators ​
| Function | Description |
|---|---|
meshFromStrip(points, width, name?) | Quad strip ribbon from a polyline |
meshFromLoop(points, width, name?) | Closed quad strip from a polyline loop |
meshFromBezier(bezier, width, samples?, name?) | Quad strip along a single bezier curve |
meshFromBezierStrip(strip, width, samples?, name?) | Quad strip along a bezier strip path |
meshFromBezierLoop(loop, width, samples?, name?) | Closed quad strip along a bezier loop |
Mesh ​
Constructor: new Mesh(name: string, data?: MeshData)
| Member | Type | Description |
|---|---|---|
name | string | Mesh name |
uniqueId | number | Auto-incrementing ID |
positions | FloatBuffer? | Vertex positions (vec3) |
normals | FloatBuffer? | Vertex normals (vec3) |
tangents | FloatBuffer? | Vertex tangents (vec4) |
uv1 ... uv6 | FloatBuffer? | UV channels (vec2) |
colors | FloatBuffer? | Vertex colors (vec4) |
indices | IndexBuffer? | Triangle indices |
isDirty | boolean | Dirty flag for renderer |
vertexCount | number | Derived from positions buffer |
triangleCount | number | Derived from index buffer |
Methods: setColorsAll(color) · computeNormals() · forEachVertex(fn) · clone(name?) · markDirty() · clearDirty() · toString()
VertexView ​
Per-vertex accessor - reads/writes directly into underlying FloatBuffers.
Position: px · py · pzNormal: nx · ny · nzUV1-UV6: u1/v1 · u2/v2 · u3/v3 · u4/v4 · u5/v5 · u6/v6Color: cr · cg · cb · ca
MeshData ​
| Field | Type |
|---|---|
positions · normals · tangents | FloatBuffer? |
uv1 ... uv6 | FloatBuffer? |
colors | FloatBuffer? |
indices | IndexBuffer? |