Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/hetari/creative-coding/llms.txt

Use this file to discover all available pages before exploring further.

useAsciiRasterizer converts a raster image into a grid of ASCII characters rendered on an HTML <canvas> element. Spatial downsampling is performed using the ITU-R BT.601 perceptual luminance formula — pixel brightness maps to character density in a configurable character set, with darker subject areas producing denser glyphs. On top of the static render, the composable adds a hover interaction: moving the pointer over a highlighted region triggers a spark-like random-walk cluster that propagates highlight state to adjacent cells and decays over a configurable lifetime.

Options

imageSrc
MaybeRefOrGetter<string | undefined>
Source image URL. Accepts a plain string, a ref, a computed, or a getter function. When the value changes, the composable automatically re-runs image loading and canvas setup. URLs beginning with http:// or https:// receive crossOrigin = 'anonymous' to allow canvas pixel sampling without CORS errors.
canvasRef
MaybeRef<HTMLCanvasElement | null | undefined>
Target <canvas> element ref. The composable writes to this canvas via a 2D context. Changing the ref value triggers a fresh setup pass.
columns
MaybeRefOrGetter<number>
Number of grid columns for the ASCII raster (default: 80). The row count is derived automatically to preserve the original image’s aspect ratio.
cellSize
MaybeRefOrGetter<number>
Width and height of each square grid cell in canvas pixels (default: 20). Increasing this value produces larger, bolder characters.
fontSize
MaybeRefOrGetter<number>
Font size in pixels used for each ASCII character (default: 18). Should be slightly smaller than cellSize so characters fit within their cell.
asciiChars
MaybeRefOrGetter<string>
A string of characters ordered from lightest to darkest visual density (default: '........:::=+xX#0369'). The composable maps pixel luminance to an index in this string — bright pixels become leading dots, dark pixels become dense symbols. Characters at or below the last . index are treated as background and omitted from rendering to reduce canvas draw calls.
charColor
MaybeRefOrGetter<string>
CSS color string for the base ASCII character fill (default: '#ffffff'). Pass a reactive computed here to update character color live, e.g. in response to a dark-mode toggle.
hoverColor
MaybeRefOrGetter<string>
Background fill color applied to highlighted (hovered) cells (default: '#ff6a00').
hoverCharColor
MaybeRefOrGetter<string>
Character color used for highlighted cells (default: '#ffffff'). Lets you create a high-contrast inversion effect when the hover background is dark.
hoverRadius
MaybeRefOrGetter<number>
Maximum distance in grid units between the pointer and the nearest cell for a hover event to register (default: 8). Set lower for tighter, more precise interactions.
highlightLifetime
MaybeRefOrGetter<number>
Duration in milliseconds for which a highlighted cell remains lit before decaying (default: 300). Cells in an outer cluster stagger by an extra 10 ms per step from the origin, creating a trailing decay effect.
clusterSize
MaybeRefOrGetter<number>
Maximum number of adjacent cells lit in a single hover cluster (default: 10). The actual count per event is random in [1, clusterSize], producing organic variation.
autoLoop
boolean
When true, the composable registers a built-in RAF loop via useRafFn that calls render() every frame (default: false). Set to false when you need to coordinate rendering across multiple canvases in a single RAF callback.
autoHover
boolean
When true, the composable attaches a global window mousemove listener that calls hover() automatically (default: false). Set to false when you are managing pointer events from a parent component that needs to share them across multiple composable instances.

Return Value

isLoaded
Ref<boolean>
Becomes true after the source image has loaded and the canvas context, cell map, and font metrics have all been set up. Use this to guard rendering logic or show a loading state.
rows
Ref<number>
The computed number of grid rows, derived from columns and the image’s natural aspect ratio to prevent vertical stretching.
cells
Ref<Map<string, AsciiCell>>
A reactive Map keyed by 'col,row' strings, containing an AsciiCell entry for every non-background pixel in the image. Background cells (mapped to the dot portion of asciiChars) are pruned at build time to reduce draw overhead.
cellList
ComputedRef<AsciiCell[]>
A computed array view of all cells in the map, suitable for iteration in render() and hover calculations.
baselineOffset
Ref<number>
The vertical pixel offset from a cell’s top edge to the correct fillText baseline. Computed from live TextMetrics so characters are precisely vertically centred in their cell regardless of OS font engine differences.
loadAndSetup
(src?: string, canvas?: HTMLCanvasElement | null) => void
Manually trigger an image load and canvas setup. Useful when you need to load a different image without changing the reactive imageSrc option, or when the composable is used outside of onMounted.
render
(now?: number) => void
Draw all cells to the canvas for the given timestamp (defaults to Date.now()). Clears the canvas first, then fills each cell’s character — applying hoverColor background and hoverCharColor text for any cell whose highlightEndTime is in the future.
hover
(clientX: number, clientY: number) => void
Convert viewport pointer coordinates into grid space using the canvas’s getBoundingClientRect, find the closest cell within hoverRadius, and trigger a highlight cluster starting from that cell. Works correctly even when the canvas is scaled by CSS transforms or responsive layout.

AsciiCell Interface

interface AsciiCell {
  col: number
  row: number
  char: string
  highlightEndTime: number  // timestamp in ms; cell is highlighted while Date.now() < highlightEndTime
}

Standalone Helper Functions

These pure functions are also exported from the composable module and can be used independently of the full useAsciiRasterizer setup: buildAsciiCells(image, columns?, asciiChars?){ rows: number, cells: Map<string, AsciiCell> } Pure function that draws the image onto an offscreen sampler canvas at grid resolution, reads pixel data, and applies the ITU-R BT.601 luminance formula to map each pixel to a character. Background cells are pruned. This is the same function useAsciiRasterizer calls internally during setup. highlightAsciiCluster(cells, startCell, highlightLifetime?, clusterSize?) Sets highlightEndTime on startCell and propagates the highlight through a random neighbour walk of up to clusterSize adjacent cells. Outer cells receive staggered expiration times (+10 ms per step) to create a trailing spark decay.

Aliases

useAsciiArt and useAsciiConverter are exported as aliases for useAsciiRasterizer. All three names refer to the same function.

Manual RAF Loop Example

The following pattern is used in the ascii-hand sketch, which renders two canvases simultaneously and shares a single mousemove listener across both:
const ascii = useAsciiRasterizer({
  imageSrc: '/images/left-hand.jpg',
  canvasRef: canvasRef,
  columns: 80,
  cellSize: 20,
  fontSize: 18,
  charColor: '#803500',
  hoverColor: '#ff6a00',
  hoverRadius: 8,
  highlightLifetime: 300,
  clusterSize: 10,
})

// Manual RAF — gives precise control over when render() fires
useRafFn(() => {
  ascii.render(Date.now())
})

// Manual mousemove — coordinate hover across multiple canvases
useEventListener('mousemove', (e: MouseEvent) => {
  ascii.hover(e.clientX, e.clientY)
})
All options accept MaybeRefOrGetter — you can pass reactive refs, computed values, or plain getter functions and the composable will pick up changes automatically. imageSrc, canvasRef, columns, and asciiChars are watched by the composable; changing any of them triggers a full reload and canvas setup.
devicePixelRatio is capped internally at 2 to sharpen glyph rendering on Retina displays while avoiding inflated canvas memory on 3× or 4× mobile screens. You do not need to handle DPR scaling in your own code.

Build docs developers (and LLMs) love