textmode.js / loadables / 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
duration
Get Signature
get duration(): number;Total duration of the video in seconds.
Returns
number
height
Get Signature
get height(): number;Ideal height in grid cells.
Returns
number
Inherited from
isPlaying
Get Signature
get isPlaying(): boolean;Whether the video is currently playing.
Returns
boolean
originalHeight
Get Signature
get originalHeight(): number;Original pixel height.
Returns
number
Inherited from
TextmodeTexture.originalHeight
originalWidth
Get Signature
get originalWidth(): number;Original pixel width.
Returns
number
Inherited from
source
Get Signature
get source(): HTMLCanvasElement | HTMLVideoElement;The source element this texture captures from.
Returns
HTMLCanvasElement | HTMLVideoElement
Inherited from
texture
Get Signature
get texture(): WebGLTexture;Return the WebGL texture currently backing this source.
Returns
WebGLTexture
Inherited from
videoElement
Get Signature
get videoElement(): HTMLVideoElement;The underlying HTML video element.
Returns
HTMLVideoElement
width
Get Signature
get width(): number;Ideal width in grid cells.
Returns
number
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 | "sampled" | "fixed" | 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 | "sampled" | "fixed" | 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 of the resource and free associated WebGL textures.
This should be called when the resource is no longer needed to prevent memory leaks. Resources created via Textmodifier.loadImage, Textmodifier.loadVideo, and Textmodifier.createTexture are automatically disposed when the Textmodifier instance is destroyed, but you can call this manually to free memory earlier.
Returns
void
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);
});