GCanvas Origin System

Understanding the configurable origin-based coordinate system

Overview

GCanvas uses a top-left based coordinate system by default, matching web conventions (CSS, DOM, and standard Canvas API). The origin property allows you to configure the pivot point for positioning, rotation, and scaling.

TL;DR - Quick Reference

Origin Behavior Use Case
origin: "top-left" (default) (x, y) = top-left corner UI elements, layouts, web-style positioning
origin: "center" (x, y) = center point Game objects, rotation, scaling
originX: 0.5, originY: 1 Bottom-center Sprites standing on ground
originX: 1, originY: 0 Top-right corner Right-aligned elements

1. The Origin Property

The origin property defines the pivot point of a shape. It accepts either a string shorthand or explicit originX/originY values (0-1 normalized).

String Values:

Value originX originY Description
"top-left" 0 0 Default - position is top-left corner
"center" 0.5 0.5 Position is center point
"top-center" 0.5 0 Top edge, horizontally centered
"bottom-center" 0.5 1 Bottom edge, horizontally centered
"top-right" 1 0 Top-right corner
"bottom-left" 0 1 Bottom-left corner
"bottom-right" 1 1 Bottom-right corner
Interactive Demo: Origin Positions
// Top-left origin (default) - x,y is the top-left corner
const rect1 = new Rectangle({
  x: 100, y: 100,
  width: 80, height: 60,
  color: "#0f0"
  // origin defaults to "top-left" (originX: 0, originY: 0)
});

// Center origin - x,y is the center point
const rect2 = new Rectangle({
  x: 100, y: 100,
  width: 80, height: 60,
  color: "#0ff",
  origin: "center"  // shorthand for originX: 0.5, originY: 0.5
});

// Custom origin - bottom-center for sprites
const sprite = new Rectangle({
  x: 100, y: groundY,
  width: 32, height: 48,
  originX: 0.5,
  originY: 1  // feet at x,y position
});
Click to cycle through origins

2. How Origin Affects Transforms

The origin point is the pivot for all transformations: positioning, rotation, and scaling all happen relative to the origin.

originX: 0, originY: 0 (top-left) originX: 0.5, originY: 0.5 (center) ┌─────────────────┐ ┌─────────────────┐ │● │ │ │ │ (x,y) here │ │ ● │ │ │ │ (x,y) here │ │ │ │ │ └─────────────────┘ └─────────────────┘ Rotation around Rotation around top-left corner center point originX: 1, originY: 0 (top-right) originX: 0.5, originY: 1 (bottom-center) ┌─────────────────┐ ┌─────────────────┐ │ ●│ │ │ │ (x,y) here │ │ │ │ │ │ │ │ │ │ ● │ └─────────────────┘ └───(x,y) here────┘ Good for right- Good for sprites aligned elements standing on ground
Interactive Demo: Rotation with Different Origins
// Same position, different origins = different rotation behavior

// Rotates around top-left corner
const rect1 = new Rectangle({
  x: 150, y: 100,
  width: 60, height: 40,
  rotation: Math.PI / 4,
  origin: "top-left"
});

// Rotates around center
const rect2 = new Rectangle({
  x: 300, y: 100,
  width: 60, height: 40,
  rotation: Math.PI / 4,
  origin: "center"
});

// Rotates around bottom-center
const rect3 = new Rectangle({
  x: 450, y: 100,
  width: 60, height: 40,
  rotation: Math.PI / 4,
  origin: "bottom-center"
});
Watch rotation pivot points

3. Scaling with Origin

Scaling expands or contracts from the origin point. This is especially important for animations and hover effects.

Interactive Demo: Scaling with Different Origins
// Hover effect: scale from center (natural feel)
button.on('hover', () => {
  button.scaleX = 1.1;
  button.scaleY = 1.1;
});
// With origin: "center", button grows equally in all directions

// Scale from bottom (character jumping)
character.originY = 1;  // bottom-center
character.scaleY = 0.8; // squash
// Character compresses toward the ground
Hover over shapes to see scaling

4. Migration: Center to Top-Left

GCanvas originally used center-based positioning. The new top-left default matches web conventions better. Here's how to migrate:

Breaking Change: If upgrading from older GCanvas versions, add origin: "center" to shapes that need center-based positioning.

Old (Center-based)

// x,y was the center
const rect = new Rectangle({
  x: 100, y: 100,
  width: 80, height: 60
});
// Center was at (100, 100)
// Corners at (60,70) to (140,130)

New (Top-left default)

// x,y is now the top-left
const rect = new Rectangle({
  x: 100, y: 100,
  width: 80, height: 60,
  origin: "center"  // Add this!
});
// Now behaves like old version

Quick Migration Guide

Old Code New Code
new Circle(50, { x: 100, y: 100 }) new Circle(50, { x: 100, y: 100, origin: "center" })
new Rectangle({ x: 100, y: 100, ... }) new Rectangle({ x: 100, y: 100, ..., origin: "center" })
Shapes in Groups Add origin: "center" to each shape

5. Text Alignment (Independent)

TextShape uses the standard align and baseline properties which work independently from the origin system.

Interactive Demo: Text Alignment
// Text alignment is controlled separately
const text = new TextShape("Hello World", {
  x: 200, y: 100,
  color: "#0f0",
  font: "16px monospace",
  align: "center",     // horizontal: left, center, right
  baseline: "middle"   // vertical: top, middle, bottom
});

// Origin still affects transforms (rotation, scale)
text.origin = "center";
text.rotation = 0.1;  // Rotates around text center
Click to cycle alignments

6. Circles and Bounding Boxes

For circles, the origin is based on the bounding box, not the visual circle. This ensures consistent behavior with other shapes.

Circle with origin: "top-left" Circle with origin: "center" ┌─────────────────┐ ┌─────────────────┐ │● ╭─────╮ │ │ ╭─────╮ │ │ │ │ │ │ │ ● │ │ │ │ │ │ │ │ │ │ │ ╰─────╯ │ │ ╰─────╯ │ └─────────────────┘ └─────────────────┘ (x,y) at top-left (x,y) at center of bounding box of bounding box
Interactive Demo: Circle Origins
// Circle origin uses bounding box
const circle = new Circle(30, {
  x: 100, y: 100,
  color: "#0f0",
  origin: "center"  // Center of bounding box = center of circle
});

// For top-left origin:
// (x,y) is top-left of the bounding box
// Circle center is at (x + radius, y + radius)
Click to toggle origin

7. Practical Examples

Game Character (Bottom-Center Origin)

// Character sprite standing on ground
const player = new Sprite(this, {
  x: groundX,
  y: groundY,
  originX: 0.5,
  originY: 1  // Feet at position
});

// Jump animation - position is always feet location
player.y = groundY - jumpHeight;

UI Button (Center Origin)

// Button centered on screen
const button = new Button(this, {
  x: this.width / 2,
  y: this.height / 2,
  origin: "center"
});

// Hover scale effect works naturally
button.on('hover', () => {
  button.scaleX = button.scaleY = 1.1;
});

HUD Elements (Corner Origins)

// Score at top-left
const score = new Text(this, "Score: 0", {
  x: 10, y: 10,
  origin: "top-left"  // Default
});

// Lives at top-right
const lives = new Text(this, "Lives: 3", {
  x: this.width - 10,
  y: 10,
  origin: "top-right"
});

8. Complete Origin Reference

Interactive Demo: All Origin Positions
All 9 origin positions

Quick Reference Table

Use Case Recommended Origin Why
UI layouts "top-left" Matches CSS/web conventions
Game objects "center" Natural rotation/scaling pivot
Characters originX: 0.5, originY: 1 Feet stay on ground
Buttons/hover effects "center" Scale grows in all directions
Right-aligned UI "top-right" Easy to anchor to right edge
3D objects "center" Rotation around center

See Also