A declarative, chainable API for rapid game development and creative coding
The Fluent API provides a builder-pattern layer on top of GCanvas's object-oriented architecture. Instead of manually instantiating classes and wiring them together, you chain method calls to declaratively build your game structure.
The fluent API uses a chain of builder classes that wrap the underlying GCanvas classes:
gcanvas() for games, sketch() for creative codingThe Fluent API provides two entry points, each designed for different use cases:
Full game development API with scenes, GameObjects, events, and state management
Minimal API for quick creative coding, generative art, and prototypes
The simplest way to get started is to create a scene with a single shape.
The gcanvas() function creates a canvas, initializes the game engine,
and returns a fluent builder you can chain methods on.
import { gcanvas } from 'gcanvas';
gcanvas({ bg: '#1a1a2e' })
.scene('game')
.go({ x: 200, y: 125 })
.circle({ radius: 40, fill: '#00ff88' })
.start();
gcanvas({ bg: '#1a1a2e' }) creates a canvas with dark background.scene('game') creates a scene named "game".go({ x: 200, y: 125 }) creates a GameObject at position (200, 125).circle({ radius: 40, fill: '#00ff88' }) adds a green circle to the GO.start() starts the game loop
Each method in the chain returns a builder object that provides relevant methods.
Use .end() to navigate back up the chain, or call sibling methods directly.
import { gcanvas } from 'gcanvas';
gcanvas({ bg: '#1a1a2e' })
.scene('game')
.go({ x: 80, y: 125 })
.circle({ radius: 30, fill: '#ff6b6b' })
.end() // Back to scene
.go({ x: 200, y: 125 })
.star({ points: 5, radius: 35, fill: '#ffd93d' })
.end()
.go({ x: 320, y: 125 })
.rect({ width: 50, height: 50, fill: '#6bcb77' })
.start();
.end() - Go back to parent context.scene(name) - Switch to or create a scene.go(options) - Create a sibling GameObjectThe FluentGO builder provides shortcut methods for all GCanvas shapes. Each method accepts an options object for customization.
import { gcanvas } from 'gcanvas';
gcanvas({ bg: '#111' })
.scene('shapes')
.go({ x: 40, y: 125 }).triangle({ size: 30, fill: '#ff6b6b' }).end()
.go({ x: 105, y: 125 }).hexagon({ radius: 18, fill: '#c44dff' }).end()
.go({ x: 170, y: 125 }).diamond({ width: 28, height: 36, fill: '#4ecdc4' }).end()
.go({ x: 235, y: 125 }).heart({ size: 26, fill: '#ff6b9d' }).end()
.go({ x: 300, y: 125 }).cross({ size: 26, thickness: 6, fill: '#ffd93d' }).end()
.go({ x: 365, y: 125 }).ring({ innerRadius: 10, outerRadius: 18, fill: '#a8e6cf' }).end()
.go({ x: 430, y: 125 }).star({ points: 6, radius: 18, fill: '#ff8c42' }).end()
.go({ x: 470, y: 125 }).cloud({ size: 22, fill: '#dfe6e9' })
.start();
.circle(), .rect(), .square(), .triangle(), .line().star(), .hexagon(), .diamond(), .heart(), .ring().arrow(), .cross(), .pin(), .cloud().text(), .image(), .svg()FluentGO provides built-in motion presets that animate GameObjects with a single method call. Each motion runs automatically in the game loop.
import { gcanvas } from 'gcanvas';
gcanvas({ bg: '#1a1a2e' })
.scene('motion')
// Pulsing circle
.go({ x: 100, y: 125 })
.circle({ radius: 30, fill: '#ff6b6b' })
.pulse({ min: 0.7, max: 1.3, duration: 1 })
.end()
// Oscillating star
.go({ x: 200, y: 125 })
.star({ points: 5, radius: 25, fill: '#ffd93d' })
.oscillate({ prop: 'y', min: -30, max: 30, duration: 2 })
.end()
// Orbiting shape
.go({ x: 300, y: 125 })
.hexagon({ radius: 20, fill: '#4ecdc4' })
.orbit({ radiusX: 40, radiusY: 40, duration: 3 })
.start();
.pulse() - Scale up and down.oscillate() - Move back and forth on an axis.orbit() - Circular/elliptical orbit.float() - Random wandering.shake() - Shake effect with decay.bounce() - Bouncing motion.spiral() - Spiral outward/inward.pendulum() - Swinging rotation
For quick creative coding experiments, sketch() provides an ultra-minimal API.
It's perfect for generative art, Genuary sketches, or rapid prototyping.
import { sketch } from 'gcanvas';
sketch(400, 250, '#1a1a2e')
.radial(200, 125, 80, 12, (api, x, y, angle, i) => {
api.circle(x, y, 15, `hsl(${i * 30}, 70%, 60%)`);
})
.update((dt, ctx) => {
ctx.shapes.forEach((shape, i) => {
shape.rotation += dt * (i % 2 === 0 ? 1 : -1);
});
})
.start();
.circle(x, y, r, fill).grid(), .repeat(), .radial().update(fn)
Register event handlers with .on() to respond to user input and game events.
Keyboard events can be filtered by key using the keydown:key syntax.
import { gcanvas } from 'gcanvas';
const game = gcanvas({ bg: '#111' });
game.scene('interactive')
.go({ x: 200, y: 100, name: 'clickTarget' })
.circle({ radius: 40, fill: '#ff6b6b' })
.on('click', (ctx) => {
// ctx.go is the clicked GameObject
ctx.go.scaleX = 1.2;
ctx.go.scaleY = 1.2;
setTimeout(() => {
ctx.go.scaleX = 1;
ctx.go.scaleY = 1;
}, 100);
})
.end()
.go({ x: 200, y: 200 })
.text('Click the circle!', { fill: '#aaa' });
game.start();
.on('update', fn) - Called every frame.on('click', fn) - Mouse click events.on('keydown:space', fn) - Filtered key events.state({}) - Shared state objectctx.refs - Access named objectsFor complete API documentation, see the Fluent Module Reference.
For a full game example using the Fluent API, check out the Space Invaders demo.
For all 30 easing functions with interactive visualizations, see the Easing Functions demo.