Skip to content
tynt

tynt documentation

Learn tynt through focused cartridges and reusable patterns.

Examples and recipes

Every gallery entry is a complete cartridge under cartridges/<slug>/.

The gallery shows newer publications first by default. Sort by title or author when comparing examples, select any tag on a card to narrow the collection, or use Random to play one game from the visible results.

Learn one idea at a time

  • starter.tynt covers lifecycle, movement, A/B input, and score.
  • shapes.tynt demonstrates every drawing primitive.
  • sprites.tynt draws the tynt mark and a two-frame character.
  • coin-dash.tynt combines sprites, tile maps, camera movement, timers, collisions, randomness, and audio.
  • reaction.tynt turns deterministic frame timers into a complete reaction game.
  • tiny-quest.tynt demonstrates two-axis camera movement, world collisions, collectibles, and a goal zone.
  • platformer.tynt, flappy.tynt, snake.tynt, pong.tynt, and asteroids.tynt are compact complete games.

Find an API in a game

APIGood examples
seed() and random()reaction, snake, lunar, pong, flappy, asteroids, coin dash, tiny quest
overlap()pong, platformer, flappy, coin dash, tiny quest
pointInRect()snake, tiny quest
clamp() and wrap()starter, animation, soundboard
frame(), every(), and after()reaction, sprites, lunar, soundboard, coin dash
camera()coin dash, tiny quest
buttonReleased()starter, soundboard
triangle()starter, shapes
tone() and sfx()reaction, soundboard, snake, asteroids, platformer, flappy, pong, lunar, sokoban, sprites, coin dash, tiny quest

Fixed HUD with a moving camera

camera(playerX - 76, 0);
sprite(HERO, 8, 8, playerX, playerY, 0);
camera();
text("SCORE " + score, 6, 6, 3);

Deterministic timing

if (every(30)) tone(440, 50, 0.08);
if (after(60 * 10)) text("TIME", 68, 68, 3);

frame() counts fixed updates rather than wall-clock time, so replays remain predictable. At 60 updates per second, divide a frame duration by 60 and multiply by 1,000 to display milliseconds.

Collision helpers

if (overlap(playerX, playerY, 8, 8, coinX, coinY, 5, 5)) {
  score++;
}

if (pointInRect(playerX + 4, playerY + 4, exitX, exitY, 24, 28)) {
  finishLevel();
}

Use overlap() when two rectangular objects interact. Use pointInRect() for a center point, cursor, checkpoint, or goal zone.

Movement ranges and input edges

x = clamp(x + velocityX, 0, 152);
shade = wrap(shade + 1, 1, 4);

if (buttonReleased("a")) {
  launchChargedShot();
}

clamp() includes both ends of its range. wrap() includes min but wraps max back to min. buttonReleased() is true for exactly one update after a held input is released.

Triangles

triangle(80, 36, 104, 84, 56, 84, 3, true);

The final argument selects a filled triangle. Omit it or pass false to draw only the three edges. Triangle coordinates follow camera() like every other drawing primitive.

Sound effects and rests

Open the sound editor at tynt.dev/sounds to compose and preview a sixteen-step effect. You can copy its generated code or import an existing generated snippet to continue editing it. Copied sequences use 0 for a silent step:

const pickup = [261.63, 0, 329.63, 392] as const;
sfx(pickup, 80, 0.15, "square");

The sprite editor supports the same copy and import workflow for 8 × 8 sprites. Imports are validated as data and never executed: sprites accept exactly 64 color values from 0 to 3, while sounds accept exactly 16 nonnegative frequencies plus optional playback settings.