Fuser

How sketches run

Supported libraries, the lifecycle, what's in scope, and what's blocked.

Sketches in Fuser follow a small contract: you define setup, draw, and optionally onEvent, and Fuser handles the rest. This page covers that contract, what's in scope inside your code, and the things that won't work even though they would in plain browser JavaScript.

Supported libraries

Pick a library from the library selector in the node's settings bar. Three are live, each suited to a different kind of sketch.

The raw 2D drawing API — no abstraction, lowest overhead.

  • In scope — the ctx 2D context, the standard CanvasRenderingContext2D API.
  • Best for — full control, porting tiny existing sketches, generative work that doesn't need helpers.
  • Drawback — you write your own helpers for things p5 gives you for free (random color, noise, easings).

The creative-coding standard.

  • In scopesetup, draw, mouseX, mouseY, noise(), all p5 globals.
  • Best for — most 2D sketches. The default if you're not sure.
  • Drawback — slightly heavier than raw canvas; abstracts the 2D context behind p5's vocabulary.

WebGL-based 3D rendering.

  • In scope — the THREE namespace, scenes, cameras, meshes, lights, materials, shaders.
  • Best for — anything with depth, lighting, or shaders.
  • Drawback — WebGL contexts are limited (see below); you can only have so many Three.js sketches alive at once.

The model selector in prompt mode generates code matching whichever library you've picked.

Lifecycle: setup, draw, onEvent

Every sketch follows the same shape. Think of it as: set up your state once, then redraw it every frame, optionally responding to events.

// Variables you want to keep across frames live at the top.
let particles = [];
let bgColor;

function setup() {
  // Runs once when the sketch starts.
  // Initialize anything you want to keep across frames here:
  // load assets, seed your particle array, choose colors.
  bgColor = 'white';
  for (let i = 0; i < 200; i++) {
    particles.push({ x: width / 2, y: height / 2, vx: 0, vy: 0 });
  }
}

function draw() {
  // Runs every frame at the canvas frame rate.
  // Re-render the current state — DON'T allocate new arrays here,
  // mutate the ones from setup. The canvas isn't auto-cleared.
  background(bgColor);
  for (const p of particles) {
    p.x += p.vx;
    p.y += p.vy;
    circle(p.x, p.y, 4);
  }
}

function onEvent(event) {
  // Optional. Mouse and resize events arrive here.
  // Use it to mutate state that draw() will pick up next frame.
  if (event.type === 'mousedown') {
    bgColor = bgColor === 'white' ? 'black' : 'white';
  }
}

setup is awaited — mark it async if you need to load anything before the first frame. draw is called repeatedly at the canvas frame rate; keep it cheap and avoid allocating per frame. onEvent is optional — define it only when you want to react to user input beyond the auto-injected mouseX / mouseY / isMousePressed globals.

State lives at module scope (the variables declared above setup). setup initializes them; draw mutates them; onEvent reacts. Don't try to share state via the DOM or storage — neither is available (see What's blocked).

What's in scope

Inside your sketch, these names are available:

NameWhat it is
width / heightThe canvas dimensions in pixels.
mouseX / mouseYThe mouse position, in pixel coordinates.
isMousePressedtrue while a mouse button is held.
paramsThe parsed @fuser-params values — see Parameters and inputs.
attachmentsConnected attachment data — bitmaps, video frames, audio buffers, meshes — keyed by socket name.
getDeltaTime()A function returning seconds since the previous frame. Useful for time-based animation.
canvasThe underlying drawing surface. You rarely need to touch it directly.
ctx / glThe 2D or WebGL context, depending on the library.
Library globalsp5 in p5 mode, THREE in Three.js mode, plus any supplemental libraries you've opted into.

mouseX, mouseY, and isMousePressed are auto-injected — you don't need to import or declare them.

What's blocked

Some browser APIs you might reach for in regular JavaScript don't work inside a sketch. Each restriction has a Fuser-native replacement — the table below pairs them up.

Don't reach for…Do this instead
document, window, requestAnimationFrame (the DOM)Use draw for animation; use width / height / mouseX / mouseY for input.
Browser storage — cookies, localStorage, sessionStoragePersist values as @fuser-params defaults (auto-saved when the user tweaks a slider), or save the canvas as an asset via the Save button.
Arbitrary fetch() callsPipe the data into an attachment socket from another Fuser node.
Dynamically-generated code — eval, new Function, dynamic import()Add the library you need to the @fuser-libs block (currently only ml5), or restructure to avoid runtime eval.
Spawning workers (new Worker, SharedWorker)Lighten the work in draw — see adaptive frame throttling — or split the work across multiple sketches.

If your sketch fails because it touched one of the blocked APIs, Fuser flags it before run with a line/column pointer in the editor — see Errors before your sketch runs.

Errors before your sketch runs

Fuser checks your code before running it. If you've used a blocked API or made certain other errors, you'll see a message in the editor with the line and column of the problem.

Fix the offending line and the sketch runs. Checks happen on every code change, so you'll see issues immediately rather than at first execution.

WebGL context limits

Three.js sketches use a WebGL context. Browsers cap how many WebGL contexts can exist at once — usually 8 to 16. When you exceed the cap, Fuser will show a warning and stop the sketch. Close one of the existing WebGL sketches and the new one picks up.

A single sketch generally won't hit this on its own; the issue surfaces when you accumulate many WebGL sketches in the same flow.

Frame throttling

Sketches don't always run at 60 fps. Fuser adapts the frame rate to keep the page responsive when many sketches are alive at once or a single sketch is slow:

  • A sketch whose draw() is fast targets 30 fps.
  • A sketch that's slower drops to 15 fps.
  • Background or off-canvas sketches drop further to 5 fps.

The FPS readout on the canvas shows the actual frame rate so you can see throttling in action. If the readout is consistently low while your draw() is meant to be cheap, look for accidental work — large allocations per frame, image filters, or layout recalculations.

Transient error tolerance

A single thrown error inside draw() doesn't kill your sketch. Fuser tolerates up to three consecutive frame errors before stopping the sketch and surfacing the error. This means an intermittent failure (a missing attachment for one frame, a flaky external library) gets a chance to recover without forcing you to re-run.

If you're hitting the three-error limit repeatedly, the Try to fix action in the editor sends the runtime error back to the model for a targeted code repair — see Editor.

Supplemental libraries

Beyond the three primary libraries, Fuser supports opt-in supplemental libraries loaded on demand. Currently the only one is ml5.js — a friendly wrapper around common machine-learning models for things like image classification, body pose detection, and hand tracking.

Opt in with a // @fuser-libs block at the top of your sketch — one // @lib <name> line per library, closed by // @end-fuser-libs:

// @fuser-libs
// @lib ml5
// @end-fuser-libs

let classifier;

async function setup() {
  classifier = await ml5.imageClassifier('MobileNet');
}

When the block is present, the listed libraries are loaded and their globals (here, ml5) become available in your sketch. Without the block, ml5 isn't included — leave it off when you don't need it.

The single-line form is silently ignored

The block must use the three-line // @fuser-libs / // @lib … / // @end-fuser-libs shape. A single-line // @fuser-libs: ml5 does not parse and the library will not load — your sketch will then crash with ReferenceError: ml5 is not defined at runtime.

The FPS readout

A small live indicator on the canvas shows the current frame rate. Yellow when you drop below 30 fps; red when you drop below 15. Use it to spot expensive draw loops — if the readout goes red, you're either doing too much per frame or running too many sketches at once.

What's Next?

On this page