skifree singleton

skifree · games

The classic SKIFREE (ski downhill, dodge trees / rocks / jumps, get chased and EATEN by the abominable snowman) as a CV-controlled game module — a thin wrapper around the upstream skifree.js engine (MIT, Daniel Hough 2013). Single-instance per rack (maxInstances:1). Two bipolar CV inputs (x / y, −1..+1) synthesize the mouse cursor the skier steers TOWARD: x = cursor X across the canvas (0 = left edge, +1 = right edge), y = cursor Y (the skier always heads downhill; cursor position sets the steering angle + speed). When x and y are BOTH unpatched, mouse steering is available on the module's own surface: CLICK the slope to take the controls, then move the pointer over it and the skier heads for wherever you are pointing (pointing BELOW the skier is what sends it downhill). Any patched CV OVERRIDES the mouse, on the next pointer move, without a mode to switch (the factory writes the CV cursor each scheduler tick and the surface stops writing). The pointer position is mapped as a RATIO of the displayed picture's rect, so the 320 px dock slope and the 104 px lane thumbnail mean the same gesture; the vendored bundle's own enableMouse path is NOT used, because its handlers take their rect from the factory's detached canvas and therefore fed raw viewport pixels into a 0..320 space. One gate output: a rising-edge 10 ms pulse on every CRASH (hitting a tree / rock / snowboarder / failed jump) OR when the yeti EATS the skier — hooked to the engine's hasHitObstacle callback (upstream fires it for crashes and, via isEatenBy, for eats), so the game becomes a trigger source for envelopes / sequencers. One video output (out): the game canvas mirrored each video frame via the cross-domain audio→video bridge — patch SKIFREE → VIDEO OUT / BENTBOX / any video module to send the ski-slope render downstream (mirrors the DOOM `out` pattern). The game itself belongs to the NODE — the factory loads the bundle, builds the controller against a DETACHED canvas and disposes it when the node leaves the graph — so a rack nobody has expanded is still skiing, still crashing and still firing its gate, and the faceplate BLITs from that canvas rather than owning it. The faceplate carries the slope in two places: a steerable 320 px picture at the head of the dock full view, and a read-only thumbnail on the lane tile, both with a SCREEN switch semantic that stops the PICTURE and never the game. The `out` video port is the way to send the slope anywhere else. No audio worklet — the gate is a ConstantSourceNode pulsed on the event (PONG's pattern); the game logic runs at rAF cadence inside the bundle. Bundle committed pre-built at /skifree/skifree.bundle.js (~24 KB, esbuild IIFE of the upstream js/ classes + a thin embed wrapper); sprite sheets at /skifree/*.png. See packages/web/native/skifree/README.md for the regeneration recipe + attribution.

The classic SkiFree game wrapped as a hybrid audio/video module — ski downhill, dodge trees, rocks, and snowboarders, and outrun the yeti that eventually chases and EATS you. The skier always heads down the mountain and steers toward a cursor; you supply that cursor with two CV inputs (X and Y), so an LFO, sequencer, JOYSTICK, or envelope plays the slope. (When nothing is patched you can steer by hand instead: CLICK the slope on the module's faceplate to take the controls, then move the pointer over it — the skier heads for wherever you point, and moving the pointer BELOW the skier is what sends it downhill. Any patched CV immediately overrides the mouse.) The game produces one trigger output — a gate that pulses on every crash or yeti-eat — and one VIDEO output carrying the live game canvas, so SKIFREE can drive VIDEO OUT, BENTBOX, or any video module. It has no parameters and no internal audio (the gate is the sound source you build the patch around); it's single-instance per rack (only one SKIFREE can run at a time). The slope keeps running whether or not you are looking at it — the game lives on the node, so a rack you never expand is still skiing, still crashing and still firing its gate.

the faceplate

skifree · singletonxcvycvgategateoutvideoaudiocvgatepitch
2 inputs · 2 outputs · 0 params

inputs

idcablewhat it does
xcvBipolar CV (−1..+1) → the cursor's X position the skier steers toward. −1 = far left, 0 = straight down the fall line, +1 = far right. Read at scheduler-tick rate (a continuous position, not a gate). Patching it overrides mouse steering on the faceplate.
control voltage (CV)
ycvBipolar CV (−1..+1) → the cursor's Y position the skier steers toward. −1 = top, 0 = center, +1 = bottom — pulling the cursor lower makes the skier point more steeply downhill (faster). Continuous position, read each tick; patching it overrides the mouse.
control voltage (CV)

outputs

idcablewhat it does
gategateFires a 10 ms pulse on every crash event — hitting a tree, rock, snowboarder, or a failed jump — AND when the yeti finally eats the skier. A rising-edge trigger you can route to a crash sound, a drum hit, or a sample; the rhythm of pulses tracks how cleanly (or not) the run is going.
gate / trigger; trigger — fires once per rising edge
outvideoThe live game canvas as a cross-domain video source — each video frame the skier/mountain image is blitted into the audio→video bridge. Patch it into VIDEO OUT, BENTBOX, or any video module to display or further process the game.
RGB video stream

source

skifree.ts on GitHub.

Generated from packages/web/src/lib/{audio,video}/module-registry.ts · repo