Understanding when to use each abstraction in GCanvas
GCanvas serves two distinct use cases with different abstractions. Understanding when to use each is key to working effectively with the library.
render() manuallyupdate(dt) lifecycle| Use Case | Use This | Why |
|---|---|---|
| Static visualization | Shape + render() |
No update loop needed |
| Generative art | Shape, Group |
Direct control, no overhead |
| Game character | Sprite (GameObject) |
Needs update cycle for animation |
| UI elements | Text, Scene |
Pipeline handles positioning |
| Complex scene | Scene with children |
Hierarchical transforms, lifecycle |
| Composite shape | Group |
Transform multiple shapes together |
You can use GCanvas purely for drawing without any game infrastructure:
import { Circle, Rectangle, Group, Painter } from "gcanvas";
// Get canvas context
const canvas = document.getElementById("canvas");
const ctx = canvas.getContext("2d");
Painter.ctx = ctx;
// Create shapes
const circle = new Circle(50, { x: 100, y: 100, color: "#0f0" });
const rect = new Rectangle({ x: 200, y: 100, width: 80, height: 60, color: "#0ff" });
// Render directly - no game loop needed
circle.render();
rect.render();
// Group multiple shapes
const group = new Group({ x: 300, y: 100, rotation: Math.PI / 4 });
group.add(new Circle(20, { color: "#f0f" }));
group.add(new Rectangle({ y: 30, width: 40, height: 20, color: "#ff0" }));
group.render();
When you need animation, input handling, and managed lifecycles:
import { Game, Scene, Sprite, Text, Circle, Keys } from "gcanvas";
class MyGame extends Game {
init() {
super.init();
// Create a scene (GameObject container)
this.scene = new Scene(this, { anchor: "center" });
// Create a sprite with animation (GameObject)
this.player = new Sprite(this, { x: 0, y: 0, frameRate: 10 });
this.player.addFrame(new Circle(20, { color: "#0f0" }));
this.player.addFrame(new Circle(25, { color: "#0ff" }));
this.player.play();
// Add to scene
this.scene.add(this.player);
// Add scene to pipeline - now it's managed
this.pipeline.add(this.scene);
// Input handling
this.events.on(Keys.SPACE, () => this.player.pause());
}
update(dt) {
super.update(dt);
// Player sprite automatically updates via pipeline
}
}
update(dt) called automatically by the pipeline each frame.
Sometimes you have a Shape (or Group of shapes) that you want to add to the pipeline. Use ShapeGOFactory:
import { Game, Group, Circle, Rectangle, ShapeGOFactory } from "gcanvas";
class MyGame extends Game {
init() {
super.init();
// Create a Group of shapes
const avatar = new Group();
avatar.add(new Circle(30, { color: "#0f0" })); // head
avatar.add(new Rectangle({ y: 50, width: 40, height: 60, color: "#0f0" })); // body
// Wrap it as a GameObject so it can join the pipeline
const avatarGO = ShapeGOFactory.create(this, avatar, {
x: 100,
y: 100,
interactive: true // enables click/hover events
});
// Now it's a proper GameObject
this.pipeline.add(avatarGO);
}
}
update() on its children. Always use Scene for GameObjects.
| Class | Type | Container | Has update()? |
|---|---|---|---|
Circle, Rectangle, etc. |
Shape | Group | No |
Group |
Shape container | Group | No |
TextShape |
Shape | Group | No |
GameObject |
Base GO | Scene / Pipeline | Yes |
Scene |
GO container | Scene / Pipeline | Yes |
Sprite |
Animated GO | Scene / Pipeline | Yes |
Text |
Text GO | Scene / Pipeline | Yes |
Shape, Group.render() yourselfGameObject, Scene, SpritepipelineGame class