Skip to content

Repository files navigation

Pretext Playground Upgrade

Three interactive Canvas 2D experiences built on @chenglou/pretext — the pure TypeScript text measurement engine that bypasses DOM reflow entirely.

Live demo: https://pretext-playground-upg.vercel.app

Every character on screen is a physics body. No DOM text elements. No CSS layout. Just pretext-measured positions and real-time simulation.

Ice Dragon Jellyfish Abyss

Demos

1. 🐉 Dragon

A physics-driven ASCII serpent that glides through multilingual text. Letters scatter and spring back. Hold click to breathe fire. Shoot enemies for points.

Ice Dragon preset — click and hold to freeze letters in place. Letters accumulate cracks from dragon collision and shatter into ice shards. Enemies freeze solid then shatter after 1.5 seconds. Aurora borealis wisps drift across a deep blue sky.

Ice Dragon Breathing Ice Dragon Panel

2. 🪼 Jellyfish Abyss

A deep ocean canvas with bioluminescent jellyfish drifting through text layers. Click to send sonar pulses that push everything away. Lanternfish scatter in schools. A manta ray hunts them with ASCII letters forming its body.

Jellyfish Sonar Pulse Jellyfish Panel

3. ASCII

Five animated ASCII art scenes: Matrix Rain, Wave Text, Morph Text, Particle Text, and Typewriter.

What is Pretext?

Pretext solves one of the oldest bottlenecks in web UI: measuring text dimensions requires DOM access (getBoundingClientRect), which triggers expensive reflows. Pretext's prepare() does a one-time canvas measurement, then layout() is pure arithmetic — ~0.0002ms per call. This unlocks text-heavy UIs at 120fps without ever touching the DOM.

import { prepare, layout } from '@chenglou/pretext'

const prepared = prepare(text, '16px Inter')
const { height, lineCount } = layout(prepared, containerWidth, 20)
// No DOM. No reflow. Pure math.

Features

Dragon Page

Feature Details
Dragon 60-segment ASCII chain (◆▓▒░╬║│·) with wings, spines, eyes, fire breath
Ice Dragon Freeze letters → accumulate cracks → shatter into ice shards. Aurora borealis, frost particles, cyan cursor
Physics letters Every character is an independent physics body with velocity, rotation, spring-home force, dragon collision
Fire / Ice breath Hold click to emit particles — fire blasts letters away with burn timers, ice freezes them in place
Enemies 4 types: Grunts (1 HP), Tanks (3 HP), Fast (dart unpredictably), Ghosts (2 HP, sine wave)
3D tunnel Perspective-projected multilingual text rings scrolling into the distance
Runes Floating ambient kanji/kanji symbols drifting upward
Control panel Press P — 6 presets (Default, Gentle, Chaos, Zen, Tiny, Leviathan, Ice) + granular sliders

Jellyfish Page

Feature Details
Jellyfish 4 types with outlined bell shapes, pulsing animation, bioluminescent glow
Tentacles Spring-chain particle system attached to jellyfish bells, react to sonar pulses
Sonar pulses Click to send expanding shockwave rings that push letters and jellyfish
Lanternfish Schools of small fish with flocking AI, scatter from sonar, flee from manta
Manta ray ASCII letters form the manta body, hunts lanternfish with star-shaped glow
Caustics Layered sine wave grid simulating underwater light patterns
Bubbles Rising, wobbling bubble streams originating from ocean floor rocks
Ocean floor Rock formations at the bottom of the canvas
Sediment Ambient drifting particles settling from above
Control panel 2 presets (Surface, Twilight Zone) + 11 independent layer toggles

ASCII Page

Scene Description
Matrix Rain Green characters falling in columns, classic terminal aesthetic
Wave Text Large text block undulating with sine wave displacement
Morph Text Characters transitioning between different words
Particle Text Thousands of particles forming readable text shapes
Typewriter Characters appearing one at a time with cursor

Getting Started

pnpm install
pnpm dev

Open http://localhost:5173 and pick a tab.

Controls

Dragon

Input Action
Mouse move Dragon follows cursor
Click & hold Breathe fire (Default) or ice (Ice preset)
P Toggle control panel
Esc Close panel

Jellyfish

Input Action
Mouse move Tracks position for jellyfish AI
Click Send sonar pulse (pushes letters + jellyfish)
P Toggle control panel
Esc Close panel

Architecture

src/
├── dragon.ts              ─ Dragon page: physics, fire/ice, enemies, particles,
│                            3D tunnel, runes, UI binding, main loop (~800 lines)
├── dragon-page.ts         ─ Control panel HTML builder (sliders, toggles, presets)
├── config.ts              ─ Shared config object + presets (jellyfish)
├── jellyfish.ts           ─ Jellyfish orchestrator: wires all systems together
├── jellyfish-page.ts      ─ Jellyfish control panel HTML builder
├── jellyfish.css          ─ Jellyfish-specific styles
├── shared.css             ─ Shared nav + panel styles
├── systems/               ─ Jellyfish modular systems (all SoA, zero-GC)
│   ├── sonar.ts           ─ Click → expanding ring, pushes entities
│   ├── text.ts            ─ Pretext layout + SoA letter arrays + spring physics
│   ├── jellyfish.ts       ─ Bell outlines, glow, pulsing, 4 types, AI movement
│   ├── tentacles.ts       ─ Spring-chain tentacle particles anchored to bells
│   ├── lanternfish.ts     ─ Schooling fish with flocking AI + fear trails
│   ├── manta.ts           ─ ASCII letter manta ray, hunts lanternfish
│   ├── atmosphere.ts      ─ Caustics, bubbles, sediment
│   └── oceanFloor.ts      ─ Rock formations at canvas bottom
└── shared/utils.ts        ─ Shared utility functions

Performance patterns used throughout:

  • Structure-of-Arrays (SoA) — parallel Float32Arrays, no objects per entity
  • Swap-remove — O(1) particle/entity deletion, no splice/filter
  • Pre-allocated pools — fixed max buffers, zero GC in the game loop
  • Cached measurements — pretext layout computed once at init/resize, never in the hot path
  • Batched ctx stateprevFont tracking minimizes ctx.font assignments
  • DPR capped at 2 — prevents OOM on high-res displays
  • Delta time capped at 50ms — prevents physics explosion after tab switch

Tech Stack

  • @chenglou/pretext — text measurement engine
  • Canvas 2D — all rendering, zero DOM text elements
  • Vite — dev server and bundler (MPA with 3 entry points)
  • TypeScript — strict mode throughout

Open Source

This project is open source under the MIT License. Contributions, forks, and community experiments are welcome. If you build something interesting on top of pretext, consider sharing it — that's how this project started.

License

MIT

About

Three interactive Canvas 2D demos built on pretext — a physics-driven dragon that scatters multilingual text, a deep-ocean jellyfish abyss with sonar pulses, and animated ASCII art scenes. Every character is a physics body. Zero DOM text. ~0.0002ms per layout call.

Topics

Resources

Code of conduct

Contributing

Stars

0 stars

Watchers

0 watching

Forks

Contributors

Languages