Grid and coordinates
textmode.js renders a grid of character cells. Your code works mostly in cell coordinates, while the library handles canvas pixels, font metrics, and WebGL rendering. (⊙_⊙)
Center-based coordinates
The drawing coordinate system is centered:
(0, 0)is the center of the active grid.- negative X moves left.
- positive X moves right.
- negative Y moves up.
- positive Y moves down.
- Z is available for 3D transforms and camera workflows.
t.draw(() => {
t.background(0);
t.char("+");
t.charColor(255);
t.point(); // draws at the center
t.translate(10, -4);
t.char("@");
t.point(); // draws 10 cells right and 4 cells up
});Grid metadata
Use t.grid to inspect the active TextmodeGrid:
console.log(t.grid.cols);
console.log(t.grid.rows);
console.log(t.grid.cellWidth);
console.log(t.grid.cellHeight);The grid depends on canvas size, font size, and the active font or tileset. When those change, the grid can change too.
Canvas size vs grid size
t.width and t.height are canvas dimensions in pixels.
t.grid.cols and t.grid.rows are drawing dimensions in cells.
t.draw(() => {
t.background(0);
t.char("#");
t.charColor(255, 120, 80);
t.rect(t.grid.cols, t.grid.rows);
});Pixel density
The sketch has three related sizes:
- The logical canvas size: the
widthandheightyou pass totextmode.create()orresizeCanvas(). - The CSS display size: how large the canvas appears on the page.
- The backing-store size: the internal pixel buffer used by WebGL.
By default, these use a pixel density of 1. With pixelDensity, an internally-created canvas can keep the same logical and CSS size while rendering to a denser backing store:
const t = textmode.create({
width: 800,
height: 600,
fontSize: 16,
pixelDensity: window.devicePixelRatio,
});You can also read or update it at runtime with t.pixelDensity():
t.pixelDensity(2);t.width, t.height, and t.grid remain based on the logical canvas size, not the multiplied backing-store size. That means drawing code stays stable when you move between standard and HiDPI displays.
When you resize a HiDPI sketch, keep passing logical dimensions:
t.windowResized(() => {
t.resizeCanvas(window.innerWidth, window.innerHeight);
});Responsive and fixed grids
The grid is responsive by default. You can also set rows or columns directly:
t.grid.cols = 80;
t.grid.rows = 45;Call grid.responsive() to return to responsive sizing:
t.grid.responsive();Call grid.reset() after manual changes when you want to recompute from the current canvas and font metrics.
Layer grids
Each TextmodeLayer has its own grid. Inside a layer's draw callback, t.grid resolves to that active layer:
const smallLayer = t.layers.add({ fontSize: 8 });
smallLayer.draw(() => {
t.background(0);
t.rect(t.grid.cols, t.grid.rows);
});This allows different layers to use different font sizes, fonts, and grid densities in one composition.
Input coordinates
Mouse and touch coordinates also use center-based grid coordinates. By default, input maps to the topmost visible layer. Use inputGrid() to lock input to a specific grid:
t.inputGrid(t.layers.base.grid);
t.mousePressed((data) => {
console.log(data.position.x, data.position.y);
});Return to responsive topmost-layer mapping with:
t.inputGrid("topmost");