Documentation Index
Fetch the complete documentation index at: https://mintlify.com/BintzGavin/helios/llms.txt
Use this file to discover all available pages before exploring further.
P5.js is a creative coding library that makes drawing and animation accessible. Helios enables precise control over P5.js sketches for video export.
Basic setup
P5.js has a built-in draw loop that must be disabled. Use noLoop() and drive rendering from Helios.
import { Helios } from '@helios-project/core';
import p5 from 'p5';
const helios = new Helios({ fps: 30, duration: 10 });
const sketch = (p: p5) => {
p.setup = () => {
p.createCanvas(window.innerWidth, window.innerHeight);
p.noLoop(); // CRITICAL: Stop P5's internal loop
};
p.draw = () => {
// CRITICAL: Use Helios time, not P5 time
const time = helios.currentTime.value;
const progress = (time % 10) / 10;
p.background(20);
p.fill(255, 0, 0);
p.noStroke();
// Example animation logic
const x = p.width * progress;
const y = p.height / 2;
p.ellipse(x, y, 100);
};
p.windowResized = () => {
p.resizeCanvas(window.innerWidth, window.innerHeight);
};
};
const container = document.getElementById('p5-container');
if (container) {
const mySketch = new p5(sketch, container);
// Bind to document timeline for Renderer
helios.bindToDocumentTimeline();
// Drive P5 from Helios
helios.subscribe(() => {
// p.redraw() executes draw() once
mySketch.redraw();
});
// Expose for debugging
(window as any).helios = helios;
}
Critical patterns
Disable P5.js draw loop
P5.js automatically calls draw() at 60fps. You must disable this:
p.setup = () => {
p.createCanvas(800, 600);
p.noLoop(); // Stop automatic drawing
};
Then trigger draws manually from Helios:
helios.subscribe(() => {
mySketch.redraw(); // Call draw() once per Helios frame
});
Use Helios time, not P5 time
P5.js provides frameCount and millis() for animation. Don’t use them with Helios:
p.draw = () => {
// DON'T USE P5 TIME
// const time = p.millis() / 1000;
// const frame = p.frameCount;
// USE HELIOS TIME INSTEAD
const time = helios.currentTime.value;
const frame = helios.getState().currentFrame;
// Now animations are deterministic
const x = p.width * (time / 10);
p.ellipse(x, p.height / 2, 50);
};
Access Helios in draw function
Create the Helios instance in the outer scope to access it inside P5.js functions:
const helios = new Helios({ fps: 30, duration: 10 });
const sketch = (p: p5) => {
p.draw = () => {
const time = helios.currentTime.value; // Accessible here
// ... draw logic
};
};
Handle window resize
Update canvas size on window resize:
p.windowResized = () => {
p.resizeCanvas(window.innerWidth, window.innerHeight);
};
Complete example with animation
import { Helios } from '@helios-project/core';
import p5 from 'p5';
const helios = new Helios({ fps: 30, duration: 8 });
const sketch = (p: p5) => {
let particles: { x: number; y: number; speed: number }[] = [];
p.setup = () => {
p.createCanvas(window.innerWidth, window.innerHeight);
p.noLoop();
// Initialize particles
for (let i = 0; i < 50; i++) {
particles.push({
x: p.random(p.width),
y: p.random(p.height),
speed: p.random(0.5, 2)
});
}
};
p.draw = () => {
const time = helios.currentTime.value;
p.background(20, 20, 30);
p.noStroke();
// Draw animated particles
particles.forEach((particle, i) => {
const hue = (i * 10 + time * 50) % 360;
p.colorMode(p.HSB);
p.fill(hue, 70, 90);
const x = (particle.x + time * particle.speed * 50) % p.width;
const y = particle.y + p.sin(time + i) * 50;
const size = 20 + p.sin(time * 2 + i) * 10;
p.ellipse(x, y, size);
});
};
p.windowResized = () => {
p.resizeCanvas(window.innerWidth, window.innerHeight);
};
};
const container = document.getElementById('p5-container');
if (container) {
const mySketch = new p5(sketch, container);
helios.bindToDocumentTimeline();
helios.subscribe(() => {
mySketch.redraw();
});
(window as any).helios = helios;
}
Canvas size and resolution
P5.js renders at the canvas resolution. Larger canvases are slower:
// 1080p - good performance
p.createCanvas(1920, 1080);
// 4K - slower, more memory
p.createCanvas(3840, 2160);
// Match window size for previews
p.createCanvas(window.innerWidth, window.innerHeight);
Drawing complexity
P5.js is CPU-based. Avoid excessive draw calls per frame:
// Good: reasonable particle count
for (let i = 0; i < 100; i++) {
p.ellipse(x, y, 10);
}
// Bad: too many draw calls
for (let i = 0; i < 10000; i++) {
p.ellipse(x, y, 10); // Will be slow
}
Background clearing
Calling background() clears the canvas. For trails, use transparency:
// Full clear each frame
p.background(0);
// Fade effect (creates trails)
p.background(0, 0, 0, 25);
Image and font loading
Preload assets in preload() to avoid loading delays:
let img: p5.Image;
let font: p5.Font;
p.preload = () => {
img = p.loadImage('image.png');
font = p.loadFont('font.ttf');
};
p.setup = () => {
p.createCanvas(800, 600);
p.noLoop();
};
p.draw = () => {
p.image(img, 0, 0);
p.textFont(font);
p.text('Hello', 100, 100);
};
Shape optimization
Use built-in shapes instead of beginShape() when possible:
// Fast: built-in primitives
p.ellipse(x, y, 50);
p.rect(x, y, 100, 100);
// Slower: custom shapes
p.beginShape();
p.vertex(x1, y1);
p.vertex(x2, y2);
p.vertex(x3, y3);
p.endShape();
Frame rate considerations
P5.js is slower than WebGL-based libraries. Use lower FPS for complex sketches:
// Good for complex sketches
const helios = new Helios({ fps: 24, duration: 10 });
// May struggle with many particles
const helios = new Helios({ fps: 60, duration: 10 });
Package dependencies
{
"dependencies": {
"p5": "^1.9.0",
"@helios-project/core": "latest"
},
"devDependencies": {
"@types/p5": "^1.7.6",
"@types/node": "^20.0.0",
"typescript": "^5.0.0",
"vite": "^5.0.0"
}
}
Common issues
Sketch runs too fast
You forgot noLoop() in setup:
p.setup = () => {
p.createCanvas(800, 600);
p.noLoop(); // Required!
};
Animation not deterministic
You’re using P5.js time instead of Helios time:
// Wrong
const time = p.millis() / 1000;
// Correct
const time = helios.currentTime.value;
Random values change on replay
P5.js random() is non-deterministic. Seed it or use a deterministic pattern:
// Non-deterministic (changes each run)
const x = p.random(0, p.width);
// Deterministic (same each run)
p.randomSeed(42);
const x = p.random(0, p.width);
// Or use time-based generation
const x = p.noise(time, seed) * p.width;
Container not found
Ensure the container element exists before creating the sketch:
const container = document.getElementById('p5-container');
if (container) {
const mySketch = new p5(sketch, container);
} else {
console.error('Container not found');
}
Canvas appears blurry
P5.js doesn’t automatically handle device pixel ratio. Set it manually:
p.setup = () => {
const canvas = p.createCanvas(window.innerWidth, window.innerHeight);
canvas.elt.style.width = window.innerWidth + 'px';
canvas.elt.style.height = window.innerHeight + 'px';
p.pixelDensity(window.devicePixelRatio || 1);
p.noLoop();
};