workshop

← all creations

Subway Seagull

sprites · created 2026-08-24

32×24 pixel sprite — a white-and-gray platform seagull with a 2-frame idle bob-and-blink and a 4-frame wing-stretch flap, drawn from an editable character map.

pixel-artcanvas

The unofficial tenth member of the Straphanger / Stand Clear / nyc-conductor / Subway Rat / Platform Pigeon / Subway Cockroach / Platform Cat / Subway Raccoon platform: the one that only shows up on the elevated stretches near the water (Coney Island, the Rockaways) — a white-headed, gray-backed gull with an orange beak and legs, planted on the platform edge. Unlike the rest of the crew this one doesn’t walk: two animation loops — an idle sit (gentle bob, an eye that blinks shut on the second frame) and a wing stretch (four-frame flap: wing sweeps down and back, levels out wide, throws all the way up over the head, then levels back down), the thing gulls actually do while standing still rather than a generic flying loop.

Reuse

Render at integer scales with nearest-neighbor filtering or the edges smear. Idle plays at 2 fps, flap at 8 fps (ANIMATIONS in the module carries both).

Source

No .aseprite — the canonical source is source/subway-seagull.mjs: a framework-free ES module holding the pixel grids as character maps (one char per pixel, palette at the top). Edit a grid and regenerate everything with:

node source/render.mjs

(needs site/node_modules installed — the script resolves Playwright from there.) That one command rewrites export/, media/, thumb.png, and the demo’s bundled copy of the module, so nothing drifts.

How the frames are built

A frame is four layers composited on the 32×24 canvas, back to front: TAIL (fixed anchor, tucks under the rump), LEGS (fixed anchor, planted — this one stands rather than walks, so there’s a single stand pattern instead of a gait), BODY (head, beak and torso, at the frame’s bob offset), then WING on top so it reads over the back when folded and over everything when raised. The wing poses aren’t all the same size — folded is a compact 7-row drape, up is a 12-row spread that reaches above the head — so instead of one shared anchor like TAIL/LEGS, each frame carries its own wingTop placing that pose’s grid. Getting this wrong is exactly the failure mode to watch for: an early draft put the mid pose’s wingTop too close to the head and the wide top edge of that grid blanketed the whole face — the fix was dropping wingTop back down near the shoulder line (14, the same row folded and down use) rather than trying to slide the wing upward to suggest motion.

Gotchas

Port notes

paintFrame is grid-walking with no DOM dependency beyond a 2D context — same shape as the rest of the platform crew’s — so a DragonRuby port translates directly: keep the grids as strings, map cells to args.outputs.solids, or just consume seagull-sheet.png as a spritesheet with source_x = frame * 32. The one wrinkle versus subway-raccoon/ subway-rat is the per-frame wingTop instead of a fixed anchor — carry that value over rather than assuming every layer shares one offset.