textmode.js / loadables / TextmodeSource
Abstract Class: TextmodeSource
Abstract base class representing a textmode source asset (image, video, texture).
Extends
Disposable
Extended by
Accessors
height
Get Signature
get height(): number;Ideal height in grid cells.
Returns
number
originalHeight
Get Signature
get originalHeight(): number;Original pixel height.
Returns
number
originalWidth
Get Signature
get originalWidth(): number;Original pixel width.
Returns
number
texture
Get Signature
get texture(): WebGLTexture;Return the WebGL texture currently backing this source.
Returns
WebGLTexture
width
Get Signature
get width(): number;Ideal width in grid cells.
Returns
number
Methods
_hasFrameOverrides()
_hasFrameOverrides(): boolean;Returns
boolean
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);
});
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);
});
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);
});
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);
});
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);
});
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);
});
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);
});
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);
});
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
Disposable.disposeflipX()
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);
});
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);
});
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);
});