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
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);
});
Extends
Accessors
currentTime
Get Signature
get currentTime(): number;Current playback time in seconds.
Returns
number
Example
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);
});
duration
Get Signature
get duration(): number;Total duration of the video in seconds.
Returns
number
Example
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);
});
height
Get Signature
get height(): number;Ideal height in grid cells.
Returns
number
Example
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);
});
Inherited from
isPlaying
Get Signature
get isPlaying(): boolean;Whether the video is currently playing.
Returns
boolean
Example
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);
});
originalHeight
Get Signature
get originalHeight(): number;Original pixel height.
Returns
number
Example
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);
});
Inherited from
TextmodeTexture.originalHeight
originalWidth
Get Signature
get originalWidth(): number;Original pixel width.
Returns
number
Example
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);
});
Inherited from
source
Get Signature
get source(): HTMLCanvasElement | HTMLVideoElement;The source element this texture captures from.
Returns
HTMLCanvasElement | HTMLVideoElement
Example
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);
});
Inherited from
texture
Get Signature
get texture(): WebGLTexture;Return the WebGL texture currently backing this source.
Returns
WebGLTexture
Example
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);
});
Inherited from
videoElement
Get Signature
get videoElement(): HTMLVideoElement;The underlying HTML video element.
Returns
HTMLVideoElement
Example
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);
});
width
Get Signature
get width(): number;Ideal width in grid cells.
Returns
number
Example
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);
});
Inherited from
Methods
_hasFrameOverrides()
_hasFrameOverrides(): boolean;Returns
boolean
Inherited from
TextmodeTexture._hasFrameOverrides
background()
background(
colorOrGray,
g?,
b?,
a?): this;Defines the background color used for transparent pixels.
Parameters
| Parameter | Type | Description |
|---|---|---|
colorOrGray | string | number | TextmodeColor | A grayscale value (0-255), hex string ('#RGB', '#RRGGBB', '#RRGGBBAA'), or TextmodeColor instance |
g? | number | Optional green component (0-255) if using RGB format, or alpha (0-255) when using grayscale form |
b? | number | Optional blue component (0-255) if using RGB format |
a? | number | Optional alpha component (0-255) if using RGBA format |
Returns
this
This instance for chaining.
Example
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);
});
Inherited from
cellColor()
cellColor(
colorOrGray,
g?,
b?,
a?): this;Defines the cell color when cellColorMode is 'fixed'.
Parameters
| Parameter | Type | Description |
|---|---|---|
colorOrGray | string | number | TextmodeColor | A grayscale value (0-255), hex string ('#RGB', '#RRGGBB', '#RRGGBBAA'), or TextmodeColor instance |
g? | number | Optional green component (0-255) if using RGB format, or alpha (0-255) when using grayscale form |
b? | number | Optional blue component (0-255) if using RGB format |
a? | number | Optional alpha component (0-255) if using RGBA format |
Returns
this
This instance for chaining.
Example
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);
});
Inherited from
cellColorMode()
cellColorMode(mode): this;Set cell color mode: 'sampled' (from source) or 'fixed'.
Parameters
| Parameter | Type | Description |
|---|---|---|
mode | "fixed" | "sampled" | The cell color mode |
Returns
this
This instance for chaining.
Example
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);
});
Inherited from
characters()
characters(chars): this;Define the characters to use for brightness mapping as a string. Maximum length is 255; excess characters are ignored.
Parameters
| Parameter | Type | Description |
|---|---|---|
chars | string | String of characters to map |
Returns
this
This instance for chaining.
Example
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);
});
Inherited from
charColor()
charColor(
colorOrGray,
g?,
b?,
a?): this;Defines the character color when charColorMode is 'fixed'.
Parameters
| Parameter | Type | Description |
|---|---|---|
colorOrGray | string | number | TextmodeColor | A grayscale value (0-255), hex string ('#RGB', '#RRGGBB', '#RRGGBBAA'), or TextmodeColor instance |
g? | number | Optional green component (0-255) if using RGB format, or alpha (0-255) when using grayscale form |
b? | number | Optional blue component (0-255) if using RGB format |
a? | number | Optional alpha component (0-255) if using RGBA format |
Returns
this
This instance for chaining.
Example
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);
});
Inherited from
charColorMode()
charColorMode(mode): this;Set character color mode: 'sampled' (from source) or 'fixed'.
Parameters
| Parameter | Type | Description |
|---|---|---|
mode | "fixed" | "sampled" | The character color mode |
Returns
this
This instance for chaining.
Example
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);
});
Inherited from
charRotation()
charRotation(degrees): this;Set the character rotation in degrees (0-360).
Parameters
| Parameter | Type | Description |
|---|---|---|
degrees | number | Rotation in degrees |
Returns
this
This instance for chaining.
Example
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);
});
Inherited from
conversionMode()
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
| Parameter | Type | Description |
|---|---|---|
mode | string | Conversion mode to use. |
Returns
this
This instance for chaining.
Example
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);
});
Inherited from
TextmodeTexture.conversionMode
dispose()
dispose(): void;Dispose the video source and release the backing media element.
Returns
void
Example
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);
});
Overrides
flipX()
flipX(v): this;Set horizontal flip indicator flag.
Parameters
| Parameter | Type | Default value | Description |
|---|---|---|---|
v | number | boolean | true | Flip flag |
Returns
this
This instance for chaining.
Example
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);
});
Inherited from
flipY()
flipY(v): this;Set vertical flip indicator flag.
Parameters
| Parameter | Type | Default value | Description |
|---|---|---|---|
v | number | boolean | true | Flip flag |
Returns
this
This instance for chaining.
Example
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);
});
Inherited from
invert()
invert(v): this;Set the invert flag, swapping character and cell colors when enabled.
Parameters
| Parameter | Type | Default value | Description |
|---|---|---|---|
v | number | boolean | true | Invert flag |
Returns
this
This instance for chaining.
Example
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);
});
Inherited from
loop()
loop(shouldLoop): this;Set whether the video should loop.
Parameters
| Parameter | Type | Default value | Description |
|---|---|---|---|
shouldLoop | boolean | true | Whether to loop (defaults to true) |
Returns
this
Example
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);
});
pause()
pause(): void;Pause the video.
Returns
void
Example
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);
});
play()
play(): Promise<void>;Play the video.
Returns
Promise<void>
Promise that resolves when playback starts
Example
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);
});
speed()
speed(rate): this;Set the playback speed.
Parameters
| Parameter | Type | Description |
|---|---|---|
rate | number | Playback rate (1.0 = normal speed) |
Returns
this
Example
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);
});
stop()
stop(): void;Stop the video and reset to beginning.
Returns
void
Example
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);
});
time()
time(seconds): this;Set the current time position in the video.
Parameters
| Parameter | Type | Description |
|---|---|---|
seconds | number | Time in seconds |
Returns
this
Example
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);
});
volume()
volume(level): this;Set the volume.
Parameters
| Parameter | Type | Description |
|---|---|---|
level | number | Volume 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
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);
});