Skip to content

textmode.js / media / TextmodeVideo

Class: TextmodeVideo

Represents a video element for textmode rendering via Textmodifier.loadVideo.

It can be drawn to the canvas via Textmodifier.image.

A video uploaded currently runs through an adjustable brightness-converter that converts the video frames into a textmode representation using characters. Those adjustable options are available via chainable methods on this class.

Example

javascript
const VIDEO_URL = 'https://interactive-examples.mdn.mozilla.net/media/cc0-videos/flower.mp4';
const t = textmode.create({ width: window.innerWidth, height: window.innerHeight });

let video;

function drawLabel(text, y) {
	t.push();
	t.translate(-Math.floor(text.length / 2), y);
	t.charColor(255);

	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 () => {
	video = await t.loadVideo(VIDEO_URL);
	await video.play();
	video.loop();
	video.characters(' .:-=+*#%@');
});

t.draw(() => {
	t.background(0);
	if (!video) return;

	t.image(video);
	drawLabel('TextmodeVideo via loadVideo()', Math.floor(t.grid.rows / 2) - 2);
});

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

Accessors

currentTime

Get Signature

ts
get currentTime(): number;

Current playback time in seconds.

Returns

number

Example
javascript
const VIDEO_URL = 'https://interactive-examples.mdn.mozilla.net/media/cc0-videos/flower.mp4';
const t = textmode.create({ width: window.innerWidth, height: window.innerHeight, fontSize: 16 });

let video = null;

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 () => {
	video = await t.loadVideo(VIDEO_URL);
	video.characters(' .:-=+*#%@');
	await video.play();
});

t.draw(() => {
	t.background(5, 7, 18);

	if (video) {
		t.image(video, t.grid.cols - 8, t.grid.rows - 10);
		label(`videoElement ${video.videoElement ? 'ready' : 'pending'}`, Math.floor(t.grid.rows * 0.20));
		label(`current ${video.currentTime.toFixed(1)}s / ${video.duration.toFixed(1)}s`, Math.floor(t.grid.rows * 0.30));
		label(`isPlaying ${video.isPlaying ? 'true' : 'false'}`, Math.floor(t.grid.rows * 0.40), [120, 205, 255]);
	}

	label('click to toggle play / pause', -Math.floor(t.grid.rows * 0.34), [255, 225, 140]);
});

t.mouseClicked(async () => {
	if (!video) {
		return;
	}

	if (video.isPlaying) {
		video.pause();
		return;
	}

	await video.play();
});

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

duration

Get Signature

ts
get duration(): number;

Total duration of the video in seconds.

Returns

number

Example
javascript
const VIDEO_URL = 'https://interactive-examples.mdn.mozilla.net/media/cc0-videos/flower.mp4';
const t = textmode.create({ width: window.innerWidth, height: window.innerHeight, fontSize: 16 });

let video = null;

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 () => {
	video = await t.loadVideo(VIDEO_URL);
	video.characters(' .:-=+*#%@');
	await video.play();
});

t.draw(() => {
	t.background(5, 7, 18);

	if (video) {
		t.image(video, t.grid.cols - 8, t.grid.rows - 10);
		label(`videoElement ${video.videoElement ? 'ready' : 'pending'}`, Math.floor(t.grid.rows * 0.20));
		label(`current ${video.currentTime.toFixed(1)}s / ${video.duration.toFixed(1)}s`, Math.floor(t.grid.rows * 0.30));
		label(`isPlaying ${video.isPlaying ? 'true' : 'false'}`, Math.floor(t.grid.rows * 0.40), [120, 205, 255]);
	}

	label('click to toggle play / pause', -Math.floor(t.grid.rows * 0.34), [255, 225, 140]);
});

t.mouseClicked(async () => {
	if (!video) {
		return;
	}

	if (video.isPlaying) {
		video.pause();
		return;
	}

	await video.play();
});

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

height

Get Signature

ts
get height(): number;

Ideal height in grid cells.

Returns

number

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

const sourceCanvas = document.createElement('canvas');
sourceCanvas.width = 192;
sourceCanvas.height = 96;

const sourceContext = sourceCanvas.getContext('2d');
let source = null;

function renderSource() {
	if (!sourceContext) {
		return;
	}

	sourceContext.fillStyle = '#020617';
	sourceContext.fillRect(0, 0, sourceCanvas.width, sourceCanvas.height);
	sourceContext.fillStyle = '#34d399';
	sourceContext.fillRect(18, 18, sourceCanvas.width - 36, sourceCanvas.height - 36);
}

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(() => {
	renderSource();
	source = t.createTexture(sourceCanvas);
	source.characters(' .:-=+*#%@');
});

t.draw(() => {
	t.background(5, 7, 18);

	if (source) {
		t.image(source, t.grid.cols - 8, t.grid.rows - 10);
		label(`width ${source.width}  height ${source.height}`, Math.floor(t.grid.rows * 0.24));
		label(`original ${source.originalWidth} x ${source.originalHeight}`, Math.floor(t.grid.rows * 0.34), [120, 205, 255]);
	}

	label('TextmodeSource dimensions', -Math.floor(t.grid.rows * 0.34), [255, 225, 140]);
});

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

Inherited from

TextmodeTexture.height


isPlaying

Get Signature

ts
get isPlaying(): boolean;

Whether the video is currently playing.

Returns

boolean

Example
javascript
const VIDEO_URL = 'https://interactive-examples.mdn.mozilla.net/media/cc0-videos/flower.mp4';
const t = textmode.create({ width: window.innerWidth, height: window.innerHeight, fontSize: 16 });

let video = null;

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 () => {
	video = await t.loadVideo(VIDEO_URL);
	video.characters(' .:-=+*#%@');
	await video.play();
});

t.draw(() => {
	t.background(5, 7, 18);

	if (video) {
		t.image(video, t.grid.cols - 8, t.grid.rows - 10);
		label(`videoElement ${video.videoElement ? 'ready' : 'pending'}`, Math.floor(t.grid.rows * 0.20));
		label(`current ${video.currentTime.toFixed(1)}s / ${video.duration.toFixed(1)}s`, Math.floor(t.grid.rows * 0.30));
		label(`isPlaying ${video.isPlaying ? 'true' : 'false'}`, Math.floor(t.grid.rows * 0.40), [120, 205, 255]);
	}

	label('click to toggle play / pause', -Math.floor(t.grid.rows * 0.34), [255, 225, 140]);
});

t.mouseClicked(async () => {
	if (!video) {
		return;
	}

	if (video.isPlaying) {
		video.pause();
		return;
	}

	await video.play();
});

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

originalHeight

Get Signature

ts
get originalHeight(): number;

Original pixel height.

Returns

number

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

const sourceCanvas = document.createElement('canvas');
sourceCanvas.width = 192;
sourceCanvas.height = 96;

const sourceContext = sourceCanvas.getContext('2d');
let source = null;

function renderSource() {
	if (!sourceContext) {
		return;
	}

	sourceContext.fillStyle = '#020617';
	sourceContext.fillRect(0, 0, sourceCanvas.width, sourceCanvas.height);
	sourceContext.fillStyle = '#34d399';
	sourceContext.fillRect(18, 18, sourceCanvas.width - 36, sourceCanvas.height - 36);
}

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(() => {
	renderSource();
	source = t.createTexture(sourceCanvas);
	source.characters(' .:-=+*#%@');
});

t.draw(() => {
	t.background(5, 7, 18);

	if (source) {
		t.image(source, t.grid.cols - 8, t.grid.rows - 10);
		label(`width ${source.width}  height ${source.height}`, Math.floor(t.grid.rows * 0.24));
		label(`original ${source.originalWidth} x ${source.originalHeight}`, Math.floor(t.grid.rows * 0.34), [120, 205, 255]);
	}

	label('TextmodeSource dimensions', -Math.floor(t.grid.rows * 0.34), [255, 225, 140]);
});

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

Inherited from

TextmodeTexture.originalHeight


originalWidth

Get Signature

ts
get originalWidth(): number;

Original pixel width.

Returns

number

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

const sourceCanvas = document.createElement('canvas');
sourceCanvas.width = 192;
sourceCanvas.height = 96;

const sourceContext = sourceCanvas.getContext('2d');
let source = null;

function renderSource() {
	if (!sourceContext) {
		return;
	}

	sourceContext.fillStyle = '#020617';
	sourceContext.fillRect(0, 0, sourceCanvas.width, sourceCanvas.height);
	sourceContext.fillStyle = '#34d399';
	sourceContext.fillRect(18, 18, sourceCanvas.width - 36, sourceCanvas.height - 36);
}

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(() => {
	renderSource();
	source = t.createTexture(sourceCanvas);
	source.characters(' .:-=+*#%@');
});

t.draw(() => {
	t.background(5, 7, 18);

	if (source) {
		t.image(source, t.grid.cols - 8, t.grid.rows - 10);
		label(`width ${source.width}  height ${source.height}`, Math.floor(t.grid.rows * 0.24));
		label(`original ${source.originalWidth} x ${source.originalHeight}`, Math.floor(t.grid.rows * 0.34), [120, 205, 255]);
	}

	label('TextmodeSource dimensions', -Math.floor(t.grid.rows * 0.34), [255, 225, 140]);
});

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

Inherited from

TextmodeTexture.originalWidth


source

Get Signature

ts
get source(): HTMLCanvasElement | HTMLVideoElement;

The source element this texture captures from.

Returns

HTMLCanvasElement | HTMLVideoElement

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

const sourceCanvas = document.createElement('canvas');
sourceCanvas.width = 180;
sourceCanvas.height = 120;

const sourceContext = sourceCanvas.getContext('2d');
const texture = t.createTexture(sourceCanvas);
texture.characters(' .:-=+*#%@');

function drawSourceCanvas() {
	if (!sourceContext) {
		return;
	}

	const time = t.frameCount * 0.05;
	sourceContext.fillStyle = '#050816';
	sourceContext.fillRect(0, 0, sourceCanvas.width, sourceCanvas.height);

	const gradient = sourceContext.createLinearGradient(0, 0, sourceCanvas.width, sourceCanvas.height);
	gradient.addColorStop(0, '#1d4ed8');
	gradient.addColorStop(1, '#fb7185');
	sourceContext.fillStyle = gradient;
	sourceContext.fillRect(18, 18, sourceCanvas.width - 36, sourceCanvas.height - 36);

	sourceContext.save();
	sourceContext.translate(sourceCanvas.width / 2, sourceCanvas.height / 2);
	sourceContext.rotate(time * 0.8);
	sourceContext.fillStyle = '#fef08a';
	sourceContext.fillRect(-18, -44, 36, 88);
	sourceContext.restore();
}

function drawLabel(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(() => {
	drawSourceCanvas();

	t.background(5, 7, 18);
	t.image(texture, t.grid.cols - 8, t.grid.rows - 10);

	drawLabel('createTexture(canvas)', -Math.floor(t.grid.rows * 0.34), [255, 225, 140]);
	drawLabel(`source matches ${texture.source === sourceCanvas ? 'yes' : 'no'}`, Math.floor(t.grid.rows * 0.30), [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

Inherited from

TextmodeTexture.source


texture

Get Signature

ts
get texture(): WebGLTexture;

Return the WebGL texture currently backing this source.

Returns

WebGLTexture

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

const sourceCanvas = document.createElement('canvas');
sourceCanvas.width = 180;
sourceCanvas.height = 120;

const sourceContext = sourceCanvas.getContext('2d');
let source = null;

function renderSource() {
	if (!sourceContext) {
		return;
	}

	const gradient = sourceContext.createLinearGradient(0, 0, sourceCanvas.width, sourceCanvas.height);
	gradient.addColorStop(0, '#020617');
	gradient.addColorStop(1, '#1d4ed8');
	sourceContext.fillStyle = gradient;
	sourceContext.fillRect(0, 0, sourceCanvas.width, sourceCanvas.height);
	sourceContext.fillStyle = '#f97316';
	sourceContext.fillRect(24, 24, 132, 72);
}

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(() => {
	renderSource();
	source = t.createTexture(sourceCanvas);
	source.characters(' .:-=+*#%@');
});

t.draw(() => {
	t.background(5, 7, 18);

	if (source) {
		t.image(source, t.grid.cols - 8, t.grid.rows - 10);
	}

	label('TextmodeSource.texture', -Math.floor(t.grid.rows * 0.34), [255, 225, 140]);
	label(source && source.texture ? 'webgl texture available' : 'texture pending', Math.floor(t.grid.rows * 0.30), [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

Inherited from

TextmodeTexture.texture


videoElement

Get Signature

ts
get videoElement(): HTMLVideoElement;

The underlying HTML video element.

Returns

HTMLVideoElement

Example
javascript
const VIDEO_URL = 'https://interactive-examples.mdn.mozilla.net/media/cc0-videos/flower.mp4';
const t = textmode.create({ width: window.innerWidth, height: window.innerHeight, fontSize: 16 });

let video = null;

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 () => {
	video = await t.loadVideo(VIDEO_URL);
	video.characters(' .:-=+*#%@');
	await video.play();
});

t.draw(() => {
	t.background(5, 7, 18);

	if (video) {
		t.image(video, t.grid.cols - 8, t.grid.rows - 10);
		label(`videoElement ${video.videoElement ? 'ready' : 'pending'}`, Math.floor(t.grid.rows * 0.20));
		label(`current ${video.currentTime.toFixed(1)}s / ${video.duration.toFixed(1)}s`, Math.floor(t.grid.rows * 0.30));
		label(`isPlaying ${video.isPlaying ? 'true' : 'false'}`, Math.floor(t.grid.rows * 0.40), [120, 205, 255]);
	}

	label('click to toggle play / pause', -Math.floor(t.grid.rows * 0.34), [255, 225, 140]);
});

t.mouseClicked(async () => {
	if (!video) {
		return;
	}

	if (video.isPlaying) {
		video.pause();
		return;
	}

	await video.play();
});

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

width

Get Signature

ts
get width(): number;

Ideal width in grid cells.

Returns

number

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

const sourceCanvas = document.createElement('canvas');
sourceCanvas.width = 192;
sourceCanvas.height = 96;

const sourceContext = sourceCanvas.getContext('2d');
let source = null;

function renderSource() {
	if (!sourceContext) {
		return;
	}

	sourceContext.fillStyle = '#020617';
	sourceContext.fillRect(0, 0, sourceCanvas.width, sourceCanvas.height);
	sourceContext.fillStyle = '#34d399';
	sourceContext.fillRect(18, 18, sourceCanvas.width - 36, sourceCanvas.height - 36);
}

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(() => {
	renderSource();
	source = t.createTexture(sourceCanvas);
	source.characters(' .:-=+*#%@');
});

t.draw(() => {
	t.background(5, 7, 18);

	if (source) {
		t.image(source, t.grid.cols - 8, t.grid.rows - 10);
		label(`width ${source.width}  height ${source.height}`, Math.floor(t.grid.rows * 0.24));
		label(`original ${source.originalWidth} x ${source.originalHeight}`, Math.floor(t.grid.rows * 0.34), [120, 205, 255]);
	}

	label('TextmodeSource dimensions', -Math.floor(t.grid.rows * 0.34), [255, 225, 140]);
});

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

Inherited from

TextmodeTexture.width

Methods

_hasFrameOverrides()

ts
_hasFrameOverrides(): boolean;

Returns

boolean

Inherited from

TextmodeTexture._hasFrameOverrides


background()

ts
background(
   colorOrGray, 
   g?, 
   b?, 
   a?): this;

Defines the background color used for transparent pixels.

Parameters

ParameterTypeDescription
colorOrGraystring | number | TextmodeColorA grayscale value (0-255), hex string ('#RGB', '#RRGGBB', '#RRGGBBAA'), or TextmodeColor instance
g?numberOptional green component (0-255) if using RGB format, or alpha (0-255) when using grayscale form
b?numberOptional blue component (0-255) if using RGB format
a?numberOptional alpha component (0-255) if using RGBA format

Returns

this

This instance for chaining.

Example

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

let plainSource;
let backgroundSource;

function createTransparentCanvas() {
	const canvas = document.createElement('canvas');
	canvas.width = 160;
	canvas.height = 160;

	const ctx = canvas.getContext('2d');
	if (!ctx) return canvas;

	ctx.clearRect(0, 0, canvas.width, canvas.height);
	ctx.fillStyle = '#ffffff';
	ctx.beginPath();
	ctx.arc(canvas.width / 2, canvas.height / 2, 48, 0, Math.PI * 2);
	ctx.fill();

	ctx.fillStyle = '#000000';
	ctx.fillRect(canvas.width / 2 - 10, canvas.height / 2 - 10, 20, 20);

	return canvas;
}

function drawLabel(text, x, y) {
	t.push();
	t.translate(x - Math.floor(text.length / 2), y);
	t.charColor(255);

	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(() => {
	const canvas = createTransparentCanvas();

	plainSource = t.createTexture(canvas);
	plainSource.characters(' .:-=+*#%@');

	backgroundSource = t.createTexture(canvas);
	backgroundSource.characters(' .:-=+*#%@');
	backgroundSource.background(255, 0, 0);
});

t.draw(() => {
	t.background(40);
	if (!plainSource || !backgroundSource) return;

	const size = Math.min(plainSource.width, plainSource.height) * 0.7;
	const offset = Math.floor(size * 0.7);

	t.push();
	t.translate(-offset, 0);
	t.image(plainSource, size, size);
	t.pop();

	t.push();
	t.translate(offset, 0);
	t.image(backgroundSource, size, size);
	t.pop();

	drawLabel('default transparent fallback', -offset, Math.floor(t.grid.rows / 2) - 2);
	drawLabel('background(255, 0, 0)', offset, Math.floor(t.grid.rows / 2) - 2);
});

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

Inherited from

TextmodeTexture.background


cellColor()

ts
cellColor(
   colorOrGray, 
   g?, 
   b?, 
   a?): this;

Defines the cell color when cellColorMode is 'fixed'.

Parameters

ParameterTypeDescription
colorOrGraystring | number | TextmodeColorA grayscale value (0-255), hex string ('#RGB', '#RRGGBB', '#RRGGBBAA'), or TextmodeColor instance
g?numberOptional green component (0-255) if using RGB format, or alpha (0-255) when using grayscale form
b?numberOptional blue component (0-255) if using RGB format
a?numberOptional alpha component (0-255) if using RGBA format

Returns

this

This instance for chaining.

Example

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

let source;

function createGradientCanvas() {
	const canvas = document.createElement('canvas');
	canvas.width = 160;
	canvas.height = 160;

	const ctx = canvas.getContext('2d');
	if (!ctx) return canvas;

	const gradient = ctx.createLinearGradient(0, 0, canvas.width, canvas.height);
	gradient.addColorStop(0, '#050505');
	gradient.addColorStop(1, '#f5f5f5');
	ctx.fillStyle = gradient;
	ctx.fillRect(0, 0, canvas.width, canvas.height);

	return canvas;
}

function drawLabel(text, y) {
	t.push();
	t.translate(-Math.floor(text.length / 2), y);
	t.charColor(255);

	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(() => {
	source = t.createTexture(createGradientCanvas());
	source.characters(' .:-=+*#%@');
	source.charColorMode('fixed');
	source.charColor(255);
	source.cellColorMode('fixed');
});

t.draw(() => {
	t.background(0);
	if (!source) return;

	const blue = 32 + Math.round(64 * (1 + Math.sin(t.frameCount * 0.05)));
	source.cellColor('#000033');
	source.cellColor(0, 0, blue);
	t.image(source, source.width, source.height);
	drawLabel('cellColor(0, 0, blue)', Math.floor(t.grid.rows / 2) - 2);
});

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

Inherited from

TextmodeTexture.cellColor


cellColorMode()

ts
cellColorMode(mode): this;

Set cell color mode: 'sampled' (from source) or 'fixed'.

Parameters

ParameterTypeDescription
mode"fixed" | "sampled"The cell color mode

Returns

this

This instance for chaining.

Example

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

let sampledSource;
let fixedSource;

function createColorCanvas() {
	const canvas = document.createElement('canvas');
	canvas.width = 160;
	canvas.height = 160;

	const ctx = canvas.getContext('2d');
	if (!ctx) return canvas;

	const gradient = ctx.createLinearGradient(0, 0, canvas.width, canvas.height);
	gradient.addColorStop(0, '#00c2ff');
	gradient.addColorStop(0.5, '#00ff88');
	gradient.addColorStop(1, '#ffee00');
	ctx.fillStyle = gradient;
	ctx.fillRect(0, 0, canvas.width, canvas.height);

	return canvas;
}

function drawLabel(text, x, y) {
	t.push();
	t.translate(x - Math.floor(text.length / 2), y);
	t.charColor(255);

	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(() => {
	const canvas = createColorCanvas();

	sampledSource = t.createTexture(canvas);
	sampledSource.characters(' .:-=+*#%@');
	sampledSource.charColorMode('sampled');
	sampledSource.cellColorMode('sampled');

	fixedSource = t.createTexture(canvas);
	fixedSource.characters(' .:-=+*#%@');
	fixedSource.charColorMode('sampled');
	fixedSource.cellColorMode('fixed');
	fixedSource.cellColor('#120022');
});

t.draw(() => {
	t.background(0);
	if (!sampledSource || !fixedSource) return;

	const pulse = 64 + Math.round(64 * (1 + Math.sin(t.frameCount * 0.05)));
	fixedSource.cellColor(pulse, 0, 40);

	const size = Math.min(sampledSource.width, sampledSource.height) * 0.7;
	const offset = Math.floor(size * 0.7);

	t.push();
	t.translate(-offset, 0);
	t.image(sampledSource, size, size);
	t.pop();

	t.push();
	t.translate(offset, 0);
	t.image(fixedSource, size, size);
	t.pop();

	drawLabel("cellColorMode('sampled')", -offset, Math.floor(t.grid.rows / 2) - 2);
	drawLabel("cellColorMode('fixed')", offset, Math.floor(t.grid.rows / 2) - 2);
});

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

Inherited from

TextmodeTexture.cellColorMode


characters()

ts
characters(chars): this;

Define the characters to use for brightness mapping as a string. Maximum length is 255; excess characters are ignored.

Parameters

ParameterTypeDescription
charsstringString of characters to map

Returns

this

This instance for chaining.

Example

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

let sparseSource;
let denseSource;

function createGradientCanvas() {
	const canvas = document.createElement('canvas');
	canvas.width = 160;
	canvas.height = 160;

	const ctx = canvas.getContext('2d');
	if (!ctx) return canvas;

	const gradient = ctx.createLinearGradient(0, 0, canvas.width, canvas.height);
	gradient.addColorStop(0, '#000000');
	gradient.addColorStop(1, '#ffffff');
	ctx.fillStyle = gradient;
	ctx.fillRect(0, 0, canvas.width, canvas.height);

	return canvas;
}

function drawLabel(text, x, y) {
	t.push();
	t.translate(x - Math.floor(text.length / 2), y);
	t.charColor(255);

	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(() => {
	const canvas = createGradientCanvas();

	sparseSource = t.createTexture(canvas);
	sparseSource.characters(' .oO@');

	denseSource = t.createTexture(canvas);
	denseSource.characters(' .:-=+*#%@');
});

t.draw(() => {
	t.background(0);
	if (!sparseSource || !denseSource) return;

	const size = Math.min(sparseSource.width, sparseSource.height) * 0.7;
	const offset = Math.floor(size * 0.7);

	t.push();
	t.translate(-offset, 0);
	t.image(sparseSource, size, size);
	t.pop();

	t.push();
	t.translate(offset, 0);
	t.image(denseSource, size, size);
	t.pop();

	drawLabel("characters(' .oO@')", -offset, Math.floor(t.grid.rows / 2) - 2);
	drawLabel("characters(' .:-=+*#%@')", offset, Math.floor(t.grid.rows / 2) - 2);
});

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

Inherited from

TextmodeTexture.characters


charColor()

ts
charColor(
   colorOrGray, 
   g?, 
   b?, 
   a?): this;

Defines the character color when charColorMode is 'fixed'.

Parameters

ParameterTypeDescription
colorOrGraystring | number | TextmodeColorA grayscale value (0-255), hex string ('#RGB', '#RRGGBB', '#RRGGBBAA'), or TextmodeColor instance
g?numberOptional green component (0-255) if using RGB format, or alpha (0-255) when using grayscale form
b?numberOptional blue component (0-255) if using RGB format
a?numberOptional alpha component (0-255) if using RGBA format

Returns

this

This instance for chaining.

Example

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

let source;

function createGradientCanvas() {
	const canvas = document.createElement('canvas');
	canvas.width = 160;
	canvas.height = 160;

	const ctx = canvas.getContext('2d');
	if (!ctx) return canvas;

	const gradient = ctx.createLinearGradient(0, 0, canvas.width, canvas.height);
	gradient.addColorStop(0, '#000000');
	gradient.addColorStop(1, '#ffffff');
	ctx.fillStyle = gradient;
	ctx.fillRect(0, 0, canvas.width, canvas.height);

	return canvas;
}

function drawLabel(text, y) {
	t.push();
	t.translate(-Math.floor(text.length / 2), y);
	t.charColor(255);

	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(() => {
	source = t.createTexture(createGradientCanvas());
	source.characters(' .:-=+*#%@');
	source.charColorMode('fixed');
	source.cellColorMode('fixed');
	source.cellColor(0);
});

t.draw(() => {
	t.background(0);
	if (!source) return;

	const red = 150 + 100 * Math.sin(t.frameCount * 0.05);
	const blue = 150 + 100 * Math.cos(t.frameCount * 0.05);

	source.charColor(red, 100, blue);
	t.image(source, source.width, source.height);
	drawLabel('charColor(r, 100, b)', Math.floor(t.grid.rows / 2) - 2);
});

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

Inherited from

TextmodeTexture.charColor


charColorMode()

ts
charColorMode(mode): this;

Set character color mode: 'sampled' (from source) or 'fixed'.

Parameters

ParameterTypeDescription
mode"fixed" | "sampled"The character color mode

Returns

this

This instance for chaining.

Example

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

let sampledSource;
let fixedSource;

function createColorCanvas() {
	const canvas = document.createElement('canvas');
	canvas.width = 160;
	canvas.height = 160;

	const ctx = canvas.getContext('2d');
	if (!ctx) return canvas;

	const gradient = ctx.createLinearGradient(0, 0, canvas.width, canvas.height);
	gradient.addColorStop(0, '#ffcc00');
	gradient.addColorStop(0.5, '#ff0055');
	gradient.addColorStop(1, '#3300ff');
	ctx.fillStyle = gradient;
	ctx.fillRect(0, 0, canvas.width, canvas.height);

	return canvas;
}

function drawLabel(text, x, y) {
	t.push();
	t.translate(x - Math.floor(text.length / 2), y);
	t.charColor(255);

	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(() => {
	const canvas = createColorCanvas();

	sampledSource = t.createTexture(canvas);
	sampledSource.characters(' .:-=+*#%@');
	sampledSource.charColorMode('sampled');
	sampledSource.cellColorMode('sampled');

	fixedSource = t.createTexture(canvas);
	fixedSource.characters(' .:-=+*#%@');
	fixedSource.charColorMode('fixed');
	fixedSource.charColor(255, 80, 80);
	fixedSource.cellColorMode('sampled');
});

t.draw(() => {
	t.background(0);
	if (!sampledSource || !fixedSource) return;

	const size = Math.min(sampledSource.width, sampledSource.height) * 0.7;
	const offset = Math.floor(size * 0.7);

	t.push();
	t.translate(-offset, 0);
	t.image(sampledSource, size, size);
	t.pop();

	t.push();
	t.translate(offset, 0);
	t.image(fixedSource, size, size);
	t.pop();

	drawLabel("charColorMode('sampled')", -offset, Math.floor(t.grid.rows / 2) - 2);
	drawLabel("charColorMode('fixed')", offset, Math.floor(t.grid.rows / 2) - 2);
});

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

Inherited from

TextmodeTexture.charColorMode


charRotation()

ts
charRotation(degrees): this;

Set the character rotation in degrees (0-360).

Parameters

ParameterTypeDescription
degreesnumberRotation in degrees

Returns

this

This instance for chaining.

Example

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

let source;

function createCheckerCanvas() {
	const canvas = document.createElement('canvas');
	canvas.width = 160;
	canvas.height = 160;

	const ctx = canvas.getContext('2d');
	if (!ctx) return canvas;

	ctx.fillStyle = '#ffffff';
	ctx.fillRect(0, 0, canvas.width, canvas.height);
	ctx.fillStyle = '#000000';
	ctx.fillRect(0, 0, canvas.width / 2, canvas.height / 2);
	ctx.fillRect(canvas.width / 2, canvas.height / 2, canvas.width / 2, canvas.height / 2);

	return canvas;
}

function drawLabel(text, x, y) {
	t.push();
	t.translate(x - Math.floor(text.length / 2), y);
	t.charColor(255);

	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(() => {
	source = t.createTexture(createCheckerCanvas());
	source.characters(' .:-=+*#%@');
});

t.draw(() => {
	t.background(0);
	if (!source) return;

	const size = Math.min(source.width, source.height) * 0.7;
	const offset = Math.floor(size * 0.7);

	source.charRotation(0);
	t.push();
	t.translate(-offset, 0);
	t.image(source, size, size);
	t.pop();

	source.charRotation(90);
	t.push();
	t.translate(offset, 0);
	t.image(source, size, size);
	t.pop();

	drawLabel('charRotation(0)', -offset, Math.floor(t.grid.rows / 2) - 2);
	drawLabel('charRotation(90)', offset, Math.floor(t.grid.rows / 2) - 2);
});

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

Inherited from

TextmodeTexture.charRotation


conversionMode()

ts
conversionMode(mode): this;

Select the conversion mode for this source.

textmode.js includes only a single built-in conversion strategy 'brightness'.

Additional conversion strategies may be provided via add-on libraries.

Parameters

ParameterTypeDescription
modestringConversion mode to use.

Returns

this

This instance for chaining.

Example

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

let source;

function createGradientCanvas() {
	const canvas = document.createElement('canvas');
	canvas.width = 160;
	canvas.height = 160;

	const ctx = canvas.getContext('2d');
	if (!ctx) return canvas;

	const gradient = ctx.createLinearGradient(0, 0, canvas.width, canvas.height);
	gradient.addColorStop(0, '#040404');
	gradient.addColorStop(0.5, '#888888');
	gradient.addColorStop(1, '#f8f8f8');
	ctx.fillStyle = gradient;
	ctx.fillRect(0, 0, canvas.width, canvas.height);

	return canvas;
}

function drawLabel(text, y) {
	t.push();
	t.translate(-Math.floor(text.length / 2), y);
	t.charColor(255);

	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(() => {
	source = t.createTexture(createGradientCanvas());
	source.conversionMode('brightness');
	source.characters(' .:-=+*#%@');
});

t.draw(() => {
	t.background(0);
	if (!source) return;

	t.image(source, source.width, source.height);
	drawLabel("conversionMode('brightness')", Math.floor(t.grid.rows / 2) - 2);
});

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

Inherited from

TextmodeTexture.conversionMode


dispose()

ts
dispose(): void;

Dispose the video source and release the backing media element.

Returns

void

Example

javascript
const VIDEO_URL = 'https://interactive-examples.mdn.mozilla.net/media/cc0-videos/flower.mp4';
const t = textmode.create({ width: window.innerWidth, height: window.innerHeight, fontSize: 16 });

let video = null;
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 () => {
	video = await t.loadVideo(VIDEO_URL);
	video.characters(' .:-=+*#%@');
	await video.play();
});

t.draw(() => {
	t.background(5, 7, 18);

	if (video && !disposed) {
		t.image(video, t.grid.cols - 8, t.grid.rows - 10);
	}

	label('click to dispose video', -Math.floor(t.grid.rows * 0.34), [255, 225, 140]);
	label(disposed ? 'video disposed' : 'video active', Math.floor(t.grid.rows * 0.30), [120, 205, 255]);
});

t.mouseClicked(() => {
	if (!video || disposed) {
		return;
	}

	video.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

TextmodeTexture.dispose


flipX()

ts
flipX(v): this;

Set horizontal flip indicator flag.

Parameters

ParameterTypeDefault valueDescription
vnumber | booleantrueFlip flag

Returns

this

This instance for chaining.

Example

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

let source;

function createArrowCanvas() {
	const canvas = document.createElement('canvas');
	canvas.width = 160;
	canvas.height = 160;

	const ctx = canvas.getContext('2d');
	if (!ctx) return canvas;

	ctx.fillStyle = '#111111';
	ctx.fillRect(0, 0, canvas.width, canvas.height);
	ctx.fillStyle = '#ffffff';
	ctx.beginPath();
	ctx.moveTo(24, 80);
	ctx.lineTo(104, 28);
	ctx.lineTo(104, 60);
	ctx.lineTo(136, 60);
	ctx.lineTo(136, 100);
	ctx.lineTo(104, 100);
	ctx.lineTo(104, 132);
	ctx.closePath();
	ctx.fill();

	return canvas;
}

function drawLabel(text, x, y) {
	t.push();
	t.translate(x - Math.floor(text.length / 2), y);
	t.charColor(255);

	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(() => {
	source = t.createTexture(createArrowCanvas());
	source.characters(' .:-=+*#%@');
});

t.draw(() => {
	t.background(5, 5, 15);
	if (!source) return;

	const size = Math.min(source.width, source.height) * 0.7;
	const offset = Math.floor(size * 0.7);

	source.flipX(false);
	t.push();
	t.translate(-offset, 0);
	t.image(source, size, size);
	t.pop();

	source.flipX(true);
	t.push();
	t.translate(offset, 0);
	t.image(source, size, size);
	t.pop();

	drawLabel('flipX(false)', -offset, Math.floor(t.grid.rows / 2) - 2);
	drawLabel('flipX(true)', offset, Math.floor(t.grid.rows / 2) - 2);
});

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

Inherited from

TextmodeTexture.flipX


flipY()

ts
flipY(v): this;

Set vertical flip indicator flag.

Parameters

ParameterTypeDefault valueDescription
vnumber | booleantrueFlip flag

Returns

this

This instance for chaining.

Example

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

let source;

function createArrowCanvas() {
	const canvas = document.createElement('canvas');
	canvas.width = 160;
	canvas.height = 160;

	const ctx = canvas.getContext('2d');
	if (!ctx) return canvas;

	ctx.fillStyle = '#101010';
	ctx.fillRect(0, 0, canvas.width, canvas.height);
	ctx.fillStyle = '#ffffff';
	ctx.beginPath();
	ctx.moveTo(80, 24);
	ctx.lineTo(132, 104);
	ctx.lineTo(100, 104);
	ctx.lineTo(100, 136);
	ctx.lineTo(60, 136);
	ctx.lineTo(60, 104);
	ctx.lineTo(28, 104);
	ctx.closePath();
	ctx.fill();

	return canvas;
}

function drawLabel(text, x, y) {
	t.push();
	t.translate(x - Math.floor(text.length / 2), y);
	t.charColor(255);

	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(() => {
	source = t.createTexture(createArrowCanvas());
	source.characters(' .:-=+*#%@');
});

t.draw(() => {
	t.background(0);
	if (!source) return;

	const size = Math.min(source.width, source.height) * 0.7;
	const offset = Math.floor(size * 0.7);

	source.flipY(false);
	t.push();
	t.translate(-offset, 0);
	t.image(source, size, size);
	t.pop();

	source.flipY(true);
	t.push();
	t.translate(offset, 0);
	t.image(source, size, size);
	t.pop();

	drawLabel('flipY(false)', -offset, Math.floor(t.grid.rows / 2) - 2);
	drawLabel('flipY(true)', offset, Math.floor(t.grid.rows / 2) - 2);
});

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

Inherited from

TextmodeTexture.flipY


invert()

ts
invert(v): this;

Set the invert flag, swapping character and cell colors when enabled.

Parameters

ParameterTypeDefault valueDescription
vnumber | booleantrueInvert flag

Returns

this

This instance for chaining.

Example

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

let normalSource;
let invertedSource;

function createGradientCanvas() {
	const canvas = document.createElement('canvas');
	canvas.width = 160;
	canvas.height = 160;

	const ctx = canvas.getContext('2d');
	if (!ctx) return canvas;

	const gradient = ctx.createLinearGradient(0, 0, canvas.width, canvas.height);
	gradient.addColorStop(0, '#050505');
	gradient.addColorStop(1, '#f5f5f5');
	ctx.fillStyle = gradient;
	ctx.fillRect(0, 0, canvas.width, canvas.height);

	return canvas;
}

function drawLabel(text, x, y) {
	t.push();
	t.translate(x - Math.floor(text.length / 2), y);
	t.charColor(255);

	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(() => {
	const canvas = createGradientCanvas();

	normalSource = t.createTexture(canvas);
	normalSource.characters(' .:-=+*#%@');

	invertedSource = t.createTexture(canvas);
	invertedSource.characters(' .:-=+*#%@');
	invertedSource.invert(true);
});

t.draw(() => {
	t.background(0);
	if (!normalSource || !invertedSource) return;

	const size = Math.min(normalSource.width, normalSource.height) * 0.7;
	const offset = Math.floor(size * 0.7);

	t.push();
	t.translate(-offset, 0);
	t.image(normalSource, size, size);
	t.pop();

	t.push();
	t.translate(offset, 0);
	t.image(invertedSource, size, size);
	t.pop();

	drawLabel('invert(false)', -offset, Math.floor(t.grid.rows / 2) - 2);
	drawLabel('invert(true)', offset, Math.floor(t.grid.rows / 2) - 2);
});

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

Inherited from

TextmodeTexture.invert


loop()

ts
loop(shouldLoop): this;

Set whether the video should loop.

Parameters

ParameterTypeDefault valueDescription
shouldLoopbooleantrueWhether to loop (defaults to true)

Returns

this

Example

javascript
const VIDEO_URL = 'https://interactive-examples.mdn.mozilla.net/media/cc0-videos/flower.mp4';
const t = textmode.create({ width: window.innerWidth, height: window.innerHeight });

let video;

function drawLabel(text, y) {
	t.push();
	t.translate(-Math.floor(text.length / 2), y);
	t.charColor(255);

	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 () => {
	video = await t.loadVideo(VIDEO_URL);
	video.characters(' .:-=+*#%@');
	video.loop(false);
	await video.play();
});

t.draw(() => {
	t.background(0);
	if (!video) return;

	t.image(video);
	drawLabel('loop(false) with manual restart', Math.floor(t.grid.rows / 2) - 2);

	if (!video.isPlaying && video.currentTime >= video.duration) {
		video.time(0);
		void video.play();
	}
});

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

pause()

ts
pause(): void;

Pause the video.

Returns

void

Example

javascript
const VIDEO_URL = 'https://interactive-examples.mdn.mozilla.net/media/cc0-videos/flower.mp4';
const t = textmode.create({ width: window.innerWidth, height: window.innerHeight });

let video;

function drawLabel(text, y) {
	t.push();
	t.translate(-Math.floor(text.length / 2), y);
	t.charColor(255);

	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 () => {
	video = await t.loadVideo(VIDEO_URL);
	video.characters(' .:-=+*#%@');
	video.loop();
	await video.play();
});

t.draw(() => {
	t.background(0);
	if (!video) return;

	t.image(video);
	drawLabel(video.isPlaying ? 'click to pause()' : 'click to resume with play()', Math.floor(t.grid.rows / 2) - 2);
});

t.mouseClicked(async () => {
	if (!video) return;

	if (video.isPlaying) {
		video.pause();
		return;
	}

	await video.play();
});

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

play()

ts
play(): Promise<void>;

Play the video.

Returns

Promise<void>

Promise that resolves when playback starts

Example

javascript
const VIDEO_URL = 'https://interactive-examples.mdn.mozilla.net/media/cc0-videos/flower.mp4';
const t = textmode.create({ width: window.innerWidth, height: window.innerHeight });

let video;

function drawLabel(text, y) {
	t.push();
	t.translate(-Math.floor(text.length / 2), y);
	t.charColor(255);

	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 () => {
	video = await t.loadVideo(VIDEO_URL);
	video.characters(' .:-=+*#%@');
	await video.play();
	video.pause();
	video.time(0);
});

t.draw(() => {
	t.background(0);
	if (!video) return;

	t.image(video);
	drawLabel(video.isPlaying ? 'click to restart playback' : 'click to call play()', Math.floor(t.grid.rows / 2) - 2);
});

t.mouseClicked(async () => {
	if (!video) return;

	video.time(0);
	await video.play();
});

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

speed()

ts
speed(rate): this;

Set the playback speed.

Parameters

ParameterTypeDescription
ratenumberPlayback rate (1.0 = normal speed)

Returns

this

Example

javascript
const VIDEO_URL = 'https://interactive-examples.mdn.mozilla.net/media/cc0-videos/flower.mp4';
const t = textmode.create({ width: window.innerWidth, height: window.innerHeight });

let video;

function drawLabel(text, y) {
	t.push();
	t.translate(-Math.floor(text.length / 2), y);
	t.charColor(255);

	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 () => {
	video = await t.loadVideo(VIDEO_URL);
	video.characters(' .:-=+*#%@');
	video.loop();
	await video.play();
});

t.draw(() => {
	t.background(0);
	if (!video) return;

	const halfWidth = t.grid.cols / 2;
	const normalizedX = (t.mouse.x + halfWidth) / t.grid.cols;
	const clampedX = Math.max(0, Math.min(1, normalizedX));
	const rate = 0.1 + clampedX * 3.9;

	video.speed(rate);
	t.image(video);
	drawLabel(`speed(${rate.toFixed(1)})`, Math.floor(t.grid.rows / 2) - 2);
});

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

stop()

ts
stop(): void;

Stop the video and reset to beginning.

Returns

void

Example

javascript
const VIDEO_URL = 'https://interactive-examples.mdn.mozilla.net/media/cc0-videos/flower.mp4';
const t = textmode.create({ width: window.innerWidth, height: window.innerHeight });

let video;
let restartTimeout = null;

function drawLabel(text, y) {
	t.push();
	t.translate(-Math.floor(text.length / 2), y);
	t.charColor(255);

	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 () => {
	video = await t.loadVideo(VIDEO_URL);
	video.characters(' .:-=+*#%@');
	video.loop();
	await video.play();
});

t.draw(() => {
	t.background(0);
	if (!video) return;

	t.image(video);
	drawLabel("press 's' to stop()", Math.floor(t.grid.rows / 2) - 2);
});

t.keyPressed(() => {
	if (!video || !t.isKeyPressed('s')) return;

	video.stop();
	if (restartTimeout) clearTimeout(restartTimeout);
	restartTimeout = setTimeout(() => {
		void video.play();
		restartTimeout = null;
	}, 1000);
});

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

time()

ts
time(seconds): this;

Set the current time position in the video.

Parameters

ParameterTypeDescription
secondsnumberTime in seconds

Returns

this

Example

javascript
const VIDEO_URL = 'https://interactive-examples.mdn.mozilla.net/media/cc0-videos/flower.mp4';
const t = textmode.create({ width: window.innerWidth, height: window.innerHeight });

let video;

function drawLabel(text, y) {
	t.push();
	t.translate(-Math.floor(text.length / 2), y);
	t.charColor(255);

	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 () => {
	video = await t.loadVideo(VIDEO_URL);
	video.characters(' .:-=+*#%@');
	video.loop();
	await video.play();
});

t.draw(() => {
	t.background(0);
	if (!video) return;

	t.image(video);
	drawLabel('click to jump with time()', Math.floor(t.grid.rows / 2) - 2);
	drawLabel(`${video.currentTime.toFixed(1)}s / ${video.duration.toFixed(1)}s`, Math.floor(t.grid.rows / 2) - 4);
});

t.mouseClicked(() => {
	if (!video) return;

	video.time(Math.random() * video.duration);
});

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

volume()

ts
volume(level): this;

Set the volume.

Parameters

ParameterTypeDescription
levelnumberVolume level (0.0-1.0) Videos loaded through Textmodifier.loadVideo start muted to satisfy autoplay rules. Unmute the underlying videoElement in response to a user gesture before expecting audible volume changes.

Returns

this

Example

javascript
const VIDEO_URL = 'https://interactive-examples.mdn.mozilla.net/media/cc0-videos/flower.mp4';
const t = textmode.create({ width: window.innerWidth, height: window.innerHeight });

let video;
let audioEnabled = false;

function drawLabel(text, y) {
	t.push();
	t.translate(-Math.floor(text.length / 2), y);
	t.charColor(255);

	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 () => {
	video = await t.loadVideo(VIDEO_URL);
	video.characters(' .:-=+*#%@');
	video.loop();
	await video.play();
});

t.draw(() => {
	t.background(0);
	if (!video) return;

	t.image(video);

	if (audioEnabled) {
		const halfHeight = t.grid.rows / 2;
		const normalizedY = (t.mouse.y + halfHeight) / t.grid.rows;
		const level = 1 - Math.max(0, Math.min(1, normalizedY));

		video.volume(level);
		drawLabel(`volume(${level.toFixed(2)})`, Math.floor(t.grid.rows / 2) - 4);
	} else {
		drawLabel('click once to unmute videoElement', Math.floor(t.grid.rows / 2) - 4);
	}

	drawLabel('move vertically to change volume()', Math.floor(t.grid.rows / 2) - 2);
});

t.mouseClicked(async () => {
	if (!video || audioEnabled) return;

	video.videoElement.muted = false;
	audioEnabled = true;
	await video.play();
});

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