Repository navigation
V0.3.0 - #3
Open
alexanderilyin wants to merge 127 commits into
Open
V0.3.0#3alexanderilyin wants to merge 127 commits into
alexanderilyin wants to merge 127 commits into
Conversation
- Main menu: More games opens prototypes/ - CPU wording: a/an before 8, 11, 18, 80s - Master dice: mastered facts rarer (weak facts ~70% of rolls) - Tidy pickPracticeFacts - CLAUDE.md for the project; docs/v0.3.0-plan.md Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
- Legend: half teen x 2-9, half Tricky facts; needs 12x12+ - Pair dice: big rectangles rarer on small boards; near the end fall back to small facts that fit instead of ending half empty - Test: Tricky/Master/Legend game length; v0.3.0 log started Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…ents, schedules - server/store.js: node:sqlite storage (users, schools, classes, rosters, progress, homework, parent links, scheduled tournaments) - server/auth.js: dev provider (HMAC JWT) and Keycloak provider (RS256 via JWKS); identity keeps first name, last initial, role, email domain only - server/accounts.js: roles and rules; Cadence Park (@iusd.org) school - HTTP API; hosting a class needs a teacher; signed-in students join live classes under their account name without the OpenAI name check - progress.js: activity log, merge, fact summary, homework goals Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
- js/auth.js: dev sign-in, Keycloak PKCE ready, per-account save, first-use merge of the device's guest save, sync - account screens: sign-in dialog (guests always welcome), student homework and classes, teacher roster/stats/homework/tournaments, parent view with extra homework, live tournament banner - hosting a class needs a teacher; activity log for stats and homework - docs/privacy.md Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
- apps: multiplication, seven other games, more-games hub, server (ESM) - packages: engine, progress, ui, game-kit, classroom, auth - game.js split into section modules with an ordered run() phase (pixel-identical before and after on 11 screens) - homework only offers what the child has unlocked; Play starts it - RFC 9457 problem details and security headers on the server - CI (lint, test, build, strict docs build; pinned actions), Dependabot - MkDocs Material docs site with screenshots, ADRs, CHANGELOG Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The other games get the main game's feel: a wallet with answer, streak, win and practice bonuses; a shop with unlock chains (Medium then Hard, 20-question then Expert practice, Home multiplayer); achievements with the shared banners (@blockout/ui/rewards); stats per question. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
E: Version '2.40.0-*' for '1password-cli' was not found
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…hing decodeURIComponent ran outside the request handler's try, so one request like GET /%E0 threw an unhandled rejection and stopped the server. Decoding now answers 400, route() runs inside the try, readJson rejects on a cut-off body or after 10 s (408), and the entry point logs and exits on anything unhandled so the process manager restarts it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…-in and HTTP Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… LAN addresses in production Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The theme script moves from an inline <script> into theme.js (emitted by blockoutPage(), served from memory in vite dev), the icon sprite uses the display presentation attribute, and the two style= strings in innerHTML are set from script instead. A Playwright pass over all 11 apps found no violations or page errors. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Room codes came from Math.random (predictable) and class and parent codes from a byte modulo 31 (slightly biased). Both now use crypto.randomInt. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Token buckets per address and per account (apps/server/src/ratelimit.js, in memory for now). Code guessing is limited by counting wrong codes, not tries, because a whole school often shares one address. Live-update streams answer 404 for a wrong key, like a missing class, so they can't be used to find codes. TRUST_PROXY sets how many proxies to trust for X-Forwarded-For. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…TERM Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
JSON lines with OpenTelemetry field names in production, short text lines at a terminal. One record per request (route pattern, status, time) and an audit record per account change, by id and role only. Names, codes, keys and tokens are never logged. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…or once a minute Every API request used to update the users row (role, name, last seen). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ccess tokens The browser renews an access token a minute before it expires, and once after a 401, before giving up and signing out. The auth config is fetched without the token so renewing doesn't recurse. Dev tokens last 12 hours. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A live room's dice bag held closures, so a room couldn't be saved as JSON. diceState(size, sides) is the bag's state and diceFromState(state, rng) rolls from it (using up rare faces in the state itself); createDice is both together. Rooms keep the state and roll with it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Every account rule is async and awaits its store calls (the sqlite store still answers synchronously), so a store over the network can replace it. Schools are cached for a minute for sign-ins. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
src/store/ holds the stores behind one async interface: memory (tests, a run without a database) and the sqlite file store. test/store.contract.js checks any store the same way. markOpened now opens a schedule only once. BLOCKOUT_STORE picks the store. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
deploy/data/install.sh installs a one-member MongoDB replica set and Valkey with random passwords in Secrets (namespace blockout-data, or blockout-dev for development); forward.sh forwards both and prints the URLs. The data/ ignore rule now only covers the repo root's data/. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
src/store/mongo.js passes the same store contract as the memory and sqlite stores; numbered migrations (indexes, the first school) run once, with a lock so servers starting together wait for each other. Production requires BLOCKOUT_MONGO_URL. CI runs the store tests against MongoDB and Valkey. ADR-0006 supersedes ADR-0003. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
An event stream answered with any error (a restarting or busy server, not just a missing class) ended the class for the student. Now the page falls back to polling, which retries on errors and stops only on a 404. First tests for @blockout/classroom. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
🏫 Class beside Play (or a #class= link): join with the code, wait for the teacher, then play the whole class's rolls, pairs and tournaments, with your partner's moves shown as they make them. Results stay up until the next game; the app rejoins after it was closed; scheduled tournaments show on the menu. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@blockout/progress/grownups: how activity, homework, codes and planned tournaments read, the homework form's choices and goal, whose homework comes off. @blockout/progress/hosting: the host's choices and settings, its buttons, roster, pairs cards, podium and report. The web game's account and host screens and the admin page use them. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Teachers: My classes (classes and their join code with a QR code, roster, class homework, a student's page, their grown-ups, planned tournaments, teacher codes) and hosting a live class from the phone. Parents: My kids (link a child, their page, delete their account). Admins: accounts, teacher codes and schools. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
One small task a day on the menu, picked from the player's own Times Table: facts that need practice, then the next table to master, then a taste of the next (still locked) table, else a game that stretches a little. Worth 30 points, 10 more for each day in a row, with two new achievements. Shared rules in @blockout/progress/daily; in the web game and the phone app, for guests too. Homework shows beside it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…bles A round of every table could tick it off without asking about them. The phone's card also says what was done. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Homework (📚, now for guests too) starts with today's practice, then the homework from a teacher or grown-up; its badge counts today's task until it's done. In the web game and the phone app. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
During a game or practice round, bonuses, achievements and stickers are held and listed on the results screen, the same kind stacked into one; urgent pop-ups (a skipped roll, a failed send) still show. Pop-ups elsewhere stack repeats too, and the game's results scroll on a small phone. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A helped answer was still "first try" when help came before any wrong answer, so it earned the first-try, speedy, streak and timer bonuses. Match.firstTry (no wrong answer, no help) now decides, for games, practice and class games alike, and Speedy, Big block and Twelve times need the answer right first time. The phone app's backspace is red. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Single player climbs levels instead of buying boards and difficulties: level n is an n×n board with an n-sided die (1–12), then challenge levels (16×16, Tricky, 20×20, Master, Legend, 24×24). Beating the CPU with 80 % of answers right first try moves you up and unlocks the level's board and difficulty ids, so everything keyed on them keeps working. Free play (pick difficulty and board) opens at Level 6. The menu shows a Journey card and "Play Level N", on the web and in the phone app. The engine plays any die from 1 to 12 sides; small dice roll evenly. Old saves start on the level their unlocks and wins reach (journeyV1). ADR-0010. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Important
This repository does not receive automatic reviews because it has fewer than 10 stars. ⚙️ Run configuration
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
… instead of emojis Practice is free and goes ×1 to ×12: level n is the ×n table, with about one question in five reviewing the tables before. A round with 80 % right first try moves you up and unlocks the next table (recordPracticeLevel, in Practice.finish). Free practice opens at Practice level 2. Tables are no longer sold; old saves start on the highest table they own (practiceJourneyV1). On the web and in the phone app. ADR-0011. The menu's Journey, Free play, Learn, Expert and Play buttons and the Sign in chip use Lucide icons (mountain, sprout and brain added to the sprite). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…0 and 20 Each board from 1×1 to 12×12 has three stages: win with 80 % of answers right first try, then also without "Help me count", then also claiming more than half the board (42 levels with the six challenges). Each times table in Practice has three rounds of 5, 10 and 20 questions (36 levels); reaching the longer rounds unlocks them for Free practice, so they leave the Shop. Saves from 0.6–0.7 move to the first stage of their board or table (journeyV2, practiceJourneyV2). ADR-0012. Practice's Journey asks facts up to the table's dice again (6 for ×1–×6, 8 for ×7–×8, 12 from ×9), not every table up to × 12. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…and its timers are reached, not bought Each times table has five rounds: 5, 10 and 20 questions in Learn, then 10 in Expert, then 10 in Expert against a timer that gets shorter along each difficulty's tables (30 s, 10 s, 5 s). The round sets the length, Learn or Expert and the timer. Expert practice and its timers unlock for Free practice with the first round that brings them, so they leave the Shop. Saves from 0.8 keep their table and round (practiceJourneyV3). ADR-0013. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…answer right first try 1×1, 2×2 and 3×3 have one stage each (three stages start on 4×4, 36 levels), and a board's stage 3 asks for every answer right first try instead of more than half the board, which was mostly luck: players won and still got stuck on "So close! Now claim more than half the board". Saves keep their board and stage (journeyV3). ADR-0014. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
rollForBoard rolls again for a roll with no 1 that hasn't come up yet this game (3 × 4 and 4 × 3 are the same rectangle), then for one with no 1, then takes whatever fits, so the last 1-wide gaps still get their 1 × N. Bags remember their rolls (bag.seen, saved with a live class's bag); rejected rolls don't use up rare faces. Games are about a fifth shorter. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…at fits" and click to place Practice's second mode is Auto instead of Free practice: no tables or difficulty to pick; Practice.autoQueue asks your facts to practice (missed, not mastered since), then the facts that need practice, then Learning and not seen yet facts of the reached tables mixed, repeating weak facts rather than asking mastered ones (those only once everything reached is mastered). Four settings are gone, in the web game, the phone app and live classes: every game rolls in the app, only rolls what fits, lets the first rectangle go anywhere, and places by drawing or Auto. Click to place owners get Auto (or their points back if they had it); Real dice and the "No room" options are refunded (settingsGoneV1). Settings.enforce drops the gone settings and choices but keeps everything else (the Wardrobe's cosmetics). Old invite links still open. The engine loses the corner rule and tap-to-place. Fix: homework for a times table started a Journey round, and homework for a game played the Journey's level; table homework now starts its round, and game homework plays in Free play. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… ones for points Like the cards of a level-up: candidates() lists the tasks today's practice could deal (tables that need practice, a table to master, a taste of the next, your Journey's level, from 6×6 a board or a challenge), the most useful first; pickChoices deals it and two at random. Doing any one does today's practice. reroll() deals three others for 10 points, then 20, 40… that day. A save with one task keeps it as one of the three. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Once the mechanics are learned the game gets out of the way: fast CPU explanations on 4×4, auto roll on 5×5, auto placing on 6×6, instant CPU turns on 7×7 (with "Press a button after CPU turns" unlocked). They're Journey items now, not bought; recordLevelGame returns the settings to turn on (switches) and the clients do, with a toast, and they can be switched back in Settings, where an unreached one shows its lock. Owners keep them; an old save's start level counts only boards and difficulties. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The twelve browser apps become apps/web, a Vite multi-page app: index.html is the multiplication game at /, each <name>/index.html a page at /<name>/, with its code in src/<name>/. The seven operation games share src/operation.js, which reads the game from <body data-variant>. Three apps remain: web, server and mobile. npm run dev now starts one Vite server and the server (it had 13 persistent tasks, more than Turborepo's default concurrency of 10). The server serves apps/web/dist as plain static files, and the image copies that one folder. URLs don't change. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Development on deepspacecartel.com signs in through one Keycloak for the cluster (rts-terraform, realm dev) instead of the chart's own, which values-workspace.yaml turns off. - The dev container's keycloak-clients Feature creates Blockout's clients (.devcontainer/keycloak-clients.json) and, on every start, adds this workspace's Coder URLs for ports labelled [sign-in], dropping those of deleted workspaces. - Admins are the blockout client's admin role: the realm is shared, so realm roles no longer count. - An unverified email address counts as none: anyone can register any address, and the domain picks a school. - .env.1password no longer needs the Google secret (it's the platform's). - WIP.md: where this stopped, and the plan to replace the sync script with Terraform. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
No description provided.