Skip to content

textmode.js / fonts / TextmodeFont

Class: TextmodeFont

Manages the font used for rendering characters via TextmodeLayer.loadFont.

This class coordinates font loading, character extraction, texture atlas creation, and provides character information.

Each TextmodeLayer has its own instance of this class to allow for layer-specific font configurations.

Example

javascript
const t = textmode.create({ width: window.innerWidth, height: window.innerHeight, fontSize: 8 });
const accentLayer = t.layers.add({ fontSize: 8, offset: [0, 6] });

let customFont;

function label(text, y, color = [220, 220, 220]) {
	t.push();
	t.translate(-Math.floor(text.length / 2), y);
	t.charColor(color[0], color[1], color[2]);
	for (let i = 0; i < text.length; i++) {
		t.push();
		t.translate(i, 0);
		t.char(text[i]);
		t.point();
		t.pop();
	}
	t.pop();
}

t.setup(async () => {
	customFont = await t.loadFont('../../primitives/FROGBLOCK-V2.1.ttf', false);
	await accentLayer.loadFont(customFont);
});

t.draw(() => {
	t.background(8, 10, 22);
	label('TextmodeFont creation', -6, [255, 210, 90]);
	label(`glyphs: ${customFont ? customFont.characters.length : 'loading'}`, -2);
	label('base layer keeps its original font', 2, [150, 160, 190]);
});

accentLayer.draw(() => {
	t.clear();
	label('custom font on another layer', 0, [120, 220, 255]);
});

t.windowResized(() => {
	t.resizeCanvas(window.innerWidth, window.innerHeight);
});
codex avatar
@codex{ai-generated}Replace it with your own sketch, claim the credit, and climb the leaderboard.View sketch on GitHub

Extends

  • Disposable

Implements

  • TextmodeGlyphAtlas

Accessors

cellDimensions

Get Signature

ts
get cellDimensions(): object;

Returns the effective glyph cell dimensions used by the layer grid.

Returns

object

NameType
heightnumber
widthnumber
Example
javascript
const t = textmode.create({ width: window.innerWidth, height: window.innerHeight, fontSize: 8 });

function label(text, y, color = [220, 220, 220]) {
	t.push();
	t.translate(-Math.floor(text.length / 2), y);
	t.charColor(color[0], color[1], color[2]);

	for (let i = 0; i < text.length; i++) {
		t.push();
		t.translate(i, 0);
		t.char(text[i]);
		t.point();
		t.pop();
	}

	t.pop();
}

t.draw(() => {
	const dimensions = t.font.cellDimensions;
	t.background(7, 10, 20);

	label('TextmodeFont cell metrics', -5, [255, 220, 120]);
	label(`cell ${dimensions.width} x ${dimensions.height}px`, -1);
	label(`width ${t.font.cellWidth}  height ${t.font.cellHeight}`, 3, [120, 205, 255]);
});

t.windowResized(() => {
	t.resizeCanvas(window.innerWidth, window.innerHeight);
});
codex avatar
@codex{ai-generated}Replace it with your own sketch, claim the credit, and climb the leaderboard.View sketch on GitHub

Implementation of

ts
TextmodeGlyphAtlas.cellDimensions

cellHeight

Get Signature

ts
get cellHeight(): number;

Returns the effective glyph cell height used by the layer grid.

Returns

number

Example
javascript
const t = textmode.create({ width: window.innerWidth, height: window.innerHeight, fontSize: 8 });

function label(text, y, color = [220, 220, 220]) {
	t.push();
	t.translate(-Math.floor(text.length / 2), y);
	t.charColor(color[0], color[1], color[2]);

	for (let i = 0; i < text.length; i++) {
		t.push();
		t.translate(i, 0);
		t.char(text[i]);
		t.point();
		t.pop();
	}

	t.pop();
}

t.draw(() => {
	const dimensions = t.font.cellDimensions;
	t.background(7, 10, 20);

	label('TextmodeFont cell metrics', -5, [255, 220, 120]);
	label(`cell ${dimensions.width} x ${dimensions.height}px`, -1);
	label(`width ${t.font.cellWidth}  height ${t.font.cellHeight}`, 3, [120, 205, 255]);
});

t.windowResized(() => {
	t.resizeCanvas(window.innerWidth, window.innerHeight);
});
codex avatar
@codex{ai-generated}Replace it with your own sketch, claim the credit, and climb the leaderboard.View sketch on GitHub

Implementation of

ts
TextmodeGlyphAtlas.cellHeight

cellWidth

Get Signature

ts
get cellWidth(): number;

Returns the effective glyph cell width used by the layer grid.

Returns

number

Example
javascript
const t = textmode.create({ width: window.innerWidth, height: window.innerHeight, fontSize: 8 });

function label(text, y, color = [220, 220, 220]) {
	t.push();
	t.translate(-Math.floor(text.length / 2), y);
	t.charColor(color[0], color[1], color[2]);

	for (let i = 0; i < text.length; i++) {
		t.push();
		t.translate(i, 0);
		t.char(text[i]);
		t.point();
		t.pop();
	}

	t.pop();
}

t.draw(() => {
	const dimensions = t.font.cellDimensions;
	t.background(7, 10, 20);

	label('TextmodeFont cell metrics', -5, [255, 220, 120]);
	label(`cell ${dimensions.width} x ${dimensions.height}px`, -1);
	label(`width ${t.font.cellWidth}  height ${t.font.cellHeight}`, 3, [120, 205, 255]);
});

t.windowResized(() => {
	t.resizeCanvas(window.innerWidth, window.innerHeight);
});
codex avatar
@codex{ai-generated}Replace it with your own sketch, claim the credit, and climb the leaderboard.View sketch on GitHub

Implementation of

ts
TextmodeGlyphAtlas.cellWidth

characterMap

Get Signature

ts
get characterMap(): Map<string, TextmodeGlyph>;

Returns the character map for O(1) lookups.

Returns

Map<string, TextmodeGlyph>

Example
javascript
const t = textmode.create({ width: window.innerWidth, height: window.innerHeight, fontSize: 8 });

function label(text, y, color = [220, 220, 220]) {
	t.push();
	t.translate(-Math.floor(text.length / 2), y);
	t.charColor(color[0], color[1], color[2]);
	for (let i = 0; i < text.length; i++) {
		t.push();
		t.translate(i, 0);
		t.char(text[i]);
		t.point();
		t.pop();
	}
	t.pop();
}

t.draw(() => {
	const glyph = t.font.characterMap.get('A');
	const color = glyph ? glyph.color.map((value) => Math.round(value * 255)) : [220, 220, 220];

	t.background(8, 10, 22);
	t.char('A');
	t.charColor(color[0], color[1], color[2]);
	t.rect(10, 10);
	label('characterMap', -6, [255, 210, 90]);
	label(`map.has('A'): ${t.font.characterMap.has('A')}`, -2);
	label('fast lookup for glyph metadata', 5, [150, 160, 190]);
});

t.windowResized(() => {
	t.resizeCanvas(window.innerWidth, window.innerHeight);
});
codex avatar
@codex{ai-generated}Replace it with your own sketch, claim the credit, and climb the leaderboard.View sketch on GitHub

Implementation of

ts
TextmodeGlyphAtlas.characterMap

characters

Get Signature

ts
get characters(): readonly TextmodeGlyph[];

Returns the array of TextmodeGlyph objects in the font.

Returns

readonly TextmodeGlyph[]

Example
javascript
const t = textmode.create({ width: window.innerWidth, height: window.innerHeight, fontSize: 8 });

t.draw(() => {
	const chars = t.font.characters.slice(0, 96);
	const cols = 16;
	const rows = Math.ceil(chars.length / cols);
	const startX = -Math.floor(cols / 2);
	const startY = -Math.floor(rows / 2);

	t.background(8, 10, 22);

	for (let i = 0; i < chars.length; i++) {
		const glyph = chars[i];
		t.push();
		t.translate(startX + (i % cols), startY + Math.floor(i / cols));
		t.char(glyph.character);
		t.charColor(120 + (i % cols) * 6, 140 + (i % rows) * 10, 255 - (i % cols) * 5);
		t.point();
		t.pop();
	}
});

t.windowResized(() => {
	t.resizeCanvas(window.innerWidth, window.innerHeight);
});
codex avatar
@codex{ai-generated}Replace it with your own sketch, claim the credit, and climb the leaderboard.View sketch on GitHub

Implementation of

ts
TextmodeGlyphAtlas.characters

columns

Get Signature

ts
get columns(): number;

Returns the number of columns in the normalized glyph atlas.

Returns

number

Example
javascript
const t = textmode.create({ width: window.innerWidth, height: window.innerHeight, fontSize: 8 });

function label(text, y, color = [220, 220, 220]) {
	t.push();
	t.translate(-Math.floor(text.length / 2), y);
	t.charColor(color[0], color[1], color[2]);
	for (let i = 0; i < text.length; i++) {
		t.push();
		t.translate(i, 0);
		t.char(text[i]);
		t.point();
		t.pop();
	}
	t.pop();
}

t.draw(() => {
	const cols = t.font.textureColumns;
	t.background(8, 10, 22);
	label('textureColumns', -6, [255, 210, 90]);
	label(`atlas columns: ${cols}`, -2);

	for (let i = 0; i < cols; i++) {
		t.push();
		t.translate(-cols / 2 + i, 3);
		t.char('|');
		t.charColor(120 + (i % 12) * 10, 180, 255);
		t.line(0, -2, 0, 2);
		t.pop();
	}
});

t.windowResized(() => {
	t.resizeCanvas(window.innerWidth, window.innerHeight);
});
codex avatar
@codex{ai-generated}Replace it with your own sketch, claim the credit, and climb the leaderboard.View sketch on GitHub

Implementation of

ts
TextmodeGlyphAtlas.columns

font

Get Signature

ts
get font(): TyprFont;

Returns the Typr.js font object.

Returns

TyprFont

Example
javascript
const t = textmode.create({ width: window.innerWidth, height: window.innerHeight, fontSize: 8 });

function label(text, y, color = [220, 220, 220]) {
	t.push();
	t.translate(-Math.floor(text.length / 2), y);
	t.charColor(color[0], color[1], color[2]);

	for (let i = 0; i < text.length; i++) {
		t.push();
		t.translate(i, 0);
		t.char(text[i]);
		t.point();
		t.pop();
	}

	t.pop();
}

t.draw(() => {
	const font = t.font.font;
	const unitsPerEm = font?.head?.unitsPerEm ?? 0;
	const ascender = font?.hhea?.ascender ?? 0;

	t.background(7, 10, 20);
	label('TextmodeFont.font', -5, [255, 220, 120]);
	label(`unitsPerEm ${unitsPerEm}`, -1);
	label(`ascender ${ascender}`, 3, [120, 205, 255]);
});

t.windowResized(() => {
	t.resizeCanvas(window.innerWidth, window.innerHeight);
});
codex avatar
@codex{ai-generated}Replace it with your own sketch, claim the credit, and climb the leaderboard.View sketch on GitHub

fontFramebuffer

Get Signature

ts
get fontFramebuffer(): TextmodeFramebuffer;

Returns the WebGL framebuffer containing the font texture atlas.

Returns

TextmodeFramebuffer

Example
javascript
const t = textmode.create({ width: window.innerWidth, height: window.innerHeight, fontSize: 8 });

function label(text, y, color = [220, 220, 220]) {
	t.push();
	t.translate(-Math.floor(text.length / 2), y);
	t.charColor(color[0], color[1], color[2]);
	for (let i = 0; i < text.length; i++) {
		t.push();
		t.translate(i, 0);
		t.char(text[i]);
		t.point();
		t.pop();
	}
	t.pop();
}

t.draw(() => {
	const atlas = t.font.fontFramebuffer;
	t.background(8, 10, 22);
	label('fontFramebuffer', -5, [255, 210, 90]);
	label(`atlas size: ${atlas.width} x ${atlas.height}px`, -1);
	label(`grid: ${t.font.textureColumns} cols x ${t.font.textureRows} rows`, 3, [150, 160, 190]);
});

t.windowResized(() => {
	t.resizeCanvas(window.innerWidth, window.innerHeight);
});
codex avatar
@codex{ai-generated}Replace it with your own sketch, claim the credit, and climb the leaderboard.View sketch on GitHub

fontSize

Get Signature

ts
get fontSize(): number;

Returns the font size used for the texture atlas.

Returns

number

Example
javascript
const t = textmode.create({ width: window.innerWidth, height: window.innerHeight, fontSize: 8 });
const miniLayer = t.layers.add({ fontSize: 16, offset: [0, 6] });

function label(text, y, color = [220, 220, 220]) {
	t.push();
	t.translate(-Math.floor(text.length / 2), y);
	t.charColor(color[0], color[1], color[2]);
	for (let i = 0; i < text.length; i++) {
		t.push();
		t.translate(i, 0);
		t.char(text[i]);
		t.point();
		t.pop();
	}
	t.pop();
}

t.draw(() => {
	t.background(8, 10, 22);
	label('fontSize', -6, [255, 210, 90]);
	label(`base font size: ${t.layers.base.font.fontSize}`, -2);
	label(`upper layer font size: ${miniLayer.font.fontSize}`, 2, [150, 160, 190]);
});

miniLayer.draw(() => {
	t.clear();
	label('larger layer font', 0, [120, 220, 255]);
});

t.windowResized(() => {
	t.resizeCanvas(window.innerWidth, window.innerHeight);
});
codex avatar
@codex{ai-generated}Replace it with your own sketch, claim the credit, and climb the leaderboard.View sketch on GitHub

framebuffer

Get Signature

ts
get framebuffer(): TextmodeFramebuffer;

Returns the normalized glyph atlas framebuffer used by the ASCII shader.

Returns

TextmodeFramebuffer

Example
javascript
const t = textmode.create({ width: window.innerWidth, height: window.innerHeight, fontSize: 8 });

function label(text, y, color = [220, 220, 220]) {
	t.push();
	t.translate(-Math.floor(text.length / 2), y);
	t.charColor(color[0], color[1], color[2]);
	for (let i = 0; i < text.length; i++) {
		t.push();
		t.translate(i, 0);
		t.char(text[i]);
		t.point();
		t.pop();
	}
	t.pop();
}

t.draw(() => {
	const atlas = t.font.fontFramebuffer;
	t.background(8, 10, 22);
	label('fontFramebuffer', -5, [255, 210, 90]);
	label(`atlas size: ${atlas.width} x ${atlas.height}px`, -1);
	label(`grid: ${t.font.textureColumns} cols x ${t.font.textureRows} rows`, 3, [150, 160, 190]);
});

t.windowResized(() => {
	t.resizeCanvas(window.innerWidth, window.innerHeight);
});
codex avatar
@codex{ai-generated}Replace it with your own sketch, claim the credit, and climb the leaderboard.View sketch on GitHub

Implementation of

ts
TextmodeGlyphAtlas.framebuffer

maxGlyphDimensions

Get Signature

ts
get maxGlyphDimensions(): object;

Returns the maximum dimensions of a glyph in the font in pixels.

Returns

object

NameType
heightnumber
widthnumber
Example
javascript
const t = textmode.create({ width: window.innerWidth, height: window.innerHeight, fontSize: 8 });

function label(text, y, color = [220, 220, 220]) {
	t.push();
	t.translate(-Math.floor(text.length / 2), y);
	t.charColor(color[0], color[1], color[2]);
	for (let i = 0; i < text.length; i++) {
		t.push();
		t.translate(i, 0);
		t.char(text[i]);
		t.point();
		t.pop();
	}
	t.pop();
}

t.draw(() => {
	const dims = t.font.maxGlyphDimensions;
	const w = Math.max(2, Math.round(dims.width / 4));
	const h = Math.max(2, Math.round(dims.height / 4));

	t.background(8, 10, 22);
	t.char('#');
	t.charColor(120, 220, 255);
	t.rect(w, h);
	label('maxGlyphDimensions', -6, [255, 210, 90]);
	label(`${dims.width}px x ${dims.height}px`, -2);
	label('scaled box shows the max glyph bounds', 5, [150, 160, 190]);
});

t.windowResized(() => {
	t.resizeCanvas(window.innerWidth, window.innerHeight);
});
codex avatar
@codex{ai-generated}Replace it with your own sketch, claim the credit, and climb the leaderboard.View sketch on GitHub

rows

Get Signature

ts
get rows(): number;

Returns the number of rows in the normalized glyph atlas.

Returns

number

Example
javascript
const t = textmode.create({ width: window.innerWidth, height: window.innerHeight, fontSize: 8 });

function label(text, y, color = [220, 220, 220]) {
	t.push();
	t.translate(-Math.floor(text.length / 2), y);
	t.charColor(color[0], color[1], color[2]);
	for (let i = 0; i < text.length; i++) {
		t.push();
		t.translate(i, 0);
		t.char(text[i]);
		t.point();
		t.pop();
	}
	t.pop();
}

t.draw(() => {
	const rows = t.font.textureRows;
	t.background(8, 10, 22);
	label('textureRows', -6, [255, 210, 90]);
	label(`atlas rows: ${rows}`, -2);

	for (let i = 0; i < rows; i++) {
		t.push();
		t.translate(0, i - rows / 2 + 4);
		t.char('-');
		t.charColor(120, 170 + (i % 10) * 8, 255);
		t.line(-6, 0, 6, 0);
		t.pop();
	}
});

t.windowResized(() => {
	t.resizeCanvas(window.innerWidth, window.innerHeight);
});
codex avatar
@codex{ai-generated}Replace it with your own sketch, claim the credit, and climb the leaderboard.View sketch on GitHub

Implementation of

ts
TextmodeGlyphAtlas.rows

textureColumns

Get Signature

ts
get textureColumns(): number;

Returns the number of columns in the texture atlas.

Returns

number

Example
javascript
const t = textmode.create({ width: window.innerWidth, height: window.innerHeight, fontSize: 8 });

function label(text, y, color = [220, 220, 220]) {
	t.push();
	t.translate(-Math.floor(text.length / 2), y);
	t.charColor(color[0], color[1], color[2]);
	for (let i = 0; i < text.length; i++) {
		t.push();
		t.translate(i, 0);
		t.char(text[i]);
		t.point();
		t.pop();
	}
	t.pop();
}

t.draw(() => {
	const cols = t.font.textureColumns;
	t.background(8, 10, 22);
	label('textureColumns', -6, [255, 210, 90]);
	label(`atlas columns: ${cols}`, -2);

	for (let i = 0; i < cols; i++) {
		t.push();
		t.translate(-cols / 2 + i, 3);
		t.char('|');
		t.charColor(120 + (i % 12) * 10, 180, 255);
		t.line(0, -2, 0, 2);
		t.pop();
	}
});

t.windowResized(() => {
	t.resizeCanvas(window.innerWidth, window.innerHeight);
});
codex avatar
@codex{ai-generated}Replace it with your own sketch, claim the credit, and climb the leaderboard.View sketch on GitHub

textureRows

Get Signature

ts
get textureRows(): number;

Returns the number of rows in the texture atlas.

Returns

number

Example
javascript
const t = textmode.create({ width: window.innerWidth, height: window.innerHeight, fontSize: 8 });

function label(text, y, color = [220, 220, 220]) {
	t.push();
	t.translate(-Math.floor(text.length / 2), y);
	t.charColor(color[0], color[1], color[2]);
	for (let i = 0; i < text.length; i++) {
		t.push();
		t.translate(i, 0);
		t.char(text[i]);
		t.point();
		t.pop();
	}
	t.pop();
}

t.draw(() => {
	const rows = t.font.textureRows;
	t.background(8, 10, 22);
	label('textureRows', -6, [255, 210, 90]);
	label(`atlas rows: ${rows}`, -2);

	for (let i = 0; i < rows; i++) {
		t.push();
		t.translate(0, i - rows / 2 + 4);
		t.char('-');
		t.charColor(120, 170 + (i % 10) * 8, 255);
		t.line(-6, 0, 6, 0);
		t.pop();
	}
});

t.windowResized(() => {
	t.resizeCanvas(window.innerWidth, window.innerHeight);
});
codex avatar
@codex{ai-generated}Replace it with your own sketch, claim the credit, and climb the leaderboard.View sketch on GitHub

Methods

dispose()

ts
dispose(): void;

Dispose of all resources used by this font manager.

Returns

void

Example

javascript
const t = textmode.create({ width: window.innerWidth, height: window.innerHeight, fontSize: 8 });

let tempFont;
let disposed = false;

function label(text, y, color = [220, 220, 220]) {
	t.push();
	t.translate(-Math.floor(text.length / 2), y);
	t.charColor(color[0], color[1], color[2]);
	for (let i = 0; i < text.length; i++) {
		t.push();
		t.translate(i, 0);
		t.char(text[i]);
		t.point();
		t.pop();
	}
	t.pop();
}

t.setup(async () => {
	tempFont = await t.loadFont('../../primitives/CHUNKY.ttf', false);
});

t.draw(() => {
	t.background(8, 10, 22);
	label('dispose()', -4, [255, 210, 90]);
	label(disposed ? 'temporary font disposed' : 'disposing temp font after 3 seconds', -1);
	label('active layer font keeps rendering normally', 2, [150, 160, 190]);

	if (tempFont && !disposed && t.frameCount > 180) {
		tempFont.dispose();
		disposed = true;
	}
});

t.windowResized(() => {
	t.resizeCanvas(window.innerWidth, window.innerHeight);
});
codex avatar
@codex{ai-generated}Replace it with your own sketch, claim the credit, and climb the leaderboard.View sketch on GitHub

Overrides

ts
Disposable.dispose