• v0.9.4 1f4d549d8f

    v0.9.4 Stable

    joe released this 2026-09-30 20:23:07 +01:00 | 9 commits to main since this release

    A release about the game telling you things, and remembering them. Bindings can be changed
    without leaving it; a problem that used to go to a terminal nobody was watching is said on
    the screen; a song that will not start says why, and so does a missing audio device, which is
    no longer a crash. Song select opens on the songs you last played, and screens change with a
    wipe instead of a cut.

    Going back to 0.9.3 after this one: saving settings in 0.9.4 adds a [select] section
    to config.toml, which 0.9.3 does not know and so reads the whole file as unreadable,
    starting on defaults. Delete that section, or the file, to go back.

    Added

    • Problems are said on screen. A score, setting or calibration that would not save, a
      Play button with no songs behind it, and a display reporting an impossible refresh rate
      all used to go to stderr only — a terminal nobody is watching, and on a Deck in Gaming
      Mode no terminal at all. They now appear as a notice at the top right, with a sign for
      how serious it is, and go on their own after a few seconds. Nothing is shown over a chart
      being played; a notice raised then waits for the results screen. Everything is still
      written to stderr as well.

    • No audio device is no longer a crash. The game used to stop at startup with
      audio device and nothing else. It now starts silent, says "No audio device found" on
      every menu for the rest of the session, and refuses a song with a reason rather than
      starting one it has no clock for.

    • A song that will not start says why. Choosing one whose chart cannot be read or
      parsed, has no single-player course, or whose audio file is missing or will not open used
      to do nothing at all, with the reason on stderr. It now shows the song and the reason.

    • Recently Played. Song select opens on a category of the last 20 songs you finished,
      newest first, built from your scores rather than from a folder. A song you finish moves to
      the top straight away. How many it holds is a setting — Settings → Song select →
      Recently played song limit
      , or select.recent_limit in config.toml — from Off to 100.

    • Screens change with a wipe rather than a cut: a slanted band sweeps across and the new
      screen is behind it. Starting a song still gives the full lead-in.

    • --frame-log covers every screen, not only a chart, with a column saying which, and a
      summary per screen.

    • Bindings can be changed in the game. The bindings screen listed what every action was
      bound to and told you to edit config.toml, which is no answer at all on a handheld with
      no keyboard and no file within reach. Select on a row now waits for an input and adds
      it to that action, Left drops the last one, and a Reset to defaults row puts every
      action back. It adds rather than replaces: the defaults put five inputs on each don, and
      binding a sixth should not quietly cost the other five.

      The five actions that get you around the menus — up, down, Select, Back, and Back in a
      song — refuse to go to zero inputs and say why. Stranding yourself was the thing this
      screen could do that editing a file could not, since the screen that would undo it is the
      one you could no longer reach. Conflicts are not refused, because the cabinet's own
      layout shares a button between Select and don: binding something another action already
      has says what else it does and leaves it to you.

      A capture gives up after five seconds. Nothing can mean "cancel" on a screen where every
      input binds something, which is the same corner the input tester was in and the same way
      out.

      Nothing bound is heard until it is let go. An input is still under your finger when
      the capture closes, and by then it means whatever you just bound it to — so binding P to
      menu-left had the still-held P step left on the bindings row, which removes an input,
      which removed the P that had just been added. Removing does not repeat while a direction
      is held either: stepping through a list is what holding is for, stripping an action bare
      eleven inputs a second is not.

    • The bindings screen is a table. It was the shared settings list, which scrolls a
      window of eight rows around the cursor — and with sixteen rows to show, half the table was
      always somewhere else, on the one screen whose whole argument for not being a wheel was
      that it should be read together. It now has a layout of its own: every row on screen at
      once on a slate panel, grouped under the drum, getting around, choosing and leaving
      and this screen, with each input on a chip tinted by where it comes from — key, pad
      button, or axis. Five inputs on one action used to be a run of pad:LEFT_FACE_* text
      running the width of the screen; the prefix is now carried by the colour.

    Fixed

    • --frame-log's frame_ms was the previous frame's. Each row now carries its own.
    • Changing a video setting could pace at a refresh rate the game had already rejected. A
      display reporting, say, 2000 Hz was paced at 60 at startup and at 2000 once anything on the
      Video page was touched. Both now use the same rule.
    • An em dash drew a tofu box. The glyph atlas is ASCII, plus a handful of characters the
      interface needs, plus whatever the song titles need — and no em dash was in any of the
      three. The audio page has said "less latency, but loses your EQ — on restart" since it
      was written and has been drawing a box in the middle of it ever since. Found by
      screenshotting the new bindings screen, which sets its refusal line the same way.

    Documentation

    • Re-read OpenTaiko through 0.6.0.111 and its soundtrack through 2026-09-19. Nothing in
      three releases touches parsing, timing, judgement, scoring or the gauge; the one cited line
      that moved is recorded. The soundtrack rerated every chapter in decimals, taking fractional
      LEVEL: headers from 257 of 1885 to 709 of 1949, so format-notes.md now carries the
      reference's own rule — it truncates the number for play and turns the fraction into a ± icon
      — and the clear-threshold boundary those rerates cross is pinned by a test.

    • plan.md says what the game is, rather than what it was going to be before any of it
      existed, and the four rules the code cites back to it are now actually written in it.

    • The frame log's first run on real hardware is in timing-notes.md §9: every screen
      held a 240 Hz budget, and the only frames over it were the wipe's captures. A new library
      test, every_listed_difficulty_prepares, takes every difficulty song select lists as far
      as the audio device; on the OpenTaiko soundtrack that is 13,235 of 13,235, which closed
      step 28.

    • The README's release section describes the release it cuts — three binaries, not two —
      and the hit sounds are two curl lines from the OpenTaiko repository rather than a 122 MB
      archive.

    Downloads
  • v0.9.3 b98657e17f

    v0.9.3 Stable

    joe released this 2026-08-23 07:09:41 +01:00 | 24 commits to main since this release

    A release about being able to see what the game is telling you. Balloons behave the way the
    arcade's do rather than the way its source appeared to say, mines are bombs, and four of the
    five things the playfield says in words — the song, the difficulty, the score, the judgement
    — turned out to be set on grounds that could not carry them.

    Fixed

    • The song, its difficulty and the score are set on plates. They were small text laid
      straight onto the header band, competing with a drifting wave pattern for the same pixels
      — the playfield was the only screen in the game not putting a plate under a word that has
      to be read over a pattern. All three now sit on one, in the dark slate the roll counter
      already used rather than the song picker's brown, which belongs against the menus' warm
      ground and reads as mud on cyan. The difficulty wears its own colour, the same one its
      card wore in the picker. A title too long for the room is cut with an ellipsis rather than
      run under the score.

    • The lead-in call-out moved into the lane. "get ready" was dim grey text set above the
      lane, in the band the gauge lives in — the one place nobody is looking while they wait for
      the first note. It is now in the lane, at nearly half its height, cream over an ink
      outline like every other word in the game, and it fades out over the last third of a
      second instead of vanishing at zero.

    • The judgement word is readable now. GOOD, OK, BAD and MISS were set flat, alone among
      the words on the playfield, and placed where the reference places them — which works for
      the reference, whose gauge is in a corner, and not for us, whose gauge runs the width of
      that same band. The word was being drawn inside the gauge and its cells swallowed it. It
      is two thirds larger, outlined like everything else in the game, and dropped far enough to
      straddle the top of the lane, which is the darkest ground on the screen and the best thing
      to read a light word against. MISS is lighter as well: at #905050 it measured 2.9
      against its own outline where the other three measure 5.3, 12.1 and 13.4.

    • A letter shows beside the wheel while the song list is being crossed at speed. Holding
      a direction long enough to reach the accelerated repeat puts a row past every 35 ms, which
      is faster than a title can be read; the letter of the row the wheel is on now sits in the
      margin beside it and fades away when the scrolling stops. A single press never shows it —
      at that speed the bars say where you are and a letter over them would be noise.

    • --frame-log <file> records where every frame's time went — audio refill, our own
      update, issuing the drawing, and handing the frame over — one row per frame, written when
      the song ends. A frames-per-second number cannot describe a stutter; this can say which
      third of the frame it was in, which is usually the whole question. Off unless asked for.

    • Two things drawn every frame that did not need to be. A title too long for its plate
      was re-shortened a character at a time, sixty measurements a frame on this library's
      longest title; it halves the interval now and takes seven. A mine's fuse was drawn in
      twelve straight pieces, fifty draw calls a bomb on a chart with 360 of them; eight pieces
      is where it stops reading as a curve. Together they were costing more than everything else
      the playfield draws.

    • Mines are drawn as bombs. They were a grey disc, which is the one thing a note the
      player must not hit cannot afford to be — half a second on screen is not long enough to
      read a note by its colour alone. The reference has always drawn a bomb with a lit fuse
      (Graphics/5_Game/Mine.png, in every stock skin), so ours does too: a near-black body
      measured off that sprite, the collar, the fuse's S traced against the sprite's own body
      radius, and the spark at its tip. The body keeps our note's rings rather than the sprite's
      flat black — our lane is #222, and a black ball on it is a hole.

    • A balloon grows through six stages rather than five, opening at its smallest and
      bursting at its widest whatever its target.
      OpenTaiko loads six frames per skin and
      draws five of them: its threshold array is declared five long and its loop runs j < 5,
      so the widest frame every stock skin ships is never reached. Its ladder also opens part of
      the way up when the target is smaller than the frame count — a three-hit balloon starts at
      frame 3, looking like one somebody already got to — and lets the first frame swallow the
      remainder of an uneven division, so an eleven-hit balloon sits at its smallest for six of
      its eleven hits. Ours divides instead: even across the target, ends pinned, and frames
      skipped rather than omitted when there are fewer hits than frames. The sizes and colours are measured off Open-World
      Memories' own sprites, against the note drawn into them — 0.91 to 2.15 note radii, deep
      orange to near-white. That skin duplicates its second and third frames, so one of the six
      steps stands still; the numbers are copied as they are rather than smoothed.

    • Balloons hold at the hit zone, and inflate instead of deflating. They were drawn as a
      long bar scrolling past like a drumroll, with a disc at the judge ring that started wide
      and shrank as it was hit. Both are backwards. A balloon has no bar: from its head until
      its end the note holds at the hit zone, and only when the span runs out does it let go and
      leave with its tail. And it grows — the reference compares five thresholds against the
      hits still needed, not the hits taken, so it opens small and deep orange and is at its
      widest and palest through the last fifth before it bursts. It is now drawn as its sprites
      are: the note, a neck, and a balloon swelling away to the right of it — and it is there
      from the moment the note stops at the hit zone, not from the first hit — its count with
      it, since a count that is a target is worth reading before you start rather than after.
      The reference waits for a hit for both, which reads as the note vanishing on arrival and
      something else appearing in its place.

    • A drumroll's hits fly to the soul gauge like every other hit. They were the one
      struck note that went nowhere: not being judged, they got no burst, no judgement and no
      combo, so the flight was the only ordinary feedback left to them — and it was missing.
      At sixteen hits a second the effect was that the drum appeared to stop answering for the
      length of the roll. The flier is coloured by the surface struck and sized by the roll, as
      the reference sends it, and it flashes the gauge when it lands like any other. Balloons
      are deliberately left out: they answer a hit by deflating, and only the pop flies.

    Downloads
  • v0.9.2 725bf54bbe

    v0.9.2 Stable

    joe released this 2026-08-21 23:18:59 +01:00 | 47 commits to main since this release

    Windows gets a build, and text across the game gets read against the colour behind it rather
    than assumed to be legible on it. A third of this library's categories were drawing labels
    their own bar could not carry.

    Added

    • A Windows build, shipped with the release. scripts/release.sh cross-compiles
      taiko.exe with mingw-w64 and attaches it unless told --no-windows; nothing ships
      beside it, because every DLL it imports is a Windows system one.
      scripts/make-pack.sh --windows builds a playable folder for carrying across.

      Two things had to be fixed for it to be worth shipping. Config and scores now go to
      %APPDATA% and %LOCALAPPDATA%.
      Windows does not set HOME, so the path resolver fell
      back to "." and wrote them into whatever directory the game was launched from — a game
      started from the desktop and one started from its own folder kept two different sets of
      scores, and neither was anywhere a player would look. XDG_CONFIG_HOME and
      XDG_DATA_HOME still win where they are set, which is what makes running the Windows
      build under Wine behave the way its user expects.

      And fonts are found on Windows, in C:\Windows\Fonts and the per-user directory
      beside it, rather than through a fontconfig that is not there. That needed font
      collections to work: Windows keeps its Japanese faces almost exclusively as .ttc —
      YuGothR.ttc, meiryo.ttc, msgothic.ttc — and a collection handed to a rasteriser
      whole silently renders nothing, so they had been excluded outright and every Japanese
      title would have been a box. The new sfnt module takes one face out of a collection and
      repacks it as a font that loads. Collections count on Linux too now, which is worth two
      more glyphs of coverage on this library and makes font.path accept a .ttc instead of
      refusing it.

      Confirmed booting and reaching charts on Windows, on someone else's machine — so
      everything up to starting a song is known to work. The two differences above were verified
      under Wine. What nobody has measured is audio latency, which for a rhythm game is the part
      that matters, so calibrate before believing the timing.

    • Songs whose every chart is a two-player one can be played. Aiai had four courses,
      all STYLE:Double, so the browser offered no difficulties and Enter on it did nothing at
      all — indistinguishable from a dead key. Five of this corpus's 3578 charts are like it.
      The P1 side of a Double course is now offered for any difficulty that has no Single chart
      of its own, which is what docs/v1-scope.md always said v1 would do. It never stands
      beside the Single chart it belongs to, because that would be the same difficulty offered
      twice. The card says P1 SIDE: the chart plays fine alone but was written to interlock
      with a part that is not there, and a player who knows that will read a sparse stretch as
      the chart rather than as the game dropping notes.

    Fixed

    • The difficulty cards' level star was a tofu box. The font atlas is built from the
      characters the library uses plus a short list of the ones the game draws itself, and ★
      was on neither. Every card on the picker showed a missing-glyph box beside its level.

    • Text on the difficulty cards, chosen by contrast rather than by habit. Every card drew
      cream over a dark outline whatever colour the card was, which suited two of the seven: on
      Normal's gold it measured 2.6:1 and on Hard's green 2.5:1, against the 4.5:1 small text
      wants and the 3:1 floor for large. Each card now takes whichever of cream and ink measures
      better against it — name, level and score together, so a card is never two schemes at once.
      The song title and subtitle on the plaque behind them go the same way, cream on that orange
      being 2.9:1 to ink's 5.3:1. The rule lives in theme::text_on and the results chips, which
      had their own approximation of it, now share it.

    • Bar text on the song wheel, measured the same way. A third of this library's
      categories were drawing text that could not be read on their own bar. Two causes. The
      automatic choice between white and near-black was a threshold on a weighted average of
      the raw bytes, set at 0.62 — which climbs far more slowly through the mid-tones than the
      eye does, so a whole band of colours got white when they could not carry it; Pop's
      #42C0D3 gave white 2.2:1 where near-black gives 8.3:1. And a box's stated FORECOLOR
      was used whatever it measured: twelve of the fourteen boxes that state one chose a colour
      that cannot be read on the colour they state beside it, Pop asking for #004D68 on
      #20A0BA at 3.0:1. A stated colour is now used when it clears 4.5:1 on its own box and
      replaced when it does not. All sixty coloured categories now clear 4.5:1, the lowest at
      4.53. The main menu's Play row flips to dark ink by the same measurement, which is what
      the Easy card beside it already does with the same red.

    • The outermost bars no longer have their text washed to grey. The wheel runs off the
      top and bottom of the screen, and the corner furniture was given ground by a wash across
      the outer 17% of it. That wash lay over the bars in the band as well: a dark title on a
      mint bar came out brown, which was worse than the problem it solved. The wash now goes
      behind the wheel, where it still softens the edges of the screen, and the breadcrumb,
      counter and prompts each get a plate the size of their own words — the same brown the
      Return bars wear, since they are the same kind of thing. Song select, the main menu and
      the settings menus all change; Bindings at the foot of the settings list was the worst
      of them.

    • Sub-lines on a bar are no longer permanently half-transparent. The description under a
      menu row, a category's explanation, a song's subtitle and credit, and the song count in a
      bar's corner each carried an alpha ceiling below 1 — focus * 0.75 and the like — so that
      they stayed subordinate to the title even with the bar fully open. Alpha is a blend
      towards whatever is behind, and behind a bar's text is the bar, so what that produced was
      ink a quarter of the way into a saturated colour: not a quieter version of the text, a
      grey one. The smaller size is what makes them subordinate; they now reach full opacity,
      and focus is left to fade them in as the bar opens.

    Downloads
  • v0.9.1 897293ef20

    v0.9.1 Stable

    joe released this 2026-08-21 17:09:14 +01:00 | 56 commits to main since this release

    One fix: the notes stopped hitching as a song starts.

    Fixed

    • A frozen frame at the moment the music takes over. Chart time runs on the monotonic
      clock through the lead-in and switches to the audio clock on its first reading. But a device
      asked to play does not report where it is — it reports a position lagging real time by its
      own start-up latency, about a frame. So the first reading is behind where the lead-in had
      got to, and MasterClock refuses to hand back a time earlier than the last one, because a
      rhythm game that sees time reverse re-judges notes it has already consumed. The backward step
      became a frozen frame instead, once, exactly as the notes came on screen.

      The clock is now seeded with the time the lead-in had reached, and the existing smoothing
      walks it onto the audio's over the following frames. A chart whose OFFSET is deeper than
      the lead-in still snaps rather than crawling — that is a genuinely different starting point
      rather than device lag, and the resync threshold tells the two apart on its own. See
      docs/timing-notes.md §7.

    Downloads
  • v0.9.0 e037d9c5d2

    v0.9.0 Stable

    joe released this 2026-08-21 16:47:37 +01:00 | 58 commits to main since this release

    The game looks like a Taiko game now. Every screen was drawn in flat primitives on near-black;
    they are bright, patterned and outlined, and the notes, the gauge and the lane carry colours
    measured out of OpenTaiko's own skin rather than guessed at.

    The one fault worth naming: an existing config never received a changed default. The file
    is written on first run with every value spelled out, so anyone who had run the game before
    kept the old note colours and the old volumes indefinitely, having chosen neither. That is
    fixed for the values it had already caught, and it is a trap worth remembering — in this
    project, changing a default reaches new installs only.

    Added

    • A drifting pattern behind every screen. Seigaiha — the fan of overlapping wave crests —
      behind the menus and the playfield's header, and a quieter lattice behind the lists. One tile
      is drawn once into a texture at startup and blitted, so a frame costs a handful of quads
      rather than the thousands of arcs it would take honestly. The main menu holds its pattern
      still; everything else drifts right to left.
    • The playfield has furniture. A patterned header band, a stage below the lane where there
      had been 44% of empty window, a red-and-white awning along the bottom, and the combo on a
      drum face rather than as a bare number floating on the lane.
    • The soul gauge is the arcade's. Fifty cells stepping in two-percent increments, short and
      red below the clear threshold and half again as tall and gold above it, with the word CLEAR in
      the space that step creates and a soul at the far end for the struck notes to fly into.
    • --windowed, so a test run cannot take over the display, and --debug-hud with F10
      to toggle it — frame times as median, 99th and worst, plus a count of every frame that missed
      its budget for the whole run. A stutter is a tail, not an average.
    • A wayland build feature, off by default. See below.

    Changed

    • The menus are bright. A warm wash with the pattern over it, black keylines on every bar
      as the cabinet draws them, and a stroke around every glyph — bright grounds break light text,
      so those three had to move together.
    • The difficulty picker is a row of cards rather than a list, which is the shape of the
      choice and what the cabinet draws. Left and Right walk it; Up and Down still work, because on
      a drum the rim is the only thing that navigates.
    • The results screen is a plaque whose colour is the verdict — red, green, orange or gold —
      so it has said how it went before a word is read.
    • Note and gauge colours are sampled, not invented. Don #F84828, ka #68C0C0, the rim a
      cream #F7EFE0; the gauge red-on-dark-red below its threshold and yellow-on-dark-yellow
      above. The ka is the surprise: a soft teal rather than the saturated blue convention suggests,
      which is what stops a lane of alternating notes vibrating.
    • The combo appears at ten, as nMinDisplayedCombo.Drums does. Counting 1, 2, 3 beside the
      notes it competes with is noise.
    • Development readouts are off the play screen, behind --debug-hud where they belong.
    • Volume changes apply immediately. Hit sounds and previews each held a private copy set
      once at startup, so changing either needed the process restarted.
    • render.rs was five things in one file — 1508 lines holding the theme, the position
      model and four unrelated screens. It is 773 lines of playfield, and the rest are their own
      modules.

    Fixed

    • Two Return rows could land next to each other. The arcade's spacing rule counts forwards
      and says nothing about the step from the last one back round to the first; our list is a
      wheel, so a root of twenty-nine categories put one at 32 of 34.
    • The settings wheel dropped its top row. An entry crossed from one end to the other part
      way through the turn, so it travelled half the screen and vanished mid-flight. It crosses on
      the frame the key is pressed now.
    • The category list had no way out. On a drum that mattered: Back is not bound to a drum
      key, so a player using nothing but the drum could enter the library and never leave it.
    • --screenshot wedged the game on a fullscreen window — the first buffer swap after a
      capture never returned, and took the audio with it.
    • A display that would not report its refresh rate silently became 60. On a 144 Hz screen
      that paces every frame against a rhythm the display is not keeping. It says so now.

    Investigated and not adopted

    • Native Wayland. It works, one binary serves both backends, and no second thing would need
      maintaining. But frame pacing is indistinguishable from XWayland, and GLFW's Wayland backend
      does not implement window position, so raylib cannot tell which monitor it is on and paces to
      the wrong refresh rate. Kept as an opt-in wayland feature. See step 16.
    • A stutter under variable refresh could not be reproduced from inside the game, and the
      measurement that would settle it needs presentation timestamps that GLFW does not expose.
      Turning VRR off is the known cure; V-Sync measured as not being one.
    Downloads
  • v0.8.0 d04c25e6eb

    v0.8.0 Stable

    joe released this 2026-08-18 21:44:10 +01:00 | 106 commits to main since this release

    Every command a chart can use has now been read against the format's own reference and against
    OpenTaiko's source, and the four that were left unimplemented are in. Charts using the
    BEMANI-style scroll modes are drawn the way they were written for the first time, notes can be
    told to appear late and hold still, and they can be sent across the screen in any of eight
    directions.

    The one fault in it is in scoring, and it is a large one: on a branched chart the million was
    being divided between the wrong path, which mis-valued 280 of the 308 branched courses in a
    3578-chart library and, on two of them, made every note worth the entire million.

    Added

    • #HBSCROLL and #BMSCROLL — 35 charts. These come from the BEMANI series and measure a
      note's distance in beats where Taiko measures it in time, so a tempo change slides every
      note already on screen instead of changing the speed of the ones that follow. Supporting them
      meant carrying a second timeline through the parser, in sixteenth notes, alongside the clock.
      #BMSCROLL additionally discards #SCROLL entirely.

      The two models agree completely on a single note — one beat away is the same distance under
      either — and differ only on two, which is worth knowing because the obvious test passes under
      both and proves nothing.

    • #SUDDEN — 12 charts. Notes stay invisible until a set time before they are due, then
      appear already in position and hold still until a second time, and only then travel. Four
      rules came out of the reference and none of them were guessable: an unset value is positive
      infinity rather than zero, so misreading it blanks the chart rather than delaying it; the move
      time is truncated to whole milliseconds where the show time keeps its fraction; a show time
      with no move time hides rolls outright, which the reference's own source calls a bug and
      keeps; and only the horizontal freezes, so a note under a complex #SCROLL drifts vertically
      while standing still.

    • #DIRECTION — 2 charts. Eight directions, and the diagonals travel √2 times as fast
      because both components carry the full speed rather than the speed resolved between them. Its
      vertical is only a suggestion: a complex #SCROLL overrides it, while its horizontal is
      replaced outright.

    • SCOREMODE: and a [scoring] section in config.toml. The header selects one of the
      older arcade schemes — flat 1000 a note, or eleven tiers stepping every ten combo, or five
      tiers stepping at 10, 30, 50 and 100 — and it reaches the score only when Shinuchi is off,
      exactly as in the reference, where ShinuchiMode gates the whole thing and defaults to on.
      So shinuchi = true is the default here too, and 118 charts that set the header are scored
      as they always were until you say otherwise.

    Fixed

    • The million is divided between the Master path, not the Normal one. On any branched chart
      the reference fixes the per-note value at load from listChip_Branch[2] — unbranched notes
      plus the Master path — whatever the player then plays. That is deliberate and is the branch
      system's whole incentive: a run that stays on Normal does not total a million, and reaching
      Master is what pays. Dividing by Normal instead mis-valued 280 of 308 branched courses,
      often by more than double, and on two of them — Taiko Tower 02 Kara-kuchi's Tower and
      Unending Freedom's Easy, where the Normal path holds no missable note at all — it hit the
      zero-notes guard and made every note worth the whole million.

      All five recorded plays still match to the point, because none of those charts distinguishes
      the two rules: SHAPESHIFTER's Normal and Master paths hold the same 1001 notes.

    • A scroll mode set before #START is honoured. That was the required position for these
      commands until the format's 1.2 revision and the reference still reads them there. Two charts
      use it, and both were being recorded as unknown commands and drawn with the wrong model.

    Changed

    • The soul gauge keeps the rate it had. The gauge's fill and the score's denominator are two
      different rules in the reference — the score is fixed at load from the Master path, the gauge
      follows whichever path is being played — so fixing the one deliberately did not move the
      other. The gauge remains normalised over the Normal path, which is identical to the reference
      on every unbranched chart and is listed as open for the 308 that branch.

    Documentation

    • docs/reference-constants.md §2c and §2d — which path the
      million is divided between, and the three scoring schemes with the switch that hides them.
    • docs/format-notes.md §7d — the beat timeline, #SUDDEN, and
      #DIRECTION; and why a complex #SCROLL on a bar line needed no fixing after all, the
      rotation it might have wanted being a TJAPlayer3 bug OpenTaiko does not have.
    • The soul gauge rate should switch with the branch path and does not. Found while settling
      the scoring denominator, and recorded rather than fixed: it needs the gauge to carry three
      rates rather than one, which is a change to the type and not a constant.
    • Two lists of open questions were retired, both having been answered. Step 0.4's six —
      judgement windows, the score formula, gauge rates, roll and balloon scoring, the OFFSET
      sign, and the scroll maths — now point at where each was settled.
    • Two new steps: the screen the arcade draws, and charts that are not TJA. And a note on
      the five pure crates, which are likely to outlive this binary and should be changed with that
      in mind.
    Downloads
  • v0.7.2 8a6fdcb088

    v0.7.2 Stable

    joe released this 2026-08-18 12:21:56 +01:00 | 109 commits to main since this release

    Nothing new. Every command a chart can use was read against the format's own reference and
    against OpenTaiko's source, and it turned up one more fault of the same family as 0.7.1's: a
    section written to run backwards was running forwards instead. Nine courses across six
    charts
    were laid out wrongly, the worst of them by eight seconds.

    Fixed

    • A negative #BPMCHANGE is honoured rather than thrown away. A negative BPM flips the
      sign of the beat duration, which is how a chart lays a section out backwards, and the
      reference puts no check on the value at all. Refusing it would on its own have played those
      sections at the wrong speed — but a negative #MEASURE was already honoured, and charts
      pair the two. A negative bar over a negative BPM is a positive time duration, so taking
      one sign and refusing the other produced the one combination neither is meant to appear in
      and walked the definition cursor the wrong way. Across the 3578-chart corpus this moved
      9 courses in 6 charts by 1.03 to 8.06 seconds, changed no note count, and touched
      nothing else.

      Two of the three affected non-Dan charts check themselves: the fixed course was the only
      one in its file using a negative #BPMCHANGE, and it now ends where its own siblings
      always did. Rainy Tear's Oni ended at 208.62 s against 209.66 s for its Hard, Normal and
      Easy, and now ends at 209.66 s too. Nothing arranged that agreement.

      This one would not have been caught by the end-of-audio check that 0.7.1's work
      recommended: all nine last notes fall inside their own audio before and after. Displacement
      inside a song is the harder kind to see, and only the reference finds it.

    • #BPMCHANGE 0 stays rejected, being the one value with no meaning. The reference would
      divide by it, the format reference marks it unspecified and records that it crashes some
      simulators, and no chart in the corpus writes one.

    Documentation

    • Every command in the corpus is now accounted for, in
      docs/format-notes.md §7c — forty of them, each either implemented,
      confirmed correct against a named line of the reference, or recorded as a deliberate
      divergence with the number of charts it costs. Three are known to be wrong and are written
      down as such rather than left to be rediscovered: #HBSCROLL and #BMSCROLL (35 charts)
      select a beat-based position model we do not draw with, #SUDDEN (12 charts) is
      unimplemented, and a complex #SCROLL should rotate bar lines where we move them
      vertically.
    • #NMSCROLL turns out to be the default mode, so ignoring it was already right and the
      19 charts using it were never wrong — one of several assumptions this pass was able to
      retire rather than reopen.
    • A miscount was corrected. The note-character table claimed A and B never occur in
      the corpus; they occur 78 and 109 times, and did when it was written. Nothing behaved
      wrongly, both having been aliased to 3 and 4 regardless, so the fault was only ever in
      the writing — which is the argument for checking the notes against the reference and not
      only the code.
    Downloads
  • v0.7.1 9a59742125

    v0.7.1 Stable

    joe released this 2026-08-18 02:56:13 +01:00 | 111 commits to main since this release

    Nothing new. Charts that branch were being read wrongly in six separate ways, and the worst
    of them left 181 charts playing seconds out of step with their own music — 90 of those
    ending after their own audio had stopped, with notes nobody could ever reach. This release
    only puts notes back where they belong.

    The faults were found by walking the format against OpenTaiko's source rather than reasoning
    about it, and then settled by playing SHAPESHIFTER — the chart that prompted the work —
    beside OpenTaiko playing the same file. Its gimmicks now land at the same moments in both.

    Fixed

    • 181 charts were playing seconds out of step with their own music. A #MEASURE or
      #BARLINEOFF on the line before a #BRANCHSTART was being read as an empty bar of rest,
      which pushed the branched section — and, since the song carries on from where a branch
      ends, everything after it — most of a measure late. Commands are not a measure; only note
      data makes one. Across the 3578-chart corpus this moved 216 courses by a median of 6.3
      seconds
      and put 90 of them back inside their own audio: SHAPESHIFTER's Oni was
      ending 5.8 s after the song had finished, with notes that could never be played.
    • Branches are decided at the right moment. The determining point is the last bar line
      before the branch, so the lead is however long that measure was — not a measure computed
      from the signature in force. SHAPESHIFTER's fake-outs lead by half a beat and now do; they
      led by 3.5 beats, so the swap the chart exists for happened off screen. Roll conditions
      wait for the roll to end, a hidden bar line still decides a branch, and a chart opening on
      one is judged four beats before it starts.
    • Branch points are ordered by when they are decided, not by where their section starts
      — two different times, which a negative #MEASURE can put in different orders. Ties keep
      the order they were written in, so a chart can bury an unwanted branch change under a
      wanted one, as the reference's own changelog describes.
    • A branch group ends where its last-defined path left off, not where the longest one
      did — the same answer on an ordinary chart, and the wrong one whenever a path rewinds
      through negative measures. This is what stopped SHAPESHIFTER's central trick working:
      its two branch changes are folded onto one instant so that the unwanted one is hidden
      under the wanted one, and we were missing that instant by three bars and showing both.
      You now see one "level up" at 75 s where there were two changes 2.45 s apart.
    • A branched chart names its path from the first frame, reading "Normal" until something
      changes it, rather than showing nothing until the first branch. HIDDENBRANCH is now read
      and is the only thing that holds the name back.
    Downloads
  • v0.7.0 7beb355ec5

    v0.7.0 Stable

    joe released this 2026-08-17 19:28:47 +01:00 | 117 commits to main since this release

    The drum is the whole interface now: it works the menus, the screens say so, and the
    playfield answers every hit.

    Added

    • Every hit is answered. A note bursts at the judge ring and flies off to the soul
      gauge on a bowed arc, which is what makes a fast stream read as a stream — the last dozen
      hits are still on screen. The gauge flashes when a note lands on it, 560 ms after it was
      struck, rather than when it was hit. Every timing is OpenTaiko's, written up in
      docs/reference-constants.md §7; reading them rather than
      guessing turned up three things nobody would invent, including that a BAD is answered
      with nothing at all
      .
    • The combo bounces on the reference's own thirteen-step curve, peaking 18% larger four
      frames in, and changes colour at 50, 100 and 300. The judgement eases into place over
      410 ms and fades over the last 50.
    • A big note taken with both hands gets a second, larger burst — the distinction has
      been scored since 0.4.0 and shown nowhere until now.
    • Go-go time arrives rather than merely being tinted: the lane brightens and a spray of
      sparks is thrown up from six points across the bottom.
    • Rolls and balloons answer too. A roll shows a framed count that lingers 2.44 s after
      the last hit rather than blinking with each one; a balloon counts down and deflates in
      five stages as its target approaches.
    • The drum works the menus, as it does on the cabinet: the rim moves — D up, K
      down — and either don key, F or J, chooses. That is the whole interface for
      anyone playing on a real drum, where those four inputs are all there is. D no longer
      moves the cursor right, since one key cannot both move and adjust on a screen that reads
      them together.
    • A way out you can see. Song select repeats a Return entry through every category
      — the arcade's floor(n / 7) + 1 of them, so a way out is never more than seven presses
      away — and the difficulty screen offers Back first, before the difficulties. Bound
      keys were not enough: on a real drum there is no Escape key.

    Fixed

    • A song no longer loops when its audio runs out before its chart does. "R"ast GaMES!! played itself twice, and the second time — every note already resolved — all
      that appeared were the drumrolls. raylib loops a music stream by default and the clock is
      the audio's own position, so the wrap took chart time back to zero with it. A song now
      ends when either its chart or its audio does.
    • A one-pixel line of undimmed bar along the bottom of the song wheel, where the fade
      stopped a row short of the screen.
    • A category explanation split across lines no longer reads community- made.

    Changed

    • Autoplay drums rolls, at the 16.6 hits a second the reference assumes when budgeting
      a roll's share of the score. It never touched them before, which left the only feedback a
      roll has impossible to see without a player. One consequence: --auto can now score over
      1,000,000 on a roll-heavy chart, which is what happens to anyone rolling faster than the
      budget assumes.

    Documentation

    • Branching, as the format actually defines it — the determining point is the last bar
      line before #BRANCHSTART, branch changes at the same instant resolve by definition
      order, and negative #MEASURE overlays rather than skips. Three sources agree:
      the charter of SHAPESHIFTER with his own diagrams,
      IepIweidieng's TJA reference,
      and OpenTaiko's source. We have it wrong, in a way this release does not yet fix:
      see step 17a in implementation-plan.md.
    • Step 11's gate is reopened. SHAPESHIFTER was signed off as matching the reference and
      does not; the score check that appeared to confirm it is arithmetic on judgement counts
      and says nothing about where a note is drawn.
    Downloads
  • v0.6.0 08fcf54bfd

    v0.6.0 Stable

    joe released this 2026-08-17 10:48:08 +01:00 | 128 commits to main since this release

    Song select was a file browser that happened to hold songs. It is now a wheel, and so is
    every menu that reaches it.

    Added

    • Song select is a wheel of coloured bars, turning past a fixed middle with the
      selection opened out — its jacket, credits and difficulty levels inside the bar rather
      than in a panel off to one side. The neighbours above and below stay visible, so moving
      reads as the wheel turning rather than a page redrawing.
    • Categories bring their own colours and descriptions. box.def has always carried
      them — 50 of this corpus's 51 categories set BOXCOLOR and 41 set the explanation
      lines — and none of it had ever been drawn. Songs wear the colour of the box they are in,
      which turns a library into a set of coloured places rather than a page of words.
    • The main menu and the settings screens are the same wheel. Each settings screen has a
      colour and its rows wear it, so opening Audio keeps the colour of the bar that opened it.
      Values are drawn on every bar, not only the selected one, so a screen of settings can
      still be read at a glance. Bindings stays a list on purpose: it is a table to be read, and
      a wheel would show one binding and hide the other ten.
    • Songs are auditioned while you browse. Resting on one for a third of a second plays it
      from its DEMOSTART — the part the charter chose — fading in, and returning there after
      25 seconds rather than wandering into the rest of the song. Scrolling past a hundred songs
      starts none of them.
    • Holding a direction scrolls, accelerating after a second so a 500-song library can be
      crossed without pressing anything 500 times.

    Fixed

    • A quarter of the jackets never appeared. raylib builds without JPEG support unless
      asked for it, and 94 of this library's 398 covers are JPEGs — they failed to load and drew
      as "no art" with nothing said about why. All 398 now load.
    • Loading a jacket no longer stutters the browser. Decoding one takes 8.6 ms at the
      median and 164 ms at worst — ten frames — so with a load on every step, scrolling
      visibly hitched. Decoding and resizing now happen on their own thread; only the upload to
      the GPU stays on the main one, and that is 0.8 ms at its worst. The selection is fetched
      first and then the two bars either side, so stepping to a neighbour usually finds it
      already there.
    • Jackets are held at 512 px rather than 1024 — one is drawn at about 475 px on a 4K screen —
      which takes a full cache from 81 MB to 25 MB, and the cache now evicts oldest-first
      instead of emptying itself when it fills.
    • A category explanation hard-wrapped mid-word no longer reads community- made.
    Downloads