Skip to content

Refactor coaster to ride any time series, not just stocks - #4

Open
Jonezzyboy wants to merge 1 commit into
stablyai:mainfrom
Jonezzyboy:generic-time-series
Open

Refactor coaster to ride any time series, not just stocks#4
Jonezzyboy wants to merge 1 commit into
stablyai:mainfrom
Jonezzyboy:generic-time-series

Conversation

@Jonezzyboy

Copy link
Copy Markdown

Closes #1

The coaster engine is now data-agnostic: a ride is any time series, not just a stock chart. Existing stock rides are untouched (regenerated index.json came out byte-identical for all 14).

How it works

New src/series.js normalization layer. Every ride JSON — legacy stock format or the new generic format — passes through normalizeRide() at load, producing the one shape the engine consumes:

  • points[].value (from value, or legacy close)
  • norm(v) → 0..1 altitude scale: log or linear, explicit via "scale" or auto-detected (log when all values are positive and the range spans ≥4x)
  • fmtValue() display formatting: currency for stocks, unit: { prefix, suffix } otherwise (with K/M/B abbreviation)
  • stats computed generically, with zero/negative values guarded throughout
  • headlines/milestones attach to the nearest point by date in the engine, so raw series need no preprocessing

Engine decoupling. Track altitude uses ride.norm/spanScore instead of hardcoded Math.log(close); HUD, minimap, menu previews, and the ride-end summary use fmtValue/norm, tolerate series without dates (point labels instead of year markers), and switch wording for non-currency rides (TOTAL CHANGE/WORST DIP vs TOTAL RETURN/$1,000 INVESTED); terrain seeding and signage key off ride.id. Drawdown embers, ATH confetti, and the lava trench all still fire — they were already value-relative.

Feeding in a series

  1. ?data=<url> fetches any series JSON and boards it directly (e.g. ?data=data/TOKENS.json&go=1)
  2. Drop a JSON in data-pipeline/series/ and run npm run data:series — published to public/data/ and added to the menu; the pipeline now regenerates index.json from output files

Format documented in the README ("Ride any time series").

Demo ride: TOKENS

A startup's daily Claude token usage over a year (373 points, ~1.5M → ~128M tok/day): agent-mode liftoff, an HN spike, a 95% region outage that carves the lava trench and fires a "REGION OUTAGE" billboard, and a prompt-caching dip. Rides as a NIGHTMARE-rated coaster with the HUD reading "118.4M tok, +8149% since start".

Testing

  • test/smoke.mjs grows a leg riding TOKENS via ?data= (checks the unit renders and the cart advances); full suite passes with 15 menu cards and zero console errors
  • Screenshot-verified: menu card, outage/trench section, peak gold blocks, and both generic and stock end-summaries
  • Bonus fix along the way: the intraday SPCX summary now reads "DAYS RIDDEN 1" instead of "YEARS RIDDEN 0.0"

🤖 Generated with Claude Code

Adds src/series.js, a normalization layer every ride JSON passes through
at load: points get a generic .value (from value or legacy close), stats
are computed, altitude comes from a norm(v) scale function (log or
linear, auto-detected when unspecified), and values format through a
per-ride fmtValue (currency for stocks, unit prefix/suffix otherwise).
Headlines/milestones attach to the nearest point by date in the engine,
so raw series need no pipeline preprocessing.

Engine changes: track altitude uses ride.norm/spanScore instead of
hardcoded Math.log(close); HUD, minimap, menu previews and the ride-end
summary use fmtValue/norm, tolerate series without dates (labels instead
of year markers), and switch wording for non-currency rides; terrain
seeding and signage key off ride.id. Zero/negative values are guarded
throughout. Legacy stock JSON works unchanged.

Feeding in a series:
- ?data=<url> loads any series JSON and boards it directly
- data-pipeline/series/*.json publishes via npm run data:series; the
  pipeline now regenerates index.json from the output files (stock
  entries unchanged byte-for-byte)

Includes a demo ride, TOKENS: a startup's daily Claude token usage over
a year, with an agent-mode liftoff, a 95% region outage (lava trench),
and a prompt-caching dip. Smoke test grows a ?data= leg riding it.

Closes stablyai#1

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Refactor the roller coaster so it can take any time series data (e.g. token usage overtime)

1 participant