Skip to content

textmode.js / Textmodifier

Class: Textmodifier

Manages textmode rendering on a HTMLCanvasElement and provides methods for drawing, font management, event handling, and animation control.

If the Textmodifier instance is created without a canvas parameter, it creates a new HTMLCanvasElement to draw on using the textmode.js drawing API. If a canvas is provided, it will use that canvas instead.

Extends

  • (Anonymous class)<this>.IRenderingMixin.IFontMixin.IAnimationMixin.IMouseMixin.ITouchMixin.IKeyboardMixin

Implements

  • ITextmodifier

Accessors

canvas

Get Signature

ts
get canvas(): HTMLCanvasElement;

Get the textmodifier canvas containing the rendered output.

Returns

HTMLCanvasElement

Implementation of

ts
ITextmodifier.canvas

drawFramebuffer

Get Signature

ts
get drawFramebuffer(): TextmodeFramebuffer;

Get the WebGL framebuffer used for drawing operations in Textmodifier.draw.

Returns

TextmodeFramebuffer

Implementation of

ts
ITextmodifier.drawFramebuffer

font

Get Signature

ts
get font(): TextmodeFont;

Get the current font object used for rendering.

Returns

TextmodeFont

Implementation of

ts
ITextmodifier.font

frameCount

Get Signature

ts
get frameCount(): number;

Get the current frame count.

Returns

number

Set Signature

ts
set frameCount(value): void;

Set the current frame count.

Parameters
ParameterType
valuenumber
Returns

void

Implementation of

ts
ITextmodifier.frameCount

grid

Get Signature

ts
get grid(): TextmodeGrid;

Get the current grid object used for rendering.

Returns

TextmodeGrid

Implementation of

ts
ITextmodifier.grid

height

Get Signature

ts
get height(): number;

Get the height of the canvas in pixels.

Returns

number

Implementation of

ts
ITextmodifier.height

isDisposed

Get Signature

ts
get isDisposed(): boolean;

Check if the instance has been disposed/destroyed.

Returns

boolean

Implementation of

ts
ITextmodifier.isDisposed

lastKeyPressed

Get Signature

ts
get lastKeyPressed(): null | string;

Get the last key that was pressed.

Returns the key string of the last pressed key, or null if no key has been pressed.

Show example
javascript
const t = textmode.create({ width: 800, height: 600 });

t.draw(() => {
  t.background(0);

  const lastKey = t.lastKeyPressed;
  if (lastKey) {
    // Display the last pressed key
    t.char(lastKey);
    t.charColor(255, 255, 255);
    t.point();
  }
});
Returns

null | string

Implementation of

ts
ITextmodifier.lastKeyPressed

lastKeyReleased

Get Signature

ts
get lastKeyReleased(): null | string;

Get the last key that was released.

Returns the key string of the last released key, or null if no key has been released.

Show example
javascript
const t = textmode.create({ width: 800, height: 600 });

t.draw(() => {
  t.background(0);

  const lastKey = t.lastKeyReleased;
  if (lastKey) {
    // Display the last released key
    t.char(lastKey);
    t.charColor(128, 128, 128);
    t.point();
  }
});
Returns

null | string

Implementation of

ts
ITextmodifier.lastKeyReleased

loading

Get Signature

ts
get loading(): LoadingScreenManager;

Provides access to the loading screen manager to control boot-time loading UX.

Show example
javascript
const t = textmode.create({ width: 800, height: 600, loadingScreen: { message: 'loading...' } });

t.setup(async () => {
  // Initialize two loading phases
  const phase1 = t.loading.addPhase('Loading assets');
  const phase2 = t.loading.addPhase('Initializing game');

  // Start the first phase and simulate asset loading
  await phase1.track(async () => {
    for (let i = 0; i <= 5; i++) {
      phase1.report(i / 5);
      // Small delay — increases visibility of the loading animation
      await new Promise((r) => setTimeout(r, 200));
    }
  });

  // Start the second phase and simulate initialization
  await phase2.track(async () => {
    for (let i = 0; i <= 5; i++) {
      phase2.report(i / 5);
      await new Promise((r) => setTimeout(r, 150));
    }
  });

  // Optionally set a final message before the screen transitions away
  t.loading.message('Ready - enjoy!');
});
Returns

LoadingScreenManager

Implementation of

ts
ITextmodifier.loading

modifierState

Get Signature

ts
get modifierState(): object;

Get current modifier key states.

Returns an object with boolean properties for each modifier key.

Show example
javascript
const t = textmode.create({ width: 800, height: 600 });

t.draw(() => {
    t.background(0);
    const mods = t.modifierState;

    // Change behavior based on modifier keys
    if (mods.shift) {
        // Draw in caps or with different behavior
        t.char('S');
        t.charColor(255, 255, 0);
        t.point();
    }

    if (mods.ctrl) {
        // Control key is pressed
        t.translate(2, 0);
        t.char('C');
        t.charColor(0, 255, 255);
        t.point();
    }
});
Returns
NameTypeDescription
altbooleanWhether the Alt key is currently pressed
ctrlbooleanWhether the Ctrl key is currently pressed
metabooleanWhether the Meta key (Command on Mac, Windows key on Windows) is currently pressed
shiftbooleanWhether the Shift key is currently pressed

Implementation of

ts
ITextmodifier.modifierState

mouse

Get Signature

ts
get mouse(): MousePosition;

Get the current mouse position in grid coordinates.

Returns the mouse position as grid cell coordinates (column, row).

If the mouse is outside the grid or the instance is not ready, it returns { x: -1, y: -1 }.

Show example
javascript
const t = textmode.create({ width: 800, height: 600 });

t.draw(() => {
    t.background(0);
    
    // Convert mouse position from top-left origin to center-based origin
    const centerX = Math.round(t.mouse.x - (t.grid.cols - 1) / 2);
    const centerY = Math.round(t.mouse.y - (t.grid.rows - 1) / 2);
    
    t.translate(centerX, centerY);
    t.char('*');
    t.charColor(255, 0, 0);
    t.cellColor(100);
    t.point();
});
Returns

MousePosition

Implementation of

ts
ITextmodifier.mouse

overlay

Get Signature

ts
get overlay(): 
  | undefined
  | TextmodeImage;

If in overlay mode, returns the TextmodeImage instance capturing the target canvas/video content, allowing further configuration of the conversion parameters.

Show example
javascript
// Create the textmode instance using the p5 canvas as input overlay
const t = textmode.create({ fontSize: 16, canvas: p.canvas, overlay: true });

// Configure overlay conversion once fonts and grid are ready
t.setup(() => {
  t.overlay
    .characters(' .:-=+*#%@')        // Character set for brightness mapping
    .cellColorMode('fixed')          // Use fixed background cell color
    .cellColor(0, 0, 0)              // Black background for each cell
    .charColorMode('sampled')        // Sample the character color from the image
    .background(0, 0, 0, 255);       // Black fallback for transparent pixels
});

// In the draw loop, pass the overlay into the text grid
t.draw(() => {
  t.clear();
  t.image(t.overlay, t.grid.cols, t.grid.rows);
});
Returns

| undefined | TextmodeImage

Implementation of

ts
ITextmodifier.overlay

pressedKeys

Get Signature

ts
get pressedKeys(): string[];

Get all currently pressed keys.

Returns an array of key strings that are currently being held down.

Show example
javascript
const t = textmode.create({ width: 800, height: 600 });

t.draw(() => {
    t.background(0);

    const pressed = t.pressedKeys;

    // Display all currently pressed keys
    pressed.forEach((key, index) => {
        t.push();
        t.char(key[0] || '?'); // Show first character of key name
        t.charColor(255, 200, 100);
        t.translate(index, 0);
        t.point();
        t.pop();
    });
});
Returns

string[]

Implementation of

ts
ITextmodifier.pressedKeys

touches

Get Signature

ts
get touches(): TouchPosition[];

Get the currently active touches in grid coordinates.

Returns a copy of each touch, including grid position, client coordinates, and pressure when available. Use this inside a draw loop to react to active multi-touch scenarios.

Show example
javascript
t.draw(() => {
  for (const touch of t.touches) {
    t.point(touch.x, touch.y);
  }
});
Returns

TouchPosition[]

Implementation of

ts
ITextmodifier.touches

width

Get Signature

ts
get width(): number;

Get the width of the canvas in pixels.

Returns

number

Implementation of

ts
ITextmodifier.width

Methods

arc()

ts
arc(
   width, 
   height, 
   startAngle, 
   endAngle): void;

Draw an arc with the current settings. Position is controlled via translate, push, and pop.

Parameters

ParameterTypeDescription
widthnumberWidth of the arc
heightnumberHeight of the arc
startAnglenumberStarting angle in degrees
endAnglenumberEnding angle in degrees

Returns

void

Show example
javascript
const t = textmode.create({
  width: 800,
  height: 600,
})

t.draw(() => {
  t.background(0);
  t.rotateZ(t.frameCount);
  t.char('A');
  t.arc(10, 10, 0, 90);
});

Implementation of

ts
ITextmodifier.arc

background()

ts
background(
   value, 
   g?, 
   b?, 
   a?): void;

Set the background color for the canvas.

Parameters

ParameterTypeDescription
valuestring | number | TextmodeColorA TextmodeColor, hex string, grayscale value, or single RGB channel
g?numberOptional green component when providing RGB channels or alpha when used with grayscale
b?numberOptional blue component when providing RGB channels
a?numberOptional alpha component (0-255)

Returns

void

Show example
javascript
const t = textmode.create({
  width: 800,
  height: 600,
});

const midnight = t.color('#0b1d3a');

t.draw(() => {
  // Set the background using a reusable color
  t.background(midnight);

  // Or inline RGB(A) notation
  //t.background(32, 48, 64);

  // Or hex string
  //t.background('#203040');

  t.char('M');
  t.rotateZ(t.frameCount * 2);
  t.rect(12, 12);
});

Implementation of

ts
ITextmodifier.background

bezierCurve()

ts
bezierCurve(
   x1, 
   y1, 
   cp1x, 
   cp1y, 
   cp2x, 
   cp2y, 
   x2, 
   y2): void;

Draw a smooth cubic bezier curve between two points with two control points. The curve thickness is controlled by the current lineWeight setting.

Parameters

ParameterTypeDescription
x1numberStart point X coordinate
y1numberStart point Y coordinate
cp1xnumberFirst control point X coordinate
cp1ynumberFirst control point Y coordinate
cp2xnumberSecond control point X coordinate
cp2ynumberSecond control point Y coordinate
x2numberEnd point X coordinate
y2numberEnd point Y coordinate

Returns

void

Show example
javascript
const t = textmode.create({
  width: 800,
  height: 600,
})

t.draw(() => {
  t.background(0);
  t.translate(-t.grid.cols / 2, -t.grid.rows / 2);

  // Draw a smooth S-curve
  t.char('*');
  t.charColor(255, 100, 255); // Magenta
  t.lineWeight(2);

  // Rotate the curve around its geometric center
  // The bezier's control points: (5,20), (15,5), (25,35), (35,20)
  // Center = average of points; translate to center then draw with local coordinates
  const cx = (5 + 15 + 25 + 35) / 4;
  const cy = (20 + 5 + 35 + 20) / 4;

  t.translate(cx, cy);
  t.rotateZ(t.frameCount * 2);
  t.bezierCurve(5 - cx, 20 - cy, 15 - cx, 5 - cy, 25 - cx, 35 - cy, 35 - cx, 20 - cy);
});

Implementation of

ts
ITextmodifier.bezierCurve

cellColor()

ts
cellColor(
   value, 
   g?, 
   b?, 
   a?): void;

Set the cell background color for subsequent rendering operations. Accepts channel values, hex strings, or a TextmodeColor instance.

Parameters

ParameterTypeDescription
valuestring | number | TextmodeColorColor object, hex string, or grayscale value (0-255)
g?numberOptional green component when providing RGB values or alpha when using grayscale form
b?numberOptional blue component when providing RGB values
a?numberOptional alpha component (0-255)

Returns

void

Show example
javascript
const t = textmode.create({
  width: 800,
  height: 600,
})

const dusk = t.color('#203040');

t.draw(() => {
  t.background(0);
  t.cellColor(dusk);
  t.char('A');
  t.rotateZ(t.frameCount * 2);
  t.rect(10, 10);
});

Implementation of

ts
ITextmodifier.cellColor

char()

ts
char(character): void;

Set the character to be used for subsequent rendering operations. Accepts a single character string or a TextmodeColor produced via color. When a color is provided, the encoded glyph information is applied if available.

Parameters

ParameterType
characterstring | TextmodeColor

Returns

void

Show example
javascript
const t = textmode.create({
  width: 800,
  height: 600,
})

let semicolon;

t.setup(() => {
 semicolon = t.color(';');
});

t.draw(() => {
  t.background(0);
  t.char('A');
  t.rect(10, 10);

  t.char(semicolon);
  t.translate(15, 0);
  t.rect(10, 10);
});

Implementation of

ts
ITextmodifier.char

charColor()

ts
charColor(
   value, 
   g?, 
   b?, 
   a?): void;

Set the character color for subsequent rendering operations. Accepts channel values, hex strings, or a TextmodeColor instance.

Parameters

ParameterTypeDescription
valuestring | number | TextmodeColorColor object, hex string, or grayscale value (0-255)
g?numberOptional green component when providing RGB values or alpha when using grayscale form
b?numberOptional blue component when providing RGB values
a?numberOptional alpha component (0-255)

Returns

void

Show example
javascript
const t = textmode.create({
  width: 800,
  height: 600,
})

const hotPink = t.color(255, 105, 180);

t.draw(() => {
  t.background(0);
  t.char('A');
  t.charColor(hotPink);
  t.rect(10, 10);
});

Implementation of

ts
ITextmodifier.charColor

charRotation()

ts
charRotation(degrees): void;

Set the character rotation angle for subsequent character rendering.

Parameters

ParameterTypeDescription
degreesnumberThe rotation angle in degrees

Returns

void

Show example
javascript
const t = textmode.create({
  width: 800,
  height: 600,
})

t.draw(() => {
  t.background(0);
  t.char('A');
  t.charRotation(90); // Rotate character 90 degrees
  t.rotateZ(t.frameCount * 2);
  t.rect(10, 10);
});

Implementation of

ts
ITextmodifier.charRotation

clear()

ts
clear(): void;

Clear the canvas.

Returns

void

Show example
javascript
const t = textmode.create({
 width: 800,
 height: 600,
})

t.draw(() => {
 // Clear the canvas
 t.clear();
});

Implementation of

ts
ITextmodifier.clear

color()

ts
color(
   value, 
   g?, 
   b?, 
   a?): TextmodeColor;

Create a reusable color object compatible with textmode drawing APIs.

Accepts grayscale, RGB, RGBA, and hex string values as arguments. Returned TextmodeColor instances can be passed to background, char, charColor, cellColor, and more.

Parameters

ParameterTypeDescription
valuestring | number | TextmodeColorGrayscale value, hex string, single character, or an existing color
g?numberOptional green component, or value when using grayscale form
b?numberOptional blue component, or value when using grayscale form
a?numberOptional alpha component when using RGB form Example usage of the color helper.

Returns

TextmodeColor

Show example
javascript
const t = textmode.create({ width: 800, height: 600 });

// Grayscale (0 = black, 255 = white)
const gray = t.color(128);

// RGB
const hotPink = t.color(255, 105, 180);

// RGBA (alpha 0-255)
const semiTransparentRed = t.color(255, 0, 0, 128);

// Hex string
const dusk = t.color('#203040');

t.draw(() => {
    // Using colors with other drawing APIs
    t.background(gray);
    t.charColor(hotPink);
    t.char('A');
    t.rect(5, 5);

    t.translate(5, 0);
    t.cellColor(dusk);
    t.char('*');
    t.rect(5, 5);

    t.translate(5, 0);
    t.charColor("#FF00FF");
    t.char("B");
    t.rect(5, 5);
});

Implementation of

ts
ITextmodifier.color

createFilterShader()

ts
createFilterShader(fragmentSource): Promise<GLShader>;

Create a custom filter shader from fragment shader source code or a file path. The fragment shader automatically receives the standard vertex shader inputs and must output to the 3 MRT attachments (character/transform, primary color, secondary color).

Parameters

ParameterTypeDescription
fragmentSourcestringThe fragment shader source code or a file path (e.g., './shader.frag')

Returns

Promise<GLShader>

A Promise that resolves to a compiled shader ready for use with shader

Show example
javascript
const t = textmode.create({
  width: 800,
  height: 600,
})

let waveShader;

t.setup(async () => {
  // Load shader from file
  waveShader = await t.createFilterShader('./shader.frag');
  
  // Or create from inline source
  // waveShader = await t.createFilterShader(`#version 300 es
  //   precision highp float;
  //   
  //   in vec2 v_uv;
  //   in vec3 v_character;
  //   in vec4 v_primaryColor;
  //   in vec4 v_secondaryColor;
  //   
  //   uniform float u_time;
  //   
  //   layout(location = 0) out vec4 o_character;
  //   layout(location = 1) out vec4 o_primaryColor;
  //   layout(location = 2) out vec4 o_secondaryColor;
  //   
  //   void main() {
  //     // Shader code here
  //   }
  // `);
});

t.draw(() => {
  if (waveShader) {
    t.shader(waveShader);
    t.setUniform('u_time', t.frameCount * 0.003);
    t.rect(t.grid.cols, t.grid.rows);
  }
});

Implementation of

ts
ITextmodifier.createFilterShader

createFramebuffer()

ts
createFramebuffer(options): TextmodeFramebuffer;

Create a new framebuffer for offscreen rendering.

The framebuffer uses the same MRT structure as the main rendering pipeline. By default it allocates 4 attachments (character + color data).

Parameters

ParameterTypeDescription
optionsTextmodeFramebufferOptionsConfiguration options for the framebuffer.

Returns

TextmodeFramebuffer

A new Framebuffer instance.

Show example
javascript
const t = textmode.create({
  width: 800,
  height: 600,
});

// Create a framebuffer with 50x30 grid cells
const fb = t.createFramebuffer({
  width: 50,
  height: 30
});

t.draw(() => {
  // Render to framebuffer
  fb.begin();
  t.background(255, 0, 0);
  t.charColor(255);
  t.char('A');
  t.rect(20, 10);
  fb.end();
  
  // Render framebuffer to main canvas
  t.background(0);
  t.rotateZ(t.frameCount * 2);
  t.image(fb);
});

Implementation of

ts
ITextmodifier.createFramebuffer

cursor()

ts
cursor(cursor?): void;

Set the mouse cursor for the textmode canvas.

Provide any valid CSS cursor value (e.g. 'default', 'pointer', 'crosshair', 'move', 'text', 'grab', 'grabbing', 'none', 'zoom-in', 'zoom-out', 'ns-resize', 'ew-resize', 'nwse-resize', 'nesw-resize', etc.), or a CSS url(...) cursor. Call with no argument or an empty string to reset to default.

See MDN for all options: https://developer.mozilla.org/en-US/docs/Web/CSS/cursor

Parameters

ParameterType
cursor?string

Returns

void

Show example
javascript
const t = textmode.create({ width: 800, height: 600 });
const target = { width: 30, height: 15 };

t.draw(() => {
  t.background(0);
  t.charColor(255); // keep char visible
  t.char('*');
  t.rect(target.width, target.height);

  // Rectangle is centered at (0, 0) which is grid center
  // Calculate bounds relative to grid center
  const centerX = t.grid.cols / 2;
  const centerY = t.grid.rows / 2;

  const halfRectWidth = target.width / 2;
  const halfRectHeight = target.height / 2;

  const rectLeft = centerX - halfRectWidth;
  const rectRight = centerX + halfRectWidth;
  const rectTop = centerY - halfRectHeight;
  const rectBottom = centerY + halfRectHeight;

  const hovering =
    t.mouse.x >= rectLeft && t.mouse.x < rectRight &&
    t.mouse.y >= rectTop && t.mouse.y < rectBottom;

  t.cursor(hovering ? 'pointer' : 'default');
});

Implementation of

ts
ITextmodifier.cursor

destroy()

ts
destroy(): void;

Completely destroy this Textmodifier instance and free all associated resources.

After calling this method, the instance should not be used and will be eligible for garbage collection.

Returns

void

Show example
javascript
// Create a textmodifier instance
const textmodifier = textmode.create();

// ...

// When done, completely clean up
textmodifier.destroy();

// Instance is now safely disposed and ready for garbage collection

Implementation of

ts
ITextmodifier.destroy

doubleTap()

ts
doubleTap(callback): void;

Register a callback for double tap gestures.

Double taps reuse the same TouchTapEventData as taps with taps set to 2. This helper lets you supply a dedicated handler when you want to treat double taps differently.

Parameters

ParameterTypeDescription
callbackTouchTapHandlerThe function to call when a double tap is detected.

Returns

void

Show example
javascript
t.doubleTap((data) => {
  console.log('Double tap detected', data.touch);
});

Implementation of

ts
ITextmodifier.doubleTap

draw()

ts
draw(callback): void;

Set a draw callback function that will be executed before each render.

This callback function is where all drawing commands should be placed for textmode rendering.

Parameters

ParameterTypeDescription
callback() => voidThe function to call before each render

Returns

void

Show example
javascript
// Create a textmodifier instance
const t = textmode.create({
 width: 800,
 height: 600,
});

// Set up draw callback
t.draw(() => {
  // Set background color
  t.background(128);
  
  // Draw a textmode rectangle
  t.char('A');
  t.rotateZ(t.frameCount * 2);
  t.rect(16, 16);
});

Implementation of

ts
ITextmodifier.draw

ellipse()

ts
ellipse(width, height): void;

Draw an ellipse with the current settings. Position is controlled via translate, push, and pop.

Parameters

ParameterTypeDescription
widthnumberWidth of the ellipse
heightnumberHeight of the ellipse

Returns

void

Show example
javascript
const t = textmode.create({
  width: 800,
  height: 600,
})

t.draw(() => {
  t.background(0);
  t.char('O');
  t.rotateZ(t.frameCount * 2);
  t.ellipse(10, 8);
});

Implementation of

ts
ITextmodifier.ellipse

flipX()

ts
flipX(toggle): void;

Toggle horizontal flipping for subsequent character rendering.

Parameters

ParameterTypeDescription
togglebooleanWhether to flip horizontally

Returns

void

Show example
javascript
const t = textmode.create({
  width: 800,
  height: 600,
})

t.draw(() => {
  t.background(0);
  t.flipX(true);
  t.rect(5, 5);
});

Implementation of

ts
ITextmodifier.flipX

flipY()

ts
flipY(toggle): void;

Toggle vertical flipping for subsequent character rendering.

Parameters

ParameterTypeDescription
togglebooleanWhether to flip vertically

Returns

void

Show example
javascript
const t = textmode.create({
  width: 800,
  height: 600,
})

t.draw(() => {
  t.background(0);
  t.flipY(true);
  t.rect(5, 5);
});

Implementation of

ts
ITextmodifier.flipY

fontSize()

ts
fontSize(size): void;

Set the font size used for rendering.

Parameters

ParameterTypeDescription
sizenumberThe font size to set.

Returns

void

Show example
javascript
// Create a Textmodifier instance
const t = textmode.create();

t.setup(() => {
 // Set the font size to 32
 t.fontSize(32);
});

t.draw(() => {
 t.background(0);
 t.char('A');
 t.rect(5, 5);
});

Implementation of

ts
ITextmodifier.fontSize

frameRate()

ts
frameRate(fps?): number | void;

Set the maximum frame rate. If called without arguments, returns the current measured frame rate.

Parameters

ParameterTypeDescription
fps?numberThe maximum frames per second for rendering.

Returns

number | void

Show example
javascript
// Create a Textmodifier instance
const textmodifier = textmode.create();

// Set the maximum frame rate to 30 FPS
textmodifier.frameRate(30);

// Draw something at the set frame rate
t.draw(() => {
  t.background(0);
  t.char('A');
  t.rect(5, 5);
});

Implementation of

ts
ITextmodifier.frameRate

image()

ts
image(
   source, 
   width?, 
   height?): void;

Draw a TextmodeFramebuffer or TextmodeSource (TextmodeImage/TextmodeVideo) to the current render target.

Parameters

ParameterTypeDescription
sourceTextmodeFramebuffer | TextmodeSourceThe TextmodeFramebuffer or TextmodeSource to render
width?numberWidth to potentially scale the content
height?numberHeight to potentially scale the content

Returns

void

Show example
javascript
const t = textmode.create({
  width: 800,
  height: 600,
});

const fb = t.createFramebuffer({width: 30, height: 20});

t.draw(() => {
  // Draw something to the framebuffer
  fb.begin();
  t.clear();
  t.charColor(255, 0, 0);
  t.char('A');
  t.rect(20, 10);
  fb.end();
  
  // Clear main canvas and render framebuffer content
  t.background(0);
  
  // Render at original size
  t.image(fb);
  
  // Render scaled version
  // t.image(fb, 60, 40);
});

Implementation of

ts
ITextmodifier.image

invert()

ts
invert(toggle): void;

Toggle color inversion for subsequent character rendering.

Parameters

ParameterTypeDescription
togglebooleanWhether to invert colors

Returns

void

Show example
javascript
const t = textmode.create({
  width: 800,
  height: 600,
})

t.draw(() => {
  t.background(0);
  t.invert(true);
  t.char('A');
  t.rotateZ(t.frameCount * 2);
  t.rect(5, 5);
});

Implementation of

ts
ITextmodifier.invert

isKeyPressed()

ts
isKeyPressed(key): boolean;

Check if a specific key is currently being pressed.

Parameters

ParameterTypeDescription
keystringThe key to check (e.g., 'a', 'Enter', 'ArrowLeft')

Returns

boolean

true if the key is currently pressed, false otherwise

Show example
javascript
const t = textmode.create({ width: 800, height: 600 });

let playerX = 0;
let playerY = 0;

t.draw(() => {
  t.background(0);
  
  // Check for arrow keys to move a character
  if (t.isKeyPressed('ArrowUp')) {
    playerY -= 1;
  }
  if (t.isKeyPressed('ArrowDown')) {
    playerY += 1;
  }
  if (t.isKeyPressed('ArrowLeft')) {
    playerX -= 1;
  }
  if (t.isKeyPressed('ArrowRight')) {
    playerX += 1;
  }
  
  // Draw player character
  t.char('@');
  t.charColor(255, 255, 0);
  t.translate(playerX, playerY);
  t.point();
});

Implementation of

ts
ITextmodifier.isKeyPressed

isLooping()

ts
isLooping(): boolean;

Check whether the textmodifier is currently running the automatic render loop.

Returns

boolean

True if the render loop is currently active, false otherwise.

Show example
javascript
const textmodifier = textmode.create(canvas);

// Check loop status in different states
console.log(textmodifier.isLooping()); // true (looping)

textmodifier.noLoop();
console.log(textmodifier.isLooping()); // false (not looping)

textmodifier.loop();
console.log(textmodifier.isLooping()); // true (looping)

Implementation of

ts
ITextmodifier.isLooping

keyPressed()

ts
keyPressed(callback): void;

Set a callback function that will be called when a key is pressed down.

Parameters

ParameterTypeDescription
callbackKeyboardEventHandlerThe function to call when a key is pressed

Returns

void

Show example
javascript
const t = textmode.create({ width: 800, height: 600 });

let lastKey = '?';
let pulse = 0;

// Update some visual state when a key is pressed
t.keyPressed((data) => {
  lastKey = data.key;
  pulse = 6; // make the next frames brighter
});

t.draw(() => {
  t.background(0);
  
  // Fade brightness back down each frame
  const glow = Math.max(0, pulse--);
  const brightness = 120 + glow * 20;
  t.charColor(brightness, brightness, 0);
  
  // Show the last pressed key at the center of the grid
  t.push();
  t.translate(t.grid.cols / 2, t.grid.rows / 2);
  t.char(lastKey.length ? lastKey[0] : '?');
  t.point();
  t.pop();
});

Implementation of

ts
ITextmodifier.keyPressed

keyReleased()

ts
keyReleased(callback): void;

Set a callback function that will be called when a key is released.

Parameters

ParameterTypeDescription
callbackKeyboardEventHandlerThe function to call when a key is released

Returns

void

Show example
javascript
const t = textmode.create({ width: 800, height: 600 });

let lastRelease = '?';
let fade = 0;

// Capture the most recent key release and trigger a pulse
t.keyReleased((data) => {
  lastRelease = data.key;
  fade = 10;
});

t.draw(() => {
  t.background(0);

  // Dim the glow over time
  const glow = Math.max(0, fade--);
  const color = 80 + glow * 17;
  t.charColor(color, color, 255);
  
  t.char(lastRelease.length ? lastRelease[0] : '?');
  t.point();
});

Implementation of

ts
ITextmodifier.keyReleased

line()

ts
line(
   x1, 
   y1, 
   x2, 
   y2): void;

Draw a line from point (x1, y1) to point (x2, y2) with the settings.

Parameters

ParameterTypeDescription
x1numberX-coordinate of the line start point
y1numberY-coordinate of the line start point
x2numberX-coordinate of the line end point
y2numberY-coordinate of the line end point

Returns

void

Show example
javascript
const t = textmode.create({
  width: 800,
  height: 600,
})

t.draw(() => {
  t.background(0);

  t.char('*');
  t.charColor(255, 100, 255); // Magenta
  t.lineWeight(2);

  const halfWidth = 5;
  const halfHeight = 7.5;

  t.push();
  t.rotateZ(t.frameCount * 2);
  t.line(-halfWidth, halfHeight, halfWidth, -halfHeight);
  t.pop();
});

Implementation of

ts
ITextmodifier.line

lineWeight()

ts
lineWeight(weight): void;

Update the line weight (thickness) for subsequent line and bezierCurve calls.

Parameters

ParameterTypeDescription
weightnumberThe line weight (thickness) to set.

Returns

void

Show example
javascript
const t = textmode.create({
    width: 800,
    height: 600,
})

t.draw(() => {
    t.background('#050810');

    // Animate the weight so every line breathes differently
    const layers = 6;
    const halfCols = t.grid.cols / 2;
    const spacing = 4;

    for (let i = 0; i < layers; i++) {
        const phase = t.frameCount * 0.03 + i * 0.8;
        const pulse = 0.75 + 3.25 * (0.5 + 0.5 * Math.sin(phase));
        const wobble = Math.sin(phase * 1.6) * 4;
        const centeredRow = (i - (layers - 1) / 2) * spacing;

        t.lineWeight(Math.round(pulse));
        t.charColor(160 + i * 12, 200 - i * 8, 255);
        t.char('-');
        t.line(
            -halfCols + 2,
            centeredRow + wobble,
            halfCols - 2,
            centeredRow - wobble,
        );
    }
});

Implementation of

ts
ITextmodifier.lineWeight

loadFont()

ts
loadFont(fontSource): Promise<void>;

Update the font used for rendering.

Parameters

ParameterTypeDescription
fontSourcestringThe URL of the font to load.

Returns

Promise<void>

Show example
javascript
// Create a Textmodifier instance
const t = textmode.create();

t.setup(async () => {
 // Load a custom font from a URL
 await t.loadFont('https://example.com/fonts/myfont.ttf');

 // Local font example
 // await t.loadFont('./fonts/myfont.ttf'); 
});

Implementation of

ts
ITextmodifier.loadFont

loadImage()

ts
loadImage(src): Promise<TextmodeImage>;

Load an image and return a TextmodeImage that can be drawn with image().

The loaded image can be rendered to the canvas using the image method. This function returns a Promise that resolves when the image has loaded.

Parameters

ParameterTypeDescription
srcstring | HTMLImageElementURL or existing HTMLImageElement

Returns

Promise<TextmodeImage>

A Promise that resolves to a TextmodeImage object

Show example
javascript
const t = textmode.create({
    width: 800,
    height: 600,
});

let img;

t.setup(async () => {
    img = await t.loadImage('https://images.unsplash.com/photo-1506905925346-21bda4d32df4?w=800&q=80');
    img.characters(" .:-=+*#%@");
});

t.draw(() => {
    t.background(0);

    if (img) {
        // Draw the loaded image
        t.image(img);
    }
});

Implementation of

ts
ITextmodifier.loadImage

loadVideo()

ts
loadVideo(src, options?): Promise<TextmodeVideo>;

Load a video and return a TextmodeVideo that can be drawn with image().

Parameters

ParameterTypeDescription
srcstring | HTMLVideoElementURL or existing HTMLVideoElement
options?TextmodeVideoOptionsOptional configuration for preloading behavior. Provide frameRate to preload frames, onProgress to observe preload progress, onComplete to know when preloading finished, and onError to catch preload failures.

Returns

Promise<TextmodeVideo>

Show example
javascript
const t = textmode.create({
    width: 800,
    height: 600,
});

let video;

t.setup(async () => {
    video = await t.loadVideo('https://interactive-examples.mdn.mozilla.net/media/cc0-videos/flower.mp4');
    // Start playback and enable looping so the video keeps playing
    video.play();
    video.loop();

    video.characters(" .:-=+*#%@");
});

t.draw(() => {
    t.background(0);

    if (video) {
        // Draw the loaded video
        t.image(video);
    }
});

Implementation of

ts
ITextmodifier.loadVideo

longPress()

ts
longPress(callback): void;

Register a callback for long press gestures.

A long press is emitted when the user keeps a finger on the canvas without moving beyond the configured tolerance. The event includes the press duration in milliseconds.

Parameters

ParameterTypeDescription
callbackTouchLongPressHandlerThe function to call when a long press gesture is detected.

Returns

void

Show example
javascript
t.longPress((data) => {
  console.log(`Long press for ${Math.round(data.duration)}ms`);
});

Implementation of

ts
ITextmodifier.longPress

loop()

ts
loop(): void;

Resume the rendering loop if it was stopped by noLoop.

Returns

void

Show example
javascript
const t = textmode.create({ width: 800, height: 600 });

// Toggle loop on SPACE
t.keyPressed((data) => {
  if (data.key === ' ') {
    if (t.isLooping()) {
      t.noLoop();
    } else {
      t.loop();
    }
  }
});

t.draw(() => {
  t.background(0);
  t.char('A');
  t.charColor(255, 255, 255);
  t.rotateZ(t.frameCount * 2);
  t.rect(16, 16);
});

Implementation of

ts
ITextmodifier.loop

mouseClicked()

ts
mouseClicked(callback): void;

Set a callback function that will be called when the mouse is clicked.

Parameters

ParameterTypeDescription
callbackMouseEventHandlerThe function to call when the mouse is clicked

Returns

void

Show example
javascript
// Click to spawn ripples.

const t = textmode.create({ width: 800, height: 600 });

// Store ripples as { x, y } in center-based coordinates
const ripples = [];

// Create a ripple at the clicked grid cell
t.mouseClicked((data) => {
  // Convert top-left grid coords to center-based coords (matching draw-time origin)
  const centerX = Math.round(data.position.x - (t.grid.cols - 1) / 2);
  const centerY = Math.round(data.position.y - (t.grid.rows - 1) / 2);

  ripples.push({ x: centerX, y: centerY, age: 0, maxAge: 20 });
});

t.draw(() => {
  t.background(0);

  // Update and draw ripples (iterate backwards when removing)
  for (let i = ripples.length - 1; i >= 0; i--) {
    const r = ripples[i];
    r.age++;
    const life = r.age / r.maxAge;                    // 0..1
    const radius = 1 + life * 7;                      // expands from ~1 to ~8
    const intensity = Math.round(255 * (1 - life));   // fades out

    // Keep cells dark so characters stand out
    t.charColor(intensity, intensity, 255);
    t.cellColor(0);

    t.push();
    // position already in center-based coordinates
    t.translate(r.x, r.y);

    // Draw a ring by sampling points around the circle
    for (let a = 0; a < Math.PI * 2; a += Math.PI / 8) {
      const ox = Math.round(Math.cos(a) * radius);
      const oy = Math.round(Math.sin(a) * radius);
      t.push();
      t.translate(ox, oy);
      t.char('*');
      t.point();
      t.pop();
    }

    t.pop();

    // Remove finished ripples
    if (r.age > r.maxAge) {
      ripples.splice(i, 1);
    }
  }

  // Show crosshair for the current mouse cell. Convert t.mouse (top-left origin)
  // to the center-based coordinates used for drawing just like above.
  if (t.mouse.x !== -1 && t.mouse.y !== -1) {
    const cx = Math.round(t.mouse.x - (t.grid.cols - 1) / 2);
    const cy = Math.round(t.mouse.y - (t.grid.rows - 1) / 2);
    t.push();
    t.charColor(180);
    t.translate(cx, cy);
    t.char('+');
    t.point();
    t.pop();
  }
});

Implementation of

ts
ITextmodifier.mouseClicked

mouseMoved()

ts
mouseMoved(callback): void;

Set a callback function that will be called when the mouse moves.

Parameters

ParameterTypeDescription
callbackMouseEventHandlerThe function to call when the mouse moves

Returns

void

Show example
javascript
// Trail of particles following the mouse.

const t = textmode.create({ width: 800, height: 600 });

const trail = [];
const maxTrail = 120;
let lastMouse = null;

t.mouseMoved((data) => {
  if (data.position.x === -1 || data.position.y === -1) return;
  
  // Convert to center-based coords
  const cx = Math.round(data.position.x - (t.grid.cols - 1) / 2);
  const cy = Math.round(data.position.y - (t.grid.rows - 1) / 2);
  
  // Spawn multiple particles based on movement speed
  const dx = lastMouse ? cx - lastMouse.x : 0;
  const dy = lastMouse ? cy - lastMouse.y : 0;
  const speed = Math.sqrt(dx * dx + dy * dy);
  const count = Math.max(1, Math.ceil(speed * 1.5));
  
  for (let i = 0; i < count; i++) {
    trail.push({ 
      x: cx, 
      y: cy, 
      age: 0, 
      maxAge: 15 + Math.random() * 10 
    });
  }
  
  lastMouse = { x: cx, y: cy };
  if (trail.length > maxTrail) trail.splice(0, trail.length - maxTrail);
});

t.draw(() => {
  t.background(0);
  
  // Draw and age particles
  for (let i = trail.length - 1; i >= 0; i--) {
    const p = trail[i];
    p.age++;
    
    if (p.age >= p.maxAge) {
      trail.splice(i, 1);
      continue;
    }
    
    const life = 1 - (p.age / p.maxAge);
    const brightness = Math.round(255 * life);
    const chars = ['.', '*', 'o', '@'];
    const idx = Math.floor(life * chars.length);
    
    t.push();
    t.charColor(brightness, brightness * 0.6, 255);
    t.translate(p.x, p.y);
    t.char(chars[Math.min(idx, chars.length - 1)]);
    t.point();
    t.pop();
  }
});

Implementation of

ts
ITextmodifier.mouseMoved

mousePressed()

ts
mousePressed(callback): void;

Set a callback function that will be called when the mouse is pressed down.

Parameters

ParameterTypeDescription
callbackMouseEventHandlerThe function to call when the mouse is pressed

Returns

void

Show example
javascript
// Hold mouse to spray particles that fall with gravity.

const t = textmode.create({ width: 800, height: 600 });

const particles = [];
let pressing = false;

t.mousePressed((data) => {
  if (data.position.x === -1 || data.position.y === -1) return;
  pressing = true;
});

t.mouseReleased(() => {
  pressing = false;
});

t.draw(() => {
  t.background(0);
  
  // Spawn particles while pressing
  if (pressing && t.mouse.x !== -1) {
    const cx = Math.round(t.mouse.x - (t.grid.cols - 1) / 2);
    const cy = Math.round(t.mouse.y - (t.grid.rows - 1) / 2);
    
    for (let i = 0; i < 3; i++) {
      particles.push({
        x: cx,
        y: cy,
        vx: (Math.random() - 0.5) * 0.8,
        vy: Math.random() * -0.5 - 0.2,
        age: 0,
        maxAge: 30 + Math.random() * 20
      });
    }
  }
  
  // Update and draw particles
  for (let i = particles.length - 1; i >= 0; i--) {
    const p = particles[i];
    p.age++;
    p.vy += 0.08; // gravity
    p.x += p.vx;
    p.y += p.vy;
    
    if (p.age >= p.maxAge) {
      particles.splice(i, 1);
      continue;
    }
    
    const life = 1 - (p.age / p.maxAge);
    const brightness = Math.round(255 * life);
    
    t.push();
    t.charColor(brightness, brightness * 0.7, 100);
    t.translate(Math.round(p.x), Math.round(p.y));
    t.char(life > 0.5 ? 'o' : '.');
    t.point();
    t.pop();
  }
});

Implementation of

ts
ITextmodifier.mousePressed

mouseReleased()

ts
mouseReleased(callback): void;

Set a callback function that will be called when the mouse is released.

Parameters

ParameterTypeDescription
callbackMouseEventHandlerThe function to call when the mouse is released

Returns

void

Show example
javascript
// Drag to draw lines that fade over time.

const t = textmode.create({ width: 800, height: 600 });

const lines = [];
let dragStart = null;

t.mousePressed((data) => {
  if (data.position.x === -1 || data.position.y === -1) return;
  const cx = Math.round(data.position.x - (t.grid.cols - 1) / 2);
  const cy = Math.round(data.position.y - (t.grid.rows - 1) / 2);
  dragStart = { x: cx, y: cy };
});

t.mouseReleased((data) => {
  if (!dragStart || data.position.x === -1) return;
  const cx = Math.round(data.position.x - (t.grid.cols - 1) / 2);
  const cy = Math.round(data.position.y - (t.grid.rows - 1) / 2);
  
  // Calculate line center and local endpoints
  const centerX = (dragStart.x + cx) / 2;
  const centerY = (dragStart.y + cy) / 2;
  const dx = cx - dragStart.x;
  const dy = cy - dragStart.y;
  
  lines.push({
    cx: centerX, cy: centerY,
    dx: dx, dy: dy,
    age: 0, maxAge: 30
  });
  dragStart = null;
});

t.draw(() => {
  t.background(0);
  
  // Draw stored lines with fade
  for (let i = lines.length - 1; i >= 0; i--) {
    const ln = lines[i];
    ln.age++;
    
    if (ln.age >= ln.maxAge) {
      lines.splice(i, 1);
      continue;
    }
    
    const life = 1 - (ln.age / ln.maxAge);
    const brightness = Math.round(150 * life);
    
    t.push();
    t.charColor(brightness, brightness, 255);
    t.char('-');
    t.lineWeight(2);
    t.translate(ln.cx, ln.cy);
    t.line(-ln.dx / 2, -ln.dy / 2, ln.dx / 2, ln.dy / 2);
    t.pop();
  }
  
  // Draw current drag line
  if (dragStart && t.mouse.x !== -1) {
    const cx = Math.round(t.mouse.x - (t.grid.cols - 1) / 2);
    const cy = Math.round(t.mouse.y - (t.grid.rows - 1) / 2);
    const centerX = (dragStart.x + cx) / 2;
    const centerY = (dragStart.y + cy) / 2;
    const dx = cx - dragStart.x;
    const dy = cy - dragStart.y;
    
    t.push();
    t.charColor(255, 200, 0);
    t.char('o');
    t.lineWeight(2);
    t.translate(centerX, centerY);
    t.line(-dx / 2, -dy / 2, dx / 2, dy / 2);
    t.pop();
  }
});

Implementation of

ts
ITextmodifier.mouseReleased

mouseScrolled()

ts
mouseScrolled(callback): void;

Set a callback function that will be called when the mouse wheel is scrolled.

Parameters

ParameterTypeDescription
callbackMouseEventHandlerThe function to call when the mouse wheel is scrolled

Returns

void

Show example
javascript
// Scroll to create expanding rings.

const t = textmode.create({ width: 800, height: 600 });

const rings = [];

t.mouseScrolled((data) => {
  if (data.position.x === -1 || data.position.y === -1) return;
  
  const cx = Math.round(data.position.x - (t.grid.cols - 1) / 2);
  const cy = Math.round(data.position.y - (t.grid.rows - 1) / 2);
  
  // Use scroll delta to determine ring intensity and direction
  const scrollSpeed = 2;
  const intensity = Math.min(scrollSpeed * 30, 255);
  const scrollDown = (data.delta?.y || 0) > 0;
  
  rings.push({
    x: cx,
    y: cy,
    radius: 1,
    maxRadius: 5 + scrollSpeed * 0.5,
    color: intensity,
    scrollDown: scrollDown,
    age: 0,
    maxAge: 20
  });
});

t.draw(() => {
  t.background(0);
  
  // Update and draw rings
  for (let i = rings.length - 1; i >= 0; i--) {
    const r = rings[i];
    r.age++;
    r.radius += (r.maxRadius - r.radius) * 0.15;
    
    if (r.age >= r.maxAge) {
      rings.splice(i, 1);
      continue;
    }
    
    const life = 1 - (r.age / r.maxAge);
    const brightness = Math.round(r.color * life);
    
    t.push();
    // Blue for scroll down, orange for scroll up
    if (r.scrollDown) {
      t.charColor(brightness * 0.5, brightness * 0.8, 255);
    } else {
      t.charColor(255, brightness * 0.6, brightness * 0.3);
    }
    t.translate(r.x, r.y);
    
    // Draw ring
    for (let a = 0; a < Math.PI * 2; a += Math.PI / 6) {
      const ox = Math.round(Math.cos(a) * r.radius);
      const oy = Math.round(Math.sin(a) * r.radius);
      t.push();
      t.translate(ox, oy);
      t.char('o');
      t.point();
      t.pop();
    }
    t.pop();
  }
});

Implementation of

ts
ITextmodifier.mouseScrolled

noLoop()

ts
noLoop(): void;

Stop the automatic rendering loop.

This method pauses the render loop without, allowing it to be resumed later with loop. This is useful for temporarily pausing animation while maintaining the ability to continue it.

Returns

void

Show example
javascript
const t = textmode.create({ width: 800, height: 600 });

// Toggle loop on SPACE
t.keyPressed((data) => {
  if (data.key === ' ') {
    if (t.isLooping()) {
      t.noLoop();
    } else {
      t.loop();
    }
  }
});

t.draw(() => {
  t.background(0);
  t.char('A');
  t.charColor(255, 255, 255);
  t.rotateZ(t.frameCount * 2);
  t.rect(16, 16);
});

Implementation of

ts
ITextmodifier.noLoop

ortho()

ts
ortho(): void;

Enable orthographic projection for the current frame.

By default, textmode.js uses perspective projection. Calling this function switches to orthographic projection for all geometries drawn in the current frame. Orthographic projection renders objects without perspective distortion - parallel lines remain parallel regardless of depth, and objects don't appear smaller as they move away from the camera.

Note: The projection mode resets to perspective at the start of each frame, so ortho() must be called in every frame where you want orthographic projection.

Returns

void

Show example
javascript
const t = textmode.create({
  width: 800,
  height: 600,
});

let useOrtho = false;

// Toggle between ortho and perspective with spacebar
t.keyPressed((data) => {
  if (data.key === ' ') {
    useOrtho = !useOrtho;
  }
});

t.draw(() => {
  t.background(0);
  
  // Enable orthographic projection if toggled on
  if (useOrtho) {
    t.ortho();
  }
  
  // Animate the rectangle back and forth on the z-axis
  const zPos = Math.sin(t.frameCount * 0.01) * 50;
  
  t.push();
  t.translate(0, 0, zPos);
  t.rotateZ(t.frameCount * 2);
  t.rotateX(t.frameCount * 1.5);
  t.char('A');
  t.charColor(255, 100, 200);
  t.rect(16, 16);
  t.pop();
});

Implementation of

ts
ITextmodifier.ortho

pinch()

ts
pinch(callback): void;

Register a callback for pinch gestures, receiving scale deltas.

Pinch gestures involve two touch points. The callback receives the current scale relative to the initial distance and the change since the previous update, enabling zoom interactions.

Parameters

ParameterTypeDescription
callbackTouchPinchHandlerThe function to call when a pinch gesture is detected.

Returns

void

Show example
javascript
t.pinch((data) => {
  console.log(`Pinch scale: ${data.scale.toFixed(2)}`);
});

Implementation of

ts
ITextmodifier.pinch

point()

ts
point(): void;

Draw a 1x1 rectangle with the current settings.

Returns

void

Show example
javascript
const t = textmode.create({ width: 800, height: 600 });

t.draw(() => {
  t.background(0);

  const angle = t.frameCount * 0.06;
  const radius = Math.min(t.grid.cols, t.grid.rows) * 0.35;

  // Draw a short trail of points behind the leading point
  for (let i = 0; i < 10; i++) {
    const a = angle - i * 0.18;
    const r = radius * (1 - i * 0.08);
    const x = Math.round(Math.cos(a) * r);
    const y = Math.round(Math.sin(a) * r);

    // Color and brightness fade across the trail
    const brightness = Math.max(40, 255 - i * 20);
    const blue = Math.max(60, 255 - i * 25);
    const green = 120 + i * 8;

    t.push();
    t.translate(x, y);
    t.char('*');
    t.charColor(brightness, green, blue);
    t.point();

    t.pop();
  }

  // Leading point drawn with highest brightness
  t.char('@');
  t.charColor(255, 255, 160);
  t.translate(Math.round(Math.cos(angle) * radius), Math.round(Math.sin(angle) * radius));
  t.point();
});

Implementation of

ts
ITextmodifier.point

pop()

ts
pop(): void;

Restore the most recently saved rendering state from the state stack. Use with push to isolate style changes within a block.

Returns

void

Show example
javascript
const t = textmode.create({ width: 800, height: 600 });

t.draw(() => {
  t.background(0);

  // Draw three rotating shapes with isolated transformations and colors
  for (let i = 0; i < 3; i++) {
    t.push(); // Save state
    t.translate(i * 12 - 12, 0);
    t.rotateZ(t.frameCount * (1 + i * 0.5));
    t.charColor(100 + i * 70, 255 - i * 50, 150);
    t.char(['*', '@', '#'][i]);
    t.rect(8, 8);
    t.pop(); // Restore state - next iteration starts fresh
  }
});

Implementation of

ts
ITextmodifier.pop

push()

ts
push(): void;

Save the current rendering state to the state stack. Use with pop to isolate style changes within a block.

Returns

void

Show example
javascript
const t = textmode.create({ width: 800, height: 600 });

t.draw(() => {
  t.background(0);

  // Draw three rotating shapes with isolated transformations and colors
  for (let i = 0; i < 3; i++) {
    t.push(); // Save state
    t.translate(i * 12 - 12, 0);
    t.rotateZ(t.frameCount * (1 + i * 0.5));
    t.charColor(100 + i * 70, 255 - i * 50, 150);
    t.char(['*', '@', '#'][i]);
    t.rect(8, 8);
    t.pop(); // Restore state - next iteration starts fresh
  }
});

Implementation of

ts
ITextmodifier.push

rect()

ts
rect(width?, height?): void;

Draw a rectangle with the current settings. Position is controlled via translate, push, and pop.

Parameters

ParameterTypeDescription
width?numberWidth of the rectangle
height?numberHeight of the rectangle

Returns

void

Show example
javascript
const t = textmode.create({
  width: 800,
  height: 600,
})

t.draw(() => {
  // Set the background color to black
  t.background(0);

  // Position and draw a filled rectangle
  t.char('A');
  t.charColor(255, 255, 255); // White
  t.rotateZ(t.frameCount * 2);
  t.rect(16, 16);
});

Implementation of

ts
ITextmodifier.rect

redraw()

ts
redraw(n?): void;

Execute the render function a specified number of times.

This method is useful when the render loop has been stopped with noLoop, allowing you to trigger rendering on demand.

Parameters

ParameterTypeDescription
n?numberThe number of times to execute the render function. Defaults to 1.

Returns

void

Show example
javascript
// Press SPACE to manually trigger single frames while loop is paused.

const t = textmode.create({ width: 800, height: 600 });

let rotation = 0;

t.keyPressed((data) => {
  if (data.key === ' ') {
    rotation += 15; // Increment rotation
    t.redraw(); // Manually trigger one frame
  }
});

t.draw(() => {
  if(t.frameCount === 1) {
    t.noLoop();
  }

  t.background(0);
  
  t.push();
  t.char('A');
  t.charColor(100, 200, 255);
  t.rotateZ(rotation);
  t.rect(13, 13);
  t.pop();
  
  // Show instruction text
  t.push();
  t.translate(-5, -10);
  t.charColor(150);
  const msg = 'PRESS SPACE';
  [...msg].forEach((char, i) => {
    t.push();
    t.translate(i, 0);
    t.char(char);
    t.point();
    t.pop();
  });
  t.pop();
});

Implementation of

ts
ITextmodifier.redraw

resizeCanvas()

ts
resizeCanvas(width, height): void;

Resize the canvas and adjust all related components accordingly.

Parameters

ParameterTypeDescription
widthnumberThe new width of the canvas.
heightnumberThe new height of the canvas.

Returns

void

Show example
javascript
// Create a standalone textmodifier instance
const t = textmode.create({
  width: window.innerWidth,
  height: window.innerHeight,
});

// Draw callback to update content
t.draw(() => {
 // Set background color
 t.background(128);
 t.char('A');
 t.rotateZ(t.frameCount * 2);
 t.rect(16, 16);
});

// Set up window resize callback
t.windowResized(() => {
  // Resize the canvas to match window size
  t.resizeCanvas(window.innerWidth, window.innerHeight);
});

Implementation of

ts
ITextmodifier.resizeCanvas

rotate()

ts
rotate(
   degreesX?, 
   degreesY?, 
   degreesZ?): void;

Sets the rotation angles for subsequent shape rendering operations.

All geometries rotate around the center of the shape.

Parameters

ParameterTypeDescription
degreesX?numberThe rotation angle in degrees around the X-axis (optional, defaults to 0)
degreesY?numberThe rotation angle in degrees around the Y-axis (optional, defaults to 0)
degreesZ?numberThe rotation angle in degrees around the Z-axis (optional, defaults to 0)

Returns

void

Show example
javascript
const t = textmode.create({ width: 800, height: 600 });

t.draw(() => {
  t.background(0);
  
  // Draw three rectangles rotating in 3D space with different axes
  for (let i = 0; i < 3; i++) {
    t.push();
    t.translate(i * 15 - 15, 0, 0);
    
    const angle = t.frameCount * (1.5 + i * 0.5);
    // Each shape rotates around different combinations of axes
    t.rotate(angle * 0.7, angle * 0.5, angle);
    
    t.char(['T', 'X', 'T'][i]);
    t.charColor(100 + i * 60, 200 - i * 40, 255);
    t.rect(10, 10);
    t.pop();
  }
});

Implementation of

ts
ITextmodifier.rotate

rotateGesture()

ts
rotateGesture(callback): void;

Register a callback for rotate gestures, receiving rotation deltas in degrees.

Rotation callbacks provide the cumulative rotation and delta rotation since the last update, along with the gesture centre in grid coordinates. Ideal for dial-like interactions.

Parameters

ParameterTypeDescription
callbackTouchRotateHandlerThe function to call when a rotation gesture is detected.

Returns

void

Show example
javascript
t.rotateGesture((data) => {
  console.log(`Rotated ${data.deltaRotation.toFixed(1)}°`);
});

Implementation of

ts
ITextmodifier.rotateGesture

rotateX()

ts
rotateX(degrees): void;

Sets the X-axis rotation angle for subsequent shape rendering operations.

All geometries rotate around the center of the shape.

Parameters

ParameterTypeDescription
degreesnumberThe rotation angle in degrees around the X-axis

Returns

void

Show example
javascript
const t = textmode.create({ width: 800, height: 600 });

t.draw(() => {
  t.background(0);
  t.char('A');
  t.charColor(255, 150, 100);
  t.rotateX(t.frameCount * 2); // Flip forward/backward
  t.rect(12, 12);
});

Implementation of

ts
ITextmodifier.rotateX

rotateY()

ts
rotateY(degrees): void;

Sets the Y-axis rotation angle for subsequent shape rendering operations.

All geometries rotate around the center of the shape.

Parameters

ParameterTypeDescription
degreesnumberThe rotation angle in degrees around the Y-axis

Returns

void

Show example
javascript
const t = textmode.create({ width: 800, height: 600 });

t.draw(() => {
  t.background(0);
  t.char('B');
  t.charColor(100, 255, 200);
  t.rotateY(t.frameCount * 2); // Spin left/right
  t.rect(12, 12);
});

Implementation of

ts
ITextmodifier.rotateY

rotateZ()

ts
rotateZ(degrees): void;

Sets the Z-axis rotation angle for subsequent shape rendering operations.

All geometries rotate around the center of the shape.

Parameters

ParameterTypeDescription
degreesnumberThe rotation angle in degrees around the Z-axis

Returns

void

Show example
javascript
const t = textmode.create({ width: 800, height: 600 });

t.draw(() => {
  t.background(0);
  t.char('C');
  t.charColor(255, 220, 100);
  t.rotateZ(t.frameCount * 2); // Spin clockwise
  t.rect(12, 12);
});

Implementation of

ts
ITextmodifier.rotateZ

setUniform()

ts
setUniform(name, value): void;

Set a uniform value for the current custom shader.

Parameters

ParameterTypeDescription
namestringThe name of the uniform variable
valueUniformValueThe value to set

Returns

void

Show example
javascript
const t = textmode.create({ width: 800, height: 600 });

const pulseShader = t.createFilterShader(`#version 300 es
  precision highp float;
  in vec2 v_uv;
  uniform float u_time;
  layout(location = 0) out vec4 o_character;
  layout(location = 1) out vec4 o_primaryColor;
  layout(location = 2) out vec4 o_secondaryColor;
  
  void main() {
    float pulse = 0.5 + 0.5 * sin(u_time + length(v_uv - 0.5) * 8.0);
    vec3 color = vec3(pulse * 0.3, pulse * 0.8, pulse);
    o_character = vec4(pulse, 0.0, 0.0, 0.0);
    o_primaryColor = vec4(color, 1.0);
    o_secondaryColor = vec4(color * 0.3, 1.0);
  }
`);

t.draw(() => {
  t.shader(pulseShader);
  t.setUniform('u_time', t.frameCount * 0.005);
  t.rect(t.grid.cols, t.grid.rows);
});

Implementation of

ts
ITextmodifier.setUniform

setUniforms()

ts
setUniforms(uniforms): void;

Set multiple uniform values for the current custom shader.

Parameters

ParameterTypeDescription
uniformsRecord<string, UniformValue>Object containing uniform name-value pairs

Returns

void

Show example
javascript
const t = textmode.create({ width: 800, height: 600 });

const rippleShader = t.createFilterShader(`#version 300 es
  precision highp float;
  in vec2 v_uv;
  uniform float u_time;
  uniform vec2 u_center;
  layout(location = 0) out vec4 o_character;
  layout(location = 1) out vec4 o_primaryColor;
  layout(location = 2) out vec4 o_secondaryColor;
  
  void main() {
    float dist = length(v_uv - u_center);
    float wave = sin(dist * 20.0 - u_time * 2.0) * 0.5 + 0.5;
    vec3 color = mix(vec3(0.2, 0.4, 0.8), vec3(0.9, 0.6, 0.3), wave);
    o_character = vec4(wave, 0.0, 0.0, 0.0);
    o_primaryColor = vec4(color, 1.0);
    o_secondaryColor = vec4(color * 0.4, 1.0);
  }
`);

t.draw(() => {
  t.shader(rippleShader);
  t.setUniforms({
    u_time: t.frameCount * 0.0005,
    u_center: [0.5, 0.5]
  });
  t.rect(t.grid.cols, t.grid.rows);
});

Implementation of

ts
ITextmodifier.setUniforms

setup()

ts
setup(callback): void;

Set a setup callback function that will be executed once when initialization is complete.

This callback is called after font loading and grid initialization, allowing access to properties like textmodifier.grid.cols for calculating layout or setup variables.

Parameters

ParameterTypeDescription
callback() => void | Promise<void>The function to call when setup is complete

Returns

void

Show example
javascript
const textmodifier = textmode.create({
  width: 800,
  height: 600,
  fontSize: 16
});

// Setup callback - called once when ready
textmodifier.setup(() => {
  // Now you can access grid properties
  const cols = textmodifier.grid.cols;
  const rows = textmodifier.grid.rows;
  
  // Initialize any variables that depend on grid size
  rectWidth = Math.floor(cols / 3);
  rectHeight = Math.floor(rows / 2);
});

// Draw callback - called every frame
textmodifier.draw(() => {
  textmodifier.background(128);
  textmodifier.char('A');
  textmodifier.rotateZ(textmodifier.frameCount * 2);
  textmodifier.rect(rectWidth, rectHeight);
});

Implementation of

ts
ITextmodifier.setup

shader()

ts
shader(shader): void;

Set a custom shader for subsequent rendering operations.

Parameters

ParameterTypeDescription
shaderGLShaderThe custom shader to use

Returns

void

Show example
javascript
const t = textmode.create({ width: 800, height: 600 });

const glitchShader = t.createFilterShader(`#version 300 es
  precision highp float;
  in vec2 v_uv;
  uniform float u_intensity;
  layout(location = 0) out vec4 o_character;
  layout(location = 1) out vec4 o_primaryColor;
  layout(location = 2) out vec4 o_secondaryColor;
  
  void main() {
    vec2 offset = vec2(sin(v_uv.y * 50.0) * u_intensity, 0.0);
    float pattern = fract(v_uv.x * 20.0 + offset.x);
    vec3 color = vec3(pattern, 1.0 - pattern, 0.5);
    o_character = vec4(pattern, 0.0, 0.0, 0.0);
    o_primaryColor = vec4(color, 1.0);
    o_secondaryColor = vec4(color * 0.5, 1.0);
  }
`);

t.draw(() => {
  t.shader(glitchShader);
  t.setUniform('u_intensity', Math.sin(t.frameCount * 0.1) * 0.02);
  t.rect(t.grid.cols, t.grid.rows);
});

Implementation of

ts
ITextmodifier.shader

swipe()

ts
swipe(callback): void;

Register a callback for swipe gestures.

Swipes provide the dominant direction (up, down, left, right), travelled distance, and velocity in CSS pixels per millisecond. Useful for panning, flicks, or quick shortcuts.

Parameters

ParameterTypeDescription
callbackTouchSwipeHandlerThe function to call when a swipe gesture is detected.

Returns

void

Show example
javascript
t.swipe((data) => {
  console.log(`Swipe ${data.direction} with distance ${data.distance}`);
});

Implementation of

ts
ITextmodifier.swipe

tap()

ts
tap(callback): void;

Register a callback for tap gestures.

A tap is fired when the user quickly touches and releases the canvas without travelling far. Use TouchTapEventData.taps to determine whether the gesture is a single or multi tap.

Parameters

ParameterTypeDescription
callbackTouchTapHandlerThe function to call when a tap gesture is detected.

Returns

void

Show example
javascript
t.tap((data) => {
  console.log(`Tapped at ${data.touch.x}, ${data.touch.y}`);
});

Implementation of

ts
ITextmodifier.tap

touchCancelled()

ts
touchCancelled(callback): void;

Set a callback function that will be called when a touch is cancelled by the browser.

Cancellation can occur when the browser takes ownership for scrolling or if the gesture leaves the window. Treat this as an aborted touch and clean up any in-progress state.

Parameters

ParameterTypeDescription
callbackTouchEventHandlerThe function to call when a touch is cancelled.

Returns

void

Show example
javascript
t.touchCancelled((data) => {
  console.warn(`Touch ${data.touch.id} cancelled by the browser`);
});

Implementation of

ts
ITextmodifier.touchCancelled

touchEnded()

ts
touchEnded(callback): void;

Set a callback function that will be called when a touch ends normally.

This fires after the finger leaves the canvas surface and the browser raises a touchend event. Use it to finalise state such as drawing strokes or completing gestures.

Parameters

ParameterTypeDescription
callbackTouchEventHandlerThe function to call when a touch ends.

Returns

void

Show example
javascript
t.touchEnded((data) => {
  console.log(`Touch ${data.touch.id} finished at ${data.touch.x}, ${data.touch.y}`);
});

Implementation of

ts
ITextmodifier.touchEnded

touchMoved()

ts
touchMoved(callback): void;

Set a callback function that will be called when a touch point moves across the canvas.

The provided callback is invoked continuously while the browser reports move events. Use the previousTouch and deltaTime fields to derive velocity or gesture behaviour.

Parameters

ParameterTypeDescription
callbackTouchEventHandlerThe function to call when a touch moves.

Returns

void

Show example
javascript
t.touchMoved((data) => {
  const { touch, previousTouch } = data;
  if (previousTouch) {
    console.log(`Touch moved by ${touch.x - previousTouch.x}, ${touch.y - previousTouch.y}`);
  }
});

Implementation of

ts
ITextmodifier.touchMoved

touchStarted()

ts
touchStarted(callback): void;

Set a callback function that will be called when a touch point begins.

The callback receives TouchEventData containing the touch that triggered the event, all active touches, and the original DOM event. Use this to react when the user places one or more fingers on the canvas.

Parameters

ParameterTypeDescription
callbackTouchEventHandlerThe function to call when a touch starts.

Returns

void

Show example
javascript
t.touchStarted((data) => {
  console.log(`Touch ${data.touch.id} began at ${data.touch.x}, ${data.touch.y}`);
});

Implementation of

ts
ITextmodifier.touchStarted

translate()

ts
translate(
   x?, 
   y?, 
   z?): void;

Sets the translation offsets for subsequent shape rendering operations.

All geometries are displaced by the specified amounts. Similar to p5.js translate().

Parameters

ParameterTypeDescription
x?numberTranslation along the X-axis in pixels (optional, defaults to 0)
y?numberTranslation along the Y-axis in pixels (optional, defaults to 0)
z?numberTranslation along the Z-axis in pixels (optional, defaults to 0)

Returns

void

Show example
javascript
const t = textmode.create({ width: 800, height: 600 });

t.draw(() => {
  t.background(0);
  
  // Draw a grid of shapes with different translations
  for (let i = 0; i < 3; i++) {
    t.push();
    t.translate(i * 12 - 12, Math.sin(t.frameCount * 0.05 + i) * 3);
    t.char('A');
    t.charColor(100 + i * 70, 150, 255 - i * 50);
    t.rect(8, 8);
    t.pop();
  }
});

Implementation of

ts
ITextmodifier.translate

translateX()

ts
translateX(pixels): void;

Sets the X-axis translation offset for subsequent shape rendering operations.

Parameters

ParameterTypeDescription
pixelsnumberThe translation offset in pixels along the X-axis

Returns

void

Show example
javascript
const t = textmode.create({ width: 800, height: 600 });

t.draw(() => {
  t.background(0);
  t.char('→');
  t.charColor(255, 180, 100);
  t.translateX(Math.sin(t.frameCount * 0.05) * 15); // Slide left/right
  t.rect(10, 10);
});

Implementation of

ts
ITextmodifier.translateX

translateY()

ts
translateY(pixels): void;

Sets the Y-axis translation offset for subsequent shape rendering operations.

Parameters

ParameterTypeDescription
pixelsnumberThe translation offset in pixels along the Y-axis

Returns

void

Show example
javascript
const t = textmode.create({ width: 800, height: 600 });

t.draw(() => {
  t.background(0);
  t.char('↓');
  t.charColor(100, 255, 180);
  t.translateY(Math.sin(t.frameCount * 0.05) * 10); // Bounce up/down
  t.rect(10, 10);
});

Implementation of

ts
ITextmodifier.translateY

translateZ()

ts
translateZ(pixels): void;

Sets the Z-axis translation offset for subsequent shape rendering operations.

Parameters

ParameterTypeDescription
pixelsnumberThe translation offset in pixels along the Z-axis

Returns

void

Show example
javascript
const t = textmode.create({ width: 800, height: 600 });

t.draw(() => {
  t.background(0);
  t.char('O');
  t.charColor(180, 120, 255);
  t.translateZ(Math.sin(t.frameCount * 0.05) * 20); // Pulse in/out
  t.rect(12, 12);
});

Implementation of

ts
ITextmodifier.translateZ

triangle()

ts
triangle(
   x1, 
   y1, 
   x2, 
   y2, 
   x3, 
   y3): void;

Draw a triangle with the current settings.

Parameters

ParameterTypeDescription
x1numberX-coordinate of the first vertex
y1numberY-coordinate of the first vertex
x2numberX-coordinate of the second vertex
y2numberY-coordinate of the second vertex
x3numberX-coordinate of the third vertex
y3numberY-coordinate of the third vertex

Returns

void

Show example
javascript
const t = textmode.create({ width: 800, height: 600 });

t.draw(() => {
  t.background(0);
  t.char('*');
  t.charColor(255, 100, 150);
  
  const angle = t.frameCount * 0.02;
  const size = 15;
  t.triangle(
    Math.cos(angle) * size, Math.sin(angle) * size,
    Math.cos(angle + 2.09) * size, Math.sin(angle + 2.09) * size,
    Math.cos(angle + 4.19) * size, Math.sin(angle + 4.19) * size
  );
});

Implementation of

ts
ITextmodifier.triangle

windowResized()

ts
windowResized(callback): void;

Set a callback function that will be called when the window is resized.

Parameters

ParameterTypeDescription
callback() => voidThe function to call when the window is resized.

Returns

void

Show example
javascript
// Create a standalone textmodifier instance
const t = textmode.create({
  width: window.innerWidth,
  height: window.innerHeight,
});

// Draw callback to update content
t.draw(() => {
 // Set background color
 t.background(128);
 t.char('A');
 t.rotateZ(t.frameCount * 2);
 t.rect(16, 16);
});

// Set up window resize callback
t.windowResized(() => {
  // Resize the canvas to match window size
  t.resizeCanvas(window.innerWidth, window.innerHeight);
});

Implementation of

ts
ITextmodifier.windowResized