A 1-bit frame of Jaws, advancing every 15 minutes. Live at jaws.superfun.games and on TRMNL e-ink displays.
The current frame is a pure function of the clock, so nothing has to be
committed or redeployed to keep the display correct. This is the whole point of
the current design: the previous version committed a new public/current.png
every 15 minutes via a GitHub Action, and every commit triggered a Netlify
deploy (~96 paid deploys/day). That's gone.
-
Frames:
frames/seq-0001.png…frames/seq-5301.png— 5,301 contiguous 1-bit stills, served statically. -
The math lives in two mirrored files (keep their constants in sync):
frame.js— browser version, used byindex.htmlandscreen.html.netlify/functions/_frame.mjs— Node version, used by the functions.
The sequence is phased as a countdown to the upcoming July 4th night:
index = (5300 - floor((nextJuly4Night - now) / 15min)) mod 5301So the final frame (
seq-5301.png) always lands on July 4th night (9:00 PM US Eastern by default — seeEND_HOUR_ET). The ~55-day straight run before it plays cleanly fromseq-0001.pngtoseq-5301.png(5,301 × 15 min ≈ 55 days, starting ~May 10th). The target automatically rolls to the next year after July 4th passes, so it ends on July 4th every year with no code change, and the sequence loops in between.One consequence of pinning a fixed calendar date to a ~55-day loop: just after July 4th night the countdown re-targets next year and the frame jumps once (mid-sequence) before continuing to loop forward toward the next July 4th. This single yearly re-sync is unavoidable unless the loop length divides a year evenly.
-
Website:
index.html/screen.htmlcompute the frame client-side, show it, and swap to the next one exactly at each 15-minute boundary. No backend. -
TRMNL:
netlify/functions/ping-trmnl.mjsruns on a 15-minute schedule and POSTs the current frame to the TRMNL custom-plugin webhook. Function invocations do not trigger deploys, so this costs nothing extra. The payload keys match the old function so the TRMNL template keeps working. -
Legacy
current.png:netlify/functions/current-frame.mjs302-redirects/current.pngand/public/current.pngto the correct frame, so old links stay correct without committing anything (wired up innetlify.toml).
- Cadence: change
INTERVAL_MSin bothframe.jsand_frame.mjs(and the cron inping-trmnl.mjs'sconfig.schedule). - Ending time: change
END_HOUR_ET(andET_UTC_OFFSETif not US Eastern) in both files to move when the final frame shows on July 4th night. - Tests:
npm test(runsnode --test) verifies the frame math and that the referenced frame files exist.
_data/image_counter.txtand_data/image_list.txtare leftovers from the old GitHub Action flow and are no longer read by anything.- Deploys now only happen when you actually push site changes — not on a timer.