Skip to content

Releases: sarang-cmd/bench

v1.2.8

Choose a tag to compare

@github-actions github-actions released this 01 Nov 14:25
9c5258e

1.2.8 - 2026-11-01

The site's page check has been red since 1.2.6, and the release went out anyway:
the add-in build, the core tests, the WebAssembly build and the toolchain job all
passed, so Bench-1.2.7.g3a and its zip are real - only "Site build and page
checks" failed, and it has been failing the same way since I added the starter
pack card to /downloads.

  • check-pages.mjs checked a file nothing had fetched. A fresh checkout has
    no site/public/Bench-*.g3a and no site/public/Bench-starterpack-*.zip; both
    are gitignored and fetch-addin.mjs puts them there during npm run build,
    which runs after the page check. So the new "the zip the page offers is
    really there, and hashes to what the page prints" check reported
    "described but missing from public/" on every run. It now runs
    fetch-addin.mjs itself before rendering, exactly as it already ran
    fetch-spike.mjs for the same reason; a failure there is reported, not fatal,
    because the page still renders and the checks still say what is missing.

  • The add-in gets the same check: the page prints a size and a SHA-256 for
    the .g3a, and that file is now compared with them too, so a stale download in
    public/ cannot be served under a hash that belongs to a different build.

  • Reproduced before fixing: a fresh git clone --branch v1.2.7, npm ci,
    node scripts/check-pages.mjs fails with exactly the CI message
    (FAIL starter pack zip: Bench-starterpack-1.2.7.zip is described but missing from public/), and passes after the change.

  • dist/ keeps one starter pack zip: Bench-starterpack-1.2.8.zip (the ten
    files, unchanged since 1.2.7), so the repository does not accumulate a copy per
    release. The release job already deletes the old one before copying the new.

Nothing about the add-in changed: no C, no screen, no key. The tag exists so the
pipeline that builds a release is green end to end: the v1.2.7 tag points at a
commit from before this fix, so its own site job stays red for good.

v1.2.7

Choose a tag to compare

@github-actions github-actions released this 01 Nov 14:15
c01ad4a

1.2.7 - 2026-11-01

Wording, not behaviour: the demo is the starter pack now. Everything the
add-in, the zip, the repository and the site call it uses one name, because
"demo" was doing three jobs at once - a demo of the software, throwaway sample
data, and the files a new install needs to have something to read.

  • Every user-facing mention says starter pack: the README section, the
    downloads page card, docs/TUTORIAL.md, docs/STATUS.md, dist/README.md,
    the hardware checklist and the in-app comments. No screen inside the add-in
    said "demo", so no tour script changed its content; step 99 is still the
    first-run screenshot and the image is now 99_starterpack_seeded.png.
  • The names on disk follow: demo/ is starterpack/,
    Bench-demo-<version>.zip is Bench-starterpack-<version>.zip,
    tools/gen_demo.py is tools/gen_starterpack.py,
    tools/make_demo_zip.py is tools/make_starterpack_zip.py, and the make
    targets are starterpack-gen, starterpack-check, starterpack-zip and
    starterpack-zip-check. So is the code: src/platform/starter.{h,c}
    (starter_install()), src/apps/starter_data.{h,c} (starter_files[],
    starter_file_count), and tests/test_starter_data.c,
    tests/test_starter_files.c, tools/test_starterpack.py.
  • The wasm build follows too: the file the browser simulator seeds its
    in-memory filesystem with is starterpack.json, and the worker's message key
    is starterpack.
  • What did not change: the ten files, their text, the destination folders
    (Bench/notes, Bench/cards, Bench/study, Bench/formulas), the rule that
    only missing files are written, the ASCII-only check and the size budget. The
    cards gained a few bytes because their own first line said "sample content for
    the demo folder" and now says "starter pack folder" - 17 877 B becomes
    17 901 B, and the zip 10 479 B becomes 10 495 B. Unverified on device.
  • 1.2.6 keeps its own names: that release carries Bench-1.2.6.g3a and
    Bench-demo-1.2.6.zip, and its entry below still says demo, because that is
    what it shipped. From this version on, the file to download is
    Bench-starterpack-1.2.7.zip.
  • two things the rename broke, both fixed here: the wasm build looked for a
    directory called starter pack (a path hit by the rename), found none, and
    wrote a zero-file seed - the browser simulator would have booted with an empty
    card; it now fails the build rather than ship an empty seed. And
    BENCH_NO_STARTERPACK= counted as "set", because the tour passes an empty
    value when it wants the seed kept, so the first-run screenshot showed an empty
    card. It reads the value now, and step 99 runs against a fresh filesystem.

v1.2.6

Choose a tag to compare

@github-actions github-actions released this 01 Nov 13:24
9ed9435

1.2.6 - 2026-11-01

Numbers here describe the source in main. The release carries
Bench-1.2.6.g3a built by CI from this commit, and nobody has had it on a
calculator yet
.

  • The demo travels inside the add-in now: a .g3a is one file, so a folder
    cannot come with it, and "copy demo/notes into Bench/notes" was three steps
    on a PC before a new install had anything to look at. The ten demo files - the
    three notes, the three decks, the study log and the three formula booklets -
    are compiled into the add-in as C literals and written to the card on the first
    run, so a fresh install opens Notes, Cards, Study log and Formula book and
    finds something in every one. Rules: only files that are not there yet are
    written, so nothing you wrote is ever overwritten, and at most twelve files are
    written per run. The text is generated from demo/ and
    docs/samples/formulas/ by tools/gen_demo.py; make demo-check fails when
    the generated table and the sources drift apart, and tests/test_demo_data.c
    reads every entry back with the same checks (printable ASCII, len equal to
    the joined length, no duplicate, source file unchanged). One booklet is over
    the 4095 bytes ISO C promises for a string literal, so each file is a list of
    chunks the add-in joins before writing - the generator refuses anything over
    6144 bytes, the size store_write() takes. Unverified on device.
  • The same demo is a separate download too: Bench-demo-1.2.6.zip holds
    Bench/notes, Bench/cards, Bench/study and Bench/formulas, so it
    extracts onto D:\ in USB Flash mode and lands exactly where the add-in
    writes. It is for a full card, a second card, or editing the notes on a PC
    before they ever reach the calculator. Built by tools/make_demo_zip.py,
    reproducible (sorted entries, fixed timestamps), checked in CI against the same
    sources, attached to the release and kept in dist/.
  • store_exists(): the seeding needed a way to ask whether a file is there
    without reading it, so src/platform/store.{h,c} gained one (a BFile_Open
    in a world switch, closed immediately, no read). src/platform/demo.c is the
    only caller and never touches anything else.
  • What this does not do: it does not touch a file that already exists, does
    not run anywhere but start-up, and does not write anything outside
    \fls0\Bench. A card that is full or write-protected still gets a working
    add-in, just without the demo - demo_install() ignores the failure.

v1.2.3

Choose a tag to compare

@github-actions github-actions released this 01 Nov 12:43
62e63aa

1.2.3 - 2026-11-01

Numbers here describe the source in main, not a run on hardware: 1.2.3 is
built by CI from this commit, and nobody has had it on a calculator yet.

  • The calculator build has been failing since the Pi game landed:
    app_pi.c calls nt_append without including ui/numtext.h. The host
    preview took it as a warning and drew a perfect screenshot; the fxSDK build
    runs -Werror=implicit-function-declaration and stopped, so there has been no
    .g3a since 1.1.0 and the tagged release for 1.2.2 could not exist. The
    include is one line; the reason it went unseen for four merges is that the two
    builds disagreed about which warnings matter, so the preview now compiles with
    the same -Werror=implicit-function-declaration as the calculator and the
    candidate .g3a cannot be the only thing that finds it.

  • The committed WebAssembly build is rebuilt from these sources, so the
    simulator on the site is the same code as the screenshots again. Its smoke
    runs (down,exe and the worker path) pass. Unverified on device.

  • The screen checker can see a label sitting on a border: it compared
    rectangles, so two things that merely touched were "not overlapping" and
    passed. The menu's first-run hint spent eleven merged pull requests with its
    ascenders on the bottom tile border, and 97 green screenshots said nothing
    about it. scr_frame is traced now - scr_fill records only panels of 8x4 or
    more, and a two-pixel border is exactly the size that goes wrong - and a label
    within two pixels of any frame, inside or out, fails the run. Checked against
    the old layout: it reports the hint and nothing else, so the rule has teeth
    without inventing work on the other 96 screens. docs/design.md lists it.
    Unverified on device.

  • The softkey bar has room to breathe, and the first-run hint is no longer
    jammed into the tiles
    : a 10-pixel label in a 16-pixel bar left three pixels
    above and below, so the six labels read as text pressed into a slot rather
    than six buttons. The bar is 20 pixels now, dividers stop short of its top and
    bottom edges, a label keeps at least four pixels from the separator beside it
    and is ellipsised rather than run into its neighbour, and the bar grows into
    the content area on all thirteen screens at once because every screen places
    its footer relative to TH_SOFT_H. The menu's first-run hint also had its
    ascenders on the bottom tile border: it now has its own band, sized from the
    text, and the grid stops clear of it, so there are eight pixels above the
    words and five below. The line also lost the words "a tile" so it keeps a
    margin at both ends instead of running edge to edge. Unverified on device.

  • The site was not deploying at all: node scripts/gen-tools.mjs has failed
    on every push since the four V2 tools landed, because each says in its own
    words what it does and site/src/toolCopy.js still listed twenty-two of them.
    The build reported "registry tool "factor" (Prime factors) has no copy" and
    stopped, so the last successful deployment predates Prime factors, Percentages,
    the Formula book and the Pi game. All four are in toolCopy.js now, with their
    real screenshots, and are in the "own words" set that needs proofreading.

  • The download picks the newest build by version, not by file date: dist/
    is a git checkout, so every .g3a in it is written at the same moment and the
    order the filesystem hands back decided which one the page offered. It offered
    1.0.0 while 1.1.0 sat beside it. The fallback compares the numbers in the file
    name now, and a build's commit and date are dropped when the bytes came from a
    different file than the one BUILD.txt describes.

  • CodeRabbit, configured in the repository instead of a dashboard:
    .coderabbit.yaml tells the reviewer what this project actually breaks on -
    src/core must not include gint or libm, a screen may only use the nine
    palette colours with 2 px ink borders and a 3 px shadow under the selected
    item, a new core function needs a test with a concrete vector, a regenerated
    table is not a code change, and files are written to flash only at session
    end. Generated files, images, binaries and the site lockfile are out of scope,
    poems and UML diagrams are off, and automatic approvals are off because
    merging here depends on whether anyone ran the build on a calculator.
    tools/check_coderabbit.py parses the YAML with its own small reader - no new
    dependency - and rejects an unknown key, a path_instructions glob that
    matches no file (how a rule for a renamed directory stops applying), a tool
    switched on with no config file or for a language the repository does not
    contain, tabs and CRLF. make coderabbit-check runs it and CI runs that.
    Installing the GitHub App is the one step a commit cannot do;
    docs/CODERABBIT.md has the four clicks. Unverified on device.

  • A version number that moves with the work, and a check that it did: the
    tree said 1.1.0 through fourteen merged pull requests, so the About screen, the
    .g3a name and the website would have disagreed with the changelog the moment
    anything shipped. The rule is now that every change bumps the version in the
    same commit - patch for a fix or a doc, minor for a feature, major only for a
    storage-layout change - and the version of record is 1.2.0. tools/ bump_version.py rewrites version.txt, the src/version.h fallback and the
    example file name in CMakeLists.txt in one command (make bump-minor,
    make bump-patch), and --check compares those against the changelog heading
    and the README badge, naming each file that disagrees. make test runs it, and
    so does CI, so a forgotten bump fails a build instead of shipping. 21 Python
    tests cover the arithmetic and the rewriting, including that a bad version is
    refused before any file is touched. The README's version badge now links to the
    releases page rather than to releases/tag/v<version>, because between a bump
    and a release there is no such tag and a badge pointing at a 404 is a lie about
    a page. Unverified on device.

  • Percentages tool: the four questions a paper asks - percentage change,
    add or take a percentage, reverse percentage, compound growth or depreciation -
    on one Math screen, with the working written out under the answer. The point
    of the reverse question is that it divides (34 / (1 - 15/100) = 40), which is
    what people get wrong by adding 15% of 34 back on. src/core/percent.c with 41
    checks covers the vectors (500 at 4.5% for 7 years is 680.43; a car at 12% for
    5 years keeps 52.8%), zero years, a negative rate, and the three questions with
    no answer - a change from zero, a 100% discount, a period count outside 0..200

    • each of which is a sentence on screen rather than a 0 or an inf. One bug
      caught by the tests before the screen existed: the fast exponentiation gave up
      on an overflow by returning the principal, so a question with an unshowable
      answer said "no growth". Unverified on device.
  • The formula book: the IB AA HL, Physics 2025 and Chemistry 2025 booklet
    content, as a Study tile called Formula book. The booklets are plain text in
    Bench/formulas/, one .txt per booklet, so a teacher (or you) can add one
    without a rebuild - the list shows every file in the folder and its first #
    line as the description. The viewer scrolls a line at a time and jumps a
    topic at a time with LEFT/RIGHT, headings coloured red, blue and ink by
    level. New src/core/formula.c holds the line and heading arithmetic with 40
    checks, including that a jump ignores ### sub-headings - with those counted,
    a booklet with a heading every few lines moved five lines a press, which is
    not a section.
    The content is a transcription nobody has proofread yet: the PDFs print
    formulae as images, so the text was typed, and it is marked as unproofread in
    three places - the first line of every booklet, docs/samples/formulas/ needs-human-proofreading/README.md, and the help page. Treat an unproofed
    line as unchecked.

  • The Pi game: a Study tile. The digits you have earned stay on screen,
    grouped five to a line; type the next ones, EXE checks them, and the first
    wrong digit costs a life. Three lives, F2 gives the next digit away and costs
    one - a hint that is free is not part of a game - and the round ends with how
    far you got and the best of the session. Nothing is written to the card, so
    the best score lives and dies with the session, which is what the file-write
    rule allows. The digits are src/core/pi.c: 200 of them, and
    tests/test_pi.c checks the table against a Rabinowitz-Wagon spigot computed
    from the algorithm rather than copied - a typo in the table cannot hide by
    being duplicated in the test (40 checks, first 100 digits plus the human
    check that the 100th decimal is 9). pi_match stops at the first wrong digit
    so a guess that runs off the end cannot read past the table.
    Unverified on device.

  • Prime factors, on its own screen in Math: factorisation existed, three
    levels down a list of nine Number theory functions, which is not where anyone
    looks for it. The new screen takes a number up to 18 digits and shows the
    factorisation written out - 360 = 2^3 x 3^2 x 5 - with the four numbers that
    follow from it: divisor count, divisor sum, totient and square-free part, plus
    how many distinct primes and whether the number is a perfect square. F2 halves
    the number and factors again, which is the question that usually comes next.
    New in core/numtheory.c, each with vectors checked by hand (1091 checks in
    that suite): nt_factor_text (exact buffer arithmetic, so a text of exactly
    the buffer's length is accepted and one byte less refused),
    nt_divisor_count, nt_divisor_sum (the geometric series without a division,
    wrapping ...

Read more

v1.1.0

Choose a tag to compare

@github-actions github-actions released this 01 Nov 00:54
30c596d

1.1.0 - 2026-11-01

The two bugs from the first hardware session, the V2 tools, and the machinery
that stops the next one. Not run on a device yet: the 1.0.0 rows in
docs/HARDWARE.md are the only hardware results that exist.

  • A hardware report you can fill in on the calculator (V2, workstream J):
    Settings gained F3, which opens a screen listing the eight assumptions
    Bench makes about the CASIO filesystem, the font, ALPHA, the clock and the
    frame time. Each row starts at not tried; LEFT/RIGHT marks it works or
    fails after the matching test in docs/HARDWARE.md. F2 writes
    state/hwreport.txt in plain text, so the result comes off the calculator by
    copy rather than by retyping, and nothing is written at any other moment.
    The formatter is src/core/hwreport.c (63 native checks, including a buffer
    that is one byte too small), and docs/HARDWARE.md says how the file slots
    into the report.

  • A shared number field and a history of answers (V2, workstream A5):
    src/core/numedit.c is the one place that decides what a numeric field
    accepts - digits, at most one dot, a lone zero replaced rather than stacked, a
    leading dot turned into 0. - with numedit_valid() for "would numparse read
    this?" (54 checks). The moles screen was carrying its own copy, which is how
    1.2.3 got in; it now uses the shared one. src/core/history.c keeps the last
    eight formatted results (33 checks) and the Root finder pushes every solve onto
    it, with F4 to show the list - a panel, not a file, so nothing is written to
    flash.

  • WebAssembly build, and the loader that copes without it (V2, workstream
    G)
    : tools/sim/sim.c gains an __EMSCRIPTEN__ path - keys from the page,
    the framebuffer handed back as RGBA - and tools/wasm/build.sh compiles the
    same sources the screenshots come from with emscripten and Asyncify. The
    binary is a build artifact and is not in git: the site's /simulator page
    loads it when this deployment has one and says so in one line when it does
    not, and the gallery stays underneath either way. CI has an optional job for
    it. Not built or run here: there is no emscripten in this environment, so
    the C is unverified by compilation.

  • Browser widths in CI (V2, workstream B): site/scripts/check-widths.mjs
    loads all eight routes at 320, 390, 768, 1024 and 1440 px and fails on a
    horizontal scrollbar, an element that crosses the right edge or one wider than
    the viewport. Chromium could not be downloaded here, so the sweep has only run
    in CI; the result of that first run is in the pull request.

  • Demo content (V2, workstream D): demo/ holds three notes, three decks
    and a fortnight study log so a fresh install is not three empty screens. The
    text is written from scratch, not copied from a booklet or a past paper, and
    demo/README.md says in its first section that it needs human proofreading.
    tests/test_demo_files.c reads every demo file with the add-in's own parsers
    (108 checks) and fails on a single skipped line, so the sample cannot rot into
    something the calculator refuses to read.

  • The site is eight pages, not one (V2): /features, /simulator,
    /tutorial, /install, /downloads, /changelog and /about join the
    landing page, which keeps its layout. src/router.jsx is a 120-line path
    switch with real <a href>s, so back, forward, middle-click and a shared link
    all work; vercel.json rewrites every path to index.html. Every route sets
    its own title, description, canonical and Open Graph image.
    scripts/gen-stats.mjs and scripts/gen-changelog.mjs write the numbers and
    the changelog from CHANGELOG.md, docs/tools.json and src/, and
    scripts/check-pages.mjs renders all eight routes in Node and fails the build
    if one throws. Eight 1200x630 Open Graph cards come from
    tools/brand/make_brand.py. The canonical URL is now
    bench-gdc.vercel.app everywhere; sitemap.xml lists all eight
    routes.

  • The simulator page is honest about the simulator: the interactive
    WebAssembly build (workstream G) is not done, and the page says so instead of
    pretending. What it shows today is the real frame buffer: 75 captures made by
    the add-in's own simulator.

  • Settings, five rows (V2): src/core/settings.c gains two keys,
    angle_unit (0 degrees, 1 radians) and tour_done (0 or 1). The screen now
    lists the unit the Triangle tool opens in and whether the first-run line on
    the home screen has been read; app_triangle_init() takes its starting unit
    from the setting, and F3/F4 still switch for that session only, without
    writing the file. A settings file from 1.0.0 still loads: the new keys fall
    back to their defaults. 687 native checks in tests/test_settings.c.
    Unverified on device.

  • First-run hint (V2): with tour_done 0 the home screen prints one line
    above the softkeys - "F1-F4 categories, F5 explains a tile, EXE opens it" -
    and opening help with F5 sets tour_done and writes the file once.

  • Complex numbers (F6): src/core/cplx.c adds, subtracts, multiplies,
    divides (division by zero is a NaN, not a wrong number), raises to an integer
    power and reports the modulus, the argument (with bm_atan2, new in
    src/core/mathfn.c) and the polar form. src/apps/app_cplx.c shows all three
    at once, F2 cycles the operation, F3/F4 pick degrees or radians in the title
    bar. 37 native checks. Unverified on device.

  • The M1 spike has its own artifact. It used to ride inside bench-g3a,
    next to the add-in, so the thing you download to get Bench offered two
    .g3a files and one of them printed diagnostics. bench-g3a now holds
    Bench-<version>.g3a and nothing else; the spike is in bench-spike. It was
    never a release asset and still is not.

  • Root finder (F4): src/core/roots.c does bisection, Newton (numeric
    derivative, step 1e-6) and the secant method, keeping every iterate so the
    screen can show n, x, f(x) and the step size. src/apps/app_roots.c solves
    from the shared expression engine, F2 cycles the method, F3 solves, and a
    small plot marks each iterate on the curve. A bracket with no sign change, a
    zero slope and a parse error each get their own sentence and column. 40
    native checks. Unverified on device.

  • Statistics with working (F7): src/core/stats.c gives n, sum, mean,
    median, mode, range, both quartile methods, the outlier fences and the
    population and sample standard deviations (53 native checks). Paired data
    gets the least squares line, r and r squared. src/apps/app_stats.c adds
    values as you type them, shows the summary and a box plot, has a screen for
    the working and a screen for the regression. Unverified on device.

  • SUVAT and projectiles (F10): src/core/suvat.c solves any three of s, u,
    v, a and t, one table entry per triple, and reports the equation each answer
    came from; when a quadratic gives two sensible times it keeps the first and
    names the second (73 native checks). src/apps/app_suvat.c fills the grid as
    you type, marks worked-out values with a dot, and draws the flight path for a
    launch speed, angle and height. Unverified on device.

  • Moles and solutions (F11): src/core/chem.c covers n = m / Mr, c = n / V,
    pV = nRT with R in kPa dm3, dilution and the two percentages, refusing a zero
    where a formula divides (47 native checks). src/apps/app_moles.c has one
    mode per family, opens each on a worked example, and writes the substitution
    out under the answer. Unverified on device.

  • Base and bits (F12): src/core/base.c parses and prints any base from 2
    to 36, writes two's complement at 8, 16 and 32 bits (hex padded to the width,
    binary grouped in fours), and does AND, OR, XOR and logical shifts, refusing a
    shift of 63 or more (78 native checks). src/apps/app_base.c shows one value
    in five bases with all three widths, and a second tab for the operators; F2
    opens the letter keyboard because the keypad has no A-F keys. Unverified on
    device.

  • Lab graph (F8): src/core/graph.c fits a line to measured points and
    quotes the standard error of the gradient and the intercept from the
    residuals, plus a round axis range for the plot (42 native checks).
    src/apps/app_graph.c takes x, y and an error per point, lists them with the
    fit, and draws the graph with a bar through each point and the line of best
    fit. Unverified on device.

  • Study log (F13), Notes v2 (F14) and Cards v2 (F15): a plain text
    log of what you studied and for how long, with totals, days logged and the
    longest streak (src/core/logbook.c, 56 native checks); the Notes footer now
    counts words as well as lines (textsearch_words, 6 more checks); and a
    Cards deck can be drilled in a mixed order inside each box
    (leitner_shuffle, deterministic for a session, 8 more checks). Bench cannot
    read the calendar - gint's date fields were never checked on the hardware - so
    a log entry takes the day after the newest one and UP/DOWN moves it.
    Unverified on device.

Fixed

  • Home tiles: the icon vanished on the selected tile. The icon was painted
    in the tool's accent colour on a tile filled with that same colour. Every
    foreground is now chosen by measurement (col_better_on), the icon is drawn
    with a 2 px outline, and a check samples the pixels afterwards. This is
    unverified on device: nobody has looked at the new screen on a calculator yet.
  • Labels drawn in a colour too close to their background. Ink on red is
    2.75:1, paper on teal 3.00:1, a red cursor on the yellow field 2.91:1. Text is
    now ink or blue on paper, and a selected tile is ink with paper text instead
    of a tinted tile with a paper plate under the label.
  • The keyboard covered half of the note behind it. The modal now clears the
    content area first, and the space key is marked instead of being drawn as an
    empty cell....
Read more

v1.0.0

Choose a tag to compare

@github-actions github-actions released this 31 Oct 19:31
c31aad3

1.0.0 - 2026-10-31

First release. One add-in, five tools, settings and an About screen.

Added

  • Shell: home screen with six tiles in the Bauhaus palette, title bar,
    softkey bar, lists, fields, modals, a progress bar and an on-screen keyboard.
    src/platform/{screen,input,store,mem} are the only files that call gint;
    src/apps/app_menu.c routes, src/main.c runs the loop.
  • Pacer (src/apps/app_pacer.c): setup, plan with the checkpoint table,
    run with clock, marks, target, gap line and next checkpoint, done screen with
    the final gap.
  • Uncertainty (src/apps/app_uncert.c): six operations, chain mode, value
    and absolute and percentage uncertainty on the result screen.
  • Cards (src/apps/app_cards.c): deck list, deck report with problem lines,
    session with reveal, summary, box statistics; progress file written once at
    the end of a session.
  • Notes (src/apps/app_notes.c): file list, Markdown and plain text
    rendering, scroll by line and page, search with wrap, heading list, per-line
    span drawing with the Phase A style (colour and underline).
  • Number theory (src/apps/app_numtheory.c): nine functions, forms,
    results with steps for gcd and ext gcd, a progress bar for factorisation that
    EXIT cancels.
  • Settings (src/apps/app_settings.c, src/core/settings.c): uncertainty
    figures, pacer checkpoint size, note width; the file is written only when a
    value changes.
  • About (src/apps/app_about.c): version, build date, target, framebuffer
    and window sizes, largest free block, limits, and the Exam Mode note.
  • Brand: assets-cg/icon-uns.png and icon-sel.png (92x64, neobrutalist
    B with a red square and three bars), a wordmark SVG and a 1200x630 card, all
    drawn by tools/brand/make_brand.py. No bitmap fonts, no external assets.
  • Host preview: tools/sim/ (a gint stand-in, key scripts and a tour) and
    make sim, make shots, which render every screen to docs/images.
  • CI: .github/workflows/build.yml runs the native tests, the Python
    tests, the preview, and builds Bench-<version>.g3a with the real fxSDK,
    attaching it to the release on a v* tag.
  • Docs: README.md, docs/STATUS.md, docs/toolchain.md, docs/spike.md,
    site/ (the landing page: React 18 + Vite + Tailwind, deployed on Vercel).

Storage layout (new)

Bench/notes/*.md|*.txt     notes (Notes)
Bench/cards/*.txt          decks, "question | answer" a line (Cards)
Bench/state/cards.sav      "# Bench cards state v1", "session N", "<hash> <box>"
Bench/state/settings.cfg   "key value" lines, written on change only

The folder tree is created on first run. Files are written once and renamed
into place; the calculator's filesystem needs even-sized writes, so an
odd-length text file is padded with a newline.

Notes

  • Screen geometry: 396x224 framebuffer, the OS shows the middle 384x216, so
    every drawing call goes through src/platform/screen.c and its SCR_X,
    SCR_Y offset. No app knows the offset exists.
  • Colours are raw RGB565 words rather than C_RGB(): gint's macro shifts green
    by six while its own constants put green at bits 5..10, so the macro would
    move green one bit. The three palette colours are written out in theme.h
    with the hex they came from.
  • Text entry never relies on ALPHA: the search field uses the on-screen
    keyboard, so a wrong ALPHA mapping cannot break input.

Test log

make test     NATIVE TESTS PASSED (11 test programs)
              cards 95, leitner 126, md_layout 95, md_parse 203, numfmt 182,
              numparse 62, numtheory 1027, pacer 114, settings 659,
              textsearch 84, uncert 144  ->  2791 checks, 0 failed
make py-test  28 tests, OK
make sim      ok
make shots    26 screens rendered

Calculator side: not run by the agent (no fxSDK and no hardware here, see
docs/STATUS.md), so this version is 1.0.0 of the code, not a hardware-tested
release.

Bench - automatic build from main

Choose a tag to compare

@github-actions github-actions released this 31 Oct 19:50
ea94a10

Automatic build

Bench 1.0.0, built from the tip of main on 2026-10-31 (commit ea94a10).

Replaces the previous automatic build. For the released version, use the
tagged release instead.

What is in it

  • Merge pull request #14 from sarang-cmd/arena/300c6ae2-bench
  • CI: run the automatic build once on push, to prove it end to end
  • Merge pull request #13 from sarang-cmd/arena/300c6ae2-bench
  • CI: a rolling automatic build every few days
  • Merge pull request #12 from sarang-cmd/arena/ad6d6f87-bench
  • Docs: the release exists, and here is where the file is
  • Merge pull request #11 from sarang-cmd/arena/ad6d6f87-bench
  • CI: give the release what it needs
  • Merge pull request #8 from sarang-cmd/arena/c64871cf-bench
  • Fix the .g3a copy that failed the link step; split the toolchain job