Skip to content

Duckademy

Temporarily unavailable

Apple TV drawing duel with two iPhones as the controllers. No internet, no server, no account.

Private repository

Overview

Two apps, one game. The Apple TV draws a rune and shows both strokes live; each player traces it with a finger on their own iPhone. Pairing, the live strokes and the score all travel over the local network, with no backend anywhere in the loop.

Problem

A party game on a television cannot ask five people to make an account and join a lobby. And the same rune drawn small, off-centre or from the bottom up is still the same rune, so scoring had to judge the shape rather than the coordinates.

Trade-off

Seven ducks of 31 frames each is more texture than an Apple TV should hold at once, so the animation store keeps exactly one atlas: it clears the current one, loads the next on its own serial queue, and cancels the previous load when you keep flicking through the roster. The swap is staged rather than hidden — a sparkle placeholder and a short crossfade — so the loading reads as part of the game.

What it does

Zero-configuration pairing over MultipeerConnectivity — no account, no internet
Strokes scored on device by discrete Fréchet distance against the reference SVG
Normalised for position, size and direction, so only the shape counts
35 playable runes, each with its own precision threshold
Strokes streamed at ~66 Hz as unreliable packets; the score sent reliably
Seven animated ducks at 24 fps, in a classic and a timed game mode

Stack

tvOSiOSSwiftSwiftUIUIKitMultipeerConnectivityPencilKitSpriteKitCoreGraphicsCoreHapticsAVFoundationPocketSVG

What I took from it

Fréchet distance compares trajectories rather than clouds of points, which is exactly what a stroke is. Running it twice — against the reference and against the reference reversed — is what stopped punishing anyone who draws bottom-up, and the density of sampled points turned out to be the latency dial for the whole comparison.

More iOS work

Work

Set in Uncut Sans and Commit Mono. Built to the iOS metrics: 8pt grid, 17px body, 44px targets, spring physics.

© 2026 Lucas Santhiago. All rights reserved.