Compare commits

..

10 Commits

Author SHA1 Message Date
semantic-release-bot
ac6c3c1376 chore(abacus-react): release v2.10.0 [skip ci]
# [2.10.0](https://github.com/antialias/soroban-abacus-flashcards/compare/abacus-react-v2.9.0...abacus-react-v2.10.0) (2025-11-05)

### Bug Fixes

* replace regex HTML parsing with deterministic bead position calculations in icon generation ([41a3707](41a3707841))

### Features

* add cropToActiveBeads prop to AbacusStatic and AbacusReact ([35b0824](35b0824fc4))
* **calendar:** add beautiful daily calendar with locale-based paper size detection ([bdca315](bdca3154f8))
* **calendar:** add i18n support and cropped abacus day numbers ([5242f89](5242f890f7))
* **i18n:** add internationalization for all create pages ([b080970](b080970d76))
2025-11-05 15:59:39 +00:00
Thomas Hallock
104f3e65d4 docs: add Storybook stories demonstrating cropToActiveBeads feature
Add comprehensive cropping examples including:
- Basic cropping (with and without hideInactiveBeads)
- Padding configuration examples
- Interactive AbacusReact examples with different scale factors
- Favicon-style icons (all 31 days) showing adaptive crop positioning
- Compact mode showcase

These stories demonstrate how cropping adapts to active bead positions,
resulting in different vertical positions for each value (intentional behavior).

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-05 09:58:12 -06:00
Thomas Hallock
35b0824fc4 feat: add cropToActiveBeads prop to AbacusStatic and AbacusReact
- Add cropToActiveBeads prop to AbacusSVGRenderer that accepts boolean or {padding} object
- Pass actual scaleFactor to calculateAbacusCrop for correct crop calculations at any scale
- Remove double scaling (was multiplying width/height by scaleFactor after crop already included it)
- Add cropToActiveBeads prop to AbacusStatic config and pass through to renderer
- Add cropToActiveBeads prop to AbacusReact config and pass through to renderer

This enables both components to crop the SVG viewBox to show only active beads with optional padding, working correctly at all scale factors (0.8, 1.0, 1.5, 2.0, etc.).

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-05 09:57:58 -06:00
Thomas Hallock
b080970d76 feat(i18n): add internationalization for all create pages
Implemented i18n across all three create pages with translations for 7 languages (en, de, ja, hi, es, la, goh):

- Created comprehensive translation files in src/i18n/locales/create/
- Updated /create (hub) page with all card content translations
- Updated /create/abacus page with parameter labels and help text
- Updated /create/flashcards page with UI elements and status messages
- Integrated create translations into main messages system

Translation coverage includes:
- Page titles and subtitles
- Feature descriptions and lists
- Form labels and placeholders
- Button text (normal and loading states)
- Error messages
- Help text and instructions

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-05 09:57:15 -06:00
semantic-release-bot
80657a6604 chore(release): 4.68.0 [skip ci]
## [4.68.0](https://github.com/antialias/soroban-abacus-flashcards/compare/v4.67.1...v4.68.0) (2025-11-05)

### Features

* **3d-abacus:** change default columns from 13 to 4 ([cd15c70](cd15c70a25))
* **abacus-react:** add AbacusStatic for React Server Components ([3b8e864](3b8e864cfa))
* **abacus-react:** add core utility functions for state management ([e65541c](e65541c100))
* **abacus-react:** add layout and educational props ([35bbcec](35bbcecb9e))
* **abacus-react:** add pre-defined theme presets ([cf1f950](cf1f950c7c))
* **abacus-react:** add React hooks for abacus calculations ([de038d2](de038d2afc))
* **abacus-react:** add separate /static export path for React Server Components ([ed69f6b](ed69f6b917))
* **abacus-react:** add shared dimension calculator for consistent sizing ([e5ba772](e5ba772fde))
* **abacus-react:** export new utilities, hooks, and themes ([ce4e44d](ce4e44d630))
* **abacus:** add nativeAbacusNumbers setting to schema and UI ([79f7347](79f7347d48))
* add 3D printing support for abacus models ([dafdfdd](dafdfdd233))
* add client-side OpenSCAD WASM support for 3D preview ([eaaf17c](eaaf17cd4c))
* add comprehensive metadata, SEO, and make AbacusReact SSR-compatible ([0922ea1](0922ea10b7))
* add comprehensive Storybook coverage and migration guide ([7a4a37e](7a4a37ec6d))
* add game preview system with mock arcade environment ([25880cc](25880cc7e4))
* add per-player stats tracking system ([613301c](613301cd13))
* add Strategy & Tactics section to Rithmomachia guide ([81ead65](81ead65680))
* add unified trophy abacus with hero mode integration ([6620418](6620418a70))
* **arcade:** add ability to deactivate remote players without kicking user ([3628426](3628426a56))
* **arcade:** add native abacus numbers support to pressure gauge ([1d525c7](1d525c7b53))
* **arcade:** add Rithmomachia (Battle of Numbers) game ([2fc0a05](2fc0a05f7f))
* **arcade:** add yjs-demo collaborative game and Yjs persistence layer ([d568955](d568955d6a))
* **arcade:** auto-create room when user has none ([ff88c3a](ff88c3a1b8))
* **calendar:** add beautiful daily calendar with locale-based paper size detection ([bdca315](bdca3154f8))
* **calendar:** add i18n support and cropped abacus day numbers ([5242f89](5242f890f7))
* **card-sorting:** add activity feed notifications for collaborative mode ([1461414](1461414ef4))
* **card-sorting:** add auto-submit countdown for perfect sequences ([780a716](780a7161bc))
* **card-sorting:** add bezier curves to connecting arrows ([4d8e873](4d8e873358))
* **card-sorting:** add CardPosition type and position syncing ([656f5a7](656f5a7838))
* **card-sorting:** add collapsible stats sidebar for spectators ([6527c26](6527c26a81))
* **card-sorting:** add game mode selector UI to setup phase ([d25b888](d25b888ffb))
* **card-sorting:** add GameMode type system for multiplayer support ([fd76533](fd765335ef))
* **card-sorting:** add green border to correctly positioned cards ([16fca86](16fca86b76)), closes [#22c55](https://github.com/antialias/soroban-abacus-flashcards/issues/22c55)
* **card-sorting:** add player emoji indicators on moving cards ([3a82099](3a82099757))
* **card-sorting:** add react-spring animations for real-time sync ([c367e0c](c367e0ceec))
* **card-sorting:** add smooth transition to drop shadow ([b0b93d0](b0b93d0175))
* **card-sorting:** add spectator mode UI enhancements ([ee7345d](ee7345d641)), closes [#6366f1](https://github.com/antialias/soroban-abacus-flashcards/issues/6366f1) [#8b5cf6](https://github.com/antialias/soroban-abacus-flashcards/issues/8b5cf6)
* **card-sorting:** add team scoring UI for collaborative mode ([ed6f177](ed6f177914)), closes [#a78](https://github.com/antialias/soroban-abacus-flashcards/issues/a78) [#8b5cf6](https://github.com/antialias/soroban-abacus-flashcards/issues/8b5cf6)
* **card-sorting:** add updateCardPositions action to Provider ([f6ed4a2](f6ed4a27a2))
* **card-sorting:** auto-arrange prefix/suffix cards in corners ([4ba7f24](4ba7f24717))
* **card-sorting:** fade correctly positioned cards to 50% opacity ([7028cfc](7028cfc511))
* **card-sorting:** gentler spring animation for locked cards ([47189cb](47189cb6e7))
* **card-sorting:** implement continuous bezier curve paths ([2d93024](2d9302410f))
* **card-sorting:** improve card distribution for natural scattered look ([0b0503f](0b0503f035))
* **card-sorting:** make player emoji fill entire card background ([2e7a02c](2e7a02c9e4))
* **card-sorting:** optimize results screen for mobile ([d188789](d188789069))
* **card-sorting:** redesign setup screen with modern UI ([73cf967](73cf967492))
* **card-sorting:** scale correctly positioned cards to 50% ([222dc55](222dc555fa))
* **card-sorting:** shrink/fade cards in correct suffix as well ([8f6feec](8f6feec4f2))
* **card-sorting:** smooth spring transition from game table to results grid ([c5f39d5](c5f39d51eb))
* **card-sorting:** wrap prefix/suffix cards to multiple rows ([e3184dd](e3184dd0d4))
* complete 3D enhancement integration for all three proposals ([5ac55cc](5ac55cc149))
* **create-room:** replace hardcoded game grid with dynamic Radix Select dropdown ([83d0ba2](83d0ba26f5))
* dynamic day-of-month favicon using subprocess pattern ([4d0795a](4d0795a9df))
* dynamically crop favicon to active beads for maximum size ([5670322](567032296a))
* enable 3D enhancement on hero/open MyAbacus modes ([37e330f](37e330f26e))
* **games:** add autoplay and improve carousel layout ([9f51edf](9f51edfaa9))
* **games:** add horizontal scroll support to carousels ([a224abb](a224abb6f6))
* **games:** add rotating games hero carousel ([24231e6](24231e6b2e))
* **i18n:** add dynamic locale switching without page reload ([fe9bfea](fe9bfeabf9))
* **i18n:** add global language selector to navigation ([0506360](0506360117))
* **i18n:** add homepage translations for all supported languages ([8c9d35a](8c9d35a3b4))
* **i18n:** add Old High German (goh) language support ([b334a15](b334a15255))
* **i18n:** complete Old High German translations for all locales ([0b06a1c](0b06a1ce00))
* **i18n:** internationalize games page and tutorial content ([4253964](4253964af1))
* **i18n:** internationalize homepage with English translations ([40cff14](40cff143c7))
* **i18n:** migrate from react-i18next to next-intl ([9016b76](9016b76024))
* **i18n:** update games page hero section copy ([6333c60](6333c60352))
* install embla-carousel-autoplay for games carousel ([946e5d1](946e5d1910))
* install embla-carousel-react for player profile carousel ([642ae95](642ae95738))
* internationalize guide page with 6 languages ([e9c320b](e9c320bb10))
* internationalize tutorial player ([26d41cf](26d41cfd05))
* optimize card sorting for mobile displays ([b443ee9](b443ee9cdc))
* Redesign Rithmomachia setup page with dramatic medieval theme ([6ae4d13](6ae4d13dc7))
* **rithmomachia:** add 80% opacity to guide modal when not hovered ([4a78485](4a78485d2e))
* **rithmomachia:** add CaptureContext for capture dialog state management ([d7eb957](d7eb957a8d))
* **rithmomachia:** add ghost panel preview for guide docking ([c0d6526](c0d6526d30))
* **rithmomachia:** add guide docking with resizable panels ([f457f1a](f457f1a1c2))
* **rithmomachia:** add helper piece selection for mathematical captures ([cae3359](cae3359587))
* **rithmomachia:** add helpful error messages for failed captures ([b172440](b172440a41))
* **rithmomachia:** add initial board visual to guide Overview section ([d42bcff](d42bcff0d9))
* **rithmomachia:** Add interactive playing guide modal ([3121d82](3121d8240a))
* **rithmomachia:** add number bond visualization and helper placeholders ([82d8913](82d89131f0))
* **rithmomachia:** add ratio capture example to guide ([9150b0c](9150b0c678))
* **rithmomachia:** add standalone guide page route ([3fcc79f](3fcc79fe9e))
* **rithmomachia:** add useBoardLayout hook for centralized layout calculations ([27f1c98](27f1c989d5))
* **rithmomachia:** add usePieceSelection hook for selection state management ([275f401](275f401e3c))
* **rithmomachia:** add visual board examples to Capture section ([74bc3c0](74bc3c0dcf))
* **rithmomachia:** add visual board examples to Harmony section ([1d5f01c](1d5f01c966))
* **rithmomachia:** add visual winning example to Victory section ([b7fac78](b7fac78829))
* **rithmomachia:** auto-size tab labels with react-textfit ([9fd5406](9fd54067ce))
* **rithmomachia:** cycle through valid helpers with dynamic number tooltips ([4829e41](4829e41ea1))
* **rithmomachia:** enhance capture relation UI with smooth animations ([0a30801](0a308016e9))
* **rithmomachia:** enhance Harmony section with comprehensive content ([f555856](f5558563ea))
* **rithmomachia:** enhance Pieces section with visual examples and pyramid details ([55aff82](55aff829f4))
* **rithmomachia:** enhance Pyramid section with comprehensive details ([9fde1ef](9fde1ef9e7))
* **rithmomachia:** guide defaults to docked right on open ([11f674d](11f674d542))
* **rithmomachia:** improve guide pieces section layout ([a270bfc](a270bfc0cc))
* **rithmomachia:** improve guide UX and add persistence ([b314740](b314740697))
* **rithmomachia:** improve roster status notice UX ([e27df45](e27df45256))
* **rithmomachia:** integrate roster warning into game nav ([8a11594](8a11594203))
* **rithmomachia:** make guide modal ultra-responsive down to 150px width ([0474197](04741971b2))
* **rithmomachia:** recreate original guide modal header layout ([2489695](24896957d0))
* **rithmomachia:** show capture error on hover instead of click ([339b678](339b6780f6))
* **rithmomachia:** show pyramid face numbers on hover instead of selection ([b0c4523](b0c4523c0b))
* **rithmomachia:** show pyramid face numbers when selected ([5c186f3](5c186f3947))
* **rithmomachia:** show pyramid face numbers when selected with subtle animation ([5c2ddbe](5c2ddbef05))
* **rithmomachia:** show real preview layout when dragging guide to dock ([17d2460](17d2460a87))
* **rithmomachia:** simplify guide language for clarity ([85cb630](85cb630add))
* **rithmomachia:** skip helper selection UI and auto-select first valid helper ([be2a00e](be2a00e8b3))
* **rithmomachia:** Update harmony system to classical three-piece proportions ([08c9762](08c97620f5))
* **rithmomachia:** Update to traditional board setup with 25 pieces per side ([0769eaa](0769eaaa1d))
* **rithmomachia:** use actual piece SVGs in number bond with 2.5s rotation animation ([976a7de](976a7de949))
* **room-share:** add QR code button for easy mobile joining ([349290a](349290ac6a))
* show rithmomachia turn in nav ([7c89bfe](7c89bfef9c))
* switch to royal color theme with transparent background ([944ad65](944ad6574e)), closes [#fbbf24](https://github.com/antialias/soroban-abacus-flashcards/issues/fbbf24) [#f59e0](https://github.com/antialias/soroban-abacus-flashcards/issues/f59e0) [#a855f7](https://github.com/antialias/soroban-abacus-flashcards/issues/a855f7) [#7e22](https://github.com/antialias/soroban-abacus-flashcards/issues/7e22)
* **web:** add test page for AbacusStatic RSC compatibility ([903dea2](903dea2584))
* **web:** add test page for AbacusStatic Server Component ([3588d5a](3588d5acde))
* **web:** add Typst-based preview endpoint with React Suspense ([599a758](599a758471))
* **web:** add year abacus to calendar header and make grid bolder ([867c7ee](867c7ee172)), closes [#333](https://github.com/antialias/soroban-abacus-flashcards/issues/333)
* **web:** improve calendar abacus preview styling ([8439727](8439727b15))
* **web:** optimize monthly calendar for single-page layout ([b277a89](b277a89415))
* **web:** redesign monthly calendar as single composite SVG ([8ce8038](8ce8038bae))

### Bug Fixes

* **abacus-react:** add data-testid attributes back to beads for testing ([23ae1b0](23ae1b0c6f))
* **abacus-react:** correct column highlighting offset in AbacusStatic ([0641eb7](0641eb719e))
* **abacus-react:** fix animations by preventing component remounting ([be7d4c4](be7d4c4713))
* **abacus-react:** restore original AbacusReact measurements and positioning ([88c0baa](88c0baaad9))
* add xmlns to AbacusStatic for Typst SVG parsing ([98cd019](98cd019d4a))
* adjust hero abacus position to avoid covering subtitle ([f03d341](f03d341314))
* **arcade:** add automatic retry for version conflict rejections ([fbcde25](fbcde2505f))
* **arcade:** allow deactivating players from users who left the room ([7c1c2d7](7c1c2d7beb))
* **arcade:** implement optimistic locking in session manager ([71fd66d](71fd66d96a))
* board rotation now properly fills height in portrait mode ([b5a96ea](b5a96eaeb1))
* **card-sorting:** add border radius to outer card container ([a922eba](a922eba73c))
* **card-sorting:** add debug logging for spring animations ([d42947e](d42947eb8d))
* **card-sorting:** add missing gameMode support after hard reset ([a832325](a832325deb))
* **card-sorting:** add missing useMemo import ([949d76d](949d76d844))
* **card-sorting:** add overflow hidden to clip rounded corners ([84c66fe](84c66feec6))
* **card-sorting:** adjust connecting paths for scaled cards ([829c741](829c741e55))
* **card-sorting:** adjust game board for spectator panels ([fc5cf12](fc5cf1216f))
* **card-sorting:** adjust viewport dimensions for spectator panels ([4dce16c](4dce16cca4))
* **card-sorting:** animate cards from game board to results grid ([17d45fe](17d45fe88c))
* **card-sorting:** correct suffix card detection in auto-arrange ([d02ab59](d02ab5922c))
* **card-sorting:** enable card scaling for spectators ([6b095c3](6b095c3383))
* **card-sorting:** enable New Game button during active gameplay ([f3f6eca](f3f6eca1db))
* **card-sorting:** end drag immediately when card becomes locked ([ae45298](ae45298ec4))
* **card-sorting:** filter local player from emoji overlays on dragged cards ([dc2d94a](dc2d94aaa5))
* **card-sorting:** fix results panel layout to not cover cards ([4b4fbfe](4b4fbfef32))
* **card-sorting:** hide activity notifications in spectator mode ([5cca279](5cca279687))
* **card-sorting:** keep arrow sequence numbers upright ([79c9469](79c94699fa))
* **card-sorting:** lock correctly positioned prefix/suffix cards ([170abed](170abed231))
* **card-sorting:** lock spring positions after initial animation completes ([275cc62](275cc62a52))
* **card-sorting:** New Game now restarts with same settings instantly ([f3687ed](f3687ed236))
* **card-sorting:** only shrink/fade cards in correct prefix ([51368c6](51368c6ec5))
* **card-sorting:** preserve card positions on pause/resume ([0d8af09](0d8af09517))
* **card-sorting:** preserve rotation when starting drag ([3364144](3364144fb6))
* **card-sorting:** prevent duplicate START_GAME moves on Play Again ([a0b14f8](a0b14f87e9))
* **card-sorting:** prevent ghost movements with proper optimistic updates ([bd014be](bd014bec4f))
* **card-sorting:** prevent infinite loop when all cards are correct ([34785f4](34785f466f))
* **card-sorting:** prevent infinite loop with tolerance-based position comparison ([627b873](627b873382))
* **card-sorting:** prevent position jump when clicking rotated cards ([564a00f](564a00f82b))
* **card-sorting:** prevent replaying own movements from server ([308168a](308168a7fb))
* **card-sorting:** prevent springs from reinitializing on window resize ([30953b8](30953b8c4a))
* **card-sorting:** prevent springs from resetting after animation ([8aff60c](8aff60ce3f))
* **card-sorting:** remove hasAnimatedRef logic causing backwards animation ([a44aa5a](a44aa5a4c2))
* **card-sorting:** remove remaining reveal numbers references ([15c53ea](15c53ea4eb))
* **card-sorting:** restore prefix/suffix card shrinking visual feedback ([f5fb4d7](f5fb4d7b76))
* **card-sorting:** show only active players in team members section ([fa9f1a5](fa9f1a568f))
* **card-sorting:** smooth scale animation while dragging cards ([0eefc33](0eefc332ac))
* **card-sorting:** stabilize inferred sequence for locked cards during drag ([b0cd194](b0cd194838))
* **card-sorting:** use empty deps array for useSprings to prevent recreation ([cee399e](cee399ed15))
* **card-sorting:** use ref to track initialized state and prevent re-animation ([f389afa](f389afa831))
* **card-sorting:** use same coordinate system for game board and results ([6972fdf](6972fdf110))
* **complement-race:** prevent delivery move thrashing in steam sprint mode ([e1258ee](e1258ee041))
* configure favicon metadata and improve bead visibility ([e1369fa](e1369fa275))
* copy entire packages/core and packages/templates ([0ccada0](0ccada0ca7))
* correct hero abacus scroll direction to flow with page content ([4232746](423274657c))
* correct Typst template path in Dockerfile ([4c518de](4c518decb7))
* delete existing user sessions before creating new ones ([0cced47](0cced47a0f))
* **docker:** add scripts, abacus-react, and tsx for production calendar generation ([33eb90e](33eb90e316))
* **docker:** upgrade OpenSCAD to 2024.11 to fix CGAL intersection bug ([e1bcd24](e1bcd24169))
* extract pure SVG content from AbacusReact renders ([b07f1c4](b07f1c4216))
* **games:** prevent horizontal page scroll from carousel overflow ([5a8c98f](5a8c98fc10))
* **games:** smooth scroll feel for carousel wheel navigation ([f80a73b](f80a73b35c))
* **games:** use specific transition properties for smooth carousel loop ([187271e](187271e515))
* **guide:** increase abacus sizes - they were too small ([1074624](1074624b2f))
* **guide:** make abacus sizes consistent and add nav spacing ([bea4842](bea4842a29))
* **guide:** remove inner containers and tighten margins ([7e54c6f](7e54c6f4fc))
* **i18n:** eliminate FOUC by loading messages server-side ([4d4d930](4d4d930bd3))
* **i18n:** use useMessages() for tutorial translations ([95b0105](95b0105ca3))
* include column posts in favicon bounding box ([0b2f481](0b2f48106a))
* increase server update debounce to 2000ms for low bandwidth ([633ff12](633ff12750))
* Integrate threshold input into Point Victory card ([b29bbee](b29bbeefca))
* **layout:** add systematic spacing for fixed nav bar ([4559fb1](4559fb121d))
* **layout:** remove wrapper, use utility class for nav spacing ([247c3d9](247c3d9874))
* mark dynamic routes as force-dynamic to prevent static generation errors ([d7b35d9](d7b35d9544))
* **nav:** restrict transparent hero styling to home page only ([fab227d](fab227d686))
* **nav:** show full navigation on /games page ([d3fe6ac](d3fe6acbb0))
* **qr-button:** improve layout and z-index ([646a422](646a4228d0))
* **qr-button:** increase mini QR code size to 80px ([61ac737](61ac7378bd))
* **qr-button:** increase mini QR code to 84px ([3fae5ea](3fae5ea6fa))
* **qr-button:** make button square and increase QR size ([dc2d466](dc2d46663b))
* **qr-button:** match height of stacked buttons ([81f202d](81f202d215))
* reduce padding to minimize gap below last bead ([0e529be](0e529be789))
* remove distracting parallax and wobble 3D effects ([28a2d40](28a2d40996))
* remove wobble physics and enhance wood grain visibility ([5d97673](5d97673406))
* replace regex HTML parsing with deterministic bead position calculations in icon generation ([41a3707](41a3707841))
* resolve z-index layering and hero abacus visibility issues ([ed9a050](ed9a050d64))
* rewrite 3D stories to use props instead of CSS wrappers ([26bdb11](26bdb11237))
* **rithmomachia:** add missing i18next dependencies ([91154d9](91154d9364))
* **rithmomachia:** add missing pyramid section keys to Japanese (ja.json) ([dae615e](dae615ee72))
* **rithmomachia:** adjust error dialog sizing to prevent text clipping ([cda1126](cda1126cb0))
* **rithmomachia:** adjust roster notice position to not overlap nav ([7093223](709322373a))
* **rithmomachia:** change undock icon to pop-out arrow ([2a91748](2a91748493))
* **rithmomachia:** correct board dimensions to 16x8 and restore original layout values ([cfac277](cfac277505))
* **rithmomachia:** Correct board setup to match reference image exactly ([618e563](618e56358d))
* **rithmomachia:** correct makeMove parameter types for capture handling ([aafb64f](aafb64f3e3))
* **rithmomachia:** fix guide modal resize drift by calculating from initial state ([1bcd99c](1bcd99c949))
* **rithmomachia:** fix harmony section translation structure for hi/ja/es ([14259a1](14259a19a9))
* **rithmomachia:** fix modal resizing zoom issue ([4fa20f4](4fa20f44cb))
* **rithmomachia:** Fix TypeScript errors in playing guide modal ([4834ece](4834ece98e))
* **rithmomachia:** handle pyramid pieces in hover error tooltip ([56f3164](56f3164155))
* **rithmomachia:** implement proper board cropping and highlighting in guide ([d0a8fcd](d0a8fcdea6))
* **rithmomachia:** improve guide modal tab navigation at narrow widths ([a673177](a673177bec))
* **rithmomachia:** reconnect player assignment UI and fix setup layout ([a1a0374](a1a0374fac))
* **rithmomachia:** render guide as docked in preview panel ([190f8cf](190f8cf302))
* **rithmomachia:** show actual values in tooltips for non-helper relations ([774c6b0](774c6b0ce7))
* **rithmomachia:** show guest-friendly message when they can't fix too many players ([54bfd2f](54bfd2fac8))
* **rithmomachia:** smooth guide dragging from docked state without jump ([8f4a79c](8f4a79c9b0))
* **rithmomachia:** validate move path before showing capture error on hover ([bd49964](bd49964186))
* **room-info:** hide Leave Room button when user is alone ([5927f61](5927f61c3c))
* separate horizontal and vertical bounding box logic ([83090df](83090df4df))
* tolerate OpenSCAD CGAL warnings if output file is created ([88993f3](88993f3662))
* **tutorial:** correct column validation for bead highlights ([9ba1824](9ba1824226))
* **tutorial:** fix overlay rendering, arrow indicators, and bead visibility ([a804316](a80431608d))
* use absolute positioning for hero abacus to eliminate scroll lag ([096104b](096104b094))
* use Debian base for deps stage to match runner for binary compatibility ([f8fe6e4](f8fe6e4a41))
* use default BOSL2 branch instead of non-existent v2.0.0 tag ([f4ffc5b](f4ffc5b027))
* use nested SVG viewBox for actual cropping, not just scaling ([440b492](440b492e85))
* various game improvements and UI enhancements ([b67cf61](b67cf610c5))
* **web,docker:** add --format flag for Typst and upgrade to v0.13.0 ([19b9d7a](19b9d7a74f))
* **web:** add dynamic export to rithmomachia page ([329e623](329e623212))
* **web:** fix Typst PDF generation path resolution ([7ce1287](7ce1287525))
* **web:** generate styled-system artifacts during build ([293390a](293390ae35))
* **web:** move react-dom/server import to API route to satisfy Next.js ([00a8bc3](00a8bc3e5e))
* **web:** move tsx to production dependencies for calendar generation ([ffae9c1](ffae9c1bdb))
* **web:** prevent abacus overlap in composite calendar ([448f93c](448f93c1e2)), closes [#f0f0f0](https://github.com/antialias/soroban-abacus-flashcards/issues/f0f0f0)
* **web:** use AbacusStatic for calendar SVG generation ([08c6a41](08c6a419e2))
* **web:** use dynamic import for react-dom/server in API route ([4f93c7d](4f93c7d996))
* **web:** use nested SVG elements to prevent coordinate space conflicts ([f9cbee8](f9cbee8fcd))

### Performance Improvements

* optimize Docker image size to reduce build failures ([9ca3106](9ca3106361))

### Code Refactoring

* **card-sorting:** remove reveal numbers feature ([ea5e3e8](ea5e3e838b))
* **card-sorting:** send complete card sequence instead of individual moves ([e4df843](e4df8432b9))
* **games:** implement carousel, fix victories bug, add conditional stats ([82c133f](82c133f742))
* **games:** move page title to nav bar ([712ee58](712ee58e59))
* **games:** remove redundant subtitle below nav ([ad5bb87](ad5bb87325))
* **games:** remove wheel scrolling, enable overflow visible carousel ([876513c](876513c9cc))
* **layout:** make nav height truly self-referential ([9886302](98863026b7))
* remove debug console.log statements ([32f51ae](32f51ae739))
* reorganize Harmony and Victory guide sections ([fb629c4](fb629c44ea))
* restructure /create page into hub with sub-pages ([b91b23d](b91b23d95f))
* **rithmomachia:** extract board and capture components (phase 2+3) ([a0a867b](a0a867b271))
* **rithmomachia:** extract CaptureErrorDialog component (Phase 2 partial) ([f0a066d](f0a066d8f0))
* **rithmomachia:** extract constants and coordinate utilities (Phase 1) ([eace0ed](eace0ed529))
* **rithmomachia:** extract guide sections into separate files ([765525d](765525dc45))
* **rithmomachia:** extract hooks (phase 5) ([324a659](324a65992f))
* **rithmomachia:** extract phase components (phase 4) ([11364f6](11364f6394))
* **rithmomachia:** extract reusable components from SetupPhase ([3abc325](3abc325ea2))
* **rithmomachia:** make setup phase UI more compact ([e55f848](e55f848a26))
* **rithmomachia:** redesign error notification with modern UI ([dfeeb0e](dfeeb0e0db)), closes [#1e293](https://github.com/antialias/soroban-abacus-flashcards/issues/1e293) [#0f172](https://github.com/antialias/soroban-abacus-flashcards/issues/0f172) [#f1f5f9](https://github.com/antialias/soroban-abacus-flashcards/issues/f1f5f9)
* **rithmomachia:** simplify capture error dialog to one-liner ([82a5eb2](82a5eb2e4b))
* **rithmomachia:** Update board setup to authoritative CSV layout ([0471da5](0471da598d))
* **rithmomachia:** update capture components to use CaptureContext ([2ab6ab5](2ab6ab5799))
* **rithmomachia:** use useBoardLayout and usePieceSelection in BoardDisplay ([0ab7a1d](0ab7a1df32))
* use AbacusReact for dynamic Open Graph image ([9c20f12](9c20f12bac))
* **web:** import utility functions from abacus-react ([7228bbc](7228bbc2eb))
* **web:** move calendar generators to src/utils for proper compilation ([379698f](379698fea3))
* **web:** return calendar SVG preview with PDF generation ([14a5de0](14a5de0dfa))
* **web:** use ABACUS_THEMES instead of manual style definitions ([9f7f001](9f7f001d74))
* **web:** use client-side React rendering for live calendar preview ([f880cbe](f880cbe4bf))
* **web:** use compact prop for inline mini-abacus ([ff1d60a](ff1d60a233))
* **web:** use direct function imports instead of execSync for calendar generation ([9f1715f](9f1715f085))
* **web:** use stdin/stdout for Typst compilation ([06f68cc](06f68cc74c))

### Documentation

* **abacus-react:** add Storybook stories for AbacusStatic ([4f9dc46](4f9dc4666d))
* **abacus-react:** add Storybook stories for new features ([6a1cec0](6a1cec06a7))
* **abacus-react:** export AbacusStatic and update README ([74f2d97](74f2d97434))
* **abacus-react:** update documentation for new features ([35d8734](35d8734a3a))
* **abacus-react:** update README with /static import path for RSC ([72a4c2b](72a4c2b80c))
* add 3D enhancement documentation to README ([cc96802](cc96802df8))
* add critical section on never adding tsx to production dependencies ([770cfc3](770cfc3aca))
* add database migration guide and playing guide modal spec ([5a29af7](5a29af78e2))
* add deployment verification guidelines to prevent false positives ([3d8da23](3d8da2348b))
* **card-sorting:** add comprehensive multiplayer plan ([008ccea](008ccead0f))
* clarify dev server management in Claude Code instructions ([e08fdfd](e08fdfd676))
* **rithmomachia:** Add concise one-page playing guide ([e3c1f10](e3c1f10233))
* update workflow to require manual testing before commits ([0991796](0991796f1e))

### Styles

* **rithmomachia:** improve divider styling and make tabs responsive ([88ca35e](88ca35e044)), closes [#e5e7](https://github.com/antialias/soroban-abacus-flashcards/issues/e5e7) [#9ca3](https://github.com/antialias/soroban-abacus-flashcards/issues/9ca3)
* **rithmomachia:** improve pyramid face numbers visibility and contrast ([94e5e6a](94e5e6a268)), closes [#fbbf24](https://github.com/antialias/soroban-abacus-flashcards/issues/fbbf24) [#b45309](https://github.com/antialias/soroban-abacus-flashcards/issues/b45309)
* **rithmomachia:** increase pyramid face numbers size and boldness ([7bf2d73](7bf2d730d3))

### Tests

* trigger compose-updater deployment test ([2b06aae](2b06aae394))
* verify compose-updater automatic deployment cycle ([af0552c](af0552ccd9))
2025-11-05 15:47:44 +00:00
Thomas Hallock
5242f890f7 feat(calendar): add i18n support and cropped abacus day numbers
This commit implements two enhancements to the calendar feature:

1. i18n Support:
   - Created translation files for all 7 languages (en, de, ja, hi, es, la, goh)
   - Updated CalendarConfigPanel to use translations for UI labels
   - Updated CalendarPreview to use translations for status messages
   - Updated calendar page to use translations for page title/subtitle
   - Added calendarMessages export and integrated into main messages.ts

2. Cropped Abacus Day Numbers:
   - Enabled cropToActiveBeads feature for monthly calendar day abacuses
   - Abacuses now fill calendar cells more efficiently
   - Extracts cropped viewBox from rendered SVG for proper scaling
   - Uses custom padding (top: 8, bottom: 2, left: 5, right: 5)
   - Dynamically scales cropped abacuses to fit cells

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-05 09:43:01 -06:00
semantic-release-bot
b9416883b6 chore(release): 4.68.0 [skip ci]
## [4.68.0](https://github.com/antialias/soroban-abacus-flashcards/compare/v4.67.1...v4.68.0) (2025-11-05)

### Features

* **3d-abacus:** change default columns from 13 to 4 ([cd15c70](cd15c70a25))
* **abacus-react:** add AbacusStatic for React Server Components ([3b8e864](3b8e864cfa))
* **abacus-react:** add core utility functions for state management ([e65541c](e65541c100))
* **abacus-react:** add layout and educational props ([35bbcec](35bbcecb9e))
* **abacus-react:** add pre-defined theme presets ([cf1f950](cf1f950c7c))
* **abacus-react:** add React hooks for abacus calculations ([de038d2](de038d2afc))
* **abacus-react:** add separate /static export path for React Server Components ([ed69f6b](ed69f6b917))
* **abacus-react:** add shared dimension calculator for consistent sizing ([e5ba772](e5ba772fde))
* **abacus-react:** export new utilities, hooks, and themes ([ce4e44d](ce4e44d630))
* **abacus:** add nativeAbacusNumbers setting to schema and UI ([79f7347](79f7347d48))
* add 3D printing support for abacus models ([dafdfdd](dafdfdd233))
* add client-side OpenSCAD WASM support for 3D preview ([eaaf17c](eaaf17cd4c))
* add comprehensive metadata, SEO, and make AbacusReact SSR-compatible ([0922ea1](0922ea10b7))
* add comprehensive Storybook coverage and migration guide ([7a4a37e](7a4a37ec6d))
* add game preview system with mock arcade environment ([25880cc](25880cc7e4))
* add per-player stats tracking system ([613301c](613301cd13))
* add Strategy & Tactics section to Rithmomachia guide ([81ead65](81ead65680))
* add unified trophy abacus with hero mode integration ([6620418](6620418a70))
* **arcade:** add ability to deactivate remote players without kicking user ([3628426](3628426a56))
* **arcade:** add native abacus numbers support to pressure gauge ([1d525c7](1d525c7b53))
* **arcade:** add Rithmomachia (Battle of Numbers) game ([2fc0a05](2fc0a05f7f))
* **arcade:** add yjs-demo collaborative game and Yjs persistence layer ([d568955](d568955d6a))
* **arcade:** auto-create room when user has none ([ff88c3a](ff88c3a1b8))
* **calendar:** add beautiful daily calendar with locale-based paper size detection ([bdca315](bdca3154f8))
* **card-sorting:** add activity feed notifications for collaborative mode ([1461414](1461414ef4))
* **card-sorting:** add auto-submit countdown for perfect sequences ([780a716](780a7161bc))
* **card-sorting:** add bezier curves to connecting arrows ([4d8e873](4d8e873358))
* **card-sorting:** add CardPosition type and position syncing ([656f5a7](656f5a7838))
* **card-sorting:** add collapsible stats sidebar for spectators ([6527c26](6527c26a81))
* **card-sorting:** add game mode selector UI to setup phase ([d25b888](d25b888ffb))
* **card-sorting:** add GameMode type system for multiplayer support ([fd76533](fd765335ef))
* **card-sorting:** add green border to correctly positioned cards ([16fca86](16fca86b76)), closes [#22c55](https://github.com/antialias/soroban-abacus-flashcards/issues/22c55)
* **card-sorting:** add player emoji indicators on moving cards ([3a82099](3a82099757))
* **card-sorting:** add react-spring animations for real-time sync ([c367e0c](c367e0ceec))
* **card-sorting:** add smooth transition to drop shadow ([b0b93d0](b0b93d0175))
* **card-sorting:** add spectator mode UI enhancements ([ee7345d](ee7345d641)), closes [#6366f1](https://github.com/antialias/soroban-abacus-flashcards/issues/6366f1) [#8b5cf6](https://github.com/antialias/soroban-abacus-flashcards/issues/8b5cf6)
* **card-sorting:** add team scoring UI for collaborative mode ([ed6f177](ed6f177914)), closes [#a78](https://github.com/antialias/soroban-abacus-flashcards/issues/a78) [#8b5cf6](https://github.com/antialias/soroban-abacus-flashcards/issues/8b5cf6)
* **card-sorting:** add updateCardPositions action to Provider ([f6ed4a2](f6ed4a27a2))
* **card-sorting:** auto-arrange prefix/suffix cards in corners ([4ba7f24](4ba7f24717))
* **card-sorting:** fade correctly positioned cards to 50% opacity ([7028cfc](7028cfc511))
* **card-sorting:** gentler spring animation for locked cards ([47189cb](47189cb6e7))
* **card-sorting:** implement continuous bezier curve paths ([2d93024](2d9302410f))
* **card-sorting:** improve card distribution for natural scattered look ([0b0503f](0b0503f035))
* **card-sorting:** make player emoji fill entire card background ([2e7a02c](2e7a02c9e4))
* **card-sorting:** optimize results screen for mobile ([d188789](d188789069))
* **card-sorting:** redesign setup screen with modern UI ([73cf967](73cf967492))
* **card-sorting:** scale correctly positioned cards to 50% ([222dc55](222dc555fa))
* **card-sorting:** shrink/fade cards in correct suffix as well ([8f6feec](8f6feec4f2))
* **card-sorting:** smooth spring transition from game table to results grid ([c5f39d5](c5f39d51eb))
* **card-sorting:** wrap prefix/suffix cards to multiple rows ([e3184dd](e3184dd0d4))
* complete 3D enhancement integration for all three proposals ([5ac55cc](5ac55cc149))
* **create-room:** replace hardcoded game grid with dynamic Radix Select dropdown ([83d0ba2](83d0ba26f5))
* dynamic day-of-month favicon using subprocess pattern ([4d0795a](4d0795a9df))
* dynamically crop favicon to active beads for maximum size ([5670322](567032296a))
* enable 3D enhancement on hero/open MyAbacus modes ([37e330f](37e330f26e))
* **games:** add autoplay and improve carousel layout ([9f51edf](9f51edfaa9))
* **games:** add horizontal scroll support to carousels ([a224abb](a224abb6f6))
* **games:** add rotating games hero carousel ([24231e6](24231e6b2e))
* **i18n:** add dynamic locale switching without page reload ([fe9bfea](fe9bfeabf9))
* **i18n:** add global language selector to navigation ([0506360](0506360117))
* **i18n:** add homepage translations for all supported languages ([8c9d35a](8c9d35a3b4))
* **i18n:** add Old High German (goh) language support ([b334a15](b334a15255))
* **i18n:** complete Old High German translations for all locales ([0b06a1c](0b06a1ce00))
* **i18n:** internationalize games page and tutorial content ([4253964](4253964af1))
* **i18n:** internationalize homepage with English translations ([40cff14](40cff143c7))
* **i18n:** migrate from react-i18next to next-intl ([9016b76](9016b76024))
* **i18n:** update games page hero section copy ([6333c60](6333c60352))
* install embla-carousel-autoplay for games carousel ([946e5d1](946e5d1910))
* install embla-carousel-react for player profile carousel ([642ae95](642ae95738))
* internationalize guide page with 6 languages ([e9c320b](e9c320bb10))
* internationalize tutorial player ([26d41cf](26d41cfd05))
* optimize card sorting for mobile displays ([b443ee9](b443ee9cdc))
* Redesign Rithmomachia setup page with dramatic medieval theme ([6ae4d13](6ae4d13dc7))
* **rithmomachia:** add 80% opacity to guide modal when not hovered ([4a78485](4a78485d2e))
* **rithmomachia:** add CaptureContext for capture dialog state management ([d7eb957](d7eb957a8d))
* **rithmomachia:** add ghost panel preview for guide docking ([c0d6526](c0d6526d30))
* **rithmomachia:** add guide docking with resizable panels ([f457f1a](f457f1a1c2))
* **rithmomachia:** add helper piece selection for mathematical captures ([cae3359](cae3359587))
* **rithmomachia:** add helpful error messages for failed captures ([b172440](b172440a41))
* **rithmomachia:** add initial board visual to guide Overview section ([d42bcff](d42bcff0d9))
* **rithmomachia:** Add interactive playing guide modal ([3121d82](3121d8240a))
* **rithmomachia:** add number bond visualization and helper placeholders ([82d8913](82d89131f0))
* **rithmomachia:** add ratio capture example to guide ([9150b0c](9150b0c678))
* **rithmomachia:** add standalone guide page route ([3fcc79f](3fcc79fe9e))
* **rithmomachia:** add useBoardLayout hook for centralized layout calculations ([27f1c98](27f1c989d5))
* **rithmomachia:** add usePieceSelection hook for selection state management ([275f401](275f401e3c))
* **rithmomachia:** add visual board examples to Capture section ([74bc3c0](74bc3c0dcf))
* **rithmomachia:** add visual board examples to Harmony section ([1d5f01c](1d5f01c966))
* **rithmomachia:** add visual winning example to Victory section ([b7fac78](b7fac78829))
* **rithmomachia:** auto-size tab labels with react-textfit ([9fd5406](9fd54067ce))
* **rithmomachia:** cycle through valid helpers with dynamic number tooltips ([4829e41](4829e41ea1))
* **rithmomachia:** enhance capture relation UI with smooth animations ([0a30801](0a308016e9))
* **rithmomachia:** enhance Harmony section with comprehensive content ([f555856](f5558563ea))
* **rithmomachia:** enhance Pieces section with visual examples and pyramid details ([55aff82](55aff829f4))
* **rithmomachia:** enhance Pyramid section with comprehensive details ([9fde1ef](9fde1ef9e7))
* **rithmomachia:** guide defaults to docked right on open ([11f674d](11f674d542))
* **rithmomachia:** improve guide pieces section layout ([a270bfc](a270bfc0cc))
* **rithmomachia:** improve guide UX and add persistence ([b314740](b314740697))
* **rithmomachia:** improve roster status notice UX ([e27df45](e27df45256))
* **rithmomachia:** integrate roster warning into game nav ([8a11594](8a11594203))
* **rithmomachia:** make guide modal ultra-responsive down to 150px width ([0474197](04741971b2))
* **rithmomachia:** recreate original guide modal header layout ([2489695](24896957d0))
* **rithmomachia:** show capture error on hover instead of click ([339b678](339b6780f6))
* **rithmomachia:** show pyramid face numbers on hover instead of selection ([b0c4523](b0c4523c0b))
* **rithmomachia:** show pyramid face numbers when selected ([5c186f3](5c186f3947))
* **rithmomachia:** show pyramid face numbers when selected with subtle animation ([5c2ddbe](5c2ddbef05))
* **rithmomachia:** show real preview layout when dragging guide to dock ([17d2460](17d2460a87))
* **rithmomachia:** simplify guide language for clarity ([85cb630](85cb630add))
* **rithmomachia:** skip helper selection UI and auto-select first valid helper ([be2a00e](be2a00e8b3))
* **rithmomachia:** Update harmony system to classical three-piece proportions ([08c9762](08c97620f5))
* **rithmomachia:** Update to traditional board setup with 25 pieces per side ([0769eaa](0769eaaa1d))
* **rithmomachia:** use actual piece SVGs in number bond with 2.5s rotation animation ([976a7de](976a7de949))
* **room-share:** add QR code button for easy mobile joining ([349290a](349290ac6a))
* show rithmomachia turn in nav ([7c89bfe](7c89bfef9c))
* switch to royal color theme with transparent background ([944ad65](944ad6574e)), closes [#fbbf24](https://github.com/antialias/soroban-abacus-flashcards/issues/fbbf24) [#f59e0](https://github.com/antialias/soroban-abacus-flashcards/issues/f59e0) [#a855f7](https://github.com/antialias/soroban-abacus-flashcards/issues/a855f7) [#7e22](https://github.com/antialias/soroban-abacus-flashcards/issues/7e22)
* **web:** add test page for AbacusStatic RSC compatibility ([903dea2](903dea2584))
* **web:** add test page for AbacusStatic Server Component ([3588d5a](3588d5acde))
* **web:** add Typst-based preview endpoint with React Suspense ([599a758](599a758471))
* **web:** add year abacus to calendar header and make grid bolder ([867c7ee](867c7ee172)), closes [#333](https://github.com/antialias/soroban-abacus-flashcards/issues/333)
* **web:** improve calendar abacus preview styling ([8439727](8439727b15))
* **web:** optimize monthly calendar for single-page layout ([b277a89](b277a89415))
* **web:** redesign monthly calendar as single composite SVG ([8ce8038](8ce8038bae))

### Bug Fixes

* **abacus-react:** add data-testid attributes back to beads for testing ([23ae1b0](23ae1b0c6f))
* **abacus-react:** correct column highlighting offset in AbacusStatic ([0641eb7](0641eb719e))
* **abacus-react:** fix animations by preventing component remounting ([be7d4c4](be7d4c4713))
* **abacus-react:** restore original AbacusReact measurements and positioning ([88c0baa](88c0baaad9))
* add xmlns to AbacusStatic for Typst SVG parsing ([98cd019](98cd019d4a))
* adjust hero abacus position to avoid covering subtitle ([f03d341](f03d341314))
* **arcade:** add automatic retry for version conflict rejections ([fbcde25](fbcde2505f))
* **arcade:** allow deactivating players from users who left the room ([7c1c2d7](7c1c2d7beb))
* **arcade:** implement optimistic locking in session manager ([71fd66d](71fd66d96a))
* board rotation now properly fills height in portrait mode ([b5a96ea](b5a96eaeb1))
* **card-sorting:** add border radius to outer card container ([a922eba](a922eba73c))
* **card-sorting:** add debug logging for spring animations ([d42947e](d42947eb8d))
* **card-sorting:** add missing gameMode support after hard reset ([a832325](a832325deb))
* **card-sorting:** add missing useMemo import ([949d76d](949d76d844))
* **card-sorting:** add overflow hidden to clip rounded corners ([84c66fe](84c66feec6))
* **card-sorting:** adjust connecting paths for scaled cards ([829c741](829c741e55))
* **card-sorting:** adjust game board for spectator panels ([fc5cf12](fc5cf1216f))
* **card-sorting:** adjust viewport dimensions for spectator panels ([4dce16c](4dce16cca4))
* **card-sorting:** animate cards from game board to results grid ([17d45fe](17d45fe88c))
* **card-sorting:** correct suffix card detection in auto-arrange ([d02ab59](d02ab5922c))
* **card-sorting:** enable card scaling for spectators ([6b095c3](6b095c3383))
* **card-sorting:** enable New Game button during active gameplay ([f3f6eca](f3f6eca1db))
* **card-sorting:** end drag immediately when card becomes locked ([ae45298](ae45298ec4))
* **card-sorting:** filter local player from emoji overlays on dragged cards ([dc2d94a](dc2d94aaa5))
* **card-sorting:** fix results panel layout to not cover cards ([4b4fbfe](4b4fbfef32))
* **card-sorting:** hide activity notifications in spectator mode ([5cca279](5cca279687))
* **card-sorting:** keep arrow sequence numbers upright ([79c9469](79c94699fa))
* **card-sorting:** lock correctly positioned prefix/suffix cards ([170abed](170abed231))
* **card-sorting:** lock spring positions after initial animation completes ([275cc62](275cc62a52))
* **card-sorting:** New Game now restarts with same settings instantly ([f3687ed](f3687ed236))
* **card-sorting:** only shrink/fade cards in correct prefix ([51368c6](51368c6ec5))
* **card-sorting:** preserve card positions on pause/resume ([0d8af09](0d8af09517))
* **card-sorting:** preserve rotation when starting drag ([3364144](3364144fb6))
* **card-sorting:** prevent duplicate START_GAME moves on Play Again ([a0b14f8](a0b14f87e9))
* **card-sorting:** prevent ghost movements with proper optimistic updates ([bd014be](bd014bec4f))
* **card-sorting:** prevent infinite loop when all cards are correct ([34785f4](34785f466f))
* **card-sorting:** prevent infinite loop with tolerance-based position comparison ([627b873](627b873382))
* **card-sorting:** prevent position jump when clicking rotated cards ([564a00f](564a00f82b))
* **card-sorting:** prevent replaying own movements from server ([308168a](308168a7fb))
* **card-sorting:** prevent springs from reinitializing on window resize ([30953b8](30953b8c4a))
* **card-sorting:** prevent springs from resetting after animation ([8aff60c](8aff60ce3f))
* **card-sorting:** remove hasAnimatedRef logic causing backwards animation ([a44aa5a](a44aa5a4c2))
* **card-sorting:** remove remaining reveal numbers references ([15c53ea](15c53ea4eb))
* **card-sorting:** restore prefix/suffix card shrinking visual feedback ([f5fb4d7](f5fb4d7b76))
* **card-sorting:** show only active players in team members section ([fa9f1a5](fa9f1a568f))
* **card-sorting:** smooth scale animation while dragging cards ([0eefc33](0eefc332ac))
* **card-sorting:** stabilize inferred sequence for locked cards during drag ([b0cd194](b0cd194838))
* **card-sorting:** use empty deps array for useSprings to prevent recreation ([cee399e](cee399ed15))
* **card-sorting:** use ref to track initialized state and prevent re-animation ([f389afa](f389afa831))
* **card-sorting:** use same coordinate system for game board and results ([6972fdf](6972fdf110))
* **complement-race:** prevent delivery move thrashing in steam sprint mode ([e1258ee](e1258ee041))
* configure favicon metadata and improve bead visibility ([e1369fa](e1369fa275))
* copy entire packages/core and packages/templates ([0ccada0](0ccada0ca7))
* correct hero abacus scroll direction to flow with page content ([4232746](423274657c))
* correct Typst template path in Dockerfile ([4c518de](4c518decb7))
* delete existing user sessions before creating new ones ([0cced47](0cced47a0f))
* **docker:** add scripts, abacus-react, and tsx for production calendar generation ([33eb90e](33eb90e316))
* **docker:** upgrade OpenSCAD to 2024.11 to fix CGAL intersection bug ([e1bcd24](e1bcd24169))
* extract pure SVG content from AbacusReact renders ([b07f1c4](b07f1c4216))
* **games:** prevent horizontal page scroll from carousel overflow ([5a8c98f](5a8c98fc10))
* **games:** smooth scroll feel for carousel wheel navigation ([f80a73b](f80a73b35c))
* **games:** use specific transition properties for smooth carousel loop ([187271e](187271e515))
* **guide:** increase abacus sizes - they were too small ([1074624](1074624b2f))
* **guide:** make abacus sizes consistent and add nav spacing ([bea4842](bea4842a29))
* **guide:** remove inner containers and tighten margins ([7e54c6f](7e54c6f4fc))
* **i18n:** eliminate FOUC by loading messages server-side ([4d4d930](4d4d930bd3))
* **i18n:** use useMessages() for tutorial translations ([95b0105](95b0105ca3))
* include column posts in favicon bounding box ([0b2f481](0b2f48106a))
* increase server update debounce to 2000ms for low bandwidth ([633ff12](633ff12750))
* Integrate threshold input into Point Victory card ([b29bbee](b29bbeefca))
* **layout:** add systematic spacing for fixed nav bar ([4559fb1](4559fb121d))
* **layout:** remove wrapper, use utility class for nav spacing ([247c3d9](247c3d9874))
* mark dynamic routes as force-dynamic to prevent static generation errors ([d7b35d9](d7b35d9544))
* **nav:** restrict transparent hero styling to home page only ([fab227d](fab227d686))
* **nav:** show full navigation on /games page ([d3fe6ac](d3fe6acbb0))
* **qr-button:** improve layout and z-index ([646a422](646a4228d0))
* **qr-button:** increase mini QR code size to 80px ([61ac737](61ac7378bd))
* **qr-button:** increase mini QR code to 84px ([3fae5ea](3fae5ea6fa))
* **qr-button:** make button square and increase QR size ([dc2d466](dc2d46663b))
* **qr-button:** match height of stacked buttons ([81f202d](81f202d215))
* reduce padding to minimize gap below last bead ([0e529be](0e529be789))
* remove distracting parallax and wobble 3D effects ([28a2d40](28a2d40996))
* remove wobble physics and enhance wood grain visibility ([5d97673](5d97673406))
* replace regex HTML parsing with deterministic bead position calculations in icon generation ([41a3707](41a3707841))
* resolve z-index layering and hero abacus visibility issues ([ed9a050](ed9a050d64))
* rewrite 3D stories to use props instead of CSS wrappers ([26bdb11](26bdb11237))
* **rithmomachia:** add missing i18next dependencies ([91154d9](91154d9364))
* **rithmomachia:** add missing pyramid section keys to Japanese (ja.json) ([dae615e](dae615ee72))
* **rithmomachia:** adjust error dialog sizing to prevent text clipping ([cda1126](cda1126cb0))
* **rithmomachia:** adjust roster notice position to not overlap nav ([7093223](709322373a))
* **rithmomachia:** change undock icon to pop-out arrow ([2a91748](2a91748493))
* **rithmomachia:** correct board dimensions to 16x8 and restore original layout values ([cfac277](cfac277505))
* **rithmomachia:** Correct board setup to match reference image exactly ([618e563](618e56358d))
* **rithmomachia:** correct makeMove parameter types for capture handling ([aafb64f](aafb64f3e3))
* **rithmomachia:** fix guide modal resize drift by calculating from initial state ([1bcd99c](1bcd99c949))
* **rithmomachia:** fix harmony section translation structure for hi/ja/es ([14259a1](14259a19a9))
* **rithmomachia:** fix modal resizing zoom issue ([4fa20f4](4fa20f44cb))
* **rithmomachia:** Fix TypeScript errors in playing guide modal ([4834ece](4834ece98e))
* **rithmomachia:** handle pyramid pieces in hover error tooltip ([56f3164](56f3164155))
* **rithmomachia:** implement proper board cropping and highlighting in guide ([d0a8fcd](d0a8fcdea6))
* **rithmomachia:** improve guide modal tab navigation at narrow widths ([a673177](a673177bec))
* **rithmomachia:** reconnect player assignment UI and fix setup layout ([a1a0374](a1a0374fac))
* **rithmomachia:** render guide as docked in preview panel ([190f8cf](190f8cf302))
* **rithmomachia:** show actual values in tooltips for non-helper relations ([774c6b0](774c6b0ce7))
* **rithmomachia:** show guest-friendly message when they can't fix too many players ([54bfd2f](54bfd2fac8))
* **rithmomachia:** smooth guide dragging from docked state without jump ([8f4a79c](8f4a79c9b0))
* **rithmomachia:** validate move path before showing capture error on hover ([bd49964](bd49964186))
* **room-info:** hide Leave Room button when user is alone ([5927f61](5927f61c3c))
* separate horizontal and vertical bounding box logic ([83090df](83090df4df))
* tolerate OpenSCAD CGAL warnings if output file is created ([88993f3](88993f3662))
* **tutorial:** correct column validation for bead highlights ([9ba1824](9ba1824226))
* **tutorial:** fix overlay rendering, arrow indicators, and bead visibility ([a804316](a80431608d))
* use absolute positioning for hero abacus to eliminate scroll lag ([096104b](096104b094))
* use Debian base for deps stage to match runner for binary compatibility ([f8fe6e4](f8fe6e4a41))
* use default BOSL2 branch instead of non-existent v2.0.0 tag ([f4ffc5b](f4ffc5b027))
* use nested SVG viewBox for actual cropping, not just scaling ([440b492](440b492e85))
* various game improvements and UI enhancements ([b67cf61](b67cf610c5))
* **web,docker:** add --format flag for Typst and upgrade to v0.13.0 ([19b9d7a](19b9d7a74f))
* **web:** add dynamic export to rithmomachia page ([329e623](329e623212))
* **web:** fix Typst PDF generation path resolution ([7ce1287](7ce1287525))
* **web:** generate styled-system artifacts during build ([293390a](293390ae35))
* **web:** move react-dom/server import to API route to satisfy Next.js ([00a8bc3](00a8bc3e5e))
* **web:** move tsx to production dependencies for calendar generation ([ffae9c1](ffae9c1bdb))
* **web:** prevent abacus overlap in composite calendar ([448f93c](448f93c1e2)), closes [#f0f0f0](https://github.com/antialias/soroban-abacus-flashcards/issues/f0f0f0)
* **web:** use AbacusStatic for calendar SVG generation ([08c6a41](08c6a419e2))
* **web:** use dynamic import for react-dom/server in API route ([4f93c7d](4f93c7d996))
* **web:** use nested SVG elements to prevent coordinate space conflicts ([f9cbee8](f9cbee8fcd))

### Performance Improvements

* optimize Docker image size to reduce build failures ([9ca3106](9ca3106361))

### Code Refactoring

* **card-sorting:** remove reveal numbers feature ([ea5e3e8](ea5e3e838b))
* **card-sorting:** send complete card sequence instead of individual moves ([e4df843](e4df8432b9))
* **games:** implement carousel, fix victories bug, add conditional stats ([82c133f](82c133f742))
* **games:** move page title to nav bar ([712ee58](712ee58e59))
* **games:** remove redundant subtitle below nav ([ad5bb87](ad5bb87325))
* **games:** remove wheel scrolling, enable overflow visible carousel ([876513c](876513c9cc))
* **layout:** make nav height truly self-referential ([9886302](98863026b7))
* remove debug console.log statements ([32f51ae](32f51ae739))
* reorganize Harmony and Victory guide sections ([fb629c4](fb629c44ea))
* restructure /create page into hub with sub-pages ([b91b23d](b91b23d95f))
* **rithmomachia:** extract board and capture components (phase 2+3) ([a0a867b](a0a867b271))
* **rithmomachia:** extract CaptureErrorDialog component (Phase 2 partial) ([f0a066d](f0a066d8f0))
* **rithmomachia:** extract constants and coordinate utilities (Phase 1) ([eace0ed](eace0ed529))
* **rithmomachia:** extract guide sections into separate files ([765525d](765525dc45))
* **rithmomachia:** extract hooks (phase 5) ([324a659](324a65992f))
* **rithmomachia:** extract phase components (phase 4) ([11364f6](11364f6394))
* **rithmomachia:** extract reusable components from SetupPhase ([3abc325](3abc325ea2))
* **rithmomachia:** make setup phase UI more compact ([e55f848](e55f848a26))
* **rithmomachia:** redesign error notification with modern UI ([dfeeb0e](dfeeb0e0db)), closes [#1e293](https://github.com/antialias/soroban-abacus-flashcards/issues/1e293) [#0f172](https://github.com/antialias/soroban-abacus-flashcards/issues/0f172) [#f1f5f9](https://github.com/antialias/soroban-abacus-flashcards/issues/f1f5f9)
* **rithmomachia:** simplify capture error dialog to one-liner ([82a5eb2](82a5eb2e4b))
* **rithmomachia:** Update board setup to authoritative CSV layout ([0471da5](0471da598d))
* **rithmomachia:** update capture components to use CaptureContext ([2ab6ab5](2ab6ab5799))
* **rithmomachia:** use useBoardLayout and usePieceSelection in BoardDisplay ([0ab7a1d](0ab7a1df32))
* use AbacusReact for dynamic Open Graph image ([9c20f12](9c20f12bac))
* **web:** import utility functions from abacus-react ([7228bbc](7228bbc2eb))
* **web:** move calendar generators to src/utils for proper compilation ([379698f](379698fea3))
* **web:** return calendar SVG preview with PDF generation ([14a5de0](14a5de0dfa))
* **web:** use ABACUS_THEMES instead of manual style definitions ([9f7f001](9f7f001d74))
* **web:** use client-side React rendering for live calendar preview ([f880cbe](f880cbe4bf))
* **web:** use compact prop for inline mini-abacus ([ff1d60a](ff1d60a233))
* **web:** use direct function imports instead of execSync for calendar generation ([9f1715f](9f1715f085))
* **web:** use stdin/stdout for Typst compilation ([06f68cc](06f68cc74c))

### Documentation

* **abacus-react:** add Storybook stories for AbacusStatic ([4f9dc46](4f9dc4666d))
* **abacus-react:** add Storybook stories for new features ([6a1cec0](6a1cec06a7))
* **abacus-react:** export AbacusStatic and update README ([74f2d97](74f2d97434))
* **abacus-react:** update documentation for new features ([35d8734](35d8734a3a))
* **abacus-react:** update README with /static import path for RSC ([72a4c2b](72a4c2b80c))
* add 3D enhancement documentation to README ([cc96802](cc96802df8))
* add critical section on never adding tsx to production dependencies ([770cfc3](770cfc3aca))
* add database migration guide and playing guide modal spec ([5a29af7](5a29af78e2))
* add deployment verification guidelines to prevent false positives ([3d8da23](3d8da2348b))
* **card-sorting:** add comprehensive multiplayer plan ([008ccea](008ccead0f))
* clarify dev server management in Claude Code instructions ([e08fdfd](e08fdfd676))
* **rithmomachia:** Add concise one-page playing guide ([e3c1f10](e3c1f10233))
* update workflow to require manual testing before commits ([0991796](0991796f1e))

### Styles

* **rithmomachia:** improve divider styling and make tabs responsive ([88ca35e](88ca35e044)), closes [#e5e7](https://github.com/antialias/soroban-abacus-flashcards/issues/e5e7) [#9ca3](https://github.com/antialias/soroban-abacus-flashcards/issues/9ca3)
* **rithmomachia:** improve pyramid face numbers visibility and contrast ([94e5e6a](94e5e6a268)), closes [#fbbf24](https://github.com/antialias/soroban-abacus-flashcards/issues/fbbf24) [#b45309](https://github.com/antialias/soroban-abacus-flashcards/issues/b45309)
* **rithmomachia:** increase pyramid face numbers size and boldness ([7bf2d73](7bf2d730d3))

### Tests

* trigger compose-updater deployment test ([2b06aae](2b06aae394))
* verify compose-updater automatic deployment cycle ([af0552c](af0552ccd9))
2025-11-05 15:36:34 +00:00
Thomas Hallock
bdca3154f8 feat(calendar): add beautiful daily calendar with locale-based paper size detection
Implement fully-featured daily calendar generation with enhanced visual design:

Daily Calendar Features:
- Beautiful single-page-per-day design with decorative borders
- Blue double-border frame for visual polish
- Light blue header section with uppercase month name (Georgia serif)
- Large prominent day-of-week text (42pt)
- 2.5x larger day abacus as main focal point
- Styled notes section with warm yellow background
- Full support for all paper sizes (US Letter, A4, A3, Tabloid)

Preview System:
- Add live preview support for daily calendars
- Generate composite SVG for preview (avoid Typst multi-page export issues)
- Show "Live Preview (First Day)" label for daily format
- Use same composite SVG approach as monthly calendars

Locale Detection:
- Auto-detect paper size from browser locale on page load
- US Letter for US, CA, MX, GT, PA, DO, PR, PH
- A4 for all other countries
- Hardcoded mapping (stable, no external deps needed)

Code Quality:
- Remove all debug console.log statements
- Fix unused imports
- Format and lint all files

Technical Details:
- Daily preview creates single composite SVG with embedded abacuses
- Uses Typst's responsive layout (percentages) for multi-size support
- Matches monthly calendar's single-image-export pattern
- Full PDF generation uses Typst #page() for multi-page output

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-05 09:32:00 -06:00
semantic-release-bot
651b14f630 chore(release): 4.68.0 [skip ci]
## [4.68.0](https://github.com/antialias/soroban-abacus-flashcards/compare/v4.67.1...v4.68.0) (2025-11-05)

### Features

* **3d-abacus:** change default columns from 13 to 4 ([cd15c70](cd15c70a25))
* **abacus-react:** add AbacusStatic for React Server Components ([3b8e864](3b8e864cfa))
* **abacus-react:** add core utility functions for state management ([e65541c](e65541c100))
* **abacus-react:** add layout and educational props ([35bbcec](35bbcecb9e))
* **abacus-react:** add pre-defined theme presets ([cf1f950](cf1f950c7c))
* **abacus-react:** add React hooks for abacus calculations ([de038d2](de038d2afc))
* **abacus-react:** add separate /static export path for React Server Components ([ed69f6b](ed69f6b917))
* **abacus-react:** add shared dimension calculator for consistent sizing ([e5ba772](e5ba772fde))
* **abacus-react:** export new utilities, hooks, and themes ([ce4e44d](ce4e44d630))
* **abacus:** add nativeAbacusNumbers setting to schema and UI ([79f7347](79f7347d48))
* add 3D printing support for abacus models ([dafdfdd](dafdfdd233))
* add client-side OpenSCAD WASM support for 3D preview ([eaaf17c](eaaf17cd4c))
* add comprehensive metadata, SEO, and make AbacusReact SSR-compatible ([0922ea1](0922ea10b7))
* add comprehensive Storybook coverage and migration guide ([7a4a37e](7a4a37ec6d))
* add game preview system with mock arcade environment ([25880cc](25880cc7e4))
* add per-player stats tracking system ([613301c](613301cd13))
* add Strategy & Tactics section to Rithmomachia guide ([81ead65](81ead65680))
* add unified trophy abacus with hero mode integration ([6620418](6620418a70))
* **arcade:** add ability to deactivate remote players without kicking user ([3628426](3628426a56))
* **arcade:** add native abacus numbers support to pressure gauge ([1d525c7](1d525c7b53))
* **arcade:** add Rithmomachia (Battle of Numbers) game ([2fc0a05](2fc0a05f7f))
* **arcade:** add yjs-demo collaborative game and Yjs persistence layer ([d568955](d568955d6a))
* **arcade:** auto-create room when user has none ([ff88c3a](ff88c3a1b8))
* **card-sorting:** add activity feed notifications for collaborative mode ([1461414](1461414ef4))
* **card-sorting:** add auto-submit countdown for perfect sequences ([780a716](780a7161bc))
* **card-sorting:** add bezier curves to connecting arrows ([4d8e873](4d8e873358))
* **card-sorting:** add CardPosition type and position syncing ([656f5a7](656f5a7838))
* **card-sorting:** add collapsible stats sidebar for spectators ([6527c26](6527c26a81))
* **card-sorting:** add game mode selector UI to setup phase ([d25b888](d25b888ffb))
* **card-sorting:** add GameMode type system for multiplayer support ([fd76533](fd765335ef))
* **card-sorting:** add green border to correctly positioned cards ([16fca86](16fca86b76)), closes [#22c55](https://github.com/antialias/soroban-abacus-flashcards/issues/22c55)
* **card-sorting:** add player emoji indicators on moving cards ([3a82099](3a82099757))
* **card-sorting:** add react-spring animations for real-time sync ([c367e0c](c367e0ceec))
* **card-sorting:** add smooth transition to drop shadow ([b0b93d0](b0b93d0175))
* **card-sorting:** add spectator mode UI enhancements ([ee7345d](ee7345d641)), closes [#6366f1](https://github.com/antialias/soroban-abacus-flashcards/issues/6366f1) [#8b5cf6](https://github.com/antialias/soroban-abacus-flashcards/issues/8b5cf6)
* **card-sorting:** add team scoring UI for collaborative mode ([ed6f177](ed6f177914)), closes [#a78](https://github.com/antialias/soroban-abacus-flashcards/issues/a78) [#8b5cf6](https://github.com/antialias/soroban-abacus-flashcards/issues/8b5cf6)
* **card-sorting:** add updateCardPositions action to Provider ([f6ed4a2](f6ed4a27a2))
* **card-sorting:** auto-arrange prefix/suffix cards in corners ([4ba7f24](4ba7f24717))
* **card-sorting:** fade correctly positioned cards to 50% opacity ([7028cfc](7028cfc511))
* **card-sorting:** gentler spring animation for locked cards ([47189cb](47189cb6e7))
* **card-sorting:** implement continuous bezier curve paths ([2d93024](2d9302410f))
* **card-sorting:** improve card distribution for natural scattered look ([0b0503f](0b0503f035))
* **card-sorting:** make player emoji fill entire card background ([2e7a02c](2e7a02c9e4))
* **card-sorting:** optimize results screen for mobile ([d188789](d188789069))
* **card-sorting:** redesign setup screen with modern UI ([73cf967](73cf967492))
* **card-sorting:** scale correctly positioned cards to 50% ([222dc55](222dc555fa))
* **card-sorting:** shrink/fade cards in correct suffix as well ([8f6feec](8f6feec4f2))
* **card-sorting:** smooth spring transition from game table to results grid ([c5f39d5](c5f39d51eb))
* **card-sorting:** wrap prefix/suffix cards to multiple rows ([e3184dd](e3184dd0d4))
* complete 3D enhancement integration for all three proposals ([5ac55cc](5ac55cc149))
* **create-room:** replace hardcoded game grid with dynamic Radix Select dropdown ([83d0ba2](83d0ba26f5))
* dynamic day-of-month favicon using subprocess pattern ([4d0795a](4d0795a9df))
* dynamically crop favicon to active beads for maximum size ([5670322](567032296a))
* enable 3D enhancement on hero/open MyAbacus modes ([37e330f](37e330f26e))
* **games:** add autoplay and improve carousel layout ([9f51edf](9f51edfaa9))
* **games:** add horizontal scroll support to carousels ([a224abb](a224abb6f6))
* **games:** add rotating games hero carousel ([24231e6](24231e6b2e))
* **i18n:** add dynamic locale switching without page reload ([fe9bfea](fe9bfeabf9))
* **i18n:** add global language selector to navigation ([0506360](0506360117))
* **i18n:** add homepage translations for all supported languages ([8c9d35a](8c9d35a3b4))
* **i18n:** add Old High German (goh) language support ([b334a15](b334a15255))
* **i18n:** complete Old High German translations for all locales ([0b06a1c](0b06a1ce00))
* **i18n:** internationalize games page and tutorial content ([4253964](4253964af1))
* **i18n:** internationalize homepage with English translations ([40cff14](40cff143c7))
* **i18n:** migrate from react-i18next to next-intl ([9016b76](9016b76024))
* **i18n:** update games page hero section copy ([6333c60](6333c60352))
* install embla-carousel-autoplay for games carousel ([946e5d1](946e5d1910))
* install embla-carousel-react for player profile carousel ([642ae95](642ae95738))
* internationalize guide page with 6 languages ([e9c320b](e9c320bb10))
* internationalize tutorial player ([26d41cf](26d41cfd05))
* optimize card sorting for mobile displays ([b443ee9](b443ee9cdc))
* Redesign Rithmomachia setup page with dramatic medieval theme ([6ae4d13](6ae4d13dc7))
* **rithmomachia:** add 80% opacity to guide modal when not hovered ([4a78485](4a78485d2e))
* **rithmomachia:** add CaptureContext for capture dialog state management ([d7eb957](d7eb957a8d))
* **rithmomachia:** add ghost panel preview for guide docking ([c0d6526](c0d6526d30))
* **rithmomachia:** add guide docking with resizable panels ([f457f1a](f457f1a1c2))
* **rithmomachia:** add helper piece selection for mathematical captures ([cae3359](cae3359587))
* **rithmomachia:** add helpful error messages for failed captures ([b172440](b172440a41))
* **rithmomachia:** add initial board visual to guide Overview section ([d42bcff](d42bcff0d9))
* **rithmomachia:** Add interactive playing guide modal ([3121d82](3121d8240a))
* **rithmomachia:** add number bond visualization and helper placeholders ([82d8913](82d89131f0))
* **rithmomachia:** add ratio capture example to guide ([9150b0c](9150b0c678))
* **rithmomachia:** add standalone guide page route ([3fcc79f](3fcc79fe9e))
* **rithmomachia:** add useBoardLayout hook for centralized layout calculations ([27f1c98](27f1c989d5))
* **rithmomachia:** add usePieceSelection hook for selection state management ([275f401](275f401e3c))
* **rithmomachia:** add visual board examples to Capture section ([74bc3c0](74bc3c0dcf))
* **rithmomachia:** add visual board examples to Harmony section ([1d5f01c](1d5f01c966))
* **rithmomachia:** add visual winning example to Victory section ([b7fac78](b7fac78829))
* **rithmomachia:** auto-size tab labels with react-textfit ([9fd5406](9fd54067ce))
* **rithmomachia:** cycle through valid helpers with dynamic number tooltips ([4829e41](4829e41ea1))
* **rithmomachia:** enhance capture relation UI with smooth animations ([0a30801](0a308016e9))
* **rithmomachia:** enhance Harmony section with comprehensive content ([f555856](f5558563ea))
* **rithmomachia:** enhance Pieces section with visual examples and pyramid details ([55aff82](55aff829f4))
* **rithmomachia:** enhance Pyramid section with comprehensive details ([9fde1ef](9fde1ef9e7))
* **rithmomachia:** guide defaults to docked right on open ([11f674d](11f674d542))
* **rithmomachia:** improve guide pieces section layout ([a270bfc](a270bfc0cc))
* **rithmomachia:** improve guide UX and add persistence ([b314740](b314740697))
* **rithmomachia:** improve roster status notice UX ([e27df45](e27df45256))
* **rithmomachia:** integrate roster warning into game nav ([8a11594](8a11594203))
* **rithmomachia:** make guide modal ultra-responsive down to 150px width ([0474197](04741971b2))
* **rithmomachia:** recreate original guide modal header layout ([2489695](24896957d0))
* **rithmomachia:** show capture error on hover instead of click ([339b678](339b6780f6))
* **rithmomachia:** show pyramid face numbers on hover instead of selection ([b0c4523](b0c4523c0b))
* **rithmomachia:** show pyramid face numbers when selected ([5c186f3](5c186f3947))
* **rithmomachia:** show pyramid face numbers when selected with subtle animation ([5c2ddbe](5c2ddbef05))
* **rithmomachia:** show real preview layout when dragging guide to dock ([17d2460](17d2460a87))
* **rithmomachia:** simplify guide language for clarity ([85cb630](85cb630add))
* **rithmomachia:** skip helper selection UI and auto-select first valid helper ([be2a00e](be2a00e8b3))
* **rithmomachia:** Update harmony system to classical three-piece proportions ([08c9762](08c97620f5))
* **rithmomachia:** Update to traditional board setup with 25 pieces per side ([0769eaa](0769eaaa1d))
* **rithmomachia:** use actual piece SVGs in number bond with 2.5s rotation animation ([976a7de](976a7de949))
* **room-share:** add QR code button for easy mobile joining ([349290a](349290ac6a))
* show rithmomachia turn in nav ([7c89bfe](7c89bfef9c))
* switch to royal color theme with transparent background ([944ad65](944ad6574e)), closes [#fbbf24](https://github.com/antialias/soroban-abacus-flashcards/issues/fbbf24) [#f59e0](https://github.com/antialias/soroban-abacus-flashcards/issues/f59e0) [#a855f7](https://github.com/antialias/soroban-abacus-flashcards/issues/a855f7) [#7e22](https://github.com/antialias/soroban-abacus-flashcards/issues/7e22)
* **web:** add test page for AbacusStatic RSC compatibility ([903dea2](903dea2584))
* **web:** add test page for AbacusStatic Server Component ([3588d5a](3588d5acde))
* **web:** add Typst-based preview endpoint with React Suspense ([599a758](599a758471))
* **web:** add year abacus to calendar header and make grid bolder ([867c7ee](867c7ee172)), closes [#333](https://github.com/antialias/soroban-abacus-flashcards/issues/333)
* **web:** improve calendar abacus preview styling ([8439727](8439727b15))
* **web:** optimize monthly calendar for single-page layout ([b277a89](b277a89415))
* **web:** redesign monthly calendar as single composite SVG ([8ce8038](8ce8038bae))

### Bug Fixes

* **abacus-react:** add data-testid attributes back to beads for testing ([23ae1b0](23ae1b0c6f))
* **abacus-react:** correct column highlighting offset in AbacusStatic ([0641eb7](0641eb719e))
* **abacus-react:** fix animations by preventing component remounting ([be7d4c4](be7d4c4713))
* **abacus-react:** restore original AbacusReact measurements and positioning ([88c0baa](88c0baaad9))
* add xmlns to AbacusStatic for Typst SVG parsing ([98cd019](98cd019d4a))
* adjust hero abacus position to avoid covering subtitle ([f03d341](f03d341314))
* **arcade:** add automatic retry for version conflict rejections ([fbcde25](fbcde2505f))
* **arcade:** allow deactivating players from users who left the room ([7c1c2d7](7c1c2d7beb))
* **arcade:** implement optimistic locking in session manager ([71fd66d](71fd66d96a))
* board rotation now properly fills height in portrait mode ([b5a96ea](b5a96eaeb1))
* **card-sorting:** add border radius to outer card container ([a922eba](a922eba73c))
* **card-sorting:** add debug logging for spring animations ([d42947e](d42947eb8d))
* **card-sorting:** add missing gameMode support after hard reset ([a832325](a832325deb))
* **card-sorting:** add missing useMemo import ([949d76d](949d76d844))
* **card-sorting:** add overflow hidden to clip rounded corners ([84c66fe](84c66feec6))
* **card-sorting:** adjust connecting paths for scaled cards ([829c741](829c741e55))
* **card-sorting:** adjust game board for spectator panels ([fc5cf12](fc5cf1216f))
* **card-sorting:** adjust viewport dimensions for spectator panels ([4dce16c](4dce16cca4))
* **card-sorting:** animate cards from game board to results grid ([17d45fe](17d45fe88c))
* **card-sorting:** correct suffix card detection in auto-arrange ([d02ab59](d02ab5922c))
* **card-sorting:** enable card scaling for spectators ([6b095c3](6b095c3383))
* **card-sorting:** enable New Game button during active gameplay ([f3f6eca](f3f6eca1db))
* **card-sorting:** end drag immediately when card becomes locked ([ae45298](ae45298ec4))
* **card-sorting:** filter local player from emoji overlays on dragged cards ([dc2d94a](dc2d94aaa5))
* **card-sorting:** fix results panel layout to not cover cards ([4b4fbfe](4b4fbfef32))
* **card-sorting:** hide activity notifications in spectator mode ([5cca279](5cca279687))
* **card-sorting:** keep arrow sequence numbers upright ([79c9469](79c94699fa))
* **card-sorting:** lock correctly positioned prefix/suffix cards ([170abed](170abed231))
* **card-sorting:** lock spring positions after initial animation completes ([275cc62](275cc62a52))
* **card-sorting:** New Game now restarts with same settings instantly ([f3687ed](f3687ed236))
* **card-sorting:** only shrink/fade cards in correct prefix ([51368c6](51368c6ec5))
* **card-sorting:** preserve card positions on pause/resume ([0d8af09](0d8af09517))
* **card-sorting:** preserve rotation when starting drag ([3364144](3364144fb6))
* **card-sorting:** prevent duplicate START_GAME moves on Play Again ([a0b14f8](a0b14f87e9))
* **card-sorting:** prevent ghost movements with proper optimistic updates ([bd014be](bd014bec4f))
* **card-sorting:** prevent infinite loop when all cards are correct ([34785f4](34785f466f))
* **card-sorting:** prevent infinite loop with tolerance-based position comparison ([627b873](627b873382))
* **card-sorting:** prevent position jump when clicking rotated cards ([564a00f](564a00f82b))
* **card-sorting:** prevent replaying own movements from server ([308168a](308168a7fb))
* **card-sorting:** prevent springs from reinitializing on window resize ([30953b8](30953b8c4a))
* **card-sorting:** prevent springs from resetting after animation ([8aff60c](8aff60ce3f))
* **card-sorting:** remove hasAnimatedRef logic causing backwards animation ([a44aa5a](a44aa5a4c2))
* **card-sorting:** remove remaining reveal numbers references ([15c53ea](15c53ea4eb))
* **card-sorting:** restore prefix/suffix card shrinking visual feedback ([f5fb4d7](f5fb4d7b76))
* **card-sorting:** show only active players in team members section ([fa9f1a5](fa9f1a568f))
* **card-sorting:** smooth scale animation while dragging cards ([0eefc33](0eefc332ac))
* **card-sorting:** stabilize inferred sequence for locked cards during drag ([b0cd194](b0cd194838))
* **card-sorting:** use empty deps array for useSprings to prevent recreation ([cee399e](cee399ed15))
* **card-sorting:** use ref to track initialized state and prevent re-animation ([f389afa](f389afa831))
* **card-sorting:** use same coordinate system for game board and results ([6972fdf](6972fdf110))
* **complement-race:** prevent delivery move thrashing in steam sprint mode ([e1258ee](e1258ee041))
* configure favicon metadata and improve bead visibility ([e1369fa](e1369fa275))
* copy entire packages/core and packages/templates ([0ccada0](0ccada0ca7))
* correct hero abacus scroll direction to flow with page content ([4232746](423274657c))
* correct Typst template path in Dockerfile ([4c518de](4c518decb7))
* delete existing user sessions before creating new ones ([0cced47](0cced47a0f))
* **docker:** add scripts, abacus-react, and tsx for production calendar generation ([33eb90e](33eb90e316))
* **docker:** upgrade OpenSCAD to 2024.11 to fix CGAL intersection bug ([e1bcd24](e1bcd24169))
* extract pure SVG content from AbacusReact renders ([b07f1c4](b07f1c4216))
* **games:** prevent horizontal page scroll from carousel overflow ([5a8c98f](5a8c98fc10))
* **games:** smooth scroll feel for carousel wheel navigation ([f80a73b](f80a73b35c))
* **games:** use specific transition properties for smooth carousel loop ([187271e](187271e515))
* **guide:** increase abacus sizes - they were too small ([1074624](1074624b2f))
* **guide:** make abacus sizes consistent and add nav spacing ([bea4842](bea4842a29))
* **guide:** remove inner containers and tighten margins ([7e54c6f](7e54c6f4fc))
* **i18n:** eliminate FOUC by loading messages server-side ([4d4d930](4d4d930bd3))
* **i18n:** use useMessages() for tutorial translations ([95b0105](95b0105ca3))
* include column posts in favicon bounding box ([0b2f481](0b2f48106a))
* increase server update debounce to 2000ms for low bandwidth ([633ff12](633ff12750))
* Integrate threshold input into Point Victory card ([b29bbee](b29bbeefca))
* **layout:** add systematic spacing for fixed nav bar ([4559fb1](4559fb121d))
* **layout:** remove wrapper, use utility class for nav spacing ([247c3d9](247c3d9874))
* mark dynamic routes as force-dynamic to prevent static generation errors ([d7b35d9](d7b35d9544))
* **nav:** restrict transparent hero styling to home page only ([fab227d](fab227d686))
* **nav:** show full navigation on /games page ([d3fe6ac](d3fe6acbb0))
* **qr-button:** improve layout and z-index ([646a422](646a4228d0))
* **qr-button:** increase mini QR code size to 80px ([61ac737](61ac7378bd))
* **qr-button:** increase mini QR code to 84px ([3fae5ea](3fae5ea6fa))
* **qr-button:** make button square and increase QR size ([dc2d466](dc2d46663b))
* **qr-button:** match height of stacked buttons ([81f202d](81f202d215))
* reduce padding to minimize gap below last bead ([0e529be](0e529be789))
* remove distracting parallax and wobble 3D effects ([28a2d40](28a2d40996))
* remove wobble physics and enhance wood grain visibility ([5d97673](5d97673406))
* replace regex HTML parsing with deterministic bead position calculations in icon generation ([41a3707](41a3707841))
* resolve z-index layering and hero abacus visibility issues ([ed9a050](ed9a050d64))
* rewrite 3D stories to use props instead of CSS wrappers ([26bdb11](26bdb11237))
* **rithmomachia:** add missing i18next dependencies ([91154d9](91154d9364))
* **rithmomachia:** add missing pyramid section keys to Japanese (ja.json) ([dae615e](dae615ee72))
* **rithmomachia:** adjust error dialog sizing to prevent text clipping ([cda1126](cda1126cb0))
* **rithmomachia:** adjust roster notice position to not overlap nav ([7093223](709322373a))
* **rithmomachia:** change undock icon to pop-out arrow ([2a91748](2a91748493))
* **rithmomachia:** correct board dimensions to 16x8 and restore original layout values ([cfac277](cfac277505))
* **rithmomachia:** Correct board setup to match reference image exactly ([618e563](618e56358d))
* **rithmomachia:** correct makeMove parameter types for capture handling ([aafb64f](aafb64f3e3))
* **rithmomachia:** fix guide modal resize drift by calculating from initial state ([1bcd99c](1bcd99c949))
* **rithmomachia:** fix harmony section translation structure for hi/ja/es ([14259a1](14259a19a9))
* **rithmomachia:** fix modal resizing zoom issue ([4fa20f4](4fa20f44cb))
* **rithmomachia:** Fix TypeScript errors in playing guide modal ([4834ece](4834ece98e))
* **rithmomachia:** handle pyramid pieces in hover error tooltip ([56f3164](56f3164155))
* **rithmomachia:** implement proper board cropping and highlighting in guide ([d0a8fcd](d0a8fcdea6))
* **rithmomachia:** improve guide modal tab navigation at narrow widths ([a673177](a673177bec))
* **rithmomachia:** reconnect player assignment UI and fix setup layout ([a1a0374](a1a0374fac))
* **rithmomachia:** render guide as docked in preview panel ([190f8cf](190f8cf302))
* **rithmomachia:** show actual values in tooltips for non-helper relations ([774c6b0](774c6b0ce7))
* **rithmomachia:** show guest-friendly message when they can't fix too many players ([54bfd2f](54bfd2fac8))
* **rithmomachia:** smooth guide dragging from docked state without jump ([8f4a79c](8f4a79c9b0))
* **rithmomachia:** validate move path before showing capture error on hover ([bd49964](bd49964186))
* **room-info:** hide Leave Room button when user is alone ([5927f61](5927f61c3c))
* separate horizontal and vertical bounding box logic ([83090df](83090df4df))
* tolerate OpenSCAD CGAL warnings if output file is created ([88993f3](88993f3662))
* **tutorial:** correct column validation for bead highlights ([9ba1824](9ba1824226))
* **tutorial:** fix overlay rendering, arrow indicators, and bead visibility ([a804316](a80431608d))
* use absolute positioning for hero abacus to eliminate scroll lag ([096104b](096104b094))
* use Debian base for deps stage to match runner for binary compatibility ([f8fe6e4](f8fe6e4a41))
* use default BOSL2 branch instead of non-existent v2.0.0 tag ([f4ffc5b](f4ffc5b027))
* use nested SVG viewBox for actual cropping, not just scaling ([440b492](440b492e85))
* various game improvements and UI enhancements ([b67cf61](b67cf610c5))
* **web,docker:** add --format flag for Typst and upgrade to v0.13.0 ([19b9d7a](19b9d7a74f))
* **web:** add dynamic export to rithmomachia page ([329e623](329e623212))
* **web:** fix Typst PDF generation path resolution ([7ce1287](7ce1287525))
* **web:** generate styled-system artifacts during build ([293390a](293390ae35))
* **web:** move react-dom/server import to API route to satisfy Next.js ([00a8bc3](00a8bc3e5e))
* **web:** move tsx to production dependencies for calendar generation ([ffae9c1](ffae9c1bdb))
* **web:** prevent abacus overlap in composite calendar ([448f93c](448f93c1e2)), closes [#f0f0f0](https://github.com/antialias/soroban-abacus-flashcards/issues/f0f0f0)
* **web:** use AbacusStatic for calendar SVG generation ([08c6a41](08c6a419e2))
* **web:** use dynamic import for react-dom/server in API route ([4f93c7d](4f93c7d996))
* **web:** use nested SVG elements to prevent coordinate space conflicts ([f9cbee8](f9cbee8fcd))

### Performance Improvements

* optimize Docker image size to reduce build failures ([9ca3106](9ca3106361))

### Code Refactoring

* **card-sorting:** remove reveal numbers feature ([ea5e3e8](ea5e3e838b))
* **card-sorting:** send complete card sequence instead of individual moves ([e4df843](e4df8432b9))
* **games:** implement carousel, fix victories bug, add conditional stats ([82c133f](82c133f742))
* **games:** move page title to nav bar ([712ee58](712ee58e59))
* **games:** remove redundant subtitle below nav ([ad5bb87](ad5bb87325))
* **games:** remove wheel scrolling, enable overflow visible carousel ([876513c](876513c9cc))
* **layout:** make nav height truly self-referential ([9886302](98863026b7))
* remove debug console.log statements ([32f51ae](32f51ae739))
* reorganize Harmony and Victory guide sections ([fb629c4](fb629c44ea))
* restructure /create page into hub with sub-pages ([b91b23d](b91b23d95f))
* **rithmomachia:** extract board and capture components (phase 2+3) ([a0a867b](a0a867b271))
* **rithmomachia:** extract CaptureErrorDialog component (Phase 2 partial) ([f0a066d](f0a066d8f0))
* **rithmomachia:** extract constants and coordinate utilities (Phase 1) ([eace0ed](eace0ed529))
* **rithmomachia:** extract guide sections into separate files ([765525d](765525dc45))
* **rithmomachia:** extract hooks (phase 5) ([324a659](324a65992f))
* **rithmomachia:** extract phase components (phase 4) ([11364f6](11364f6394))
* **rithmomachia:** extract reusable components from SetupPhase ([3abc325](3abc325ea2))
* **rithmomachia:** make setup phase UI more compact ([e55f848](e55f848a26))
* **rithmomachia:** redesign error notification with modern UI ([dfeeb0e](dfeeb0e0db)), closes [#1e293](https://github.com/antialias/soroban-abacus-flashcards/issues/1e293) [#0f172](https://github.com/antialias/soroban-abacus-flashcards/issues/0f172) [#f1f5f9](https://github.com/antialias/soroban-abacus-flashcards/issues/f1f5f9)
* **rithmomachia:** simplify capture error dialog to one-liner ([82a5eb2](82a5eb2e4b))
* **rithmomachia:** Update board setup to authoritative CSV layout ([0471da5](0471da598d))
* **rithmomachia:** update capture components to use CaptureContext ([2ab6ab5](2ab6ab5799))
* **rithmomachia:** use useBoardLayout and usePieceSelection in BoardDisplay ([0ab7a1d](0ab7a1df32))
* use AbacusReact for dynamic Open Graph image ([9c20f12](9c20f12bac))
* **web:** import utility functions from abacus-react ([7228bbc](7228bbc2eb))
* **web:** move calendar generators to src/utils for proper compilation ([379698f](379698fea3))
* **web:** return calendar SVG preview with PDF generation ([14a5de0](14a5de0dfa))
* **web:** use ABACUS_THEMES instead of manual style definitions ([9f7f001](9f7f001d74))
* **web:** use client-side React rendering for live calendar preview ([f880cbe](f880cbe4bf))
* **web:** use compact prop for inline mini-abacus ([ff1d60a](ff1d60a233))
* **web:** use direct function imports instead of execSync for calendar generation ([9f1715f](9f1715f085))
* **web:** use stdin/stdout for Typst compilation ([06f68cc](06f68cc74c))

### Documentation

* **abacus-react:** add Storybook stories for AbacusStatic ([4f9dc46](4f9dc4666d))
* **abacus-react:** add Storybook stories for new features ([6a1cec0](6a1cec06a7))
* **abacus-react:** export AbacusStatic and update README ([74f2d97](74f2d97434))
* **abacus-react:** update documentation for new features ([35d8734](35d8734a3a))
* **abacus-react:** update README with /static import path for RSC ([72a4c2b](72a4c2b80c))
* add 3D enhancement documentation to README ([cc96802](cc96802df8))
* add critical section on never adding tsx to production dependencies ([770cfc3](770cfc3aca))
* add database migration guide and playing guide modal spec ([5a29af7](5a29af78e2))
* add deployment verification guidelines to prevent false positives ([3d8da23](3d8da2348b))
* **card-sorting:** add comprehensive multiplayer plan ([008ccea](008ccead0f))
* clarify dev server management in Claude Code instructions ([e08fdfd](e08fdfd676))
* **rithmomachia:** Add concise one-page playing guide ([e3c1f10](e3c1f10233))
* update workflow to require manual testing before commits ([0991796](0991796f1e))

### Styles

* **rithmomachia:** improve divider styling and make tabs responsive ([88ca35e](88ca35e044)), closes [#e5e7](https://github.com/antialias/soroban-abacus-flashcards/issues/e5e7) [#9ca3](https://github.com/antialias/soroban-abacus-flashcards/issues/9ca3)
* **rithmomachia:** improve pyramid face numbers visibility and contrast ([94e5e6a](94e5e6a268)), closes [#fbbf24](https://github.com/antialias/soroban-abacus-flashcards/issues/fbbf24) [#b45309](https://github.com/antialias/soroban-abacus-flashcards/issues/b45309)
* **rithmomachia:** increase pyramid face numbers size and boldness ([7bf2d73](7bf2d730d3))

### Tests

* trigger compose-updater deployment test ([2b06aae](2b06aae394))
* verify compose-updater automatic deployment cycle ([af0552c](af0552ccd9))
2025-11-05 15:14:39 +00:00
Thomas Hallock
41a3707841 fix: replace regex HTML parsing with deterministic bead position calculations in icon generation
- Replace fragile regex parsing in generateDayIcon.tsx with proper bead
  position calculations using numberToAbacusState(), calculateStandardDimensions(),
  and calculateBeadPosition() from @soroban/abacus-react
- Add query parameter support to /icon route for testing different days (e.g. /icon?day=15)
- Fix icon cropping to properly show only active beads with dynamic viewBox
- Validate day parameter (1-31) and return 400 for invalid values
- Different cache duration for production (1 hour) vs testing (1 minute)

Results:
- Day 1: 48.88px height (minimal)
- Day 5: 48.88px height (single heaven bead)
- Day 25: 100.18px height (many active beads)
- Day 31: 93.88px height

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-05 09:10:17 -06:00
36 changed files with 3236 additions and 244 deletions

View File

@@ -1,6 +1,996 @@
## [4.68.0](https://github.com/antialias/soroban-abacus-flashcards/compare/v4.67.1...v4.68.0) (2025-11-05)
### Features
* **3d-abacus:** change default columns from 13 to 4 ([cd15c70](https://github.com/antialias/soroban-abacus-flashcards/commit/cd15c70a25c597c17ee5d2f816b1c85ba8ce4ce9))
* **abacus-react:** add AbacusStatic for React Server Components ([3b8e864](https://github.com/antialias/soroban-abacus-flashcards/commit/3b8e864cfa3af50b1912ce7ff55003d7f6b9c229))
* **abacus-react:** add core utility functions for state management ([e65541c](https://github.com/antialias/soroban-abacus-flashcards/commit/e65541c100e590a51448750c6d5178ed4f3e8eeb))
* **abacus-react:** add layout and educational props ([35bbcec](https://github.com/antialias/soroban-abacus-flashcards/commit/35bbcecb9e36f1ef5917a5a629f5e78f1f490e9c))
* **abacus-react:** add pre-defined theme presets ([cf1f950](https://github.com/antialias/soroban-abacus-flashcards/commit/cf1f950c7c5fb9ee1f0de673235d6f037be3b9d6))
* **abacus-react:** add React hooks for abacus calculations ([de038d2](https://github.com/antialias/soroban-abacus-flashcards/commit/de038d2afc26c36c1490d5ea45dace0ab812c5cc))
* **abacus-react:** add separate /static export path for React Server Components ([ed69f6b](https://github.com/antialias/soroban-abacus-flashcards/commit/ed69f6b917c543bbcaa4621a0e63745bee70f5bf))
* **abacus-react:** add shared dimension calculator for consistent sizing ([e5ba772](https://github.com/antialias/soroban-abacus-flashcards/commit/e5ba772fde9839c22daec92007f052ca125c7695))
* **abacus-react:** export new utilities, hooks, and themes ([ce4e44d](https://github.com/antialias/soroban-abacus-flashcards/commit/ce4e44d6302746053ad40dc61bab57ef3a0a9f31))
* **abacus:** add nativeAbacusNumbers setting to schema and UI ([79f7347](https://github.com/antialias/soroban-abacus-flashcards/commit/79f7347d4800646378470a7f9aca8e7f2fd5573c))
* add 3D printing support for abacus models ([dafdfdd](https://github.com/antialias/soroban-abacus-flashcards/commit/dafdfdd233b53464b9825a8a9b5f2e6206fc54cb))
* add client-side OpenSCAD WASM support for 3D preview ([eaaf17c](https://github.com/antialias/soroban-abacus-flashcards/commit/eaaf17cd4c675bfd40e0573b9c99f0c733d926aa))
* add comprehensive metadata, SEO, and make AbacusReact SSR-compatible ([0922ea1](https://github.com/antialias/soroban-abacus-flashcards/commit/0922ea10b77e7d16b8c414c596d23cb11e20c1cc))
* add comprehensive Storybook coverage and migration guide ([7a4a37e](https://github.com/antialias/soroban-abacus-flashcards/commit/7a4a37ec6d0171782778e18122da782f069e0556))
* add game preview system with mock arcade environment ([25880cc](https://github.com/antialias/soroban-abacus-flashcards/commit/25880cc7e463f98a5a23c812c1ffd43734d3fe1f))
* add per-player stats tracking system ([613301c](https://github.com/antialias/soroban-abacus-flashcards/commit/613301cd137ad6f712571a0be45c708ce391fc8f))
* add Strategy & Tactics section to Rithmomachia guide ([81ead65](https://github.com/antialias/soroban-abacus-flashcards/commit/81ead65680892efa4d0ab07e7f0ef77eb1bc1405))
* add unified trophy abacus with hero mode integration ([6620418](https://github.com/antialias/soroban-abacus-flashcards/commit/6620418a704dcca810b511a5f394084521104e6b))
* **arcade:** add ability to deactivate remote players without kicking user ([3628426](https://github.com/antialias/soroban-abacus-flashcards/commit/3628426a567d7e0273be75cce64632ae04b7d5eb))
* **arcade:** add native abacus numbers support to pressure gauge ([1d525c7](https://github.com/antialias/soroban-abacus-flashcards/commit/1d525c7b5320984a1582b8ab7eae57895c728428))
* **arcade:** add Rithmomachia (Battle of Numbers) game ([2fc0a05](https://github.com/antialias/soroban-abacus-flashcards/commit/2fc0a05f7f557cee55f7d31b585499dd04e68ff9))
* **arcade:** add yjs-demo collaborative game and Yjs persistence layer ([d568955](https://github.com/antialias/soroban-abacus-flashcards/commit/d568955d6abf389e6ab7c6979e33122a65917a46))
* **arcade:** auto-create room when user has none ([ff88c3a](https://github.com/antialias/soroban-abacus-flashcards/commit/ff88c3a1b81703a87a1d57eeb5cc139da7d9df04))
* **calendar:** add beautiful daily calendar with locale-based paper size detection ([bdca315](https://github.com/antialias/soroban-abacus-flashcards/commit/bdca3154f8336e17a7031be8d2917f9cf05f274a))
* **calendar:** add i18n support and cropped abacus day numbers ([5242f89](https://github.com/antialias/soroban-abacus-flashcards/commit/5242f890f725c872a74b6ee45cd611092628690a))
* **card-sorting:** add activity feed notifications for collaborative mode ([1461414](https://github.com/antialias/soroban-abacus-flashcards/commit/1461414ef4d0b213af241213447c91eed1abe5fb))
* **card-sorting:** add auto-submit countdown for perfect sequences ([780a716](https://github.com/antialias/soroban-abacus-flashcards/commit/780a7161bc05c2ca6597d7d8d89f01afd33d9f4d))
* **card-sorting:** add bezier curves to connecting arrows ([4d8e873](https://github.com/antialias/soroban-abacus-flashcards/commit/4d8e873358271fe3fd50b228aea8277e20aa5966))
* **card-sorting:** add CardPosition type and position syncing ([656f5a7](https://github.com/antialias/soroban-abacus-flashcards/commit/656f5a7838ed6003c214ec484d4c37072270fa8d))
* **card-sorting:** add collapsible stats sidebar for spectators ([6527c26](https://github.com/antialias/soroban-abacus-flashcards/commit/6527c26a8166b23f074e85eb335a15800c1947a2))
* **card-sorting:** add game mode selector UI to setup phase ([d25b888](https://github.com/antialias/soroban-abacus-flashcards/commit/d25b888ffb3915d2d482442ab708ba3e159af512))
* **card-sorting:** add GameMode type system for multiplayer support ([fd76533](https://github.com/antialias/soroban-abacus-flashcards/commit/fd765335efbc91366c596c7789b92882cd3379d9))
* **card-sorting:** add green border to correctly positioned cards ([16fca86](https://github.com/antialias/soroban-abacus-flashcards/commit/16fca86b7687115f1cf565c533a512e92946e3a8)), closes [#22c55](https://github.com/antialias/soroban-abacus-flashcards/issues/22c55)
* **card-sorting:** add player emoji indicators on moving cards ([3a82099](https://github.com/antialias/soroban-abacus-flashcards/commit/3a8209975728cdcf914c43ba08339454a9e2457f))
* **card-sorting:** add react-spring animations for real-time sync ([c367e0c](https://github.com/antialias/soroban-abacus-flashcards/commit/c367e0ceece41d8e7c2bc8aebe3239ff6053a115))
* **card-sorting:** add smooth transition to drop shadow ([b0b93d0](https://github.com/antialias/soroban-abacus-flashcards/commit/b0b93d0175c8a1c8958d6ba346d969c234fdd6ff))
* **card-sorting:** add spectator mode UI enhancements ([ee7345d](https://github.com/antialias/soroban-abacus-flashcards/commit/ee7345d641e0ee72915afb9cdbd6d284b7e238bd)), closes [#6366f1](https://github.com/antialias/soroban-abacus-flashcards/issues/6366f1) [#8b5cf6](https://github.com/antialias/soroban-abacus-flashcards/issues/8b5cf6)
* **card-sorting:** add team scoring UI for collaborative mode ([ed6f177](https://github.com/antialias/soroban-abacus-flashcards/commit/ed6f1779141d0bc9dff2d532a3dfc638015936b5)), closes [#a78](https://github.com/antialias/soroban-abacus-flashcards/issues/a78) [#8b5cf6](https://github.com/antialias/soroban-abacus-flashcards/issues/8b5cf6)
* **card-sorting:** add updateCardPositions action to Provider ([f6ed4a2](https://github.com/antialias/soroban-abacus-flashcards/commit/f6ed4a27a26d8bfa495ba5f580a446286b9674a0))
* **card-sorting:** auto-arrange prefix/suffix cards in corners ([4ba7f24](https://github.com/antialias/soroban-abacus-flashcards/commit/4ba7f247175d93e4d339e2be7bbdb2e009992232))
* **card-sorting:** fade correctly positioned cards to 50% opacity ([7028cfc](https://github.com/antialias/soroban-abacus-flashcards/commit/7028cfc51164e9219479e6040b03c29239aa7edb))
* **card-sorting:** gentler spring animation for locked cards ([47189cb](https://github.com/antialias/soroban-abacus-flashcards/commit/47189cb6e79ed2915f5ddcc9cb3626540dfb07f3))
* **card-sorting:** implement continuous bezier curve paths ([2d93024](https://github.com/antialias/soroban-abacus-flashcards/commit/2d9302410f5e98145a435b00df3ae5fcf3f4c0b5))
* **card-sorting:** improve card distribution for natural scattered look ([0b0503f](https://github.com/antialias/soroban-abacus-flashcards/commit/0b0503f0354a4a82fe6b9bfe827729e8e5a9e329))
* **card-sorting:** make player emoji fill entire card background ([2e7a02c](https://github.com/antialias/soroban-abacus-flashcards/commit/2e7a02c9e4ab84e821d58661d6e7a326f7882afb))
* **card-sorting:** optimize results screen for mobile ([d188789](https://github.com/antialias/soroban-abacus-flashcards/commit/d188789069b4c350ce3cc0d221bd4a43dab528e0))
* **card-sorting:** redesign setup screen with modern UI ([73cf967](https://github.com/antialias/soroban-abacus-flashcards/commit/73cf96749234c480482f62392245b38c1fd5f0a0))
* **card-sorting:** scale correctly positioned cards to 50% ([222dc55](https://github.com/antialias/soroban-abacus-flashcards/commit/222dc555fa5068e2594dcc074e33f70320f5742c))
* **card-sorting:** shrink/fade cards in correct suffix as well ([8f6feec](https://github.com/antialias/soroban-abacus-flashcards/commit/8f6feec4f21d0af0d1c98daf5017eddd91d3d578))
* **card-sorting:** smooth spring transition from game table to results grid ([c5f39d5](https://github.com/antialias/soroban-abacus-flashcards/commit/c5f39d51eb45ec816f32151dc7f9d7c06360474b))
* **card-sorting:** wrap prefix/suffix cards to multiple rows ([e3184dd](https://github.com/antialias/soroban-abacus-flashcards/commit/e3184dd0d444e5dc204731f5b396d5c553cf7d11))
* complete 3D enhancement integration for all three proposals ([5ac55cc](https://github.com/antialias/soroban-abacus-flashcards/commit/5ac55cc14980b778f9be32f0833f8760aa16b631))
* **create-room:** replace hardcoded game grid with dynamic Radix Select dropdown ([83d0ba2](https://github.com/antialias/soroban-abacus-flashcards/commit/83d0ba26f5eeec3e189d279710d5bbcf13e82f29))
* dynamic day-of-month favicon using subprocess pattern ([4d0795a](https://github.com/antialias/soroban-abacus-flashcards/commit/4d0795a9df74fcb085af821eafb923bdcb5f0b0c))
* dynamically crop favicon to active beads for maximum size ([5670322](https://github.com/antialias/soroban-abacus-flashcards/commit/567032296aecaad13408bdc17d108ec7c57fb4a8))
* enable 3D enhancement on hero/open MyAbacus modes ([37e330f](https://github.com/antialias/soroban-abacus-flashcards/commit/37e330f26e5398c2358599361cd417b4aeefac7d))
* **games:** add autoplay and improve carousel layout ([9f51edf](https://github.com/antialias/soroban-abacus-flashcards/commit/9f51edfaa95c14f55a30a6eceafb9099eeed437f))
* **games:** add horizontal scroll support to carousels ([a224abb](https://github.com/antialias/soroban-abacus-flashcards/commit/a224abb6f660e1aa31ab04f5590b003fae072af9))
* **games:** add rotating games hero carousel ([24231e6](https://github.com/antialias/soroban-abacus-flashcards/commit/24231e6b2ebbdcae066344df54e7e80e7d221128))
* **i18n:** add dynamic locale switching without page reload ([fe9bfea](https://github.com/antialias/soroban-abacus-flashcards/commit/fe9bfeabf9ee66923501b18e1b69f2d666d0817d))
* **i18n:** add global language selector to navigation ([0506360](https://github.com/antialias/soroban-abacus-flashcards/commit/0506360117807665e8f5a6fcd8f1178339f6e65c))
* **i18n:** add homepage translations for all supported languages ([8c9d35a](https://github.com/antialias/soroban-abacus-flashcards/commit/8c9d35a3b43dd29664f5afb1bd96c4e584d9ec75))
* **i18n:** add Old High German (goh) language support ([b334a15](https://github.com/antialias/soroban-abacus-flashcards/commit/b334a15255ed9fa29beb43de66da0288691390c6))
* **i18n:** complete Old High German translations for all locales ([0b06a1c](https://github.com/antialias/soroban-abacus-flashcards/commit/0b06a1ce005d92e7ae9c225aba40d240e965753d))
* **i18n:** internationalize games page and tutorial content ([4253964](https://github.com/antialias/soroban-abacus-flashcards/commit/4253964af19f9aaa16f2394f41819223542fb519))
* **i18n:** internationalize homepage with English translations ([40cff14](https://github.com/antialias/soroban-abacus-flashcards/commit/40cff143c72e9228d7cce607cab64c4a6d067017))
* **i18n:** migrate from react-i18next to next-intl ([9016b76](https://github.com/antialias/soroban-abacus-flashcards/commit/9016b760247a20271255839e4dd7e5b9a8353b9f))
* **i18n:** update games page hero section copy ([6333c60](https://github.com/antialias/soroban-abacus-flashcards/commit/6333c60352b920916afd81cc3b0229706a1519fa))
* install embla-carousel-autoplay for games carousel ([946e5d1](https://github.com/antialias/soroban-abacus-flashcards/commit/946e5d19107020992be8945f8fe7c41e4bc2a0e2))
* install embla-carousel-react for player profile carousel ([642ae95](https://github.com/antialias/soroban-abacus-flashcards/commit/642ae957383cfe1d6045f645bbe426fd80c56f35))
* internationalize guide page with 6 languages ([e9c320b](https://github.com/antialias/soroban-abacus-flashcards/commit/e9c320bb1032e94c3852b9459236409da4669c09))
* internationalize tutorial player ([26d41cf](https://github.com/antialias/soroban-abacus-flashcards/commit/26d41cfd058bfdf5b61ee6e20cfc61cbecb32f45))
* optimize card sorting for mobile displays ([b443ee9](https://github.com/antialias/soroban-abacus-flashcards/commit/b443ee9cdcd9fcb7674845d8c92f7c338ad98dea))
* Redesign Rithmomachia setup page with dramatic medieval theme ([6ae4d13](https://github.com/antialias/soroban-abacus-flashcards/commit/6ae4d13dc784a87f85206c6ff6d005e5b23b678c))
* **rithmomachia:** add 80% opacity to guide modal when not hovered ([4a78485](https://github.com/antialias/soroban-abacus-flashcards/commit/4a78485d2e20f2cbf36cc898a1beafa8eb48bfbf))
* **rithmomachia:** add CaptureContext for capture dialog state management ([d7eb957](https://github.com/antialias/soroban-abacus-flashcards/commit/d7eb957a8dabbcac35e166a83dd679a628e19baa))
* **rithmomachia:** add ghost panel preview for guide docking ([c0d6526](https://github.com/antialias/soroban-abacus-flashcards/commit/c0d6526d30aca8deaeda2b7c2e27eb37af8b577c))
* **rithmomachia:** add guide docking with resizable panels ([f457f1a](https://github.com/antialias/soroban-abacus-flashcards/commit/f457f1a1c22b6cb7fff23a7701474322cf423dd9))
* **rithmomachia:** add helper piece selection for mathematical captures ([cae3359](https://github.com/antialias/soroban-abacus-flashcards/commit/cae335958751c27684bfb10c8e2e526b460954ed))
* **rithmomachia:** add helpful error messages for failed captures ([b172440](https://github.com/antialias/soroban-abacus-flashcards/commit/b172440a41e958ced98903bb8f4c2e4b423e1356))
* **rithmomachia:** add initial board visual to guide Overview section ([d42bcff](https://github.com/antialias/soroban-abacus-flashcards/commit/d42bcff0d922895549c1c12f8e02a3ae6d53425a))
* **rithmomachia:** Add interactive playing guide modal ([3121d82](https://github.com/antialias/soroban-abacus-flashcards/commit/3121d8240a567817f5f205a4ef4a788fcf451f71))
* **rithmomachia:** add number bond visualization and helper placeholders ([82d8913](https://github.com/antialias/soroban-abacus-flashcards/commit/82d89131f00517f162ec496397cb390f9ecfc52e))
* **rithmomachia:** add ratio capture example to guide ([9150b0c](https://github.com/antialias/soroban-abacus-flashcards/commit/9150b0c678ce7104fe984ee0fc93748b43a245f4))
* **rithmomachia:** add standalone guide page route ([3fcc79f](https://github.com/antialias/soroban-abacus-flashcards/commit/3fcc79fe9eae11d4bd3a724c1b1f7d086e7cae81))
* **rithmomachia:** add useBoardLayout hook for centralized layout calculations ([27f1c98](https://github.com/antialias/soroban-abacus-flashcards/commit/27f1c989d59a19844b90a5148ae27fb97161da2d))
* **rithmomachia:** add usePieceSelection hook for selection state management ([275f401](https://github.com/antialias/soroban-abacus-flashcards/commit/275f401e3c25b75fec4700a8c2d4be6e33f0afe9))
* **rithmomachia:** add visual board examples to Capture section ([74bc3c0](https://github.com/antialias/soroban-abacus-flashcards/commit/74bc3c0dcf8d1ee7084e88a04861a85f9b623809))
* **rithmomachia:** add visual board examples to Harmony section ([1d5f01c](https://github.com/antialias/soroban-abacus-flashcards/commit/1d5f01c966cf1eec9a9c19ee37f1cad93c89df40))
* **rithmomachia:** add visual winning example to Victory section ([b7fac78](https://github.com/antialias/soroban-abacus-flashcards/commit/b7fac788292e00c6060a47fdbcca89a7e7fee35c))
* **rithmomachia:** auto-size tab labels with react-textfit ([9fd5406](https://github.com/antialias/soroban-abacus-flashcards/commit/9fd54067ce257e028b02f4784568ff3f2bbb32ca))
* **rithmomachia:** cycle through valid helpers with dynamic number tooltips ([4829e41](https://github.com/antialias/soroban-abacus-flashcards/commit/4829e41ea13fae2edec10837e65e505929445782))
* **rithmomachia:** enhance capture relation UI with smooth animations ([0a30801](https://github.com/antialias/soroban-abacus-flashcards/commit/0a308016e9d6a926c52dbfc5623b60b169d16d03))
* **rithmomachia:** enhance Harmony section with comprehensive content ([f555856](https://github.com/antialias/soroban-abacus-flashcards/commit/f5558563ea93ef7428aa220c2e15e3f02711420f))
* **rithmomachia:** enhance Pieces section with visual examples and pyramid details ([55aff82](https://github.com/antialias/soroban-abacus-flashcards/commit/55aff829f4c284e8cfe6d471c0821575928b93bc))
* **rithmomachia:** enhance Pyramid section with comprehensive details ([9fde1ef](https://github.com/antialias/soroban-abacus-flashcards/commit/9fde1ef9e703e26b2450128155b53fdf2d2e1fe5))
* **rithmomachia:** guide defaults to docked right on open ([11f674d](https://github.com/antialias/soroban-abacus-flashcards/commit/11f674d542ea5e4e88bd60ff1068451805d9766e))
* **rithmomachia:** improve guide pieces section layout ([a270bfc](https://github.com/antialias/soroban-abacus-flashcards/commit/a270bfc0cc4a3b6b54ba43a5af14a227cc7d29f9))
* **rithmomachia:** improve guide UX and add persistence ([b314740](https://github.com/antialias/soroban-abacus-flashcards/commit/b31474069734350a7059cd7c73255a7e11b78eb9))
* **rithmomachia:** improve roster status notice UX ([e27df45](https://github.com/antialias/soroban-abacus-flashcards/commit/e27df45256147f958ca215f9dd1f4e133e8cf06c))
* **rithmomachia:** integrate roster warning into game nav ([8a11594](https://github.com/antialias/soroban-abacus-flashcards/commit/8a11594203fb91faee6cbc4cb74367164ecd6d85))
* **rithmomachia:** make guide modal ultra-responsive down to 150px width ([0474197](https://github.com/antialias/soroban-abacus-flashcards/commit/04741971b296976f4476ecd949e84066fc549010))
* **rithmomachia:** recreate original guide modal header layout ([2489695](https://github.com/antialias/soroban-abacus-flashcards/commit/24896957d0817758c5f64c0e3473e6a0a343af67))
* **rithmomachia:** show capture error on hover instead of click ([339b678](https://github.com/antialias/soroban-abacus-flashcards/commit/339b6780f657ace5bfe1611c4ef64bb0c2c31587))
* **rithmomachia:** show pyramid face numbers on hover instead of selection ([b0c4523](https://github.com/antialias/soroban-abacus-flashcards/commit/b0c4523c0b4669c96a50b2812ba6cb2faa3f9a22))
* **rithmomachia:** show pyramid face numbers when selected ([5c186f3](https://github.com/antialias/soroban-abacus-flashcards/commit/5c186f3947cc38f1f5db5de3e68e590b90c2d092))
* **rithmomachia:** show pyramid face numbers when selected with subtle animation ([5c2ddbe](https://github.com/antialias/soroban-abacus-flashcards/commit/5c2ddbef05d7f4195d21b084cb1c0c4193ee3c9c))
* **rithmomachia:** show real preview layout when dragging guide to dock ([17d2460](https://github.com/antialias/soroban-abacus-flashcards/commit/17d2460a8769a21d33fabc5f909cf5b939712d36))
* **rithmomachia:** simplify guide language for clarity ([85cb630](https://github.com/antialias/soroban-abacus-flashcards/commit/85cb630add395a6693ecbbe9c8fc6aaf8c47be29))
* **rithmomachia:** skip helper selection UI and auto-select first valid helper ([be2a00e](https://github.com/antialias/soroban-abacus-flashcards/commit/be2a00e8b366b5606525309b4c7813f5c35c7f7c))
* **rithmomachia:** Update harmony system to classical three-piece proportions ([08c9762](https://github.com/antialias/soroban-abacus-flashcards/commit/08c97620f5e694b8526c448c44d265e6dd1fe1eb))
* **rithmomachia:** Update to traditional board setup with 25 pieces per side ([0769eaa](https://github.com/antialias/soroban-abacus-flashcards/commit/0769eaaa1dc238b901e3a7cfe0486e6122d5eda9))
* **rithmomachia:** use actual piece SVGs in number bond with 2.5s rotation animation ([976a7de](https://github.com/antialias/soroban-abacus-flashcards/commit/976a7de949c22842f4b6da3ced990f502a1c2733))
* **room-share:** add QR code button for easy mobile joining ([349290a](https://github.com/antialias/soroban-abacus-flashcards/commit/349290ac6a411651686b64d2e6b540083d2df1d9))
* show rithmomachia turn in nav ([7c89bfe](https://github.com/antialias/soroban-abacus-flashcards/commit/7c89bfef9c60db0e2c46e920500dcc1fbe90d3df))
* switch to royal color theme with transparent background ([944ad65](https://github.com/antialias/soroban-abacus-flashcards/commit/944ad6574e01a67ce1fdbb1f2452fe632c78ce43)), closes [#fbbf24](https://github.com/antialias/soroban-abacus-flashcards/issues/fbbf24) [#f59e0](https://github.com/antialias/soroban-abacus-flashcards/issues/f59e0) [#a855f7](https://github.com/antialias/soroban-abacus-flashcards/issues/a855f7) [#7e22](https://github.com/antialias/soroban-abacus-flashcards/issues/7e22)
* **web:** add test page for AbacusStatic RSC compatibility ([903dea2](https://github.com/antialias/soroban-abacus-flashcards/commit/903dea25844f1d2b3730fbcbd8478e7af1887663))
* **web:** add test page for AbacusStatic Server Component ([3588d5a](https://github.com/antialias/soroban-abacus-flashcards/commit/3588d5acde25588ce4db3ee32adb04ace0e394d4))
* **web:** add Typst-based preview endpoint with React Suspense ([599a758](https://github.com/antialias/soroban-abacus-flashcards/commit/599a758471c43ab0fc87301c5e7eeceed608062e))
* **web:** add year abacus to calendar header and make grid bolder ([867c7ee](https://github.com/antialias/soroban-abacus-flashcards/commit/867c7ee17251b8df13665bee9c0391961975e681)), closes [#333](https://github.com/antialias/soroban-abacus-flashcards/issues/333)
* **web:** improve calendar abacus preview styling ([8439727](https://github.com/antialias/soroban-abacus-flashcards/commit/8439727b152accf61f0c28158b92788510ca086e))
* **web:** optimize monthly calendar for single-page layout ([b277a89](https://github.com/antialias/soroban-abacus-flashcards/commit/b277a89415d1823455376c3e0f641b52f3394e7c))
* **web:** redesign monthly calendar as single composite SVG ([8ce8038](https://github.com/antialias/soroban-abacus-flashcards/commit/8ce8038baeea0b8b0fffe3215746958731bd9d6a))
### Bug Fixes
* **abacus-react:** add data-testid attributes back to beads for testing ([23ae1b0](https://github.com/antialias/soroban-abacus-flashcards/commit/23ae1b0c6f878daf79a993992d43ad80a89fa790))
* **abacus-react:** correct column highlighting offset in AbacusStatic ([0641eb7](https://github.com/antialias/soroban-abacus-flashcards/commit/0641eb719ef56c67de965296006df666f83e5b08))
* **abacus-react:** fix animations by preventing component remounting ([be7d4c4](https://github.com/antialias/soroban-abacus-flashcards/commit/be7d4c471327534a95c4c75372680c629b5f12c2))
* **abacus-react:** restore original AbacusReact measurements and positioning ([88c0baa](https://github.com/antialias/soroban-abacus-flashcards/commit/88c0baaad9b83b60ab8cdcad92070cc049d61cc7))
* add xmlns to AbacusStatic for Typst SVG parsing ([98cd019](https://github.com/antialias/soroban-abacus-flashcards/commit/98cd019d4af91d7ca4e7a88f700194273476afb7))
* adjust hero abacus position to avoid covering subtitle ([f03d341](https://github.com/antialias/soroban-abacus-flashcards/commit/f03d3413145cc7ddfba93728ecdec7eabea9ada6))
* **arcade:** add automatic retry for version conflict rejections ([fbcde25](https://github.com/antialias/soroban-abacus-flashcards/commit/fbcde2505f7ff2bf3426f3458e480c4548314ba4))
* **arcade:** allow deactivating players from users who left the room ([7c1c2d7](https://github.com/antialias/soroban-abacus-flashcards/commit/7c1c2d7bebbb9a1acb274d17dd43b6ee5d196f44))
* **arcade:** implement optimistic locking in session manager ([71fd66d](https://github.com/antialias/soroban-abacus-flashcards/commit/71fd66d96a3b03650c90f59f6e516aae7dddc345))
* board rotation now properly fills height in portrait mode ([b5a96ea](https://github.com/antialias/soroban-abacus-flashcards/commit/b5a96eaeb1e29c20304142a7a0adf62f1cef570f))
* **card-sorting:** add border radius to outer card container ([a922eba](https://github.com/antialias/soroban-abacus-flashcards/commit/a922eba73c4656ee941ce4dfb1dc57a62f076570))
* **card-sorting:** add debug logging for spring animations ([d42947e](https://github.com/antialias/soroban-abacus-flashcards/commit/d42947eb8d5d3d8298f5d3b3d1644891c268dbb6))
* **card-sorting:** add missing gameMode support after hard reset ([a832325](https://github.com/antialias/soroban-abacus-flashcards/commit/a832325debde289d6928c5e6f9c24311c5e079ad))
* **card-sorting:** add missing useMemo import ([949d76d](https://github.com/antialias/soroban-abacus-flashcards/commit/949d76d844c786ada8a6373e4abb7f498f6befb9))
* **card-sorting:** add overflow hidden to clip rounded corners ([84c66fe](https://github.com/antialias/soroban-abacus-flashcards/commit/84c66feec6b4112b015e1afd95bf33b24b5f6a4f))
* **card-sorting:** adjust connecting paths for scaled cards ([829c741](https://github.com/antialias/soroban-abacus-flashcards/commit/829c741e554d1490dd7a5bbc17f2a32f7195dc07))
* **card-sorting:** adjust game board for spectator panels ([fc5cf12](https://github.com/antialias/soroban-abacus-flashcards/commit/fc5cf1216fe03edfb7e44afda01192f4b97b4f4e))
* **card-sorting:** adjust viewport dimensions for spectator panels ([4dce16c](https://github.com/antialias/soroban-abacus-flashcards/commit/4dce16cca46c965199b7e09f8b34bfa221efac33))
* **card-sorting:** animate cards from game board to results grid ([17d45fe](https://github.com/antialias/soroban-abacus-flashcards/commit/17d45fe88cd9773f5e550f6ee5a7f0c82cca2023))
* **card-sorting:** correct suffix card detection in auto-arrange ([d02ab59](https://github.com/antialias/soroban-abacus-flashcards/commit/d02ab5922c416042d525f54097a6975ae1541586))
* **card-sorting:** enable card scaling for spectators ([6b095c3](https://github.com/antialias/soroban-abacus-flashcards/commit/6b095c33830341c46139bc847ddaab3db632265e))
* **card-sorting:** enable New Game button during active gameplay ([f3f6eca](https://github.com/antialias/soroban-abacus-flashcards/commit/f3f6eca1db30df9e1e34cc4e77a069a6a3954f3d))
* **card-sorting:** end drag immediately when card becomes locked ([ae45298](https://github.com/antialias/soroban-abacus-flashcards/commit/ae45298ec48efb29587c0a1c1a7986a72821f3ef))
* **card-sorting:** filter local player from emoji overlays on dragged cards ([dc2d94a](https://github.com/antialias/soroban-abacus-flashcards/commit/dc2d94aaa58531ed4f9047e2ca92724d9264643d))
* **card-sorting:** fix results panel layout to not cover cards ([4b4fbfe](https://github.com/antialias/soroban-abacus-flashcards/commit/4b4fbfef322ecda06020ad52d4b1788267112460))
* **card-sorting:** hide activity notifications in spectator mode ([5cca279](https://github.com/antialias/soroban-abacus-flashcards/commit/5cca279687d8973d25bd9a411a55b632d1c82f63))
* **card-sorting:** keep arrow sequence numbers upright ([79c9469](https://github.com/antialias/soroban-abacus-flashcards/commit/79c94699fa1cc2a2886e3ab1addc5fcd975602f5))
* **card-sorting:** lock correctly positioned prefix/suffix cards ([170abed](https://github.com/antialias/soroban-abacus-flashcards/commit/170abed2318432f309de40692f6092bb4c4a1a45))
* **card-sorting:** lock spring positions after initial animation completes ([275cc62](https://github.com/antialias/soroban-abacus-flashcards/commit/275cc62a523d9e849f2162001141b6d75ae0925e))
* **card-sorting:** New Game now restarts with same settings instantly ([f3687ed](https://github.com/antialias/soroban-abacus-flashcards/commit/f3687ed236eff4ebe61699ec02909024c7086fb5))
* **card-sorting:** only shrink/fade cards in correct prefix ([51368c6](https://github.com/antialias/soroban-abacus-flashcards/commit/51368c6ec59d5447ce2875c5e1181dec97fd509d))
* **card-sorting:** preserve card positions on pause/resume ([0d8af09](https://github.com/antialias/soroban-abacus-flashcards/commit/0d8af09517534f1e1cf1f57160391d465a279d76))
* **card-sorting:** preserve rotation when starting drag ([3364144](https://github.com/antialias/soroban-abacus-flashcards/commit/3364144fb6212934b6ad6d63ac6e7b78b436b258))
* **card-sorting:** prevent duplicate START_GAME moves on Play Again ([a0b14f8](https://github.com/antialias/soroban-abacus-flashcards/commit/a0b14f87e9c5b32fcbb685da4e70c563f70ed91a))
* **card-sorting:** prevent ghost movements with proper optimistic updates ([bd014be](https://github.com/antialias/soroban-abacus-flashcards/commit/bd014bec4ffa12bcd8f4a4e84ff51203c90c1f1d))
* **card-sorting:** prevent infinite loop when all cards are correct ([34785f4](https://github.com/antialias/soroban-abacus-flashcards/commit/34785f466faaa6b9f2958df786af88561fa80b06))
* **card-sorting:** prevent infinite loop with tolerance-based position comparison ([627b873](https://github.com/antialias/soroban-abacus-flashcards/commit/627b873382eaa76ad16477280d10451cf2951e1a))
* **card-sorting:** prevent position jump when clicking rotated cards ([564a00f](https://github.com/antialias/soroban-abacus-flashcards/commit/564a00f82b6ca6aa8a2c0586ca49fc42d44991a8))
* **card-sorting:** prevent replaying own movements from server ([308168a](https://github.com/antialias/soroban-abacus-flashcards/commit/308168a7fb51013b0851e98b161ba1a1a3e39fbb))
* **card-sorting:** prevent springs from reinitializing on window resize ([30953b8](https://github.com/antialias/soroban-abacus-flashcards/commit/30953b8c4a3cf147f980455818f9ce8eea07837c))
* **card-sorting:** prevent springs from resetting after animation ([8aff60c](https://github.com/antialias/soroban-abacus-flashcards/commit/8aff60ce3f8d302ce5c1bde7cb773e63064c36b7))
* **card-sorting:** remove hasAnimatedRef logic causing backwards animation ([a44aa5a](https://github.com/antialias/soroban-abacus-flashcards/commit/a44aa5a4c2d84cab7cf0bbf87485bb61548fdeb2))
* **card-sorting:** remove remaining reveal numbers references ([15c53ea](https://github.com/antialias/soroban-abacus-flashcards/commit/15c53ea4eb4abb824eb0360fb645b1f3e455578e))
* **card-sorting:** restore prefix/suffix card shrinking visual feedback ([f5fb4d7](https://github.com/antialias/soroban-abacus-flashcards/commit/f5fb4d7b76e25286bcdecd017894ff2d78b31963))
* **card-sorting:** show only active players in team members section ([fa9f1a5](https://github.com/antialias/soroban-abacus-flashcards/commit/fa9f1a568f3dff2f4e5e7d3e8841b951ef1b7d04))
* **card-sorting:** smooth scale animation while dragging cards ([0eefc33](https://github.com/antialias/soroban-abacus-flashcards/commit/0eefc332ac2724c54b477301a269915e895db94f))
* **card-sorting:** stabilize inferred sequence for locked cards during drag ([b0cd194](https://github.com/antialias/soroban-abacus-flashcards/commit/b0cd194838705bb7bbf21ac9e318eaba491097b2))
* **card-sorting:** use empty deps array for useSprings to prevent recreation ([cee399e](https://github.com/antialias/soroban-abacus-flashcards/commit/cee399ed1513d32d0fff51a6f63898aa861605e1))
* **card-sorting:** use ref to track initialized state and prevent re-animation ([f389afa](https://github.com/antialias/soroban-abacus-flashcards/commit/f389afa831935e896a626f526cfee378e340a64b))
* **card-sorting:** use same coordinate system for game board and results ([6972fdf](https://github.com/antialias/soroban-abacus-flashcards/commit/6972fdf1105b6e854494efe1c4c587e6b6ff32a9))
* **complement-race:** prevent delivery move thrashing in steam sprint mode ([e1258ee](https://github.com/antialias/soroban-abacus-flashcards/commit/e1258ee0416010909774694c0b25306b6f30329c))
* configure favicon metadata and improve bead visibility ([e1369fa](https://github.com/antialias/soroban-abacus-flashcards/commit/e1369fa2754cd61745a2950e6cb767d6b08db38f))
* copy entire packages/core and packages/templates ([0ccada0](https://github.com/antialias/soroban-abacus-flashcards/commit/0ccada0ca783e635f9ae08f33a69c392018ee342))
* correct hero abacus scroll direction to flow with page content ([4232746](https://github.com/antialias/soroban-abacus-flashcards/commit/423274657c9698bba28f7246fbf48d8508d97ef9))
* correct Typst template path in Dockerfile ([4c518de](https://github.com/antialias/soroban-abacus-flashcards/commit/4c518decb7fcc0b519d07680cbfd01c94c23dd41))
* delete existing user sessions before creating new ones ([0cced47](https://github.com/antialias/soroban-abacus-flashcards/commit/0cced47a0f414a04371bdb253fc5a43e4d9557be))
* **docker:** add scripts, abacus-react, and tsx for production calendar generation ([33eb90e](https://github.com/antialias/soroban-abacus-flashcards/commit/33eb90e316f84650ae619f8c6c02c9e77c663d1b))
* **docker:** upgrade OpenSCAD to 2024.11 to fix CGAL intersection bug ([e1bcd24](https://github.com/antialias/soroban-abacus-flashcards/commit/e1bcd241691050fa05cd49e14c288b4b070a7d17))
* extract pure SVG content from AbacusReact renders ([b07f1c4](https://github.com/antialias/soroban-abacus-flashcards/commit/b07f1c421616bcfd1f949f9a42ce1b03df418945))
* **games:** prevent horizontal page scroll from carousel overflow ([5a8c98f](https://github.com/antialias/soroban-abacus-flashcards/commit/5a8c98fc10704e459690308a84dc7ee2bfa0ef6c))
* **games:** smooth scroll feel for carousel wheel navigation ([f80a73b](https://github.com/antialias/soroban-abacus-flashcards/commit/f80a73b35c324959bfd7141ebf086cb47d3c0ebc))
* **games:** use specific transition properties for smooth carousel loop ([187271e](https://github.com/antialias/soroban-abacus-flashcards/commit/187271e51527ee0129f71d77be1bd24072b963c4))
* **guide:** increase abacus sizes - they were too small ([1074624](https://github.com/antialias/soroban-abacus-flashcards/commit/1074624b2fbce1d1d887dbd6326cf22eeb31dcec))
* **guide:** make abacus sizes consistent and add nav spacing ([bea4842](https://github.com/antialias/soroban-abacus-flashcards/commit/bea4842a29aa86ca4261b4ddd6150bacc8babc46))
* **guide:** remove inner containers and tighten margins ([7e54c6f](https://github.com/antialias/soroban-abacus-flashcards/commit/7e54c6f4fc5bc4daa6088eb3381d860a495776f2))
* **i18n:** eliminate FOUC by loading messages server-side ([4d4d930](https://github.com/antialias/soroban-abacus-flashcards/commit/4d4d930bd307ce5a405fc5751af6682a9f221f1f))
* **i18n:** use useMessages() for tutorial translations ([95b0105](https://github.com/antialias/soroban-abacus-flashcards/commit/95b0105ca3b28c5adfa843e8d77a8b27d9e7ade4))
* include column posts in favicon bounding box ([0b2f481](https://github.com/antialias/soroban-abacus-flashcards/commit/0b2f48106a939307b728c86fe2ea1be1e0247ea8))
* increase server update debounce to 2000ms for low bandwidth ([633ff12](https://github.com/antialias/soroban-abacus-flashcards/commit/633ff127500c893a215491afa0e6ff814ad553bf))
* Integrate threshold input into Point Victory card ([b29bbee](https://github.com/antialias/soroban-abacus-flashcards/commit/b29bbeefcad92be42f7a3ca27ac126db4232ab26))
* **layout:** add systematic spacing for fixed nav bar ([4559fb1](https://github.com/antialias/soroban-abacus-flashcards/commit/4559fb121d0df954ebaf33616a5262c7ca633c6e))
* **layout:** remove wrapper, use utility class for nav spacing ([247c3d9](https://github.com/antialias/soroban-abacus-flashcards/commit/247c3d9874303f83641e599724a485eea8d5604a))
* mark dynamic routes as force-dynamic to prevent static generation errors ([d7b35d9](https://github.com/antialias/soroban-abacus-flashcards/commit/d7b35d954421fd7577cd2c26247666e5953b647d))
* **nav:** restrict transparent hero styling to home page only ([fab227d](https://github.com/antialias/soroban-abacus-flashcards/commit/fab227d6862672e8250b1c169b302fbae23ce4d2))
* **nav:** show full navigation on /games page ([d3fe6ac](https://github.com/antialias/soroban-abacus-flashcards/commit/d3fe6acbb0390e1df71869a4095e5ee6021e06b1))
* **qr-button:** improve layout and z-index ([646a422](https://github.com/antialias/soroban-abacus-flashcards/commit/646a4228d0573796b1a429e31bc037411024c0ff))
* **qr-button:** increase mini QR code size to 80px ([61ac737](https://github.com/antialias/soroban-abacus-flashcards/commit/61ac7378bdb01132b26bfc265a057c095ea41606))
* **qr-button:** increase mini QR code to 84px ([3fae5ea](https://github.com/antialias/soroban-abacus-flashcards/commit/3fae5ea6fa9ebd0f8fe8c9140a027be7f6a041aa))
* **qr-button:** make button square and increase QR size ([dc2d466](https://github.com/antialias/soroban-abacus-flashcards/commit/dc2d46663b8e0ec94a1508a57c4f8c2d8ba03506))
* **qr-button:** match height of stacked buttons ([81f202d](https://github.com/antialias/soroban-abacus-flashcards/commit/81f202d21556aa430402fda814519adbc8883831))
* reduce padding to minimize gap below last bead ([0e529be](https://github.com/antialias/soroban-abacus-flashcards/commit/0e529be789caf16e73f3e2ee77f52e243841aef4))
* remove distracting parallax and wobble 3D effects ([28a2d40](https://github.com/antialias/soroban-abacus-flashcards/commit/28a2d40996256700bf19cd80130b26e24441949f))
* remove wobble physics and enhance wood grain visibility ([5d97673](https://github.com/antialias/soroban-abacus-flashcards/commit/5d976734062eb3d943bfdfdd125473c56b533759))
* replace regex HTML parsing with deterministic bead position calculations in icon generation ([41a3707](https://github.com/antialias/soroban-abacus-flashcards/commit/41a3707841595a74de56c6adf6d271237f81ee0e))
* resolve z-index layering and hero abacus visibility issues ([ed9a050](https://github.com/antialias/soroban-abacus-flashcards/commit/ed9a050d64db905e1328008f25dc0014e9a81999))
* rewrite 3D stories to use props instead of CSS wrappers ([26bdb11](https://github.com/antialias/soroban-abacus-flashcards/commit/26bdb112370cece08634e3d693d15336111fc70f))
* **rithmomachia:** add missing i18next dependencies ([91154d9](https://github.com/antialias/soroban-abacus-flashcards/commit/91154d93647e59f7e5f96d1db5624a7ec9b1b9ff))
* **rithmomachia:** add missing pyramid section keys to Japanese (ja.json) ([dae615e](https://github.com/antialias/soroban-abacus-flashcards/commit/dae615ee72a7ec7d0b235a22c61ebc4af0d8eadb))
* **rithmomachia:** adjust error dialog sizing to prevent text clipping ([cda1126](https://github.com/antialias/soroban-abacus-flashcards/commit/cda1126cb0eab6840df89f3a8778d72410298093))
* **rithmomachia:** adjust roster notice position to not overlap nav ([7093223](https://github.com/antialias/soroban-abacus-flashcards/commit/709322373a91c8174d21052d184fa84dd8bda326))
* **rithmomachia:** change undock icon to pop-out arrow ([2a91748](https://github.com/antialias/soroban-abacus-flashcards/commit/2a917484938bc269cf16acb501d4d26584405e0f))
* **rithmomachia:** correct board dimensions to 16x8 and restore original layout values ([cfac277](https://github.com/antialias/soroban-abacus-flashcards/commit/cfac27750526fb1f6a7e4314a96aab3b92e08e44))
* **rithmomachia:** Correct board setup to match reference image exactly ([618e563](https://github.com/antialias/soroban-abacus-flashcards/commit/618e56358deb66cba968472f39b8d4e28b4dd211))
* **rithmomachia:** correct makeMove parameter types for capture handling ([aafb64f](https://github.com/antialias/soroban-abacus-flashcards/commit/aafb64f3e337c6cf925766fe179b91f66c4a040b))
* **rithmomachia:** fix guide modal resize drift by calculating from initial state ([1bcd99c](https://github.com/antialias/soroban-abacus-flashcards/commit/1bcd99c949e4d2b4fb1c0813debd50176fa58cb9))
* **rithmomachia:** fix harmony section translation structure for hi/ja/es ([14259a1](https://github.com/antialias/soroban-abacus-flashcards/commit/14259a19a9817d0947467faa004d5f43118f8d8d))
* **rithmomachia:** fix modal resizing zoom issue ([4fa20f4](https://github.com/antialias/soroban-abacus-flashcards/commit/4fa20f44cb9758f29d1f1512232be0fdc0b53b3d))
* **rithmomachia:** Fix TypeScript errors in playing guide modal ([4834ece](https://github.com/antialias/soroban-abacus-flashcards/commit/4834ece98e86f2fb00511bb876a5c32c289df0e0))
* **rithmomachia:** handle pyramid pieces in hover error tooltip ([56f3164](https://github.com/antialias/soroban-abacus-flashcards/commit/56f3164155beb94ceec2838bed9fc74fd75524db))
* **rithmomachia:** implement proper board cropping and highlighting in guide ([d0a8fcd](https://github.com/antialias/soroban-abacus-flashcards/commit/d0a8fcdea6aa4fdacfee33e183c92923634ee2b7))
* **rithmomachia:** improve guide modal tab navigation at narrow widths ([a673177](https://github.com/antialias/soroban-abacus-flashcards/commit/a673177bec1c709463ce0f266848f473a79f4ef0))
* **rithmomachia:** reconnect player assignment UI and fix setup layout ([a1a0374](https://github.com/antialias/soroban-abacus-flashcards/commit/a1a0374fac5dce676df5890663b75531589ed93a))
* **rithmomachia:** render guide as docked in preview panel ([190f8cf](https://github.com/antialias/soroban-abacus-flashcards/commit/190f8cf302aa966f029d05931811e217c67bfe39))
* **rithmomachia:** show actual values in tooltips for non-helper relations ([774c6b0](https://github.com/antialias/soroban-abacus-flashcards/commit/774c6b0ce712b1a77bb684457da9831e6ec91138))
* **rithmomachia:** show guest-friendly message when they can't fix too many players ([54bfd2f](https://github.com/antialias/soroban-abacus-flashcards/commit/54bfd2fac86be3597d40c67a1235e4c4ed8e2709))
* **rithmomachia:** smooth guide dragging from docked state without jump ([8f4a79c](https://github.com/antialias/soroban-abacus-flashcards/commit/8f4a79c9b0cad55336584fdc8e67409015d3a8ae))
* **rithmomachia:** validate move path before showing capture error on hover ([bd49964](https://github.com/antialias/soroban-abacus-flashcards/commit/bd49964186a0daa1639ae849b128a76081643daf))
* **room-info:** hide Leave Room button when user is alone ([5927f61](https://github.com/antialias/soroban-abacus-flashcards/commit/5927f61c3c34ba583ee45c8cee48a116c1c03071))
* separate horizontal and vertical bounding box logic ([83090df](https://github.com/antialias/soroban-abacus-flashcards/commit/83090df4dfad1d1d5cfa6c278c241526cacc7972))
* tolerate OpenSCAD CGAL warnings if output file is created ([88993f3](https://github.com/antialias/soroban-abacus-flashcards/commit/88993f36629206a7bdcf9aa9d5641f1580b64de5))
* **tutorial:** correct column validation for bead highlights ([9ba1824](https://github.com/antialias/soroban-abacus-flashcards/commit/9ba18242262cd63cc6c25361aaec3a4c0f66b161))
* **tutorial:** fix overlay rendering, arrow indicators, and bead visibility ([a804316](https://github.com/antialias/soroban-abacus-flashcards/commit/a80431608dbc4f54d8e4f1095936b95a258b4a72))
* use absolute positioning for hero abacus to eliminate scroll lag ([096104b](https://github.com/antialias/soroban-abacus-flashcards/commit/096104b094b45aa584f2b9d47a440a8c14d82fc0))
* use Debian base for deps stage to match runner for binary compatibility ([f8fe6e4](https://github.com/antialias/soroban-abacus-flashcards/commit/f8fe6e4a415f8655626af567129d0cda61b82e15))
* use default BOSL2 branch instead of non-existent v2.0.0 tag ([f4ffc5b](https://github.com/antialias/soroban-abacus-flashcards/commit/f4ffc5b0277535358bea7588309a1a4afd1983a1))
* use nested SVG viewBox for actual cropping, not just scaling ([440b492](https://github.com/antialias/soroban-abacus-flashcards/commit/440b492e85beff1612697346b6c5cfc8461e83da))
* various game improvements and UI enhancements ([b67cf61](https://github.com/antialias/soroban-abacus-flashcards/commit/b67cf610c570d54744553cd8f6694243fa50bee1))
* **web,docker:** add --format flag for Typst and upgrade to v0.13.0 ([19b9d7a](https://github.com/antialias/soroban-abacus-flashcards/commit/19b9d7a74f549c7e93c9564e4a903e1bcd5a4bbc))
* **web:** add dynamic export to rithmomachia page ([329e623](https://github.com/antialias/soroban-abacus-flashcards/commit/329e62321245ef62726c986c917f19a909a5b65e))
* **web:** fix Typst PDF generation path resolution ([7ce1287](https://github.com/antialias/soroban-abacus-flashcards/commit/7ce12875254a31d8acdb35ef5de7d36d215ccd92))
* **web:** generate styled-system artifacts during build ([293390a](https://github.com/antialias/soroban-abacus-flashcards/commit/293390ae350a6c6aa467410f68c735512104d9dd))
* **web:** move react-dom/server import to API route to satisfy Next.js ([00a8bc3](https://github.com/antialias/soroban-abacus-flashcards/commit/00a8bc3e5e8f044df280c4356d3605a852f82e84))
* **web:** move tsx to production dependencies for calendar generation ([ffae9c1](https://github.com/antialias/soroban-abacus-flashcards/commit/ffae9c1bdbccc5edb2e747a09d1fcad3b29e4eac))
* **web:** prevent abacus overlap in composite calendar ([448f93c](https://github.com/antialias/soroban-abacus-flashcards/commit/448f93c1e2a7f86bc48e678d4599ca968c6d81d2)), closes [#f0f0f0](https://github.com/antialias/soroban-abacus-flashcards/issues/f0f0f0)
* **web:** use AbacusStatic for calendar SVG generation ([08c6a41](https://github.com/antialias/soroban-abacus-flashcards/commit/08c6a419e25d220560eba13d6db437145e6e61b8))
* **web:** use dynamic import for react-dom/server in API route ([4f93c7d](https://github.com/antialias/soroban-abacus-flashcards/commit/4f93c7d996732de4bc19e7acf2d4ce803cba88b6))
* **web:** use nested SVG elements to prevent coordinate space conflicts ([f9cbee8](https://github.com/antialias/soroban-abacus-flashcards/commit/f9cbee8fcdf80641f3b82a65fad6b8a3575525fc))
### Performance Improvements
* optimize Docker image size to reduce build failures ([9ca3106](https://github.com/antialias/soroban-abacus-flashcards/commit/9ca310636183f4970db925ce8fa368e23645eb02))
### Code Refactoring
* **card-sorting:** remove reveal numbers feature ([ea5e3e8](https://github.com/antialias/soroban-abacus-flashcards/commit/ea5e3e838bd6a5b8b38469a70aa92a0e9baba769))
* **card-sorting:** send complete card sequence instead of individual moves ([e4df843](https://github.com/antialias/soroban-abacus-flashcards/commit/e4df8432b9c4a2055d47833d56b6e9fcf325ca94))
* **games:** implement carousel, fix victories bug, add conditional stats ([82c133f](https://github.com/antialias/soroban-abacus-flashcards/commit/82c133f742f3f5c40b723c18d1997b518f25b320))
* **games:** move page title to nav bar ([712ee58](https://github.com/antialias/soroban-abacus-flashcards/commit/712ee58e5956e5bbdb13d5a5fb367020c87c8c9a))
* **games:** remove redundant subtitle below nav ([ad5bb87](https://github.com/antialias/soroban-abacus-flashcards/commit/ad5bb87325a44825f0cd85b38eb0e5f0eea7a695))
* **games:** remove wheel scrolling, enable overflow visible carousel ([876513c](https://github.com/antialias/soroban-abacus-flashcards/commit/876513c9cc6323c20845ae8f1a3a5478d449f9e4))
* **layout:** make nav height truly self-referential ([9886302](https://github.com/antialias/soroban-abacus-flashcards/commit/98863026b789d09eecb0bc3e013d112889a5d038))
* remove debug console.log statements ([32f51ae](https://github.com/antialias/soroban-abacus-flashcards/commit/32f51ae739679789585182ba659ec5f1168d652d))
* reorganize Harmony and Victory guide sections ([fb629c4](https://github.com/antialias/soroban-abacus-flashcards/commit/fb629c44ea37a7b296561919a4980c10d14efed8))
* restructure /create page into hub with sub-pages ([b91b23d](https://github.com/antialias/soroban-abacus-flashcards/commit/b91b23d95ffaeeaa30dbc8579f4c30bae8829ee7))
* **rithmomachia:** extract board and capture components (phase 2+3) ([a0a867b](https://github.com/antialias/soroban-abacus-flashcards/commit/a0a867b27166a838ca7e0dcbd8f89fe1be812a80))
* **rithmomachia:** extract CaptureErrorDialog component (Phase 2 partial) ([f0a066d](https://github.com/antialias/soroban-abacus-flashcards/commit/f0a066d8f0a51d35e18f87a8436c0d05153c03b5))
* **rithmomachia:** extract constants and coordinate utilities (Phase 1) ([eace0ed](https://github.com/antialias/soroban-abacus-flashcards/commit/eace0ed52979b71870f77ee68f8568558f2aaecb))
* **rithmomachia:** extract guide sections into separate files ([765525d](https://github.com/antialias/soroban-abacus-flashcards/commit/765525dc451897f561f017e444aae892dc27177f))
* **rithmomachia:** extract hooks (phase 5) ([324a659](https://github.com/antialias/soroban-abacus-flashcards/commit/324a65992f97c295ea3968aaf54d266373f4c035))
* **rithmomachia:** extract phase components (phase 4) ([11364f6](https://github.com/antialias/soroban-abacus-flashcards/commit/11364f6394c15e49850e5cad2cbd32e1ea08a178))
* **rithmomachia:** extract reusable components from SetupPhase ([3abc325](https://github.com/antialias/soroban-abacus-flashcards/commit/3abc325ea27feee5c4cc59f02296ff218f342a81))
* **rithmomachia:** make setup phase UI more compact ([e55f848](https://github.com/antialias/soroban-abacus-flashcards/commit/e55f848a26092a2b4a5b09c3c255544ea9666f1b))
* **rithmomachia:** redesign error notification with modern UI ([dfeeb0e](https://github.com/antialias/soroban-abacus-flashcards/commit/dfeeb0e0db8b2c4a38198cf71cd918439d6c211b)), closes [#1e293](https://github.com/antialias/soroban-abacus-flashcards/issues/1e293) [#0f172](https://github.com/antialias/soroban-abacus-flashcards/issues/0f172) [#f1f5f9](https://github.com/antialias/soroban-abacus-flashcards/issues/f1f5f9)
* **rithmomachia:** simplify capture error dialog to one-liner ([82a5eb2](https://github.com/antialias/soroban-abacus-flashcards/commit/82a5eb2e4bf74f42a183a15f1129e5ec84cc5231))
* **rithmomachia:** Update board setup to authoritative CSV layout ([0471da5](https://github.com/antialias/soroban-abacus-flashcards/commit/0471da598d8d591b3f9d63f467cb35f999924c13))
* **rithmomachia:** update capture components to use CaptureContext ([2ab6ab5](https://github.com/antialias/soroban-abacus-flashcards/commit/2ab6ab57995a6d7d9c66b9fba8de945507209661))
* **rithmomachia:** use useBoardLayout and usePieceSelection in BoardDisplay ([0ab7a1d](https://github.com/antialias/soroban-abacus-flashcards/commit/0ab7a1df327d7258228af9851762555583a20d61))
* use AbacusReact for dynamic Open Graph image ([9c20f12](https://github.com/antialias/soroban-abacus-flashcards/commit/9c20f12bacff4fe7f8bd7a87032afbed9711e94b))
* **web:** import utility functions from abacus-react ([7228bbc](https://github.com/antialias/soroban-abacus-flashcards/commit/7228bbc2eb8b9b2b861d32b760b14895a1a7ee8a))
* **web:** move calendar generators to src/utils for proper compilation ([379698f](https://github.com/antialias/soroban-abacus-flashcards/commit/379698fea3fc8f04d716d35347749182d5c53b5c))
* **web:** return calendar SVG preview with PDF generation ([14a5de0](https://github.com/antialias/soroban-abacus-flashcards/commit/14a5de0dfadf423c646f4748b0de94f2483b18a1))
* **web:** use ABACUS_THEMES instead of manual style definitions ([9f7f001](https://github.com/antialias/soroban-abacus-flashcards/commit/9f7f001d747402b1578116e45c1a137519714314))
* **web:** use client-side React rendering for live calendar preview ([f880cbe](https://github.com/antialias/soroban-abacus-flashcards/commit/f880cbe4bffc898ae95d36d68615cf317d94012a))
* **web:** use compact prop for inline mini-abacus ([ff1d60a](https://github.com/antialias/soroban-abacus-flashcards/commit/ff1d60a23387d22e7ed44185dc3a8c895b7c0d12))
* **web:** use direct function imports instead of execSync for calendar generation ([9f1715f](https://github.com/antialias/soroban-abacus-flashcards/commit/9f1715f0856bcd125a79014c0c8c854c1c7b3f4d))
* **web:** use stdin/stdout for Typst compilation ([06f68cc](https://github.com/antialias/soroban-abacus-flashcards/commit/06f68cc74c31b54284808beadf67f4db08d03420))
### Documentation
* **abacus-react:** add Storybook stories for AbacusStatic ([4f9dc46](https://github.com/antialias/soroban-abacus-flashcards/commit/4f9dc4666d249c1c67c51a3901c4f657ff9723ef))
* **abacus-react:** add Storybook stories for new features ([6a1cec0](https://github.com/antialias/soroban-abacus-flashcards/commit/6a1cec06a75575cb35ddca5ef573aaf13c2352f4))
* **abacus-react:** export AbacusStatic and update README ([74f2d97](https://github.com/antialias/soroban-abacus-flashcards/commit/74f2d97434620cb8c7d49912bca3bf386408a16d))
* **abacus-react:** update documentation for new features ([35d8734](https://github.com/antialias/soroban-abacus-flashcards/commit/35d8734a3a9124564957444d3642c9e7c4348fac))
* **abacus-react:** update README with /static import path for RSC ([72a4c2b](https://github.com/antialias/soroban-abacus-flashcards/commit/72a4c2b80c1158a6eaf21abe4e807ff6e70373ac))
* add 3D enhancement documentation to README ([cc96802](https://github.com/antialias/soroban-abacus-flashcards/commit/cc96802df87c805c946ee59af509663ba570e75b))
* add critical section on never adding tsx to production dependencies ([770cfc3](https://github.com/antialias/soroban-abacus-flashcards/commit/770cfc3aca296b4f52c822710a1072fe501a0f49))
* add database migration guide and playing guide modal spec ([5a29af7](https://github.com/antialias/soroban-abacus-flashcards/commit/5a29af78e27e897ab35273611b79c4b669304f71))
* add deployment verification guidelines to prevent false positives ([3d8da23](https://github.com/antialias/soroban-abacus-flashcards/commit/3d8da2348b4e8a227e963791d15dc6718eac5af1))
* **card-sorting:** add comprehensive multiplayer plan ([008ccea](https://github.com/antialias/soroban-abacus-flashcards/commit/008ccead0f9c634fe52fd156e6f9a04d6cdd7744))
* clarify dev server management in Claude Code instructions ([e08fdfd](https://github.com/antialias/soroban-abacus-flashcards/commit/e08fdfd676b51a9fed23bda336b13f5e1d40b96c))
* **rithmomachia:** Add concise one-page playing guide ([e3c1f10](https://github.com/antialias/soroban-abacus-flashcards/commit/e3c1f10233cc0924ff96a643c7c4c1f1278de3e3))
* update workflow to require manual testing before commits ([0991796](https://github.com/antialias/soroban-abacus-flashcards/commit/0991796f1eccef345f10205e675e4c33d1a62b17))
### Styles
* **rithmomachia:** improve divider styling and make tabs responsive ([88ca35e](https://github.com/antialias/soroban-abacus-flashcards/commit/88ca35e0440157ff9349e8d3d2d3cc844f18ffea)), closes [#e5e7](https://github.com/antialias/soroban-abacus-flashcards/issues/e5e7) [#9ca3](https://github.com/antialias/soroban-abacus-flashcards/issues/9ca3)
* **rithmomachia:** improve pyramid face numbers visibility and contrast ([94e5e6a](https://github.com/antialias/soroban-abacus-flashcards/commit/94e5e6a268b387380b88b192737bd55578b98bc7)), closes [#fbbf24](https://github.com/antialias/soroban-abacus-flashcards/issues/fbbf24) [#b45309](https://github.com/antialias/soroban-abacus-flashcards/issues/b45309)
* **rithmomachia:** increase pyramid face numbers size and boldness ([7bf2d73](https://github.com/antialias/soroban-abacus-flashcards/commit/7bf2d730d370e562486b229f4d209099ff8c4463))
### Tests
* trigger compose-updater deployment test ([2b06aae](https://github.com/antialias/soroban-abacus-flashcards/commit/2b06aae39474cc80d501c47c9685fa99e7120c48))
* verify compose-updater automatic deployment cycle ([af0552c](https://github.com/antialias/soroban-abacus-flashcards/commit/af0552ccd98f7b5a62d6e4074b7d87b3716af698))
## [4.68.0](https://github.com/antialias/soroban-abacus-flashcards/compare/v4.67.1...v4.68.0) (2025-11-05)
### Features
* **3d-abacus:** change default columns from 13 to 4 ([cd15c70](https://github.com/antialias/soroban-abacus-flashcards/commit/cd15c70a25c597c17ee5d2f816b1c85ba8ce4ce9))
* **abacus-react:** add AbacusStatic for React Server Components ([3b8e864](https://github.com/antialias/soroban-abacus-flashcards/commit/3b8e864cfa3af50b1912ce7ff55003d7f6b9c229))
* **abacus-react:** add core utility functions for state management ([e65541c](https://github.com/antialias/soroban-abacus-flashcards/commit/e65541c100e590a51448750c6d5178ed4f3e8eeb))
* **abacus-react:** add layout and educational props ([35bbcec](https://github.com/antialias/soroban-abacus-flashcards/commit/35bbcecb9e36f1ef5917a5a629f5e78f1f490e9c))
* **abacus-react:** add pre-defined theme presets ([cf1f950](https://github.com/antialias/soroban-abacus-flashcards/commit/cf1f950c7c5fb9ee1f0de673235d6f037be3b9d6))
* **abacus-react:** add React hooks for abacus calculations ([de038d2](https://github.com/antialias/soroban-abacus-flashcards/commit/de038d2afc26c36c1490d5ea45dace0ab812c5cc))
* **abacus-react:** add separate /static export path for React Server Components ([ed69f6b](https://github.com/antialias/soroban-abacus-flashcards/commit/ed69f6b917c543bbcaa4621a0e63745bee70f5bf))
* **abacus-react:** add shared dimension calculator for consistent sizing ([e5ba772](https://github.com/antialias/soroban-abacus-flashcards/commit/e5ba772fde9839c22daec92007f052ca125c7695))
* **abacus-react:** export new utilities, hooks, and themes ([ce4e44d](https://github.com/antialias/soroban-abacus-flashcards/commit/ce4e44d6302746053ad40dc61bab57ef3a0a9f31))
* **abacus:** add nativeAbacusNumbers setting to schema and UI ([79f7347](https://github.com/antialias/soroban-abacus-flashcards/commit/79f7347d4800646378470a7f9aca8e7f2fd5573c))
* add 3D printing support for abacus models ([dafdfdd](https://github.com/antialias/soroban-abacus-flashcards/commit/dafdfdd233b53464b9825a8a9b5f2e6206fc54cb))
* add client-side OpenSCAD WASM support for 3D preview ([eaaf17c](https://github.com/antialias/soroban-abacus-flashcards/commit/eaaf17cd4c675bfd40e0573b9c99f0c733d926aa))
* add comprehensive metadata, SEO, and make AbacusReact SSR-compatible ([0922ea1](https://github.com/antialias/soroban-abacus-flashcards/commit/0922ea10b77e7d16b8c414c596d23cb11e20c1cc))
* add comprehensive Storybook coverage and migration guide ([7a4a37e](https://github.com/antialias/soroban-abacus-flashcards/commit/7a4a37ec6d0171782778e18122da782f069e0556))
* add game preview system with mock arcade environment ([25880cc](https://github.com/antialias/soroban-abacus-flashcards/commit/25880cc7e463f98a5a23c812c1ffd43734d3fe1f))
* add per-player stats tracking system ([613301c](https://github.com/antialias/soroban-abacus-flashcards/commit/613301cd137ad6f712571a0be45c708ce391fc8f))
* add Strategy & Tactics section to Rithmomachia guide ([81ead65](https://github.com/antialias/soroban-abacus-flashcards/commit/81ead65680892efa4d0ab07e7f0ef77eb1bc1405))
* add unified trophy abacus with hero mode integration ([6620418](https://github.com/antialias/soroban-abacus-flashcards/commit/6620418a704dcca810b511a5f394084521104e6b))
* **arcade:** add ability to deactivate remote players without kicking user ([3628426](https://github.com/antialias/soroban-abacus-flashcards/commit/3628426a567d7e0273be75cce64632ae04b7d5eb))
* **arcade:** add native abacus numbers support to pressure gauge ([1d525c7](https://github.com/antialias/soroban-abacus-flashcards/commit/1d525c7b5320984a1582b8ab7eae57895c728428))
* **arcade:** add Rithmomachia (Battle of Numbers) game ([2fc0a05](https://github.com/antialias/soroban-abacus-flashcards/commit/2fc0a05f7f557cee55f7d31b585499dd04e68ff9))
* **arcade:** add yjs-demo collaborative game and Yjs persistence layer ([d568955](https://github.com/antialias/soroban-abacus-flashcards/commit/d568955d6abf389e6ab7c6979e33122a65917a46))
* **arcade:** auto-create room when user has none ([ff88c3a](https://github.com/antialias/soroban-abacus-flashcards/commit/ff88c3a1b81703a87a1d57eeb5cc139da7d9df04))
* **calendar:** add beautiful daily calendar with locale-based paper size detection ([bdca315](https://github.com/antialias/soroban-abacus-flashcards/commit/bdca3154f8336e17a7031be8d2917f9cf05f274a))
* **card-sorting:** add activity feed notifications for collaborative mode ([1461414](https://github.com/antialias/soroban-abacus-flashcards/commit/1461414ef4d0b213af241213447c91eed1abe5fb))
* **card-sorting:** add auto-submit countdown for perfect sequences ([780a716](https://github.com/antialias/soroban-abacus-flashcards/commit/780a7161bc05c2ca6597d7d8d89f01afd33d9f4d))
* **card-sorting:** add bezier curves to connecting arrows ([4d8e873](https://github.com/antialias/soroban-abacus-flashcards/commit/4d8e873358271fe3fd50b228aea8277e20aa5966))
* **card-sorting:** add CardPosition type and position syncing ([656f5a7](https://github.com/antialias/soroban-abacus-flashcards/commit/656f5a7838ed6003c214ec484d4c37072270fa8d))
* **card-sorting:** add collapsible stats sidebar for spectators ([6527c26](https://github.com/antialias/soroban-abacus-flashcards/commit/6527c26a8166b23f074e85eb335a15800c1947a2))
* **card-sorting:** add game mode selector UI to setup phase ([d25b888](https://github.com/antialias/soroban-abacus-flashcards/commit/d25b888ffb3915d2d482442ab708ba3e159af512))
* **card-sorting:** add GameMode type system for multiplayer support ([fd76533](https://github.com/antialias/soroban-abacus-flashcards/commit/fd765335efbc91366c596c7789b92882cd3379d9))
* **card-sorting:** add green border to correctly positioned cards ([16fca86](https://github.com/antialias/soroban-abacus-flashcards/commit/16fca86b7687115f1cf565c533a512e92946e3a8)), closes [#22c55](https://github.com/antialias/soroban-abacus-flashcards/issues/22c55)
* **card-sorting:** add player emoji indicators on moving cards ([3a82099](https://github.com/antialias/soroban-abacus-flashcards/commit/3a8209975728cdcf914c43ba08339454a9e2457f))
* **card-sorting:** add react-spring animations for real-time sync ([c367e0c](https://github.com/antialias/soroban-abacus-flashcards/commit/c367e0ceece41d8e7c2bc8aebe3239ff6053a115))
* **card-sorting:** add smooth transition to drop shadow ([b0b93d0](https://github.com/antialias/soroban-abacus-flashcards/commit/b0b93d0175c8a1c8958d6ba346d969c234fdd6ff))
* **card-sorting:** add spectator mode UI enhancements ([ee7345d](https://github.com/antialias/soroban-abacus-flashcards/commit/ee7345d641e0ee72915afb9cdbd6d284b7e238bd)), closes [#6366f1](https://github.com/antialias/soroban-abacus-flashcards/issues/6366f1) [#8b5cf6](https://github.com/antialias/soroban-abacus-flashcards/issues/8b5cf6)
* **card-sorting:** add team scoring UI for collaborative mode ([ed6f177](https://github.com/antialias/soroban-abacus-flashcards/commit/ed6f1779141d0bc9dff2d532a3dfc638015936b5)), closes [#a78](https://github.com/antialias/soroban-abacus-flashcards/issues/a78) [#8b5cf6](https://github.com/antialias/soroban-abacus-flashcards/issues/8b5cf6)
* **card-sorting:** add updateCardPositions action to Provider ([f6ed4a2](https://github.com/antialias/soroban-abacus-flashcards/commit/f6ed4a27a26d8bfa495ba5f580a446286b9674a0))
* **card-sorting:** auto-arrange prefix/suffix cards in corners ([4ba7f24](https://github.com/antialias/soroban-abacus-flashcards/commit/4ba7f247175d93e4d339e2be7bbdb2e009992232))
* **card-sorting:** fade correctly positioned cards to 50% opacity ([7028cfc](https://github.com/antialias/soroban-abacus-flashcards/commit/7028cfc51164e9219479e6040b03c29239aa7edb))
* **card-sorting:** gentler spring animation for locked cards ([47189cb](https://github.com/antialias/soroban-abacus-flashcards/commit/47189cb6e79ed2915f5ddcc9cb3626540dfb07f3))
* **card-sorting:** implement continuous bezier curve paths ([2d93024](https://github.com/antialias/soroban-abacus-flashcards/commit/2d9302410f5e98145a435b00df3ae5fcf3f4c0b5))
* **card-sorting:** improve card distribution for natural scattered look ([0b0503f](https://github.com/antialias/soroban-abacus-flashcards/commit/0b0503f0354a4a82fe6b9bfe827729e8e5a9e329))
* **card-sorting:** make player emoji fill entire card background ([2e7a02c](https://github.com/antialias/soroban-abacus-flashcards/commit/2e7a02c9e4ab84e821d58661d6e7a326f7882afb))
* **card-sorting:** optimize results screen for mobile ([d188789](https://github.com/antialias/soroban-abacus-flashcards/commit/d188789069b4c350ce3cc0d221bd4a43dab528e0))
* **card-sorting:** redesign setup screen with modern UI ([73cf967](https://github.com/antialias/soroban-abacus-flashcards/commit/73cf96749234c480482f62392245b38c1fd5f0a0))
* **card-sorting:** scale correctly positioned cards to 50% ([222dc55](https://github.com/antialias/soroban-abacus-flashcards/commit/222dc555fa5068e2594dcc074e33f70320f5742c))
* **card-sorting:** shrink/fade cards in correct suffix as well ([8f6feec](https://github.com/antialias/soroban-abacus-flashcards/commit/8f6feec4f21d0af0d1c98daf5017eddd91d3d578))
* **card-sorting:** smooth spring transition from game table to results grid ([c5f39d5](https://github.com/antialias/soroban-abacus-flashcards/commit/c5f39d51eb45ec816f32151dc7f9d7c06360474b))
* **card-sorting:** wrap prefix/suffix cards to multiple rows ([e3184dd](https://github.com/antialias/soroban-abacus-flashcards/commit/e3184dd0d444e5dc204731f5b396d5c553cf7d11))
* complete 3D enhancement integration for all three proposals ([5ac55cc](https://github.com/antialias/soroban-abacus-flashcards/commit/5ac55cc14980b778f9be32f0833f8760aa16b631))
* **create-room:** replace hardcoded game grid with dynamic Radix Select dropdown ([83d0ba2](https://github.com/antialias/soroban-abacus-flashcards/commit/83d0ba26f5eeec3e189d279710d5bbcf13e82f29))
* dynamic day-of-month favicon using subprocess pattern ([4d0795a](https://github.com/antialias/soroban-abacus-flashcards/commit/4d0795a9df74fcb085af821eafb923bdcb5f0b0c))
* dynamically crop favicon to active beads for maximum size ([5670322](https://github.com/antialias/soroban-abacus-flashcards/commit/567032296aecaad13408bdc17d108ec7c57fb4a8))
* enable 3D enhancement on hero/open MyAbacus modes ([37e330f](https://github.com/antialias/soroban-abacus-flashcards/commit/37e330f26e5398c2358599361cd417b4aeefac7d))
* **games:** add autoplay and improve carousel layout ([9f51edf](https://github.com/antialias/soroban-abacus-flashcards/commit/9f51edfaa95c14f55a30a6eceafb9099eeed437f))
* **games:** add horizontal scroll support to carousels ([a224abb](https://github.com/antialias/soroban-abacus-flashcards/commit/a224abb6f660e1aa31ab04f5590b003fae072af9))
* **games:** add rotating games hero carousel ([24231e6](https://github.com/antialias/soroban-abacus-flashcards/commit/24231e6b2ebbdcae066344df54e7e80e7d221128))
* **i18n:** add dynamic locale switching without page reload ([fe9bfea](https://github.com/antialias/soroban-abacus-flashcards/commit/fe9bfeabf9ee66923501b18e1b69f2d666d0817d))
* **i18n:** add global language selector to navigation ([0506360](https://github.com/antialias/soroban-abacus-flashcards/commit/0506360117807665e8f5a6fcd8f1178339f6e65c))
* **i18n:** add homepage translations for all supported languages ([8c9d35a](https://github.com/antialias/soroban-abacus-flashcards/commit/8c9d35a3b43dd29664f5afb1bd96c4e584d9ec75))
* **i18n:** add Old High German (goh) language support ([b334a15](https://github.com/antialias/soroban-abacus-flashcards/commit/b334a15255ed9fa29beb43de66da0288691390c6))
* **i18n:** complete Old High German translations for all locales ([0b06a1c](https://github.com/antialias/soroban-abacus-flashcards/commit/0b06a1ce005d92e7ae9c225aba40d240e965753d))
* **i18n:** internationalize games page and tutorial content ([4253964](https://github.com/antialias/soroban-abacus-flashcards/commit/4253964af19f9aaa16f2394f41819223542fb519))
* **i18n:** internationalize homepage with English translations ([40cff14](https://github.com/antialias/soroban-abacus-flashcards/commit/40cff143c72e9228d7cce607cab64c4a6d067017))
* **i18n:** migrate from react-i18next to next-intl ([9016b76](https://github.com/antialias/soroban-abacus-flashcards/commit/9016b760247a20271255839e4dd7e5b9a8353b9f))
* **i18n:** update games page hero section copy ([6333c60](https://github.com/antialias/soroban-abacus-flashcards/commit/6333c60352b920916afd81cc3b0229706a1519fa))
* install embla-carousel-autoplay for games carousel ([946e5d1](https://github.com/antialias/soroban-abacus-flashcards/commit/946e5d19107020992be8945f8fe7c41e4bc2a0e2))
* install embla-carousel-react for player profile carousel ([642ae95](https://github.com/antialias/soroban-abacus-flashcards/commit/642ae957383cfe1d6045f645bbe426fd80c56f35))
* internationalize guide page with 6 languages ([e9c320b](https://github.com/antialias/soroban-abacus-flashcards/commit/e9c320bb1032e94c3852b9459236409da4669c09))
* internationalize tutorial player ([26d41cf](https://github.com/antialias/soroban-abacus-flashcards/commit/26d41cfd058bfdf5b61ee6e20cfc61cbecb32f45))
* optimize card sorting for mobile displays ([b443ee9](https://github.com/antialias/soroban-abacus-flashcards/commit/b443ee9cdcd9fcb7674845d8c92f7c338ad98dea))
* Redesign Rithmomachia setup page with dramatic medieval theme ([6ae4d13](https://github.com/antialias/soroban-abacus-flashcards/commit/6ae4d13dc784a87f85206c6ff6d005e5b23b678c))
* **rithmomachia:** add 80% opacity to guide modal when not hovered ([4a78485](https://github.com/antialias/soroban-abacus-flashcards/commit/4a78485d2e20f2cbf36cc898a1beafa8eb48bfbf))
* **rithmomachia:** add CaptureContext for capture dialog state management ([d7eb957](https://github.com/antialias/soroban-abacus-flashcards/commit/d7eb957a8dabbcac35e166a83dd679a628e19baa))
* **rithmomachia:** add ghost panel preview for guide docking ([c0d6526](https://github.com/antialias/soroban-abacus-flashcards/commit/c0d6526d30aca8deaeda2b7c2e27eb37af8b577c))
* **rithmomachia:** add guide docking with resizable panels ([f457f1a](https://github.com/antialias/soroban-abacus-flashcards/commit/f457f1a1c22b6cb7fff23a7701474322cf423dd9))
* **rithmomachia:** add helper piece selection for mathematical captures ([cae3359](https://github.com/antialias/soroban-abacus-flashcards/commit/cae335958751c27684bfb10c8e2e526b460954ed))
* **rithmomachia:** add helpful error messages for failed captures ([b172440](https://github.com/antialias/soroban-abacus-flashcards/commit/b172440a41e958ced98903bb8f4c2e4b423e1356))
* **rithmomachia:** add initial board visual to guide Overview section ([d42bcff](https://github.com/antialias/soroban-abacus-flashcards/commit/d42bcff0d922895549c1c12f8e02a3ae6d53425a))
* **rithmomachia:** Add interactive playing guide modal ([3121d82](https://github.com/antialias/soroban-abacus-flashcards/commit/3121d8240a567817f5f205a4ef4a788fcf451f71))
* **rithmomachia:** add number bond visualization and helper placeholders ([82d8913](https://github.com/antialias/soroban-abacus-flashcards/commit/82d89131f00517f162ec496397cb390f9ecfc52e))
* **rithmomachia:** add ratio capture example to guide ([9150b0c](https://github.com/antialias/soroban-abacus-flashcards/commit/9150b0c678ce7104fe984ee0fc93748b43a245f4))
* **rithmomachia:** add standalone guide page route ([3fcc79f](https://github.com/antialias/soroban-abacus-flashcards/commit/3fcc79fe9eae11d4bd3a724c1b1f7d086e7cae81))
* **rithmomachia:** add useBoardLayout hook for centralized layout calculations ([27f1c98](https://github.com/antialias/soroban-abacus-flashcards/commit/27f1c989d59a19844b90a5148ae27fb97161da2d))
* **rithmomachia:** add usePieceSelection hook for selection state management ([275f401](https://github.com/antialias/soroban-abacus-flashcards/commit/275f401e3c25b75fec4700a8c2d4be6e33f0afe9))
* **rithmomachia:** add visual board examples to Capture section ([74bc3c0](https://github.com/antialias/soroban-abacus-flashcards/commit/74bc3c0dcf8d1ee7084e88a04861a85f9b623809))
* **rithmomachia:** add visual board examples to Harmony section ([1d5f01c](https://github.com/antialias/soroban-abacus-flashcards/commit/1d5f01c966cf1eec9a9c19ee37f1cad93c89df40))
* **rithmomachia:** add visual winning example to Victory section ([b7fac78](https://github.com/antialias/soroban-abacus-flashcards/commit/b7fac788292e00c6060a47fdbcca89a7e7fee35c))
* **rithmomachia:** auto-size tab labels with react-textfit ([9fd5406](https://github.com/antialias/soroban-abacus-flashcards/commit/9fd54067ce257e028b02f4784568ff3f2bbb32ca))
* **rithmomachia:** cycle through valid helpers with dynamic number tooltips ([4829e41](https://github.com/antialias/soroban-abacus-flashcards/commit/4829e41ea13fae2edec10837e65e505929445782))
* **rithmomachia:** enhance capture relation UI with smooth animations ([0a30801](https://github.com/antialias/soroban-abacus-flashcards/commit/0a308016e9d6a926c52dbfc5623b60b169d16d03))
* **rithmomachia:** enhance Harmony section with comprehensive content ([f555856](https://github.com/antialias/soroban-abacus-flashcards/commit/f5558563ea93ef7428aa220c2e15e3f02711420f))
* **rithmomachia:** enhance Pieces section with visual examples and pyramid details ([55aff82](https://github.com/antialias/soroban-abacus-flashcards/commit/55aff829f4c284e8cfe6d471c0821575928b93bc))
* **rithmomachia:** enhance Pyramid section with comprehensive details ([9fde1ef](https://github.com/antialias/soroban-abacus-flashcards/commit/9fde1ef9e703e26b2450128155b53fdf2d2e1fe5))
* **rithmomachia:** guide defaults to docked right on open ([11f674d](https://github.com/antialias/soroban-abacus-flashcards/commit/11f674d542ea5e4e88bd60ff1068451805d9766e))
* **rithmomachia:** improve guide pieces section layout ([a270bfc](https://github.com/antialias/soroban-abacus-flashcards/commit/a270bfc0cc4a3b6b54ba43a5af14a227cc7d29f9))
* **rithmomachia:** improve guide UX and add persistence ([b314740](https://github.com/antialias/soroban-abacus-flashcards/commit/b31474069734350a7059cd7c73255a7e11b78eb9))
* **rithmomachia:** improve roster status notice UX ([e27df45](https://github.com/antialias/soroban-abacus-flashcards/commit/e27df45256147f958ca215f9dd1f4e133e8cf06c))
* **rithmomachia:** integrate roster warning into game nav ([8a11594](https://github.com/antialias/soroban-abacus-flashcards/commit/8a11594203fb91faee6cbc4cb74367164ecd6d85))
* **rithmomachia:** make guide modal ultra-responsive down to 150px width ([0474197](https://github.com/antialias/soroban-abacus-flashcards/commit/04741971b296976f4476ecd949e84066fc549010))
* **rithmomachia:** recreate original guide modal header layout ([2489695](https://github.com/antialias/soroban-abacus-flashcards/commit/24896957d0817758c5f64c0e3473e6a0a343af67))
* **rithmomachia:** show capture error on hover instead of click ([339b678](https://github.com/antialias/soroban-abacus-flashcards/commit/339b6780f657ace5bfe1611c4ef64bb0c2c31587))
* **rithmomachia:** show pyramid face numbers on hover instead of selection ([b0c4523](https://github.com/antialias/soroban-abacus-flashcards/commit/b0c4523c0b4669c96a50b2812ba6cb2faa3f9a22))
* **rithmomachia:** show pyramid face numbers when selected ([5c186f3](https://github.com/antialias/soroban-abacus-flashcards/commit/5c186f3947cc38f1f5db5de3e68e590b90c2d092))
* **rithmomachia:** show pyramid face numbers when selected with subtle animation ([5c2ddbe](https://github.com/antialias/soroban-abacus-flashcards/commit/5c2ddbef05d7f4195d21b084cb1c0c4193ee3c9c))
* **rithmomachia:** show real preview layout when dragging guide to dock ([17d2460](https://github.com/antialias/soroban-abacus-flashcards/commit/17d2460a8769a21d33fabc5f909cf5b939712d36))
* **rithmomachia:** simplify guide language for clarity ([85cb630](https://github.com/antialias/soroban-abacus-flashcards/commit/85cb630add395a6693ecbbe9c8fc6aaf8c47be29))
* **rithmomachia:** skip helper selection UI and auto-select first valid helper ([be2a00e](https://github.com/antialias/soroban-abacus-flashcards/commit/be2a00e8b366b5606525309b4c7813f5c35c7f7c))
* **rithmomachia:** Update harmony system to classical three-piece proportions ([08c9762](https://github.com/antialias/soroban-abacus-flashcards/commit/08c97620f5e694b8526c448c44d265e6dd1fe1eb))
* **rithmomachia:** Update to traditional board setup with 25 pieces per side ([0769eaa](https://github.com/antialias/soroban-abacus-flashcards/commit/0769eaaa1dc238b901e3a7cfe0486e6122d5eda9))
* **rithmomachia:** use actual piece SVGs in number bond with 2.5s rotation animation ([976a7de](https://github.com/antialias/soroban-abacus-flashcards/commit/976a7de949c22842f4b6da3ced990f502a1c2733))
* **room-share:** add QR code button for easy mobile joining ([349290a](https://github.com/antialias/soroban-abacus-flashcards/commit/349290ac6a411651686b64d2e6b540083d2df1d9))
* show rithmomachia turn in nav ([7c89bfe](https://github.com/antialias/soroban-abacus-flashcards/commit/7c89bfef9c60db0e2c46e920500dcc1fbe90d3df))
* switch to royal color theme with transparent background ([944ad65](https://github.com/antialias/soroban-abacus-flashcards/commit/944ad6574e01a67ce1fdbb1f2452fe632c78ce43)), closes [#fbbf24](https://github.com/antialias/soroban-abacus-flashcards/issues/fbbf24) [#f59e0](https://github.com/antialias/soroban-abacus-flashcards/issues/f59e0) [#a855f7](https://github.com/antialias/soroban-abacus-flashcards/issues/a855f7) [#7e22](https://github.com/antialias/soroban-abacus-flashcards/issues/7e22)
* **web:** add test page for AbacusStatic RSC compatibility ([903dea2](https://github.com/antialias/soroban-abacus-flashcards/commit/903dea25844f1d2b3730fbcbd8478e7af1887663))
* **web:** add test page for AbacusStatic Server Component ([3588d5a](https://github.com/antialias/soroban-abacus-flashcards/commit/3588d5acde25588ce4db3ee32adb04ace0e394d4))
* **web:** add Typst-based preview endpoint with React Suspense ([599a758](https://github.com/antialias/soroban-abacus-flashcards/commit/599a758471c43ab0fc87301c5e7eeceed608062e))
* **web:** add year abacus to calendar header and make grid bolder ([867c7ee](https://github.com/antialias/soroban-abacus-flashcards/commit/867c7ee17251b8df13665bee9c0391961975e681)), closes [#333](https://github.com/antialias/soroban-abacus-flashcards/issues/333)
* **web:** improve calendar abacus preview styling ([8439727](https://github.com/antialias/soroban-abacus-flashcards/commit/8439727b152accf61f0c28158b92788510ca086e))
* **web:** optimize monthly calendar for single-page layout ([b277a89](https://github.com/antialias/soroban-abacus-flashcards/commit/b277a89415d1823455376c3e0f641b52f3394e7c))
* **web:** redesign monthly calendar as single composite SVG ([8ce8038](https://github.com/antialias/soroban-abacus-flashcards/commit/8ce8038baeea0b8b0fffe3215746958731bd9d6a))
### Bug Fixes
* **abacus-react:** add data-testid attributes back to beads for testing ([23ae1b0](https://github.com/antialias/soroban-abacus-flashcards/commit/23ae1b0c6f878daf79a993992d43ad80a89fa790))
* **abacus-react:** correct column highlighting offset in AbacusStatic ([0641eb7](https://github.com/antialias/soroban-abacus-flashcards/commit/0641eb719ef56c67de965296006df666f83e5b08))
* **abacus-react:** fix animations by preventing component remounting ([be7d4c4](https://github.com/antialias/soroban-abacus-flashcards/commit/be7d4c471327534a95c4c75372680c629b5f12c2))
* **abacus-react:** restore original AbacusReact measurements and positioning ([88c0baa](https://github.com/antialias/soroban-abacus-flashcards/commit/88c0baaad9b83b60ab8cdcad92070cc049d61cc7))
* add xmlns to AbacusStatic for Typst SVG parsing ([98cd019](https://github.com/antialias/soroban-abacus-flashcards/commit/98cd019d4af91d7ca4e7a88f700194273476afb7))
* adjust hero abacus position to avoid covering subtitle ([f03d341](https://github.com/antialias/soroban-abacus-flashcards/commit/f03d3413145cc7ddfba93728ecdec7eabea9ada6))
* **arcade:** add automatic retry for version conflict rejections ([fbcde25](https://github.com/antialias/soroban-abacus-flashcards/commit/fbcde2505f7ff2bf3426f3458e480c4548314ba4))
* **arcade:** allow deactivating players from users who left the room ([7c1c2d7](https://github.com/antialias/soroban-abacus-flashcards/commit/7c1c2d7bebbb9a1acb274d17dd43b6ee5d196f44))
* **arcade:** implement optimistic locking in session manager ([71fd66d](https://github.com/antialias/soroban-abacus-flashcards/commit/71fd66d96a3b03650c90f59f6e516aae7dddc345))
* board rotation now properly fills height in portrait mode ([b5a96ea](https://github.com/antialias/soroban-abacus-flashcards/commit/b5a96eaeb1e29c20304142a7a0adf62f1cef570f))
* **card-sorting:** add border radius to outer card container ([a922eba](https://github.com/antialias/soroban-abacus-flashcards/commit/a922eba73c4656ee941ce4dfb1dc57a62f076570))
* **card-sorting:** add debug logging for spring animations ([d42947e](https://github.com/antialias/soroban-abacus-flashcards/commit/d42947eb8d5d3d8298f5d3b3d1644891c268dbb6))
* **card-sorting:** add missing gameMode support after hard reset ([a832325](https://github.com/antialias/soroban-abacus-flashcards/commit/a832325debde289d6928c5e6f9c24311c5e079ad))
* **card-sorting:** add missing useMemo import ([949d76d](https://github.com/antialias/soroban-abacus-flashcards/commit/949d76d844c786ada8a6373e4abb7f498f6befb9))
* **card-sorting:** add overflow hidden to clip rounded corners ([84c66fe](https://github.com/antialias/soroban-abacus-flashcards/commit/84c66feec6b4112b015e1afd95bf33b24b5f6a4f))
* **card-sorting:** adjust connecting paths for scaled cards ([829c741](https://github.com/antialias/soroban-abacus-flashcards/commit/829c741e554d1490dd7a5bbc17f2a32f7195dc07))
* **card-sorting:** adjust game board for spectator panels ([fc5cf12](https://github.com/antialias/soroban-abacus-flashcards/commit/fc5cf1216fe03edfb7e44afda01192f4b97b4f4e))
* **card-sorting:** adjust viewport dimensions for spectator panels ([4dce16c](https://github.com/antialias/soroban-abacus-flashcards/commit/4dce16cca46c965199b7e09f8b34bfa221efac33))
* **card-sorting:** animate cards from game board to results grid ([17d45fe](https://github.com/antialias/soroban-abacus-flashcards/commit/17d45fe88cd9773f5e550f6ee5a7f0c82cca2023))
* **card-sorting:** correct suffix card detection in auto-arrange ([d02ab59](https://github.com/antialias/soroban-abacus-flashcards/commit/d02ab5922c416042d525f54097a6975ae1541586))
* **card-sorting:** enable card scaling for spectators ([6b095c3](https://github.com/antialias/soroban-abacus-flashcards/commit/6b095c33830341c46139bc847ddaab3db632265e))
* **card-sorting:** enable New Game button during active gameplay ([f3f6eca](https://github.com/antialias/soroban-abacus-flashcards/commit/f3f6eca1db30df9e1e34cc4e77a069a6a3954f3d))
* **card-sorting:** end drag immediately when card becomes locked ([ae45298](https://github.com/antialias/soroban-abacus-flashcards/commit/ae45298ec48efb29587c0a1c1a7986a72821f3ef))
* **card-sorting:** filter local player from emoji overlays on dragged cards ([dc2d94a](https://github.com/antialias/soroban-abacus-flashcards/commit/dc2d94aaa58531ed4f9047e2ca92724d9264643d))
* **card-sorting:** fix results panel layout to not cover cards ([4b4fbfe](https://github.com/antialias/soroban-abacus-flashcards/commit/4b4fbfef322ecda06020ad52d4b1788267112460))
* **card-sorting:** hide activity notifications in spectator mode ([5cca279](https://github.com/antialias/soroban-abacus-flashcards/commit/5cca279687d8973d25bd9a411a55b632d1c82f63))
* **card-sorting:** keep arrow sequence numbers upright ([79c9469](https://github.com/antialias/soroban-abacus-flashcards/commit/79c94699fa1cc2a2886e3ab1addc5fcd975602f5))
* **card-sorting:** lock correctly positioned prefix/suffix cards ([170abed](https://github.com/antialias/soroban-abacus-flashcards/commit/170abed2318432f309de40692f6092bb4c4a1a45))
* **card-sorting:** lock spring positions after initial animation completes ([275cc62](https://github.com/antialias/soroban-abacus-flashcards/commit/275cc62a523d9e849f2162001141b6d75ae0925e))
* **card-sorting:** New Game now restarts with same settings instantly ([f3687ed](https://github.com/antialias/soroban-abacus-flashcards/commit/f3687ed236eff4ebe61699ec02909024c7086fb5))
* **card-sorting:** only shrink/fade cards in correct prefix ([51368c6](https://github.com/antialias/soroban-abacus-flashcards/commit/51368c6ec59d5447ce2875c5e1181dec97fd509d))
* **card-sorting:** preserve card positions on pause/resume ([0d8af09](https://github.com/antialias/soroban-abacus-flashcards/commit/0d8af09517534f1e1cf1f57160391d465a279d76))
* **card-sorting:** preserve rotation when starting drag ([3364144](https://github.com/antialias/soroban-abacus-flashcards/commit/3364144fb6212934b6ad6d63ac6e7b78b436b258))
* **card-sorting:** prevent duplicate START_GAME moves on Play Again ([a0b14f8](https://github.com/antialias/soroban-abacus-flashcards/commit/a0b14f87e9c5b32fcbb685da4e70c563f70ed91a))
* **card-sorting:** prevent ghost movements with proper optimistic updates ([bd014be](https://github.com/antialias/soroban-abacus-flashcards/commit/bd014bec4ffa12bcd8f4a4e84ff51203c90c1f1d))
* **card-sorting:** prevent infinite loop when all cards are correct ([34785f4](https://github.com/antialias/soroban-abacus-flashcards/commit/34785f466faaa6b9f2958df786af88561fa80b06))
* **card-sorting:** prevent infinite loop with tolerance-based position comparison ([627b873](https://github.com/antialias/soroban-abacus-flashcards/commit/627b873382eaa76ad16477280d10451cf2951e1a))
* **card-sorting:** prevent position jump when clicking rotated cards ([564a00f](https://github.com/antialias/soroban-abacus-flashcards/commit/564a00f82b6ca6aa8a2c0586ca49fc42d44991a8))
* **card-sorting:** prevent replaying own movements from server ([308168a](https://github.com/antialias/soroban-abacus-flashcards/commit/308168a7fb51013b0851e98b161ba1a1a3e39fbb))
* **card-sorting:** prevent springs from reinitializing on window resize ([30953b8](https://github.com/antialias/soroban-abacus-flashcards/commit/30953b8c4a3cf147f980455818f9ce8eea07837c))
* **card-sorting:** prevent springs from resetting after animation ([8aff60c](https://github.com/antialias/soroban-abacus-flashcards/commit/8aff60ce3f8d302ce5c1bde7cb773e63064c36b7))
* **card-sorting:** remove hasAnimatedRef logic causing backwards animation ([a44aa5a](https://github.com/antialias/soroban-abacus-flashcards/commit/a44aa5a4c2d84cab7cf0bbf87485bb61548fdeb2))
* **card-sorting:** remove remaining reveal numbers references ([15c53ea](https://github.com/antialias/soroban-abacus-flashcards/commit/15c53ea4eb4abb824eb0360fb645b1f3e455578e))
* **card-sorting:** restore prefix/suffix card shrinking visual feedback ([f5fb4d7](https://github.com/antialias/soroban-abacus-flashcards/commit/f5fb4d7b76e25286bcdecd017894ff2d78b31963))
* **card-sorting:** show only active players in team members section ([fa9f1a5](https://github.com/antialias/soroban-abacus-flashcards/commit/fa9f1a568f3dff2f4e5e7d3e8841b951ef1b7d04))
* **card-sorting:** smooth scale animation while dragging cards ([0eefc33](https://github.com/antialias/soroban-abacus-flashcards/commit/0eefc332ac2724c54b477301a269915e895db94f))
* **card-sorting:** stabilize inferred sequence for locked cards during drag ([b0cd194](https://github.com/antialias/soroban-abacus-flashcards/commit/b0cd194838705bb7bbf21ac9e318eaba491097b2))
* **card-sorting:** use empty deps array for useSprings to prevent recreation ([cee399e](https://github.com/antialias/soroban-abacus-flashcards/commit/cee399ed1513d32d0fff51a6f63898aa861605e1))
* **card-sorting:** use ref to track initialized state and prevent re-animation ([f389afa](https://github.com/antialias/soroban-abacus-flashcards/commit/f389afa831935e896a626f526cfee378e340a64b))
* **card-sorting:** use same coordinate system for game board and results ([6972fdf](https://github.com/antialias/soroban-abacus-flashcards/commit/6972fdf1105b6e854494efe1c4c587e6b6ff32a9))
* **complement-race:** prevent delivery move thrashing in steam sprint mode ([e1258ee](https://github.com/antialias/soroban-abacus-flashcards/commit/e1258ee0416010909774694c0b25306b6f30329c))
* configure favicon metadata and improve bead visibility ([e1369fa](https://github.com/antialias/soroban-abacus-flashcards/commit/e1369fa2754cd61745a2950e6cb767d6b08db38f))
* copy entire packages/core and packages/templates ([0ccada0](https://github.com/antialias/soroban-abacus-flashcards/commit/0ccada0ca783e635f9ae08f33a69c392018ee342))
* correct hero abacus scroll direction to flow with page content ([4232746](https://github.com/antialias/soroban-abacus-flashcards/commit/423274657c9698bba28f7246fbf48d8508d97ef9))
* correct Typst template path in Dockerfile ([4c518de](https://github.com/antialias/soroban-abacus-flashcards/commit/4c518decb7fcc0b519d07680cbfd01c94c23dd41))
* delete existing user sessions before creating new ones ([0cced47](https://github.com/antialias/soroban-abacus-flashcards/commit/0cced47a0f414a04371bdb253fc5a43e4d9557be))
* **docker:** add scripts, abacus-react, and tsx for production calendar generation ([33eb90e](https://github.com/antialias/soroban-abacus-flashcards/commit/33eb90e316f84650ae619f8c6c02c9e77c663d1b))
* **docker:** upgrade OpenSCAD to 2024.11 to fix CGAL intersection bug ([e1bcd24](https://github.com/antialias/soroban-abacus-flashcards/commit/e1bcd241691050fa05cd49e14c288b4b070a7d17))
* extract pure SVG content from AbacusReact renders ([b07f1c4](https://github.com/antialias/soroban-abacus-flashcards/commit/b07f1c421616bcfd1f949f9a42ce1b03df418945))
* **games:** prevent horizontal page scroll from carousel overflow ([5a8c98f](https://github.com/antialias/soroban-abacus-flashcards/commit/5a8c98fc10704e459690308a84dc7ee2bfa0ef6c))
* **games:** smooth scroll feel for carousel wheel navigation ([f80a73b](https://github.com/antialias/soroban-abacus-flashcards/commit/f80a73b35c324959bfd7141ebf086cb47d3c0ebc))
* **games:** use specific transition properties for smooth carousel loop ([187271e](https://github.com/antialias/soroban-abacus-flashcards/commit/187271e51527ee0129f71d77be1bd24072b963c4))
* **guide:** increase abacus sizes - they were too small ([1074624](https://github.com/antialias/soroban-abacus-flashcards/commit/1074624b2fbce1d1d887dbd6326cf22eeb31dcec))
* **guide:** make abacus sizes consistent and add nav spacing ([bea4842](https://github.com/antialias/soroban-abacus-flashcards/commit/bea4842a29aa86ca4261b4ddd6150bacc8babc46))
* **guide:** remove inner containers and tighten margins ([7e54c6f](https://github.com/antialias/soroban-abacus-flashcards/commit/7e54c6f4fc5bc4daa6088eb3381d860a495776f2))
* **i18n:** eliminate FOUC by loading messages server-side ([4d4d930](https://github.com/antialias/soroban-abacus-flashcards/commit/4d4d930bd307ce5a405fc5751af6682a9f221f1f))
* **i18n:** use useMessages() for tutorial translations ([95b0105](https://github.com/antialias/soroban-abacus-flashcards/commit/95b0105ca3b28c5adfa843e8d77a8b27d9e7ade4))
* include column posts in favicon bounding box ([0b2f481](https://github.com/antialias/soroban-abacus-flashcards/commit/0b2f48106a939307b728c86fe2ea1be1e0247ea8))
* increase server update debounce to 2000ms for low bandwidth ([633ff12](https://github.com/antialias/soroban-abacus-flashcards/commit/633ff127500c893a215491afa0e6ff814ad553bf))
* Integrate threshold input into Point Victory card ([b29bbee](https://github.com/antialias/soroban-abacus-flashcards/commit/b29bbeefcad92be42f7a3ca27ac126db4232ab26))
* **layout:** add systematic spacing for fixed nav bar ([4559fb1](https://github.com/antialias/soroban-abacus-flashcards/commit/4559fb121d0df954ebaf33616a5262c7ca633c6e))
* **layout:** remove wrapper, use utility class for nav spacing ([247c3d9](https://github.com/antialias/soroban-abacus-flashcards/commit/247c3d9874303f83641e599724a485eea8d5604a))
* mark dynamic routes as force-dynamic to prevent static generation errors ([d7b35d9](https://github.com/antialias/soroban-abacus-flashcards/commit/d7b35d954421fd7577cd2c26247666e5953b647d))
* **nav:** restrict transparent hero styling to home page only ([fab227d](https://github.com/antialias/soroban-abacus-flashcards/commit/fab227d6862672e8250b1c169b302fbae23ce4d2))
* **nav:** show full navigation on /games page ([d3fe6ac](https://github.com/antialias/soroban-abacus-flashcards/commit/d3fe6acbb0390e1df71869a4095e5ee6021e06b1))
* **qr-button:** improve layout and z-index ([646a422](https://github.com/antialias/soroban-abacus-flashcards/commit/646a4228d0573796b1a429e31bc037411024c0ff))
* **qr-button:** increase mini QR code size to 80px ([61ac737](https://github.com/antialias/soroban-abacus-flashcards/commit/61ac7378bdb01132b26bfc265a057c095ea41606))
* **qr-button:** increase mini QR code to 84px ([3fae5ea](https://github.com/antialias/soroban-abacus-flashcards/commit/3fae5ea6fa9ebd0f8fe8c9140a027be7f6a041aa))
* **qr-button:** make button square and increase QR size ([dc2d466](https://github.com/antialias/soroban-abacus-flashcards/commit/dc2d46663b8e0ec94a1508a57c4f8c2d8ba03506))
* **qr-button:** match height of stacked buttons ([81f202d](https://github.com/antialias/soroban-abacus-flashcards/commit/81f202d21556aa430402fda814519adbc8883831))
* reduce padding to minimize gap below last bead ([0e529be](https://github.com/antialias/soroban-abacus-flashcards/commit/0e529be789caf16e73f3e2ee77f52e243841aef4))
* remove distracting parallax and wobble 3D effects ([28a2d40](https://github.com/antialias/soroban-abacus-flashcards/commit/28a2d40996256700bf19cd80130b26e24441949f))
* remove wobble physics and enhance wood grain visibility ([5d97673](https://github.com/antialias/soroban-abacus-flashcards/commit/5d976734062eb3d943bfdfdd125473c56b533759))
* replace regex HTML parsing with deterministic bead position calculations in icon generation ([41a3707](https://github.com/antialias/soroban-abacus-flashcards/commit/41a3707841595a74de56c6adf6d271237f81ee0e))
* resolve z-index layering and hero abacus visibility issues ([ed9a050](https://github.com/antialias/soroban-abacus-flashcards/commit/ed9a050d64db905e1328008f25dc0014e9a81999))
* rewrite 3D stories to use props instead of CSS wrappers ([26bdb11](https://github.com/antialias/soroban-abacus-flashcards/commit/26bdb112370cece08634e3d693d15336111fc70f))
* **rithmomachia:** add missing i18next dependencies ([91154d9](https://github.com/antialias/soroban-abacus-flashcards/commit/91154d93647e59f7e5f96d1db5624a7ec9b1b9ff))
* **rithmomachia:** add missing pyramid section keys to Japanese (ja.json) ([dae615e](https://github.com/antialias/soroban-abacus-flashcards/commit/dae615ee72a7ec7d0b235a22c61ebc4af0d8eadb))
* **rithmomachia:** adjust error dialog sizing to prevent text clipping ([cda1126](https://github.com/antialias/soroban-abacus-flashcards/commit/cda1126cb0eab6840df89f3a8778d72410298093))
* **rithmomachia:** adjust roster notice position to not overlap nav ([7093223](https://github.com/antialias/soroban-abacus-flashcards/commit/709322373a91c8174d21052d184fa84dd8bda326))
* **rithmomachia:** change undock icon to pop-out arrow ([2a91748](https://github.com/antialias/soroban-abacus-flashcards/commit/2a917484938bc269cf16acb501d4d26584405e0f))
* **rithmomachia:** correct board dimensions to 16x8 and restore original layout values ([cfac277](https://github.com/antialias/soroban-abacus-flashcards/commit/cfac27750526fb1f6a7e4314a96aab3b92e08e44))
* **rithmomachia:** Correct board setup to match reference image exactly ([618e563](https://github.com/antialias/soroban-abacus-flashcards/commit/618e56358deb66cba968472f39b8d4e28b4dd211))
* **rithmomachia:** correct makeMove parameter types for capture handling ([aafb64f](https://github.com/antialias/soroban-abacus-flashcards/commit/aafb64f3e337c6cf925766fe179b91f66c4a040b))
* **rithmomachia:** fix guide modal resize drift by calculating from initial state ([1bcd99c](https://github.com/antialias/soroban-abacus-flashcards/commit/1bcd99c949e4d2b4fb1c0813debd50176fa58cb9))
* **rithmomachia:** fix harmony section translation structure for hi/ja/es ([14259a1](https://github.com/antialias/soroban-abacus-flashcards/commit/14259a19a9817d0947467faa004d5f43118f8d8d))
* **rithmomachia:** fix modal resizing zoom issue ([4fa20f4](https://github.com/antialias/soroban-abacus-flashcards/commit/4fa20f44cb9758f29d1f1512232be0fdc0b53b3d))
* **rithmomachia:** Fix TypeScript errors in playing guide modal ([4834ece](https://github.com/antialias/soroban-abacus-flashcards/commit/4834ece98e86f2fb00511bb876a5c32c289df0e0))
* **rithmomachia:** handle pyramid pieces in hover error tooltip ([56f3164](https://github.com/antialias/soroban-abacus-flashcards/commit/56f3164155beb94ceec2838bed9fc74fd75524db))
* **rithmomachia:** implement proper board cropping and highlighting in guide ([d0a8fcd](https://github.com/antialias/soroban-abacus-flashcards/commit/d0a8fcdea6aa4fdacfee33e183c92923634ee2b7))
* **rithmomachia:** improve guide modal tab navigation at narrow widths ([a673177](https://github.com/antialias/soroban-abacus-flashcards/commit/a673177bec1c709463ce0f266848f473a79f4ef0))
* **rithmomachia:** reconnect player assignment UI and fix setup layout ([a1a0374](https://github.com/antialias/soroban-abacus-flashcards/commit/a1a0374fac5dce676df5890663b75531589ed93a))
* **rithmomachia:** render guide as docked in preview panel ([190f8cf](https://github.com/antialias/soroban-abacus-flashcards/commit/190f8cf302aa966f029d05931811e217c67bfe39))
* **rithmomachia:** show actual values in tooltips for non-helper relations ([774c6b0](https://github.com/antialias/soroban-abacus-flashcards/commit/774c6b0ce712b1a77bb684457da9831e6ec91138))
* **rithmomachia:** show guest-friendly message when they can't fix too many players ([54bfd2f](https://github.com/antialias/soroban-abacus-flashcards/commit/54bfd2fac86be3597d40c67a1235e4c4ed8e2709))
* **rithmomachia:** smooth guide dragging from docked state without jump ([8f4a79c](https://github.com/antialias/soroban-abacus-flashcards/commit/8f4a79c9b0cad55336584fdc8e67409015d3a8ae))
* **rithmomachia:** validate move path before showing capture error on hover ([bd49964](https://github.com/antialias/soroban-abacus-flashcards/commit/bd49964186a0daa1639ae849b128a76081643daf))
* **room-info:** hide Leave Room button when user is alone ([5927f61](https://github.com/antialias/soroban-abacus-flashcards/commit/5927f61c3c34ba583ee45c8cee48a116c1c03071))
* separate horizontal and vertical bounding box logic ([83090df](https://github.com/antialias/soroban-abacus-flashcards/commit/83090df4dfad1d1d5cfa6c278c241526cacc7972))
* tolerate OpenSCAD CGAL warnings if output file is created ([88993f3](https://github.com/antialias/soroban-abacus-flashcards/commit/88993f36629206a7bdcf9aa9d5641f1580b64de5))
* **tutorial:** correct column validation for bead highlights ([9ba1824](https://github.com/antialias/soroban-abacus-flashcards/commit/9ba18242262cd63cc6c25361aaec3a4c0f66b161))
* **tutorial:** fix overlay rendering, arrow indicators, and bead visibility ([a804316](https://github.com/antialias/soroban-abacus-flashcards/commit/a80431608dbc4f54d8e4f1095936b95a258b4a72))
* use absolute positioning for hero abacus to eliminate scroll lag ([096104b](https://github.com/antialias/soroban-abacus-flashcards/commit/096104b094b45aa584f2b9d47a440a8c14d82fc0))
* use Debian base for deps stage to match runner for binary compatibility ([f8fe6e4](https://github.com/antialias/soroban-abacus-flashcards/commit/f8fe6e4a415f8655626af567129d0cda61b82e15))
* use default BOSL2 branch instead of non-existent v2.0.0 tag ([f4ffc5b](https://github.com/antialias/soroban-abacus-flashcards/commit/f4ffc5b0277535358bea7588309a1a4afd1983a1))
* use nested SVG viewBox for actual cropping, not just scaling ([440b492](https://github.com/antialias/soroban-abacus-flashcards/commit/440b492e85beff1612697346b6c5cfc8461e83da))
* various game improvements and UI enhancements ([b67cf61](https://github.com/antialias/soroban-abacus-flashcards/commit/b67cf610c570d54744553cd8f6694243fa50bee1))
* **web,docker:** add --format flag for Typst and upgrade to v0.13.0 ([19b9d7a](https://github.com/antialias/soroban-abacus-flashcards/commit/19b9d7a74f549c7e93c9564e4a903e1bcd5a4bbc))
* **web:** add dynamic export to rithmomachia page ([329e623](https://github.com/antialias/soroban-abacus-flashcards/commit/329e62321245ef62726c986c917f19a909a5b65e))
* **web:** fix Typst PDF generation path resolution ([7ce1287](https://github.com/antialias/soroban-abacus-flashcards/commit/7ce12875254a31d8acdb35ef5de7d36d215ccd92))
* **web:** generate styled-system artifacts during build ([293390a](https://github.com/antialias/soroban-abacus-flashcards/commit/293390ae350a6c6aa467410f68c735512104d9dd))
* **web:** move react-dom/server import to API route to satisfy Next.js ([00a8bc3](https://github.com/antialias/soroban-abacus-flashcards/commit/00a8bc3e5e8f044df280c4356d3605a852f82e84))
* **web:** move tsx to production dependencies for calendar generation ([ffae9c1](https://github.com/antialias/soroban-abacus-flashcards/commit/ffae9c1bdbccc5edb2e747a09d1fcad3b29e4eac))
* **web:** prevent abacus overlap in composite calendar ([448f93c](https://github.com/antialias/soroban-abacus-flashcards/commit/448f93c1e2a7f86bc48e678d4599ca968c6d81d2)), closes [#f0f0f0](https://github.com/antialias/soroban-abacus-flashcards/issues/f0f0f0)
* **web:** use AbacusStatic for calendar SVG generation ([08c6a41](https://github.com/antialias/soroban-abacus-flashcards/commit/08c6a419e25d220560eba13d6db437145e6e61b8))
* **web:** use dynamic import for react-dom/server in API route ([4f93c7d](https://github.com/antialias/soroban-abacus-flashcards/commit/4f93c7d996732de4bc19e7acf2d4ce803cba88b6))
* **web:** use nested SVG elements to prevent coordinate space conflicts ([f9cbee8](https://github.com/antialias/soroban-abacus-flashcards/commit/f9cbee8fcdf80641f3b82a65fad6b8a3575525fc))
### Performance Improvements
* optimize Docker image size to reduce build failures ([9ca3106](https://github.com/antialias/soroban-abacus-flashcards/commit/9ca310636183f4970db925ce8fa368e23645eb02))
### Code Refactoring
* **card-sorting:** remove reveal numbers feature ([ea5e3e8](https://github.com/antialias/soroban-abacus-flashcards/commit/ea5e3e838bd6a5b8b38469a70aa92a0e9baba769))
* **card-sorting:** send complete card sequence instead of individual moves ([e4df843](https://github.com/antialias/soroban-abacus-flashcards/commit/e4df8432b9c4a2055d47833d56b6e9fcf325ca94))
* **games:** implement carousel, fix victories bug, add conditional stats ([82c133f](https://github.com/antialias/soroban-abacus-flashcards/commit/82c133f742f3f5c40b723c18d1997b518f25b320))
* **games:** move page title to nav bar ([712ee58](https://github.com/antialias/soroban-abacus-flashcards/commit/712ee58e5956e5bbdb13d5a5fb367020c87c8c9a))
* **games:** remove redundant subtitle below nav ([ad5bb87](https://github.com/antialias/soroban-abacus-flashcards/commit/ad5bb87325a44825f0cd85b38eb0e5f0eea7a695))
* **games:** remove wheel scrolling, enable overflow visible carousel ([876513c](https://github.com/antialias/soroban-abacus-flashcards/commit/876513c9cc6323c20845ae8f1a3a5478d449f9e4))
* **layout:** make nav height truly self-referential ([9886302](https://github.com/antialias/soroban-abacus-flashcards/commit/98863026b789d09eecb0bc3e013d112889a5d038))
* remove debug console.log statements ([32f51ae](https://github.com/antialias/soroban-abacus-flashcards/commit/32f51ae739679789585182ba659ec5f1168d652d))
* reorganize Harmony and Victory guide sections ([fb629c4](https://github.com/antialias/soroban-abacus-flashcards/commit/fb629c44ea37a7b296561919a4980c10d14efed8))
* restructure /create page into hub with sub-pages ([b91b23d](https://github.com/antialias/soroban-abacus-flashcards/commit/b91b23d95ffaeeaa30dbc8579f4c30bae8829ee7))
* **rithmomachia:** extract board and capture components (phase 2+3) ([a0a867b](https://github.com/antialias/soroban-abacus-flashcards/commit/a0a867b27166a838ca7e0dcbd8f89fe1be812a80))
* **rithmomachia:** extract CaptureErrorDialog component (Phase 2 partial) ([f0a066d](https://github.com/antialias/soroban-abacus-flashcards/commit/f0a066d8f0a51d35e18f87a8436c0d05153c03b5))
* **rithmomachia:** extract constants and coordinate utilities (Phase 1) ([eace0ed](https://github.com/antialias/soroban-abacus-flashcards/commit/eace0ed52979b71870f77ee68f8568558f2aaecb))
* **rithmomachia:** extract guide sections into separate files ([765525d](https://github.com/antialias/soroban-abacus-flashcards/commit/765525dc451897f561f017e444aae892dc27177f))
* **rithmomachia:** extract hooks (phase 5) ([324a659](https://github.com/antialias/soroban-abacus-flashcards/commit/324a65992f97c295ea3968aaf54d266373f4c035))
* **rithmomachia:** extract phase components (phase 4) ([11364f6](https://github.com/antialias/soroban-abacus-flashcards/commit/11364f6394c15e49850e5cad2cbd32e1ea08a178))
* **rithmomachia:** extract reusable components from SetupPhase ([3abc325](https://github.com/antialias/soroban-abacus-flashcards/commit/3abc325ea27feee5c4cc59f02296ff218f342a81))
* **rithmomachia:** make setup phase UI more compact ([e55f848](https://github.com/antialias/soroban-abacus-flashcards/commit/e55f848a26092a2b4a5b09c3c255544ea9666f1b))
* **rithmomachia:** redesign error notification with modern UI ([dfeeb0e](https://github.com/antialias/soroban-abacus-flashcards/commit/dfeeb0e0db8b2c4a38198cf71cd918439d6c211b)), closes [#1e293](https://github.com/antialias/soroban-abacus-flashcards/issues/1e293) [#0f172](https://github.com/antialias/soroban-abacus-flashcards/issues/0f172) [#f1f5f9](https://github.com/antialias/soroban-abacus-flashcards/issues/f1f5f9)
* **rithmomachia:** simplify capture error dialog to one-liner ([82a5eb2](https://github.com/antialias/soroban-abacus-flashcards/commit/82a5eb2e4bf74f42a183a15f1129e5ec84cc5231))
* **rithmomachia:** Update board setup to authoritative CSV layout ([0471da5](https://github.com/antialias/soroban-abacus-flashcards/commit/0471da598d8d591b3f9d63f467cb35f999924c13))
* **rithmomachia:** update capture components to use CaptureContext ([2ab6ab5](https://github.com/antialias/soroban-abacus-flashcards/commit/2ab6ab57995a6d7d9c66b9fba8de945507209661))
* **rithmomachia:** use useBoardLayout and usePieceSelection in BoardDisplay ([0ab7a1d](https://github.com/antialias/soroban-abacus-flashcards/commit/0ab7a1df327d7258228af9851762555583a20d61))
* use AbacusReact for dynamic Open Graph image ([9c20f12](https://github.com/antialias/soroban-abacus-flashcards/commit/9c20f12bacff4fe7f8bd7a87032afbed9711e94b))
* **web:** import utility functions from abacus-react ([7228bbc](https://github.com/antialias/soroban-abacus-flashcards/commit/7228bbc2eb8b9b2b861d32b760b14895a1a7ee8a))
* **web:** move calendar generators to src/utils for proper compilation ([379698f](https://github.com/antialias/soroban-abacus-flashcards/commit/379698fea3fc8f04d716d35347749182d5c53b5c))
* **web:** return calendar SVG preview with PDF generation ([14a5de0](https://github.com/antialias/soroban-abacus-flashcards/commit/14a5de0dfadf423c646f4748b0de94f2483b18a1))
* **web:** use ABACUS_THEMES instead of manual style definitions ([9f7f001](https://github.com/antialias/soroban-abacus-flashcards/commit/9f7f001d747402b1578116e45c1a137519714314))
* **web:** use client-side React rendering for live calendar preview ([f880cbe](https://github.com/antialias/soroban-abacus-flashcards/commit/f880cbe4bffc898ae95d36d68615cf317d94012a))
* **web:** use compact prop for inline mini-abacus ([ff1d60a](https://github.com/antialias/soroban-abacus-flashcards/commit/ff1d60a23387d22e7ed44185dc3a8c895b7c0d12))
* **web:** use direct function imports instead of execSync for calendar generation ([9f1715f](https://github.com/antialias/soroban-abacus-flashcards/commit/9f1715f0856bcd125a79014c0c8c854c1c7b3f4d))
* **web:** use stdin/stdout for Typst compilation ([06f68cc](https://github.com/antialias/soroban-abacus-flashcards/commit/06f68cc74c31b54284808beadf67f4db08d03420))
### Documentation
* **abacus-react:** add Storybook stories for AbacusStatic ([4f9dc46](https://github.com/antialias/soroban-abacus-flashcards/commit/4f9dc4666d249c1c67c51a3901c4f657ff9723ef))
* **abacus-react:** add Storybook stories for new features ([6a1cec0](https://github.com/antialias/soroban-abacus-flashcards/commit/6a1cec06a75575cb35ddca5ef573aaf13c2352f4))
* **abacus-react:** export AbacusStatic and update README ([74f2d97](https://github.com/antialias/soroban-abacus-flashcards/commit/74f2d97434620cb8c7d49912bca3bf386408a16d))
* **abacus-react:** update documentation for new features ([35d8734](https://github.com/antialias/soroban-abacus-flashcards/commit/35d8734a3a9124564957444d3642c9e7c4348fac))
* **abacus-react:** update README with /static import path for RSC ([72a4c2b](https://github.com/antialias/soroban-abacus-flashcards/commit/72a4c2b80c1158a6eaf21abe4e807ff6e70373ac))
* add 3D enhancement documentation to README ([cc96802](https://github.com/antialias/soroban-abacus-flashcards/commit/cc96802df87c805c946ee59af509663ba570e75b))
* add critical section on never adding tsx to production dependencies ([770cfc3](https://github.com/antialias/soroban-abacus-flashcards/commit/770cfc3aca296b4f52c822710a1072fe501a0f49))
* add database migration guide and playing guide modal spec ([5a29af7](https://github.com/antialias/soroban-abacus-flashcards/commit/5a29af78e27e897ab35273611b79c4b669304f71))
* add deployment verification guidelines to prevent false positives ([3d8da23](https://github.com/antialias/soroban-abacus-flashcards/commit/3d8da2348b4e8a227e963791d15dc6718eac5af1))
* **card-sorting:** add comprehensive multiplayer plan ([008ccea](https://github.com/antialias/soroban-abacus-flashcards/commit/008ccead0f9c634fe52fd156e6f9a04d6cdd7744))
* clarify dev server management in Claude Code instructions ([e08fdfd](https://github.com/antialias/soroban-abacus-flashcards/commit/e08fdfd676b51a9fed23bda336b13f5e1d40b96c))
* **rithmomachia:** Add concise one-page playing guide ([e3c1f10](https://github.com/antialias/soroban-abacus-flashcards/commit/e3c1f10233cc0924ff96a643c7c4c1f1278de3e3))
* update workflow to require manual testing before commits ([0991796](https://github.com/antialias/soroban-abacus-flashcards/commit/0991796f1eccef345f10205e675e4c33d1a62b17))
### Styles
* **rithmomachia:** improve divider styling and make tabs responsive ([88ca35e](https://github.com/antialias/soroban-abacus-flashcards/commit/88ca35e0440157ff9349e8d3d2d3cc844f18ffea)), closes [#e5e7](https://github.com/antialias/soroban-abacus-flashcards/issues/e5e7) [#9ca3](https://github.com/antialias/soroban-abacus-flashcards/issues/9ca3)
* **rithmomachia:** improve pyramid face numbers visibility and contrast ([94e5e6a](https://github.com/antialias/soroban-abacus-flashcards/commit/94e5e6a268b387380b88b192737bd55578b98bc7)), closes [#fbbf24](https://github.com/antialias/soroban-abacus-flashcards/issues/fbbf24) [#b45309](https://github.com/antialias/soroban-abacus-flashcards/issues/b45309)
* **rithmomachia:** increase pyramid face numbers size and boldness ([7bf2d73](https://github.com/antialias/soroban-abacus-flashcards/commit/7bf2d730d370e562486b229f4d209099ff8c4463))
### Tests
* trigger compose-updater deployment test ([2b06aae](https://github.com/antialias/soroban-abacus-flashcards/commit/2b06aae39474cc80d501c47c9685fa99e7120c48))
* verify compose-updater automatic deployment cycle ([af0552c](https://github.com/antialias/soroban-abacus-flashcards/commit/af0552ccd98f7b5a62d6e4074b7d87b3716af698))
## [4.68.0](https://github.com/antialias/soroban-abacus-flashcards/compare/v4.67.1...v4.68.0) (2025-11-05)
### Features
* **3d-abacus:** change default columns from 13 to 4 ([cd15c70](https://github.com/antialias/soroban-abacus-flashcards/commit/cd15c70a25c597c17ee5d2f816b1c85ba8ce4ce9))
* **abacus-react:** add AbacusStatic for React Server Components ([3b8e864](https://github.com/antialias/soroban-abacus-flashcards/commit/3b8e864cfa3af50b1912ce7ff55003d7f6b9c229))
* **abacus-react:** add core utility functions for state management ([e65541c](https://github.com/antialias/soroban-abacus-flashcards/commit/e65541c100e590a51448750c6d5178ed4f3e8eeb))
* **abacus-react:** add layout and educational props ([35bbcec](https://github.com/antialias/soroban-abacus-flashcards/commit/35bbcecb9e36f1ef5917a5a629f5e78f1f490e9c))
* **abacus-react:** add pre-defined theme presets ([cf1f950](https://github.com/antialias/soroban-abacus-flashcards/commit/cf1f950c7c5fb9ee1f0de673235d6f037be3b9d6))
* **abacus-react:** add React hooks for abacus calculations ([de038d2](https://github.com/antialias/soroban-abacus-flashcards/commit/de038d2afc26c36c1490d5ea45dace0ab812c5cc))
* **abacus-react:** add separate /static export path for React Server Components ([ed69f6b](https://github.com/antialias/soroban-abacus-flashcards/commit/ed69f6b917c543bbcaa4621a0e63745bee70f5bf))
* **abacus-react:** add shared dimension calculator for consistent sizing ([e5ba772](https://github.com/antialias/soroban-abacus-flashcards/commit/e5ba772fde9839c22daec92007f052ca125c7695))
* **abacus-react:** export new utilities, hooks, and themes ([ce4e44d](https://github.com/antialias/soroban-abacus-flashcards/commit/ce4e44d6302746053ad40dc61bab57ef3a0a9f31))
* **abacus:** add nativeAbacusNumbers setting to schema and UI ([79f7347](https://github.com/antialias/soroban-abacus-flashcards/commit/79f7347d4800646378470a7f9aca8e7f2fd5573c))
* add 3D printing support for abacus models ([dafdfdd](https://github.com/antialias/soroban-abacus-flashcards/commit/dafdfdd233b53464b9825a8a9b5f2e6206fc54cb))
* add client-side OpenSCAD WASM support for 3D preview ([eaaf17c](https://github.com/antialias/soroban-abacus-flashcards/commit/eaaf17cd4c675bfd40e0573b9c99f0c733d926aa))
* add comprehensive metadata, SEO, and make AbacusReact SSR-compatible ([0922ea1](https://github.com/antialias/soroban-abacus-flashcards/commit/0922ea10b77e7d16b8c414c596d23cb11e20c1cc))
* add comprehensive Storybook coverage and migration guide ([7a4a37e](https://github.com/antialias/soroban-abacus-flashcards/commit/7a4a37ec6d0171782778e18122da782f069e0556))
* add game preview system with mock arcade environment ([25880cc](https://github.com/antialias/soroban-abacus-flashcards/commit/25880cc7e463f98a5a23c812c1ffd43734d3fe1f))
* add per-player stats tracking system ([613301c](https://github.com/antialias/soroban-abacus-flashcards/commit/613301cd137ad6f712571a0be45c708ce391fc8f))
* add Strategy & Tactics section to Rithmomachia guide ([81ead65](https://github.com/antialias/soroban-abacus-flashcards/commit/81ead65680892efa4d0ab07e7f0ef77eb1bc1405))
* add unified trophy abacus with hero mode integration ([6620418](https://github.com/antialias/soroban-abacus-flashcards/commit/6620418a704dcca810b511a5f394084521104e6b))
* **arcade:** add ability to deactivate remote players without kicking user ([3628426](https://github.com/antialias/soroban-abacus-flashcards/commit/3628426a567d7e0273be75cce64632ae04b7d5eb))
* **arcade:** add native abacus numbers support to pressure gauge ([1d525c7](https://github.com/antialias/soroban-abacus-flashcards/commit/1d525c7b5320984a1582b8ab7eae57895c728428))
* **arcade:** add Rithmomachia (Battle of Numbers) game ([2fc0a05](https://github.com/antialias/soroban-abacus-flashcards/commit/2fc0a05f7f557cee55f7d31b585499dd04e68ff9))
* **arcade:** add yjs-demo collaborative game and Yjs persistence layer ([d568955](https://github.com/antialias/soroban-abacus-flashcards/commit/d568955d6abf389e6ab7c6979e33122a65917a46))
* **arcade:** auto-create room when user has none ([ff88c3a](https://github.com/antialias/soroban-abacus-flashcards/commit/ff88c3a1b81703a87a1d57eeb5cc139da7d9df04))
* **card-sorting:** add activity feed notifications for collaborative mode ([1461414](https://github.com/antialias/soroban-abacus-flashcards/commit/1461414ef4d0b213af241213447c91eed1abe5fb))
* **card-sorting:** add auto-submit countdown for perfect sequences ([780a716](https://github.com/antialias/soroban-abacus-flashcards/commit/780a7161bc05c2ca6597d7d8d89f01afd33d9f4d))
* **card-sorting:** add bezier curves to connecting arrows ([4d8e873](https://github.com/antialias/soroban-abacus-flashcards/commit/4d8e873358271fe3fd50b228aea8277e20aa5966))
* **card-sorting:** add CardPosition type and position syncing ([656f5a7](https://github.com/antialias/soroban-abacus-flashcards/commit/656f5a7838ed6003c214ec484d4c37072270fa8d))
* **card-sorting:** add collapsible stats sidebar for spectators ([6527c26](https://github.com/antialias/soroban-abacus-flashcards/commit/6527c26a8166b23f074e85eb335a15800c1947a2))
* **card-sorting:** add game mode selector UI to setup phase ([d25b888](https://github.com/antialias/soroban-abacus-flashcards/commit/d25b888ffb3915d2d482442ab708ba3e159af512))
* **card-sorting:** add GameMode type system for multiplayer support ([fd76533](https://github.com/antialias/soroban-abacus-flashcards/commit/fd765335efbc91366c596c7789b92882cd3379d9))
* **card-sorting:** add green border to correctly positioned cards ([16fca86](https://github.com/antialias/soroban-abacus-flashcards/commit/16fca86b7687115f1cf565c533a512e92946e3a8)), closes [#22c55](https://github.com/antialias/soroban-abacus-flashcards/issues/22c55)
* **card-sorting:** add player emoji indicators on moving cards ([3a82099](https://github.com/antialias/soroban-abacus-flashcards/commit/3a8209975728cdcf914c43ba08339454a9e2457f))
* **card-sorting:** add react-spring animations for real-time sync ([c367e0c](https://github.com/antialias/soroban-abacus-flashcards/commit/c367e0ceece41d8e7c2bc8aebe3239ff6053a115))
* **card-sorting:** add smooth transition to drop shadow ([b0b93d0](https://github.com/antialias/soroban-abacus-flashcards/commit/b0b93d0175c8a1c8958d6ba346d969c234fdd6ff))
* **card-sorting:** add spectator mode UI enhancements ([ee7345d](https://github.com/antialias/soroban-abacus-flashcards/commit/ee7345d641e0ee72915afb9cdbd6d284b7e238bd)), closes [#6366f1](https://github.com/antialias/soroban-abacus-flashcards/issues/6366f1) [#8b5cf6](https://github.com/antialias/soroban-abacus-flashcards/issues/8b5cf6)
* **card-sorting:** add team scoring UI for collaborative mode ([ed6f177](https://github.com/antialias/soroban-abacus-flashcards/commit/ed6f1779141d0bc9dff2d532a3dfc638015936b5)), closes [#a78](https://github.com/antialias/soroban-abacus-flashcards/issues/a78) [#8b5cf6](https://github.com/antialias/soroban-abacus-flashcards/issues/8b5cf6)
* **card-sorting:** add updateCardPositions action to Provider ([f6ed4a2](https://github.com/antialias/soroban-abacus-flashcards/commit/f6ed4a27a26d8bfa495ba5f580a446286b9674a0))
* **card-sorting:** auto-arrange prefix/suffix cards in corners ([4ba7f24](https://github.com/antialias/soroban-abacus-flashcards/commit/4ba7f247175d93e4d339e2be7bbdb2e009992232))
* **card-sorting:** fade correctly positioned cards to 50% opacity ([7028cfc](https://github.com/antialias/soroban-abacus-flashcards/commit/7028cfc51164e9219479e6040b03c29239aa7edb))
* **card-sorting:** gentler spring animation for locked cards ([47189cb](https://github.com/antialias/soroban-abacus-flashcards/commit/47189cb6e79ed2915f5ddcc9cb3626540dfb07f3))
* **card-sorting:** implement continuous bezier curve paths ([2d93024](https://github.com/antialias/soroban-abacus-flashcards/commit/2d9302410f5e98145a435b00df3ae5fcf3f4c0b5))
* **card-sorting:** improve card distribution for natural scattered look ([0b0503f](https://github.com/antialias/soroban-abacus-flashcards/commit/0b0503f0354a4a82fe6b9bfe827729e8e5a9e329))
* **card-sorting:** make player emoji fill entire card background ([2e7a02c](https://github.com/antialias/soroban-abacus-flashcards/commit/2e7a02c9e4ab84e821d58661d6e7a326f7882afb))
* **card-sorting:** optimize results screen for mobile ([d188789](https://github.com/antialias/soroban-abacus-flashcards/commit/d188789069b4c350ce3cc0d221bd4a43dab528e0))
* **card-sorting:** redesign setup screen with modern UI ([73cf967](https://github.com/antialias/soroban-abacus-flashcards/commit/73cf96749234c480482f62392245b38c1fd5f0a0))
* **card-sorting:** scale correctly positioned cards to 50% ([222dc55](https://github.com/antialias/soroban-abacus-flashcards/commit/222dc555fa5068e2594dcc074e33f70320f5742c))
* **card-sorting:** shrink/fade cards in correct suffix as well ([8f6feec](https://github.com/antialias/soroban-abacus-flashcards/commit/8f6feec4f21d0af0d1c98daf5017eddd91d3d578))
* **card-sorting:** smooth spring transition from game table to results grid ([c5f39d5](https://github.com/antialias/soroban-abacus-flashcards/commit/c5f39d51eb45ec816f32151dc7f9d7c06360474b))
* **card-sorting:** wrap prefix/suffix cards to multiple rows ([e3184dd](https://github.com/antialias/soroban-abacus-flashcards/commit/e3184dd0d444e5dc204731f5b396d5c553cf7d11))
* complete 3D enhancement integration for all three proposals ([5ac55cc](https://github.com/antialias/soroban-abacus-flashcards/commit/5ac55cc14980b778f9be32f0833f8760aa16b631))
* **create-room:** replace hardcoded game grid with dynamic Radix Select dropdown ([83d0ba2](https://github.com/antialias/soroban-abacus-flashcards/commit/83d0ba26f5eeec3e189d279710d5bbcf13e82f29))
* dynamic day-of-month favicon using subprocess pattern ([4d0795a](https://github.com/antialias/soroban-abacus-flashcards/commit/4d0795a9df74fcb085af821eafb923bdcb5f0b0c))
* dynamically crop favicon to active beads for maximum size ([5670322](https://github.com/antialias/soroban-abacus-flashcards/commit/567032296aecaad13408bdc17d108ec7c57fb4a8))
* enable 3D enhancement on hero/open MyAbacus modes ([37e330f](https://github.com/antialias/soroban-abacus-flashcards/commit/37e330f26e5398c2358599361cd417b4aeefac7d))
* **games:** add autoplay and improve carousel layout ([9f51edf](https://github.com/antialias/soroban-abacus-flashcards/commit/9f51edfaa95c14f55a30a6eceafb9099eeed437f))
* **games:** add horizontal scroll support to carousels ([a224abb](https://github.com/antialias/soroban-abacus-flashcards/commit/a224abb6f660e1aa31ab04f5590b003fae072af9))
* **games:** add rotating games hero carousel ([24231e6](https://github.com/antialias/soroban-abacus-flashcards/commit/24231e6b2ebbdcae066344df54e7e80e7d221128))
* **i18n:** add dynamic locale switching without page reload ([fe9bfea](https://github.com/antialias/soroban-abacus-flashcards/commit/fe9bfeabf9ee66923501b18e1b69f2d666d0817d))
* **i18n:** add global language selector to navigation ([0506360](https://github.com/antialias/soroban-abacus-flashcards/commit/0506360117807665e8f5a6fcd8f1178339f6e65c))
* **i18n:** add homepage translations for all supported languages ([8c9d35a](https://github.com/antialias/soroban-abacus-flashcards/commit/8c9d35a3b43dd29664f5afb1bd96c4e584d9ec75))
* **i18n:** add Old High German (goh) language support ([b334a15](https://github.com/antialias/soroban-abacus-flashcards/commit/b334a15255ed9fa29beb43de66da0288691390c6))
* **i18n:** complete Old High German translations for all locales ([0b06a1c](https://github.com/antialias/soroban-abacus-flashcards/commit/0b06a1ce005d92e7ae9c225aba40d240e965753d))
* **i18n:** internationalize games page and tutorial content ([4253964](https://github.com/antialias/soroban-abacus-flashcards/commit/4253964af19f9aaa16f2394f41819223542fb519))
* **i18n:** internationalize homepage with English translations ([40cff14](https://github.com/antialias/soroban-abacus-flashcards/commit/40cff143c72e9228d7cce607cab64c4a6d067017))
* **i18n:** migrate from react-i18next to next-intl ([9016b76](https://github.com/antialias/soroban-abacus-flashcards/commit/9016b760247a20271255839e4dd7e5b9a8353b9f))
* **i18n:** update games page hero section copy ([6333c60](https://github.com/antialias/soroban-abacus-flashcards/commit/6333c60352b920916afd81cc3b0229706a1519fa))
* install embla-carousel-autoplay for games carousel ([946e5d1](https://github.com/antialias/soroban-abacus-flashcards/commit/946e5d19107020992be8945f8fe7c41e4bc2a0e2))
* install embla-carousel-react for player profile carousel ([642ae95](https://github.com/antialias/soroban-abacus-flashcards/commit/642ae957383cfe1d6045f645bbe426fd80c56f35))
* internationalize guide page with 6 languages ([e9c320b](https://github.com/antialias/soroban-abacus-flashcards/commit/e9c320bb1032e94c3852b9459236409da4669c09))
* internationalize tutorial player ([26d41cf](https://github.com/antialias/soroban-abacus-flashcards/commit/26d41cfd058bfdf5b61ee6e20cfc61cbecb32f45))
* optimize card sorting for mobile displays ([b443ee9](https://github.com/antialias/soroban-abacus-flashcards/commit/b443ee9cdcd9fcb7674845d8c92f7c338ad98dea))
* Redesign Rithmomachia setup page with dramatic medieval theme ([6ae4d13](https://github.com/antialias/soroban-abacus-flashcards/commit/6ae4d13dc784a87f85206c6ff6d005e5b23b678c))
* **rithmomachia:** add 80% opacity to guide modal when not hovered ([4a78485](https://github.com/antialias/soroban-abacus-flashcards/commit/4a78485d2e20f2cbf36cc898a1beafa8eb48bfbf))
* **rithmomachia:** add CaptureContext for capture dialog state management ([d7eb957](https://github.com/antialias/soroban-abacus-flashcards/commit/d7eb957a8dabbcac35e166a83dd679a628e19baa))
* **rithmomachia:** add ghost panel preview for guide docking ([c0d6526](https://github.com/antialias/soroban-abacus-flashcards/commit/c0d6526d30aca8deaeda2b7c2e27eb37af8b577c))
* **rithmomachia:** add guide docking with resizable panels ([f457f1a](https://github.com/antialias/soroban-abacus-flashcards/commit/f457f1a1c22b6cb7fff23a7701474322cf423dd9))
* **rithmomachia:** add helper piece selection for mathematical captures ([cae3359](https://github.com/antialias/soroban-abacus-flashcards/commit/cae335958751c27684bfb10c8e2e526b460954ed))
* **rithmomachia:** add helpful error messages for failed captures ([b172440](https://github.com/antialias/soroban-abacus-flashcards/commit/b172440a41e958ced98903bb8f4c2e4b423e1356))
* **rithmomachia:** add initial board visual to guide Overview section ([d42bcff](https://github.com/antialias/soroban-abacus-flashcards/commit/d42bcff0d922895549c1c12f8e02a3ae6d53425a))
* **rithmomachia:** Add interactive playing guide modal ([3121d82](https://github.com/antialias/soroban-abacus-flashcards/commit/3121d8240a567817f5f205a4ef4a788fcf451f71))
* **rithmomachia:** add number bond visualization and helper placeholders ([82d8913](https://github.com/antialias/soroban-abacus-flashcards/commit/82d89131f00517f162ec496397cb390f9ecfc52e))
* **rithmomachia:** add ratio capture example to guide ([9150b0c](https://github.com/antialias/soroban-abacus-flashcards/commit/9150b0c678ce7104fe984ee0fc93748b43a245f4))
* **rithmomachia:** add standalone guide page route ([3fcc79f](https://github.com/antialias/soroban-abacus-flashcards/commit/3fcc79fe9eae11d4bd3a724c1b1f7d086e7cae81))
* **rithmomachia:** add useBoardLayout hook for centralized layout calculations ([27f1c98](https://github.com/antialias/soroban-abacus-flashcards/commit/27f1c989d59a19844b90a5148ae27fb97161da2d))
* **rithmomachia:** add usePieceSelection hook for selection state management ([275f401](https://github.com/antialias/soroban-abacus-flashcards/commit/275f401e3c25b75fec4700a8c2d4be6e33f0afe9))
* **rithmomachia:** add visual board examples to Capture section ([74bc3c0](https://github.com/antialias/soroban-abacus-flashcards/commit/74bc3c0dcf8d1ee7084e88a04861a85f9b623809))
* **rithmomachia:** add visual board examples to Harmony section ([1d5f01c](https://github.com/antialias/soroban-abacus-flashcards/commit/1d5f01c966cf1eec9a9c19ee37f1cad93c89df40))
* **rithmomachia:** add visual winning example to Victory section ([b7fac78](https://github.com/antialias/soroban-abacus-flashcards/commit/b7fac788292e00c6060a47fdbcca89a7e7fee35c))
* **rithmomachia:** auto-size tab labels with react-textfit ([9fd5406](https://github.com/antialias/soroban-abacus-flashcards/commit/9fd54067ce257e028b02f4784568ff3f2bbb32ca))
* **rithmomachia:** cycle through valid helpers with dynamic number tooltips ([4829e41](https://github.com/antialias/soroban-abacus-flashcards/commit/4829e41ea13fae2edec10837e65e505929445782))
* **rithmomachia:** enhance capture relation UI with smooth animations ([0a30801](https://github.com/antialias/soroban-abacus-flashcards/commit/0a308016e9d6a926c52dbfc5623b60b169d16d03))
* **rithmomachia:** enhance Harmony section with comprehensive content ([f555856](https://github.com/antialias/soroban-abacus-flashcards/commit/f5558563ea93ef7428aa220c2e15e3f02711420f))
* **rithmomachia:** enhance Pieces section with visual examples and pyramid details ([55aff82](https://github.com/antialias/soroban-abacus-flashcards/commit/55aff829f4c284e8cfe6d471c0821575928b93bc))
* **rithmomachia:** enhance Pyramid section with comprehensive details ([9fde1ef](https://github.com/antialias/soroban-abacus-flashcards/commit/9fde1ef9e703e26b2450128155b53fdf2d2e1fe5))
* **rithmomachia:** guide defaults to docked right on open ([11f674d](https://github.com/antialias/soroban-abacus-flashcards/commit/11f674d542ea5e4e88bd60ff1068451805d9766e))
* **rithmomachia:** improve guide pieces section layout ([a270bfc](https://github.com/antialias/soroban-abacus-flashcards/commit/a270bfc0cc4a3b6b54ba43a5af14a227cc7d29f9))
* **rithmomachia:** improve guide UX and add persistence ([b314740](https://github.com/antialias/soroban-abacus-flashcards/commit/b31474069734350a7059cd7c73255a7e11b78eb9))
* **rithmomachia:** improve roster status notice UX ([e27df45](https://github.com/antialias/soroban-abacus-flashcards/commit/e27df45256147f958ca215f9dd1f4e133e8cf06c))
* **rithmomachia:** integrate roster warning into game nav ([8a11594](https://github.com/antialias/soroban-abacus-flashcards/commit/8a11594203fb91faee6cbc4cb74367164ecd6d85))
* **rithmomachia:** make guide modal ultra-responsive down to 150px width ([0474197](https://github.com/antialias/soroban-abacus-flashcards/commit/04741971b296976f4476ecd949e84066fc549010))
* **rithmomachia:** recreate original guide modal header layout ([2489695](https://github.com/antialias/soroban-abacus-flashcards/commit/24896957d0817758c5f64c0e3473e6a0a343af67))
* **rithmomachia:** show capture error on hover instead of click ([339b678](https://github.com/antialias/soroban-abacus-flashcards/commit/339b6780f657ace5bfe1611c4ef64bb0c2c31587))
* **rithmomachia:** show pyramid face numbers on hover instead of selection ([b0c4523](https://github.com/antialias/soroban-abacus-flashcards/commit/b0c4523c0b4669c96a50b2812ba6cb2faa3f9a22))
* **rithmomachia:** show pyramid face numbers when selected ([5c186f3](https://github.com/antialias/soroban-abacus-flashcards/commit/5c186f3947cc38f1f5db5de3e68e590b90c2d092))
* **rithmomachia:** show pyramid face numbers when selected with subtle animation ([5c2ddbe](https://github.com/antialias/soroban-abacus-flashcards/commit/5c2ddbef05d7f4195d21b084cb1c0c4193ee3c9c))
* **rithmomachia:** show real preview layout when dragging guide to dock ([17d2460](https://github.com/antialias/soroban-abacus-flashcards/commit/17d2460a8769a21d33fabc5f909cf5b939712d36))
* **rithmomachia:** simplify guide language for clarity ([85cb630](https://github.com/antialias/soroban-abacus-flashcards/commit/85cb630add395a6693ecbbe9c8fc6aaf8c47be29))
* **rithmomachia:** skip helper selection UI and auto-select first valid helper ([be2a00e](https://github.com/antialias/soroban-abacus-flashcards/commit/be2a00e8b366b5606525309b4c7813f5c35c7f7c))
* **rithmomachia:** Update harmony system to classical three-piece proportions ([08c9762](https://github.com/antialias/soroban-abacus-flashcards/commit/08c97620f5e694b8526c448c44d265e6dd1fe1eb))
* **rithmomachia:** Update to traditional board setup with 25 pieces per side ([0769eaa](https://github.com/antialias/soroban-abacus-flashcards/commit/0769eaaa1dc238b901e3a7cfe0486e6122d5eda9))
* **rithmomachia:** use actual piece SVGs in number bond with 2.5s rotation animation ([976a7de](https://github.com/antialias/soroban-abacus-flashcards/commit/976a7de949c22842f4b6da3ced990f502a1c2733))
* **room-share:** add QR code button for easy mobile joining ([349290a](https://github.com/antialias/soroban-abacus-flashcards/commit/349290ac6a411651686b64d2e6b540083d2df1d9))
* show rithmomachia turn in nav ([7c89bfe](https://github.com/antialias/soroban-abacus-flashcards/commit/7c89bfef9c60db0e2c46e920500dcc1fbe90d3df))
* switch to royal color theme with transparent background ([944ad65](https://github.com/antialias/soroban-abacus-flashcards/commit/944ad6574e01a67ce1fdbb1f2452fe632c78ce43)), closes [#fbbf24](https://github.com/antialias/soroban-abacus-flashcards/issues/fbbf24) [#f59e0](https://github.com/antialias/soroban-abacus-flashcards/issues/f59e0) [#a855f7](https://github.com/antialias/soroban-abacus-flashcards/issues/a855f7) [#7e22](https://github.com/antialias/soroban-abacus-flashcards/issues/7e22)
* **web:** add test page for AbacusStatic RSC compatibility ([903dea2](https://github.com/antialias/soroban-abacus-flashcards/commit/903dea25844f1d2b3730fbcbd8478e7af1887663))
* **web:** add test page for AbacusStatic Server Component ([3588d5a](https://github.com/antialias/soroban-abacus-flashcards/commit/3588d5acde25588ce4db3ee32adb04ace0e394d4))
* **web:** add Typst-based preview endpoint with React Suspense ([599a758](https://github.com/antialias/soroban-abacus-flashcards/commit/599a758471c43ab0fc87301c5e7eeceed608062e))
* **web:** add year abacus to calendar header and make grid bolder ([867c7ee](https://github.com/antialias/soroban-abacus-flashcards/commit/867c7ee17251b8df13665bee9c0391961975e681)), closes [#333](https://github.com/antialias/soroban-abacus-flashcards/issues/333)
* **web:** improve calendar abacus preview styling ([8439727](https://github.com/antialias/soroban-abacus-flashcards/commit/8439727b152accf61f0c28158b92788510ca086e))
* **web:** optimize monthly calendar for single-page layout ([b277a89](https://github.com/antialias/soroban-abacus-flashcards/commit/b277a89415d1823455376c3e0f641b52f3394e7c))
* **web:** redesign monthly calendar as single composite SVG ([8ce8038](https://github.com/antialias/soroban-abacus-flashcards/commit/8ce8038baeea0b8b0fffe3215746958731bd9d6a))
### Bug Fixes
* **abacus-react:** add data-testid attributes back to beads for testing ([23ae1b0](https://github.com/antialias/soroban-abacus-flashcards/commit/23ae1b0c6f878daf79a993992d43ad80a89fa790))
* **abacus-react:** correct column highlighting offset in AbacusStatic ([0641eb7](https://github.com/antialias/soroban-abacus-flashcards/commit/0641eb719ef56c67de965296006df666f83e5b08))
* **abacus-react:** fix animations by preventing component remounting ([be7d4c4](https://github.com/antialias/soroban-abacus-flashcards/commit/be7d4c471327534a95c4c75372680c629b5f12c2))
* **abacus-react:** restore original AbacusReact measurements and positioning ([88c0baa](https://github.com/antialias/soroban-abacus-flashcards/commit/88c0baaad9b83b60ab8cdcad92070cc049d61cc7))
* add xmlns to AbacusStatic for Typst SVG parsing ([98cd019](https://github.com/antialias/soroban-abacus-flashcards/commit/98cd019d4af91d7ca4e7a88f700194273476afb7))
* adjust hero abacus position to avoid covering subtitle ([f03d341](https://github.com/antialias/soroban-abacus-flashcards/commit/f03d3413145cc7ddfba93728ecdec7eabea9ada6))
* **arcade:** add automatic retry for version conflict rejections ([fbcde25](https://github.com/antialias/soroban-abacus-flashcards/commit/fbcde2505f7ff2bf3426f3458e480c4548314ba4))
* **arcade:** allow deactivating players from users who left the room ([7c1c2d7](https://github.com/antialias/soroban-abacus-flashcards/commit/7c1c2d7bebbb9a1acb274d17dd43b6ee5d196f44))
* **arcade:** implement optimistic locking in session manager ([71fd66d](https://github.com/antialias/soroban-abacus-flashcards/commit/71fd66d96a3b03650c90f59f6e516aae7dddc345))
* board rotation now properly fills height in portrait mode ([b5a96ea](https://github.com/antialias/soroban-abacus-flashcards/commit/b5a96eaeb1e29c20304142a7a0adf62f1cef570f))
* **card-sorting:** add border radius to outer card container ([a922eba](https://github.com/antialias/soroban-abacus-flashcards/commit/a922eba73c4656ee941ce4dfb1dc57a62f076570))
* **card-sorting:** add debug logging for spring animations ([d42947e](https://github.com/antialias/soroban-abacus-flashcards/commit/d42947eb8d5d3d8298f5d3b3d1644891c268dbb6))
* **card-sorting:** add missing gameMode support after hard reset ([a832325](https://github.com/antialias/soroban-abacus-flashcards/commit/a832325debde289d6928c5e6f9c24311c5e079ad))
* **card-sorting:** add missing useMemo import ([949d76d](https://github.com/antialias/soroban-abacus-flashcards/commit/949d76d844c786ada8a6373e4abb7f498f6befb9))
* **card-sorting:** add overflow hidden to clip rounded corners ([84c66fe](https://github.com/antialias/soroban-abacus-flashcards/commit/84c66feec6b4112b015e1afd95bf33b24b5f6a4f))
* **card-sorting:** adjust connecting paths for scaled cards ([829c741](https://github.com/antialias/soroban-abacus-flashcards/commit/829c741e554d1490dd7a5bbc17f2a32f7195dc07))
* **card-sorting:** adjust game board for spectator panels ([fc5cf12](https://github.com/antialias/soroban-abacus-flashcards/commit/fc5cf1216fe03edfb7e44afda01192f4b97b4f4e))
* **card-sorting:** adjust viewport dimensions for spectator panels ([4dce16c](https://github.com/antialias/soroban-abacus-flashcards/commit/4dce16cca46c965199b7e09f8b34bfa221efac33))
* **card-sorting:** animate cards from game board to results grid ([17d45fe](https://github.com/antialias/soroban-abacus-flashcards/commit/17d45fe88cd9773f5e550f6ee5a7f0c82cca2023))
* **card-sorting:** correct suffix card detection in auto-arrange ([d02ab59](https://github.com/antialias/soroban-abacus-flashcards/commit/d02ab5922c416042d525f54097a6975ae1541586))
* **card-sorting:** enable card scaling for spectators ([6b095c3](https://github.com/antialias/soroban-abacus-flashcards/commit/6b095c33830341c46139bc847ddaab3db632265e))
* **card-sorting:** enable New Game button during active gameplay ([f3f6eca](https://github.com/antialias/soroban-abacus-flashcards/commit/f3f6eca1db30df9e1e34cc4e77a069a6a3954f3d))
* **card-sorting:** end drag immediately when card becomes locked ([ae45298](https://github.com/antialias/soroban-abacus-flashcards/commit/ae45298ec48efb29587c0a1c1a7986a72821f3ef))
* **card-sorting:** filter local player from emoji overlays on dragged cards ([dc2d94a](https://github.com/antialias/soroban-abacus-flashcards/commit/dc2d94aaa58531ed4f9047e2ca92724d9264643d))
* **card-sorting:** fix results panel layout to not cover cards ([4b4fbfe](https://github.com/antialias/soroban-abacus-flashcards/commit/4b4fbfef322ecda06020ad52d4b1788267112460))
* **card-sorting:** hide activity notifications in spectator mode ([5cca279](https://github.com/antialias/soroban-abacus-flashcards/commit/5cca279687d8973d25bd9a411a55b632d1c82f63))
* **card-sorting:** keep arrow sequence numbers upright ([79c9469](https://github.com/antialias/soroban-abacus-flashcards/commit/79c94699fa1cc2a2886e3ab1addc5fcd975602f5))
* **card-sorting:** lock correctly positioned prefix/suffix cards ([170abed](https://github.com/antialias/soroban-abacus-flashcards/commit/170abed2318432f309de40692f6092bb4c4a1a45))
* **card-sorting:** lock spring positions after initial animation completes ([275cc62](https://github.com/antialias/soroban-abacus-flashcards/commit/275cc62a523d9e849f2162001141b6d75ae0925e))
* **card-sorting:** New Game now restarts with same settings instantly ([f3687ed](https://github.com/antialias/soroban-abacus-flashcards/commit/f3687ed236eff4ebe61699ec02909024c7086fb5))
* **card-sorting:** only shrink/fade cards in correct prefix ([51368c6](https://github.com/antialias/soroban-abacus-flashcards/commit/51368c6ec59d5447ce2875c5e1181dec97fd509d))
* **card-sorting:** preserve card positions on pause/resume ([0d8af09](https://github.com/antialias/soroban-abacus-flashcards/commit/0d8af09517534f1e1cf1f57160391d465a279d76))
* **card-sorting:** preserve rotation when starting drag ([3364144](https://github.com/antialias/soroban-abacus-flashcards/commit/3364144fb6212934b6ad6d63ac6e7b78b436b258))
* **card-sorting:** prevent duplicate START_GAME moves on Play Again ([a0b14f8](https://github.com/antialias/soroban-abacus-flashcards/commit/a0b14f87e9c5b32fcbb685da4e70c563f70ed91a))
* **card-sorting:** prevent ghost movements with proper optimistic updates ([bd014be](https://github.com/antialias/soroban-abacus-flashcards/commit/bd014bec4ffa12bcd8f4a4e84ff51203c90c1f1d))
* **card-sorting:** prevent infinite loop when all cards are correct ([34785f4](https://github.com/antialias/soroban-abacus-flashcards/commit/34785f466faaa6b9f2958df786af88561fa80b06))
* **card-sorting:** prevent infinite loop with tolerance-based position comparison ([627b873](https://github.com/antialias/soroban-abacus-flashcards/commit/627b873382eaa76ad16477280d10451cf2951e1a))
* **card-sorting:** prevent position jump when clicking rotated cards ([564a00f](https://github.com/antialias/soroban-abacus-flashcards/commit/564a00f82b6ca6aa8a2c0586ca49fc42d44991a8))
* **card-sorting:** prevent replaying own movements from server ([308168a](https://github.com/antialias/soroban-abacus-flashcards/commit/308168a7fb51013b0851e98b161ba1a1a3e39fbb))
* **card-sorting:** prevent springs from reinitializing on window resize ([30953b8](https://github.com/antialias/soroban-abacus-flashcards/commit/30953b8c4a3cf147f980455818f9ce8eea07837c))
* **card-sorting:** prevent springs from resetting after animation ([8aff60c](https://github.com/antialias/soroban-abacus-flashcards/commit/8aff60ce3f8d302ce5c1bde7cb773e63064c36b7))
* **card-sorting:** remove hasAnimatedRef logic causing backwards animation ([a44aa5a](https://github.com/antialias/soroban-abacus-flashcards/commit/a44aa5a4c2d84cab7cf0bbf87485bb61548fdeb2))
* **card-sorting:** remove remaining reveal numbers references ([15c53ea](https://github.com/antialias/soroban-abacus-flashcards/commit/15c53ea4eb4abb824eb0360fb645b1f3e455578e))
* **card-sorting:** restore prefix/suffix card shrinking visual feedback ([f5fb4d7](https://github.com/antialias/soroban-abacus-flashcards/commit/f5fb4d7b76e25286bcdecd017894ff2d78b31963))
* **card-sorting:** show only active players in team members section ([fa9f1a5](https://github.com/antialias/soroban-abacus-flashcards/commit/fa9f1a568f3dff2f4e5e7d3e8841b951ef1b7d04))
* **card-sorting:** smooth scale animation while dragging cards ([0eefc33](https://github.com/antialias/soroban-abacus-flashcards/commit/0eefc332ac2724c54b477301a269915e895db94f))
* **card-sorting:** stabilize inferred sequence for locked cards during drag ([b0cd194](https://github.com/antialias/soroban-abacus-flashcards/commit/b0cd194838705bb7bbf21ac9e318eaba491097b2))
* **card-sorting:** use empty deps array for useSprings to prevent recreation ([cee399e](https://github.com/antialias/soroban-abacus-flashcards/commit/cee399ed1513d32d0fff51a6f63898aa861605e1))
* **card-sorting:** use ref to track initialized state and prevent re-animation ([f389afa](https://github.com/antialias/soroban-abacus-flashcards/commit/f389afa831935e896a626f526cfee378e340a64b))
* **card-sorting:** use same coordinate system for game board and results ([6972fdf](https://github.com/antialias/soroban-abacus-flashcards/commit/6972fdf1105b6e854494efe1c4c587e6b6ff32a9))
* **complement-race:** prevent delivery move thrashing in steam sprint mode ([e1258ee](https://github.com/antialias/soroban-abacus-flashcards/commit/e1258ee0416010909774694c0b25306b6f30329c))
* configure favicon metadata and improve bead visibility ([e1369fa](https://github.com/antialias/soroban-abacus-flashcards/commit/e1369fa2754cd61745a2950e6cb767d6b08db38f))
* copy entire packages/core and packages/templates ([0ccada0](https://github.com/antialias/soroban-abacus-flashcards/commit/0ccada0ca783e635f9ae08f33a69c392018ee342))
* correct hero abacus scroll direction to flow with page content ([4232746](https://github.com/antialias/soroban-abacus-flashcards/commit/423274657c9698bba28f7246fbf48d8508d97ef9))
* correct Typst template path in Dockerfile ([4c518de](https://github.com/antialias/soroban-abacus-flashcards/commit/4c518decb7fcc0b519d07680cbfd01c94c23dd41))
* delete existing user sessions before creating new ones ([0cced47](https://github.com/antialias/soroban-abacus-flashcards/commit/0cced47a0f414a04371bdb253fc5a43e4d9557be))
* **docker:** add scripts, abacus-react, and tsx for production calendar generation ([33eb90e](https://github.com/antialias/soroban-abacus-flashcards/commit/33eb90e316f84650ae619f8c6c02c9e77c663d1b))
* **docker:** upgrade OpenSCAD to 2024.11 to fix CGAL intersection bug ([e1bcd24](https://github.com/antialias/soroban-abacus-flashcards/commit/e1bcd241691050fa05cd49e14c288b4b070a7d17))
* extract pure SVG content from AbacusReact renders ([b07f1c4](https://github.com/antialias/soroban-abacus-flashcards/commit/b07f1c421616bcfd1f949f9a42ce1b03df418945))
* **games:** prevent horizontal page scroll from carousel overflow ([5a8c98f](https://github.com/antialias/soroban-abacus-flashcards/commit/5a8c98fc10704e459690308a84dc7ee2bfa0ef6c))
* **games:** smooth scroll feel for carousel wheel navigation ([f80a73b](https://github.com/antialias/soroban-abacus-flashcards/commit/f80a73b35c324959bfd7141ebf086cb47d3c0ebc))
* **games:** use specific transition properties for smooth carousel loop ([187271e](https://github.com/antialias/soroban-abacus-flashcards/commit/187271e51527ee0129f71d77be1bd24072b963c4))
* **guide:** increase abacus sizes - they were too small ([1074624](https://github.com/antialias/soroban-abacus-flashcards/commit/1074624b2fbce1d1d887dbd6326cf22eeb31dcec))
* **guide:** make abacus sizes consistent and add nav spacing ([bea4842](https://github.com/antialias/soroban-abacus-flashcards/commit/bea4842a29aa86ca4261b4ddd6150bacc8babc46))
* **guide:** remove inner containers and tighten margins ([7e54c6f](https://github.com/antialias/soroban-abacus-flashcards/commit/7e54c6f4fc5bc4daa6088eb3381d860a495776f2))
* **i18n:** eliminate FOUC by loading messages server-side ([4d4d930](https://github.com/antialias/soroban-abacus-flashcards/commit/4d4d930bd307ce5a405fc5751af6682a9f221f1f))
* **i18n:** use useMessages() for tutorial translations ([95b0105](https://github.com/antialias/soroban-abacus-flashcards/commit/95b0105ca3b28c5adfa843e8d77a8b27d9e7ade4))
* include column posts in favicon bounding box ([0b2f481](https://github.com/antialias/soroban-abacus-flashcards/commit/0b2f48106a939307b728c86fe2ea1be1e0247ea8))
* increase server update debounce to 2000ms for low bandwidth ([633ff12](https://github.com/antialias/soroban-abacus-flashcards/commit/633ff127500c893a215491afa0e6ff814ad553bf))
* Integrate threshold input into Point Victory card ([b29bbee](https://github.com/antialias/soroban-abacus-flashcards/commit/b29bbeefcad92be42f7a3ca27ac126db4232ab26))
* **layout:** add systematic spacing for fixed nav bar ([4559fb1](https://github.com/antialias/soroban-abacus-flashcards/commit/4559fb121d0df954ebaf33616a5262c7ca633c6e))
* **layout:** remove wrapper, use utility class for nav spacing ([247c3d9](https://github.com/antialias/soroban-abacus-flashcards/commit/247c3d9874303f83641e599724a485eea8d5604a))
* mark dynamic routes as force-dynamic to prevent static generation errors ([d7b35d9](https://github.com/antialias/soroban-abacus-flashcards/commit/d7b35d954421fd7577cd2c26247666e5953b647d))
* **nav:** restrict transparent hero styling to home page only ([fab227d](https://github.com/antialias/soroban-abacus-flashcards/commit/fab227d6862672e8250b1c169b302fbae23ce4d2))
* **nav:** show full navigation on /games page ([d3fe6ac](https://github.com/antialias/soroban-abacus-flashcards/commit/d3fe6acbb0390e1df71869a4095e5ee6021e06b1))
* **qr-button:** improve layout and z-index ([646a422](https://github.com/antialias/soroban-abacus-flashcards/commit/646a4228d0573796b1a429e31bc037411024c0ff))
* **qr-button:** increase mini QR code size to 80px ([61ac737](https://github.com/antialias/soroban-abacus-flashcards/commit/61ac7378bdb01132b26bfc265a057c095ea41606))
* **qr-button:** increase mini QR code to 84px ([3fae5ea](https://github.com/antialias/soroban-abacus-flashcards/commit/3fae5ea6fa9ebd0f8fe8c9140a027be7f6a041aa))
* **qr-button:** make button square and increase QR size ([dc2d466](https://github.com/antialias/soroban-abacus-flashcards/commit/dc2d46663b8e0ec94a1508a57c4f8c2d8ba03506))
* **qr-button:** match height of stacked buttons ([81f202d](https://github.com/antialias/soroban-abacus-flashcards/commit/81f202d21556aa430402fda814519adbc8883831))
* reduce padding to minimize gap below last bead ([0e529be](https://github.com/antialias/soroban-abacus-flashcards/commit/0e529be789caf16e73f3e2ee77f52e243841aef4))
* remove distracting parallax and wobble 3D effects ([28a2d40](https://github.com/antialias/soroban-abacus-flashcards/commit/28a2d40996256700bf19cd80130b26e24441949f))
* remove wobble physics and enhance wood grain visibility ([5d97673](https://github.com/antialias/soroban-abacus-flashcards/commit/5d976734062eb3d943bfdfdd125473c56b533759))
* replace regex HTML parsing with deterministic bead position calculations in icon generation ([41a3707](https://github.com/antialias/soroban-abacus-flashcards/commit/41a3707841595a74de56c6adf6d271237f81ee0e))
* resolve z-index layering and hero abacus visibility issues ([ed9a050](https://github.com/antialias/soroban-abacus-flashcards/commit/ed9a050d64db905e1328008f25dc0014e9a81999))
* rewrite 3D stories to use props instead of CSS wrappers ([26bdb11](https://github.com/antialias/soroban-abacus-flashcards/commit/26bdb112370cece08634e3d693d15336111fc70f))
* **rithmomachia:** add missing i18next dependencies ([91154d9](https://github.com/antialias/soroban-abacus-flashcards/commit/91154d93647e59f7e5f96d1db5624a7ec9b1b9ff))
* **rithmomachia:** add missing pyramid section keys to Japanese (ja.json) ([dae615e](https://github.com/antialias/soroban-abacus-flashcards/commit/dae615ee72a7ec7d0b235a22c61ebc4af0d8eadb))
* **rithmomachia:** adjust error dialog sizing to prevent text clipping ([cda1126](https://github.com/antialias/soroban-abacus-flashcards/commit/cda1126cb0eab6840df89f3a8778d72410298093))
* **rithmomachia:** adjust roster notice position to not overlap nav ([7093223](https://github.com/antialias/soroban-abacus-flashcards/commit/709322373a91c8174d21052d184fa84dd8bda326))
* **rithmomachia:** change undock icon to pop-out arrow ([2a91748](https://github.com/antialias/soroban-abacus-flashcards/commit/2a917484938bc269cf16acb501d4d26584405e0f))
* **rithmomachia:** correct board dimensions to 16x8 and restore original layout values ([cfac277](https://github.com/antialias/soroban-abacus-flashcards/commit/cfac27750526fb1f6a7e4314a96aab3b92e08e44))
* **rithmomachia:** Correct board setup to match reference image exactly ([618e563](https://github.com/antialias/soroban-abacus-flashcards/commit/618e56358deb66cba968472f39b8d4e28b4dd211))
* **rithmomachia:** correct makeMove parameter types for capture handling ([aafb64f](https://github.com/antialias/soroban-abacus-flashcards/commit/aafb64f3e337c6cf925766fe179b91f66c4a040b))
* **rithmomachia:** fix guide modal resize drift by calculating from initial state ([1bcd99c](https://github.com/antialias/soroban-abacus-flashcards/commit/1bcd99c949e4d2b4fb1c0813debd50176fa58cb9))
* **rithmomachia:** fix harmony section translation structure for hi/ja/es ([14259a1](https://github.com/antialias/soroban-abacus-flashcards/commit/14259a19a9817d0947467faa004d5f43118f8d8d))
* **rithmomachia:** fix modal resizing zoom issue ([4fa20f4](https://github.com/antialias/soroban-abacus-flashcards/commit/4fa20f44cb9758f29d1f1512232be0fdc0b53b3d))
* **rithmomachia:** Fix TypeScript errors in playing guide modal ([4834ece](https://github.com/antialias/soroban-abacus-flashcards/commit/4834ece98e86f2fb00511bb876a5c32c289df0e0))
* **rithmomachia:** handle pyramid pieces in hover error tooltip ([56f3164](https://github.com/antialias/soroban-abacus-flashcards/commit/56f3164155beb94ceec2838bed9fc74fd75524db))
* **rithmomachia:** implement proper board cropping and highlighting in guide ([d0a8fcd](https://github.com/antialias/soroban-abacus-flashcards/commit/d0a8fcdea6aa4fdacfee33e183c92923634ee2b7))
* **rithmomachia:** improve guide modal tab navigation at narrow widths ([a673177](https://github.com/antialias/soroban-abacus-flashcards/commit/a673177bec1c709463ce0f266848f473a79f4ef0))
* **rithmomachia:** reconnect player assignment UI and fix setup layout ([a1a0374](https://github.com/antialias/soroban-abacus-flashcards/commit/a1a0374fac5dce676df5890663b75531589ed93a))
* **rithmomachia:** render guide as docked in preview panel ([190f8cf](https://github.com/antialias/soroban-abacus-flashcards/commit/190f8cf302aa966f029d05931811e217c67bfe39))
* **rithmomachia:** show actual values in tooltips for non-helper relations ([774c6b0](https://github.com/antialias/soroban-abacus-flashcards/commit/774c6b0ce712b1a77bb684457da9831e6ec91138))
* **rithmomachia:** show guest-friendly message when they can't fix too many players ([54bfd2f](https://github.com/antialias/soroban-abacus-flashcards/commit/54bfd2fac86be3597d40c67a1235e4c4ed8e2709))
* **rithmomachia:** smooth guide dragging from docked state without jump ([8f4a79c](https://github.com/antialias/soroban-abacus-flashcards/commit/8f4a79c9b0cad55336584fdc8e67409015d3a8ae))
* **rithmomachia:** validate move path before showing capture error on hover ([bd49964](https://github.com/antialias/soroban-abacus-flashcards/commit/bd49964186a0daa1639ae849b128a76081643daf))
* **room-info:** hide Leave Room button when user is alone ([5927f61](https://github.com/antialias/soroban-abacus-flashcards/commit/5927f61c3c34ba583ee45c8cee48a116c1c03071))
* separate horizontal and vertical bounding box logic ([83090df](https://github.com/antialias/soroban-abacus-flashcards/commit/83090df4dfad1d1d5cfa6c278c241526cacc7972))
* tolerate OpenSCAD CGAL warnings if output file is created ([88993f3](https://github.com/antialias/soroban-abacus-flashcards/commit/88993f36629206a7bdcf9aa9d5641f1580b64de5))
* **tutorial:** correct column validation for bead highlights ([9ba1824](https://github.com/antialias/soroban-abacus-flashcards/commit/9ba18242262cd63cc6c25361aaec3a4c0f66b161))
* **tutorial:** fix overlay rendering, arrow indicators, and bead visibility ([a804316](https://github.com/antialias/soroban-abacus-flashcards/commit/a80431608dbc4f54d8e4f1095936b95a258b4a72))
* use absolute positioning for hero abacus to eliminate scroll lag ([096104b](https://github.com/antialias/soroban-abacus-flashcards/commit/096104b094b45aa584f2b9d47a440a8c14d82fc0))
* use Debian base for deps stage to match runner for binary compatibility ([f8fe6e4](https://github.com/antialias/soroban-abacus-flashcards/commit/f8fe6e4a415f8655626af567129d0cda61b82e15))
* use default BOSL2 branch instead of non-existent v2.0.0 tag ([f4ffc5b](https://github.com/antialias/soroban-abacus-flashcards/commit/f4ffc5b0277535358bea7588309a1a4afd1983a1))
* use nested SVG viewBox for actual cropping, not just scaling ([440b492](https://github.com/antialias/soroban-abacus-flashcards/commit/440b492e85beff1612697346b6c5cfc8461e83da))
* various game improvements and UI enhancements ([b67cf61](https://github.com/antialias/soroban-abacus-flashcards/commit/b67cf610c570d54744553cd8f6694243fa50bee1))
* **web,docker:** add --format flag for Typst and upgrade to v0.13.0 ([19b9d7a](https://github.com/antialias/soroban-abacus-flashcards/commit/19b9d7a74f549c7e93c9564e4a903e1bcd5a4bbc))
* **web:** add dynamic export to rithmomachia page ([329e623](https://github.com/antialias/soroban-abacus-flashcards/commit/329e62321245ef62726c986c917f19a909a5b65e))
* **web:** fix Typst PDF generation path resolution ([7ce1287](https://github.com/antialias/soroban-abacus-flashcards/commit/7ce12875254a31d8acdb35ef5de7d36d215ccd92))
* **web:** generate styled-system artifacts during build ([293390a](https://github.com/antialias/soroban-abacus-flashcards/commit/293390ae350a6c6aa467410f68c735512104d9dd))
* **web:** move react-dom/server import to API route to satisfy Next.js ([00a8bc3](https://github.com/antialias/soroban-abacus-flashcards/commit/00a8bc3e5e8f044df280c4356d3605a852f82e84))
* **web:** move tsx to production dependencies for calendar generation ([ffae9c1](https://github.com/antialias/soroban-abacus-flashcards/commit/ffae9c1bdbccc5edb2e747a09d1fcad3b29e4eac))
* **web:** prevent abacus overlap in composite calendar ([448f93c](https://github.com/antialias/soroban-abacus-flashcards/commit/448f93c1e2a7f86bc48e678d4599ca968c6d81d2)), closes [#f0f0f0](https://github.com/antialias/soroban-abacus-flashcards/issues/f0f0f0)
* **web:** use AbacusStatic for calendar SVG generation ([08c6a41](https://github.com/antialias/soroban-abacus-flashcards/commit/08c6a419e25d220560eba13d6db437145e6e61b8))
* **web:** use dynamic import for react-dom/server in API route ([4f93c7d](https://github.com/antialias/soroban-abacus-flashcards/commit/4f93c7d996732de4bc19e7acf2d4ce803cba88b6))
* **web:** use nested SVG elements to prevent coordinate space conflicts ([f9cbee8](https://github.com/antialias/soroban-abacus-flashcards/commit/f9cbee8fcdf80641f3b82a65fad6b8a3575525fc))
### Performance Improvements
* optimize Docker image size to reduce build failures ([9ca3106](https://github.com/antialias/soroban-abacus-flashcards/commit/9ca310636183f4970db925ce8fa368e23645eb02))
### Code Refactoring
* **card-sorting:** remove reveal numbers feature ([ea5e3e8](https://github.com/antialias/soroban-abacus-flashcards/commit/ea5e3e838bd6a5b8b38469a70aa92a0e9baba769))
* **card-sorting:** send complete card sequence instead of individual moves ([e4df843](https://github.com/antialias/soroban-abacus-flashcards/commit/e4df8432b9c4a2055d47833d56b6e9fcf325ca94))
* **games:** implement carousel, fix victories bug, add conditional stats ([82c133f](https://github.com/antialias/soroban-abacus-flashcards/commit/82c133f742f3f5c40b723c18d1997b518f25b320))
* **games:** move page title to nav bar ([712ee58](https://github.com/antialias/soroban-abacus-flashcards/commit/712ee58e5956e5bbdb13d5a5fb367020c87c8c9a))
* **games:** remove redundant subtitle below nav ([ad5bb87](https://github.com/antialias/soroban-abacus-flashcards/commit/ad5bb87325a44825f0cd85b38eb0e5f0eea7a695))
* **games:** remove wheel scrolling, enable overflow visible carousel ([876513c](https://github.com/antialias/soroban-abacus-flashcards/commit/876513c9cc6323c20845ae8f1a3a5478d449f9e4))
* **layout:** make nav height truly self-referential ([9886302](https://github.com/antialias/soroban-abacus-flashcards/commit/98863026b789d09eecb0bc3e013d112889a5d038))
* remove debug console.log statements ([32f51ae](https://github.com/antialias/soroban-abacus-flashcards/commit/32f51ae739679789585182ba659ec5f1168d652d))
* reorganize Harmony and Victory guide sections ([fb629c4](https://github.com/antialias/soroban-abacus-flashcards/commit/fb629c44ea37a7b296561919a4980c10d14efed8))
* restructure /create page into hub with sub-pages ([b91b23d](https://github.com/antialias/soroban-abacus-flashcards/commit/b91b23d95ffaeeaa30dbc8579f4c30bae8829ee7))
* **rithmomachia:** extract board and capture components (phase 2+3) ([a0a867b](https://github.com/antialias/soroban-abacus-flashcards/commit/a0a867b27166a838ca7e0dcbd8f89fe1be812a80))
* **rithmomachia:** extract CaptureErrorDialog component (Phase 2 partial) ([f0a066d](https://github.com/antialias/soroban-abacus-flashcards/commit/f0a066d8f0a51d35e18f87a8436c0d05153c03b5))
* **rithmomachia:** extract constants and coordinate utilities (Phase 1) ([eace0ed](https://github.com/antialias/soroban-abacus-flashcards/commit/eace0ed52979b71870f77ee68f8568558f2aaecb))
* **rithmomachia:** extract guide sections into separate files ([765525d](https://github.com/antialias/soroban-abacus-flashcards/commit/765525dc451897f561f017e444aae892dc27177f))
* **rithmomachia:** extract hooks (phase 5) ([324a659](https://github.com/antialias/soroban-abacus-flashcards/commit/324a65992f97c295ea3968aaf54d266373f4c035))
* **rithmomachia:** extract phase components (phase 4) ([11364f6](https://github.com/antialias/soroban-abacus-flashcards/commit/11364f6394c15e49850e5cad2cbd32e1ea08a178))
* **rithmomachia:** extract reusable components from SetupPhase ([3abc325](https://github.com/antialias/soroban-abacus-flashcards/commit/3abc325ea27feee5c4cc59f02296ff218f342a81))
* **rithmomachia:** make setup phase UI more compact ([e55f848](https://github.com/antialias/soroban-abacus-flashcards/commit/e55f848a26092a2b4a5b09c3c255544ea9666f1b))
* **rithmomachia:** redesign error notification with modern UI ([dfeeb0e](https://github.com/antialias/soroban-abacus-flashcards/commit/dfeeb0e0db8b2c4a38198cf71cd918439d6c211b)), closes [#1e293](https://github.com/antialias/soroban-abacus-flashcards/issues/1e293) [#0f172](https://github.com/antialias/soroban-abacus-flashcards/issues/0f172) [#f1f5f9](https://github.com/antialias/soroban-abacus-flashcards/issues/f1f5f9)
* **rithmomachia:** simplify capture error dialog to one-liner ([82a5eb2](https://github.com/antialias/soroban-abacus-flashcards/commit/82a5eb2e4bf74f42a183a15f1129e5ec84cc5231))
* **rithmomachia:** Update board setup to authoritative CSV layout ([0471da5](https://github.com/antialias/soroban-abacus-flashcards/commit/0471da598d8d591b3f9d63f467cb35f999924c13))
* **rithmomachia:** update capture components to use CaptureContext ([2ab6ab5](https://github.com/antialias/soroban-abacus-flashcards/commit/2ab6ab57995a6d7d9c66b9fba8de945507209661))
* **rithmomachia:** use useBoardLayout and usePieceSelection in BoardDisplay ([0ab7a1d](https://github.com/antialias/soroban-abacus-flashcards/commit/0ab7a1df327d7258228af9851762555583a20d61))
* use AbacusReact for dynamic Open Graph image ([9c20f12](https://github.com/antialias/soroban-abacus-flashcards/commit/9c20f12bacff4fe7f8bd7a87032afbed9711e94b))
* **web:** import utility functions from abacus-react ([7228bbc](https://github.com/antialias/soroban-abacus-flashcards/commit/7228bbc2eb8b9b2b861d32b760b14895a1a7ee8a))
* **web:** move calendar generators to src/utils for proper compilation ([379698f](https://github.com/antialias/soroban-abacus-flashcards/commit/379698fea3fc8f04d716d35347749182d5c53b5c))
* **web:** return calendar SVG preview with PDF generation ([14a5de0](https://github.com/antialias/soroban-abacus-flashcards/commit/14a5de0dfadf423c646f4748b0de94f2483b18a1))
* **web:** use ABACUS_THEMES instead of manual style definitions ([9f7f001](https://github.com/antialias/soroban-abacus-flashcards/commit/9f7f001d747402b1578116e45c1a137519714314))
* **web:** use client-side React rendering for live calendar preview ([f880cbe](https://github.com/antialias/soroban-abacus-flashcards/commit/f880cbe4bffc898ae95d36d68615cf317d94012a))
* **web:** use compact prop for inline mini-abacus ([ff1d60a](https://github.com/antialias/soroban-abacus-flashcards/commit/ff1d60a23387d22e7ed44185dc3a8c895b7c0d12))
* **web:** use direct function imports instead of execSync for calendar generation ([9f1715f](https://github.com/antialias/soroban-abacus-flashcards/commit/9f1715f0856bcd125a79014c0c8c854c1c7b3f4d))
* **web:** use stdin/stdout for Typst compilation ([06f68cc](https://github.com/antialias/soroban-abacus-flashcards/commit/06f68cc74c31b54284808beadf67f4db08d03420))
### Documentation
* **abacus-react:** add Storybook stories for AbacusStatic ([4f9dc46](https://github.com/antialias/soroban-abacus-flashcards/commit/4f9dc4666d249c1c67c51a3901c4f657ff9723ef))
* **abacus-react:** add Storybook stories for new features ([6a1cec0](https://github.com/antialias/soroban-abacus-flashcards/commit/6a1cec06a75575cb35ddca5ef573aaf13c2352f4))
* **abacus-react:** export AbacusStatic and update README ([74f2d97](https://github.com/antialias/soroban-abacus-flashcards/commit/74f2d97434620cb8c7d49912bca3bf386408a16d))
* **abacus-react:** update documentation for new features ([35d8734](https://github.com/antialias/soroban-abacus-flashcards/commit/35d8734a3a9124564957444d3642c9e7c4348fac))
* **abacus-react:** update README with /static import path for RSC ([72a4c2b](https://github.com/antialias/soroban-abacus-flashcards/commit/72a4c2b80c1158a6eaf21abe4e807ff6e70373ac))
* add 3D enhancement documentation to README ([cc96802](https://github.com/antialias/soroban-abacus-flashcards/commit/cc96802df87c805c946ee59af509663ba570e75b))
* add critical section on never adding tsx to production dependencies ([770cfc3](https://github.com/antialias/soroban-abacus-flashcards/commit/770cfc3aca296b4f52c822710a1072fe501a0f49))
* add database migration guide and playing guide modal spec ([5a29af7](https://github.com/antialias/soroban-abacus-flashcards/commit/5a29af78e27e897ab35273611b79c4b669304f71))
* add deployment verification guidelines to prevent false positives ([3d8da23](https://github.com/antialias/soroban-abacus-flashcards/commit/3d8da2348b4e8a227e963791d15dc6718eac5af1))
* **card-sorting:** add comprehensive multiplayer plan ([008ccea](https://github.com/antialias/soroban-abacus-flashcards/commit/008ccead0f9c634fe52fd156e6f9a04d6cdd7744))
* clarify dev server management in Claude Code instructions ([e08fdfd](https://github.com/antialias/soroban-abacus-flashcards/commit/e08fdfd676b51a9fed23bda336b13f5e1d40b96c))
* **rithmomachia:** Add concise one-page playing guide ([e3c1f10](https://github.com/antialias/soroban-abacus-flashcards/commit/e3c1f10233cc0924ff96a643c7c4c1f1278de3e3))
* update workflow to require manual testing before commits ([0991796](https://github.com/antialias/soroban-abacus-flashcards/commit/0991796f1eccef345f10205e675e4c33d1a62b17))
### Styles
* **rithmomachia:** improve divider styling and make tabs responsive ([88ca35e](https://github.com/antialias/soroban-abacus-flashcards/commit/88ca35e0440157ff9349e8d3d2d3cc844f18ffea)), closes [#e5e7](https://github.com/antialias/soroban-abacus-flashcards/issues/e5e7) [#9ca3](https://github.com/antialias/soroban-abacus-flashcards/issues/9ca3)
* **rithmomachia:** improve pyramid face numbers visibility and contrast ([94e5e6a](https://github.com/antialias/soroban-abacus-flashcards/commit/94e5e6a268b387380b88b192737bd55578b98bc7)), closes [#fbbf24](https://github.com/antialias/soroban-abacus-flashcards/issues/fbbf24) [#b45309](https://github.com/antialias/soroban-abacus-flashcards/issues/b45309)
* **rithmomachia:** increase pyramid face numbers size and boldness ([7bf2d73](https://github.com/antialias/soroban-abacus-flashcards/commit/7bf2d730d370e562486b229f4d209099ff8c4463))
### Tests
* trigger compose-updater deployment test ([2b06aae](https://github.com/antialias/soroban-abacus-flashcards/commit/2b06aae39474cc80d501c47c9685fa99e7120c48))
* verify compose-updater automatic deployment cycle ([af0552c](https://github.com/antialias/soroban-abacus-flashcards/commit/af0552ccd98f7b5a62d6e4074b7d87b3716af698))
## [4.68.0](https://github.com/antialias/soroban-abacus-flashcards/compare/v4.67.1...v4.68.0) (2025-11-05)
### Features
* **3d-abacus:** change default columns from 13 to 4 ([cd15c70](https://github.com/antialias/soroban-abacus-flashcards/commit/cd15c70a25c597c17ee5d2f816b1c85ba8ce4ce9))

View File

@@ -8,7 +8,13 @@
import React from 'react'
import { renderToStaticMarkup } from 'react-dom/server'
import { AbacusReact } from '@soroban/abacus-react'
import {
AbacusReact,
numberToAbacusState,
calculateStandardDimensions,
calculateBeadPosition,
type BeadPositionConfig,
} from '@soroban/abacus-react'
// Extract just the SVG element content from rendered output
function extractSvgContent(markup: string): string {
@@ -27,50 +33,88 @@ interface BoundingBox {
maxY: number
}
/**
* Calculate bounding box for icon cropping using actual bead position calculations
* This replaces fragile regex parsing with deterministic position math
*/
function getAbacusBoundingBox(
svgContent: string,
day: number,
scaleFactor: number,
columns: number
): BoundingBox {
// Parse column posts: <rect x="..." y="..." width="..." height="..." ... >
const postRegex = /<rect\s+x="([^"]+)"\s+y="([^"]+)"\s+width="([^"]+)"\s+height="([^"]+)"/g
const postMatches = [...svgContent.matchAll(postRegex)]
// Get which beads are active for this day
const abacusState = numberToAbacusState(day, columns)
// Parse active bead transforms: <g class="abacus-bead active" transform="translate(x, y)">
const activeBeadRegex =
/<g\s+class="abacus-bead active[^"]*"\s+transform="translate\(([^,]+),\s*([^)]+)\)"/g
const beadMatches = [...svgContent.matchAll(activeBeadRegex)]
// Get layout dimensions
const dimensions = calculateStandardDimensions({
columns,
scaleFactor,
showNumbers: false,
columnLabels: [],
})
if (beadMatches.length === 0) {
// Fallback if no active beads found - show full abacus
// Calculate positions of all active beads
const activeBeadPositions: Array<{ x: number; y: number }> = []
for (let placeValue = 0; placeValue < columns; placeValue++) {
const columnState = abacusState[placeValue]
if (!columnState) continue
// Heaven bead
if (columnState.heavenActive) {
const bead: BeadPositionConfig = {
type: 'heaven',
active: true,
position: 0,
placeValue,
}
const pos = calculateBeadPosition(bead, dimensions, { earthActive: columnState.earthActive })
activeBeadPositions.push(pos)
}
// Earth beads
for (let earthPos = 0; earthPos < columnState.earthActive; earthPos++) {
const bead: BeadPositionConfig = {
type: 'earth',
active: true,
position: earthPos,
placeValue,
}
const pos = calculateBeadPosition(bead, dimensions, { earthActive: columnState.earthActive })
activeBeadPositions.push(pos)
}
}
if (activeBeadPositions.length === 0) {
// Fallback if no active beads - show full abacus
return { minX: 0, minY: 0, maxX: 50 * scaleFactor, maxY: 120 * scaleFactor }
}
// Bead dimensions (diamond): width ≈ 30px * scaleFactor, height ≈ 21px * scaleFactor
const beadHeight = 21.6 * scaleFactor
// Calculate bounding box from active bead positions
const beadSize = dimensions.beadSize
const beadWidth = beadSize * 2.5 // Diamond width is ~2.5x the size parameter
const beadHeight = beadSize * 1.8 // Diamond height is ~1.8x the size parameter
// HORIZONTAL BOUNDS: Always show full width of both columns (fixed for all days)
let minX = Infinity
let maxX = -Infinity
for (const match of postMatches) {
const x = parseFloat(match[1])
const width = parseFloat(match[3])
minX = Math.min(minX, x)
maxX = Math.max(maxX, x + width)
}
// VERTICAL BOUNDS: Crop to active beads (dynamic based on which beads are active)
let minY = Infinity
let maxY = -Infinity
for (const match of beadMatches) {
const y = parseFloat(match[2])
// Top of topmost active bead to bottom of bottommost active bead
minY = Math.min(minY, y)
maxY = Math.max(maxY, y + beadHeight)
for (const pos of activeBeadPositions) {
// Bead center is at pos.x, pos.y
// Calculate bounding box for diamond shape
minX = Math.min(minX, pos.x - beadWidth / 2)
maxX = Math.max(maxX, pos.x + beadWidth / 2)
minY = Math.min(minY, pos.y - beadHeight / 2)
maxY = Math.max(maxY, pos.y + beadHeight / 2)
}
// HORIZONTAL BOUNDS: Always show full width of all columns (consistent across all days)
// Use rod positions for consistent horizontal bounds
const rodSpacing = dimensions.rodSpacing
minX = rodSpacing / 2 - beadWidth / 2
maxX = (columns - 0.5) * rodSpacing + beadWidth / 2
return { minX, minY, maxX, maxY }
}
@@ -125,8 +169,8 @@ let svgContent = extractSvgContent(abacusMarkup)
// Remove !important from CSS (production code policy)
svgContent = svgContent.replace(/\s*!important/g, '')
// Calculate bounding box including posts, bar, and active beads
const bbox = getAbacusBoundingBox(svgContent, 1.8, 2)
// Calculate bounding box using proper bead position calculations
const bbox = getAbacusBoundingBox(day, 1.8, 2)
// Add minimal padding around active beads (in abacus coordinates)
// Less padding below since we want to cut tight to the last bead

View File

@@ -5,6 +5,7 @@ import { join } from 'path'
import { execSync } from 'child_process'
import { generateMonthlyTypst, getDaysInMonth } from '../utils/typstGenerator'
import { generateCalendarComposite } from '@/utils/calendar/generateCalendarComposite'
import { generateAbacusElement } from '@/utils/calendar/generateCalendarAbacus'
interface PreviewRequest {
month: number
@@ -26,34 +27,137 @@ export async function POST(request: NextRequest) {
return NextResponse.json({ error: 'Invalid month or year' }, { status: 400 })
}
// Only generate preview for monthly format
if (format !== 'monthly') {
return NextResponse.json({ svg: null })
}
// Dynamic import to avoid Next.js bundler issues
const { renderToStaticMarkup } = await import('react-dom/server')
// Create temp directory for SVG file
// Create temp directory for SVG file(s)
tempDir = join(tmpdir(), `calendar-preview-${Date.now()}-${Math.random()}`)
mkdirSync(tempDir, { recursive: true })
// Generate and write composite SVG
const calendarSvg = generateCalendarComposite({
month,
year,
renderToString: renderToStaticMarkup,
})
writeFileSync(join(tempDir, 'calendar.svg'), calendarSvg)
// Generate Typst document content
const daysInMonth = getDaysInMonth(year, month)
const typstContent = generateMonthlyTypst({
month,
year,
paperSize: 'us-letter',
daysInMonth,
})
let typstContent: string
if (format === 'monthly') {
// Generate and write composite SVG
const calendarSvg = generateCalendarComposite({
month,
year,
renderToString: renderToStaticMarkup,
})
writeFileSync(join(tempDir, 'calendar.svg'), calendarSvg)
typstContent = generateMonthlyTypst({
month,
year,
paperSize: 'us-letter',
daysInMonth,
})
} else {
// Daily format: Create a SINGLE composite SVG (like monthly) to avoid multi-image export issue
// Generate individual abacus SVGs
const daySvg = renderToStaticMarkup(generateAbacusElement(1, 2))
if (!daySvg || daySvg.trim().length === 0) {
throw new Error('Generated empty SVG for day 1')
}
const yearColumns = Math.max(1, Math.ceil(Math.log10(year + 1)))
const yearSvg = renderToStaticMarkup(generateAbacusElement(year, yearColumns))
if (!yearSvg || yearSvg.trim().length === 0) {
throw new Error(`Generated empty SVG for year ${year}`)
}
// Create composite SVG with both year and day abacus
const monthName = [
'January',
'February',
'March',
'April',
'May',
'June',
'July',
'August',
'September',
'October',
'November',
'December',
][month - 1]
const dayOfWeek = new Date(year, month - 1, 1).toLocaleDateString('en-US', {
weekday: 'long',
})
// Extract SVG content (remove outer <svg> tags)
const yearSvgContent = yearSvg.replace(/<svg[^>]*>/, '').replace(/<\/svg>$/, '')
const daySvgContent = daySvg.replace(/<svg[^>]*>/, '').replace(/<\/svg>$/, '')
// Create composite SVG (850x1100 = US Letter aspect ratio)
const compositeWidth = 850
const compositeHeight = 1100
const yearAbacusWidth = 120 // Natural width at scale 1
const yearAbacusHeight = 230
const dayAbacusWidth = 120
const dayAbacusHeight = 230
const compositeSvg = `<svg xmlns="http://www.w3.org/2000/svg" width="${compositeWidth}" height="${compositeHeight}" viewBox="0 0 ${compositeWidth} ${compositeHeight}">
<!-- Background -->
<rect width="${compositeWidth}" height="${compositeHeight}" fill="white"/>
<!-- Decorative border -->
<rect x="40" y="40" width="${compositeWidth - 80}" height="${compositeHeight - 80}" fill="none" stroke="#2563eb" stroke-width="3" rx="8"/>
<rect x="50" y="50" width="${compositeWidth - 100}" height="${compositeHeight - 100}" fill="none" stroke="#2563eb" stroke-width="1" rx="4"/>
<!-- Header section with background -->
<rect x="70" y="70" width="${compositeWidth - 140}" height="120" fill="#eff6ff" stroke="#2563eb" stroke-width="2" rx="6"/>
<!-- Month name -->
<text x="${compositeWidth / 2}" y="125" text-anchor="middle" font-family="Georgia, serif" font-size="48" font-weight="bold" fill="#1e40af" letter-spacing="2">
${monthName.toUpperCase()}
</text>
<!-- Year abacus (smaller, in header) -->
<svg x="${compositeWidth / 2 - yearAbacusWidth * 0.4}" y="140" width="${yearAbacusWidth * 0.8}" height="${yearAbacusHeight * 0.8}" viewBox="0 0 ${yearAbacusWidth} ${yearAbacusHeight}">
${yearSvgContent}
</svg>
<!-- Day of week (large and prominent) -->
<text x="${compositeWidth / 2}" y="260" text-anchor="middle" font-family="Georgia, serif" font-size="42" font-weight="bold" fill="#1e3a8a">
${dayOfWeek}
</text>
<!-- Day abacus (much larger, main focus) -->
<svg x="${compositeWidth / 2 - dayAbacusWidth * 1.25}" y="300" width="${dayAbacusWidth * 2.5}" height="${dayAbacusHeight * 2.5}" viewBox="0 0 ${dayAbacusWidth} ${dayAbacusHeight}">
${daySvgContent}
</svg>
<!-- Full date (below day abacus) -->
<text x="${compositeWidth / 2}" y="890" text-anchor="middle" font-family="Georgia, serif" font-size="24" font-weight="500" fill="#475569">
${monthName} 1, ${year}
</text>
<!-- Notes section with decorative box -->
<rect x="70" y="930" width="${compositeWidth - 140}" height="120" fill="#fefce8" stroke="#ca8a04" stroke-width="2" rx="4"/>
<text x="90" y="960" font-family="Georgia, serif" font-size="18" font-weight="bold" fill="#854d0e">
Notes:
</text>
<line x1="90" y1="980" x2="${compositeWidth - 90}" y2="980" stroke="#ca8a04" stroke-width="1"/>
<line x1="90" y1="1005" x2="${compositeWidth - 90}" y2="1005" stroke="#ca8a04" stroke-width="1"/>
<line x1="90" y1="1030" x2="${compositeWidth - 90}" y2="1030" stroke="#ca8a04" stroke-width="1"/>
</svg>`
writeFileSync(join(tempDir, 'daily-preview.svg'), compositeSvg)
// Use single composite image (like monthly)
typstContent = `#set page(
paper: "us-letter",
margin: (x: 0.5in, y: 0.5in),
)
#align(center + horizon)[
#image("daily-preview.svg", width: 100%, fit: "contain")
]
`
}
// Compile with Typst: stdin for .typ content, stdout for SVG output
let svg: string

View File

@@ -95,43 +95,93 @@ export function generateDailyTypst(config: TypstDailyConfig): string {
paper: "${paperConfig.typstName}",
margin: (x: ${paperConfig.marginX}, y: ${paperConfig.marginY}),
)[
// Header: Year
#align(center)[
#v(1em)
#image("year.svg", width: 30%)
#set text(font: "Georgia")
// Decorative borders
#rect(
width: 100%,
height: 100%,
stroke: (paint: rgb("#2563eb"), thickness: 3pt),
radius: 8pt,
inset: 0pt,
)[
#rect(
width: 100%,
height: 100%,
stroke: (paint: rgb("#2563eb"), thickness: 1pt),
radius: 4pt,
inset: 10pt,
)[
#v(10pt)
// Header section with background
#rect(
width: 100%,
height: 90pt,
fill: rgb("#eff6ff"),
stroke: (paint: rgb("#2563eb"), thickness: 2pt),
radius: 6pt,
)[
#align(center)[
#v(15pt)
#text(size: 32pt, weight: "bold", fill: rgb("#1e40af"), tracking: 2pt)[
${monthName.toUpperCase()}
]
#v(5pt)
#image("year.svg", width: 15%)
]
]
#v(15pt)
// Day of week (large and prominent)
#align(center)[
#text(size: 28pt, weight: "bold", fill: rgb("#1e3a8a"))[
${dayOfWeek}
]
]
#v(10pt)
// Day abacus (main focus, large)
#align(center)[
#image("day-${day}.svg", width: 45%)
]
#v(10pt)
// Full date
#align(center)[
#text(size: 18pt, weight: 500, fill: rgb("#475569"))[
${monthName} ${day}, ${year}
]
]
#v(1fr)
// Notes section with decorative box
#rect(
width: 100%,
height: 90pt,
fill: rgb("#fefce8"),
stroke: (paint: rgb("#ca8a04"), thickness: 2pt),
radius: 4pt,
)[
#v(8pt)
#text(size: 14pt, weight: "bold", fill: rgb("#854d0e"))[
#h(10pt) Notes:
]
#v(8pt)
#line(length: 95%, stroke: (paint: rgb("#ca8a04"), thickness: 1pt))
#v(8pt)
#line(length: 95%, stroke: (paint: rgb("#ca8a04"), thickness: 1pt))
#v(8pt)
#line(length: 95%, stroke: (paint: rgb("#ca8a04"), thickness: 1pt))
]
#v(10pt)
]
]
#v(2em)
// Main: Day number as large abacus
#align(center + horizon)[
#image("day-${day}.svg", width: 50%)
]
#v(2em)
// Footer: Day of week and date
#align(center)[
#text(size: 18pt, weight: "bold")[${dayOfWeek}]
#v(0.5em)
#text(size: 14pt)[${monthName} ${day}, ${year}]
]
// Notes section
#v(3em)
#line(length: 100%, stroke: 0.5pt)
#v(0.5em)
#text(size: 10pt, fill: gray)[Notes:]
#v(0.5em)
#line(length: 100%, stroke: 0.5pt)
#v(1em)
#line(length: 100%, stroke: 0.5pt)
#v(1em)
#line(length: 100%, stroke: 0.5pt)
#v(1em)
#line(length: 100%, stroke: 0.5pt)
]
${day < daysInMonth ? '' : ''}`
@@ -141,7 +191,5 @@ ${day < daysInMonth ? '' : ''}`
}
}
return `#set text(font: "Arial")
${pages}
`
return pages
}

View File

@@ -1,11 +1,13 @@
'use client'
import { useTranslations } from 'next-intl'
import { JobMonitor } from '@/components/3d-print/JobMonitor'
import { STLPreview } from '@/components/3d-print/STLPreview'
import { useState } from 'react'
import { css } from '../../../../styled-system/css'
export default function ThreeDPrintPage() {
const t = useTranslations('create.abacus')
// New unified parameter system
const [columns, setColumns] = useState(4)
const [scaleFactor, setScaleFactor] = useState(1.5)
@@ -86,13 +88,10 @@ export default function ThreeDPrintPage() {
mb: 2,
})}
>
Customize Your 3D Printable Abacus
{t('pageTitle')}
</h1>
<p className={css({ mb: 6, color: 'gray.600' })}>
Adjust the parameters below to customize your abacus, then generate and download the file
for 3D printing.
</p>
<p className={css({ mb: 6, color: 'gray.600' })}>{t('pageSubtitle')}</p>
<div
className={css({
@@ -118,7 +117,7 @@ export default function ThreeDPrintPage() {
mb: 4,
})}
>
Customization Parameters
{t('customizationTitle')}
</h2>
{/* Number of Columns */}
@@ -130,7 +129,7 @@ export default function ThreeDPrintPage() {
mb: 2,
})}
>
Number of Columns: {columns}
{t('columns.label', { count: columns })}
</label>
<input
type="range"
@@ -148,7 +147,7 @@ export default function ThreeDPrintPage() {
mt: 1,
})}
>
Total number of columns in the abacus (1-13)
{t('columns.help')}
</div>
</div>
@@ -161,7 +160,7 @@ export default function ThreeDPrintPage() {
mb: 2,
})}
>
Scale Factor: {scaleFactor.toFixed(1)}x
{t('scaleFactor.label', { factor: scaleFactor.toFixed(1) })}
</label>
<input
type="range"
@@ -179,7 +178,7 @@ export default function ThreeDPrintPage() {
mt: 1,
})}
>
Overall size multiplier (preserves aspect ratio, larger values = bigger file size)
{t('scaleFactor.help')}
</div>
</div>
@@ -192,7 +191,7 @@ export default function ThreeDPrintPage() {
mb: 2,
})}
>
Width in mm (optional)
{t('widthMm.label')}
</label>
<input
type="number"
@@ -204,7 +203,7 @@ export default function ThreeDPrintPage() {
const value = e.target.value
setWidthMm(value ? Number.parseFloat(value) : undefined)
}}
placeholder="Leave empty to use scale factor"
placeholder={t('widthMm.placeholder')}
className={css({
width: '100%',
px: 3,
@@ -225,7 +224,7 @@ export default function ThreeDPrintPage() {
mt: 1,
})}
>
Specify exact width in millimeters (overrides scale factor)
{t('widthMm.help')}
</div>
</div>
@@ -238,7 +237,7 @@ export default function ThreeDPrintPage() {
mb: 2,
})}
>
Output Format
{t('format.label')}
</label>
<div className={css({ display: 'flex', gap: 2, flexWrap: 'wrap' })}>
<button
@@ -308,7 +307,7 @@ export default function ThreeDPrintPage() {
mb: 3,
})}
>
3MF Color Customization
{t('colors.title')}
</h3>
{/* Frame Color */}
@@ -320,7 +319,7 @@ export default function ThreeDPrintPage() {
mb: 1,
})}
>
Frame Color
{t('colors.frame')}
</label>
<div className={css({ display: 'flex', gap: 2, alignItems: 'center' })}>
<input
@@ -356,7 +355,7 @@ export default function ThreeDPrintPage() {
mb: 1,
})}
>
Heaven Bead Color
{t('colors.heavenBead')}
</label>
<div className={css({ display: 'flex', gap: 2, alignItems: 'center' })}>
<input
@@ -392,7 +391,7 @@ export default function ThreeDPrintPage() {
mb: 1,
})}
>
Earth Bead Color
{t('colors.earthBead')}
</label>
<div className={css({ display: 'flex', gap: 2, alignItems: 'center' })}>
<input
@@ -428,7 +427,7 @@ export default function ThreeDPrintPage() {
mb: 1,
})}
>
Decoration Color
{t('colors.decoration')}
</label>
<div className={css({ display: 'flex', gap: 2, alignItems: 'center' })}>
<input
@@ -476,7 +475,7 @@ export default function ThreeDPrintPage() {
_hover: { bg: isGenerating ? 'blue.600' : 'blue.700' },
})}
>
{isGenerating ? 'Generating...' : 'Generate File'}
{isGenerating ? t('generate.generating') : t('generate.button')}
</button>
{/* Job Status */}
@@ -505,7 +504,7 @@ export default function ThreeDPrintPage() {
_hover: { bg: 'green.700' },
})}
>
Download {format.toUpperCase()}
{t('download', { format: format.toUpperCase() })}
</button>
)}
@@ -544,7 +543,7 @@ export default function ThreeDPrintPage() {
mb: 4,
})}
>
Preview
{t('preview.title')}
</h2>
<STLPreview columns={columns} scaleFactor={scaleFactor} />
<div
@@ -554,17 +553,9 @@ export default function ThreeDPrintPage() {
color: 'gray.600',
})}
>
<p className={css({ mb: 2 })}>
<strong>Live Preview:</strong> The preview updates automatically as you adjust
parameters (with a 1-second delay). This shows the exact mirrored book-fold design
that will be generated.
</p>
<p className={css({ mb: 2 })}>
<strong>Note:</strong> Preview generation requires OpenSCAD. If you see an error,
the preview feature only works in production (Docker). The download functionality
will still work when deployed.
</p>
<p>Use your mouse to rotate and zoom the 3D model.</p>
<p className={css({ mb: 2 })}>{t('preview.liveDescription')}</p>
<p className={css({ mb: 2 })}>{t('preview.note')}</p>
<p>{t('preview.instructions')}</p>
</div>
</div>
</div>

View File

@@ -1,5 +1,6 @@
'use client'
import { useTranslations } from 'next-intl'
import { css } from '../../../../../styled-system/css'
import { AbacusReact, useAbacusConfig } from '@soroban/abacus-react'
import { AbacusDisplayDropdown } from '@/components/AbacusDisplayDropdown'
@@ -17,21 +18,6 @@ interface CalendarConfigPanelProps {
onGenerate: () => void
}
const MONTHS = [
'January',
'February',
'March',
'April',
'May',
'June',
'July',
'August',
'September',
'October',
'November',
'December',
]
export function CalendarConfigPanel({
month,
year,
@@ -44,8 +30,24 @@ export function CalendarConfigPanel({
onPaperSizeChange,
onGenerate,
}: CalendarConfigPanelProps) {
const t = useTranslations('calendar')
const abacusConfig = useAbacusConfig()
const MONTHS = [
t('months.january'),
t('months.february'),
t('months.march'),
t('months.april'),
t('months.may'),
t('months.june'),
t('months.july'),
t('months.august'),
t('months.september'),
t('months.october'),
t('months.november'),
t('months.december'),
]
return (
<div
data-component="calendar-config-panel"
@@ -75,7 +77,7 @@ export function CalendarConfigPanel({
color: 'yellow.400',
})}
>
Calendar Format
{t('format.title')}
</legend>
<div
className={css({
@@ -104,7 +106,7 @@ export function CalendarConfigPanel({
cursor: 'pointer',
})}
/>
<span>Monthly Calendar (one page per month)</span>
<span>{t('format.monthly')}</span>
</label>
<label
className={css({
@@ -126,7 +128,7 @@ export function CalendarConfigPanel({
cursor: 'pointer',
})}
/>
<span>Daily Calendar (one page per day)</span>
<span>{t('format.daily')}</span>
</label>
</div>
</fieldset>
@@ -148,7 +150,7 @@ export function CalendarConfigPanel({
color: 'yellow.400',
})}
>
Date
{t('date.title')}
</legend>
<div
className={css({
@@ -216,7 +218,7 @@ export function CalendarConfigPanel({
color: 'yellow.400',
})}
>
Paper Size
{t('paperSize.title')}
</legend>
<select
data-element="paper-size-select"
@@ -236,10 +238,10 @@ export function CalendarConfigPanel({
_hover: { borderColor: 'gray.500' },
})}
>
<option value="us-letter">US Letter (8.5" × 11")</option>
<option value="a4">A4 (210mm × 297mm)</option>
<option value="a3">A3 (297mm × 420mm)</option>
<option value="tabloid">Tabloid (11" × 17")</option>
<option value="us-letter">{t('paperSize.usLetter')}</option>
<option value="a4">{t('paperSize.a4')}</option>
<option value="a3">{t('paperSize.a3')}</option>
<option value="tabloid">{t('paperSize.tabloid')}</option>
</select>
</fieldset>
@@ -259,7 +261,7 @@ export function CalendarConfigPanel({
color: 'gray.300',
})}
>
Calendar abacus style preview:
{t('styling.preview')}
</p>
<div
className={css({
@@ -312,7 +314,7 @@ export function CalendarConfigPanel({
},
})}
>
{isGenerating ? 'Generating PDF...' : 'Generate PDF Calendar'}
{isGenerating ? t('generate.generating') : t('generate.button')}
</button>
</div>
)

View File

@@ -1,6 +1,7 @@
'use client'
import { useQuery } from '@tanstack/react-query'
import { useTranslations } from 'next-intl'
import { css } from '../../../../../styled-system/css'
interface CalendarPreviewProps {
@@ -22,7 +23,8 @@ async function fetchTypstPreview(
})
if (!response.ok) {
throw new Error('Failed to fetch preview')
const errorData = await response.json().catch(() => ({}))
throw new Error(errorData.error || errorData.message || 'Failed to fetch preview')
}
const data = await response.json()
@@ -30,18 +32,19 @@ async function fetchTypstPreview(
}
export function CalendarPreview({ month, year, format, previewSvg }: CalendarPreviewProps) {
const t = useTranslations('calendar')
// Use React Query to fetch Typst-generated preview (client-side only)
const { data: typstPreviewSvg, isLoading } = useQuery({
queryKey: ['calendar-typst-preview', month, year, format],
queryFn: () => fetchTypstPreview(month, year, format),
enabled: typeof window !== 'undefined' && format === 'monthly', // Only run on client and for monthly format
enabled: typeof window !== 'undefined', // Run on client for both formats
})
// Use generated PDF SVG if available, otherwise use Typst live preview
const displaySvg = previewSvg || typstPreviewSvg
// Show loading state while fetching preview
if (isLoading || (!displaySvg && format === 'monthly')) {
if (isLoading || !displaySvg) {
return (
<div
data-component="calendar-preview"
@@ -63,35 +66,7 @@ export function CalendarPreview({ month, year, format, previewSvg }: CalendarPre
textAlign: 'center',
})}
>
Loading preview...
</p>
</div>
)
}
if (!displaySvg) {
return (
<div
data-component="calendar-preview"
className={css({
bg: 'gray.800',
borderRadius: '12px',
padding: '2rem',
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
justifyContent: 'center',
minHeight: '600px',
})}
>
<p
className={css({
fontSize: '1.25rem',
color: 'gray.400',
textAlign: 'center',
})}
>
{format === 'daily' ? 'Daily format - preview after generation' : 'No preview available'}
{isLoading ? t('preview.loading') : t('preview.noPreview')}
</p>
</div>
)
@@ -118,7 +93,11 @@ export function CalendarPreview({ month, year, format, previewSvg }: CalendarPre
fontWeight: 'bold',
})}
>
{previewSvg ? 'Generated PDF' : 'Live Preview'}
{previewSvg
? t('preview.generatedPdf')
: format === 'daily'
? t('preview.livePreviewFirstDay')
: t('preview.livePreview')}
</p>
<div
className={css({

View File

@@ -1,6 +1,7 @@
'use client'
import { useState } from 'react'
import { useState, useEffect } from 'react'
import { useTranslations } from 'next-intl'
import { css } from '../../../../styled-system/css'
import { useAbacusConfig } from '@soroban/abacus-react'
import { PageWithNav } from '@/components/PageWithNav'
@@ -8,6 +9,7 @@ import { CalendarConfigPanel } from './components/CalendarConfigPanel'
import { CalendarPreview } from './components/CalendarPreview'
export default function CalendarCreatorPage() {
const t = useTranslations('calendar')
const currentDate = new Date()
const abacusConfig = useAbacusConfig()
const [month, setMonth] = useState(currentDate.getMonth() + 1) // 1-12
@@ -17,6 +19,19 @@ export default function CalendarCreatorPage() {
const [isGenerating, setIsGenerating] = useState(false)
const [previewSvg, setPreviewSvg] = useState<string | null>(null)
// Detect default paper size based on user's locale (client-side only)
useEffect(() => {
// Get user's locale
const locale = navigator.language || navigator.languages?.[0] || 'en-US'
const country = locale.split('-')[1]?.toUpperCase()
// Countries that use US Letter (8.5" × 11")
const letterCountries = ['US', 'CA', 'MX', 'GT', 'PA', 'DO', 'PR', 'PH']
const detectedSize = letterCountries.includes(country || '') ? 'us-letter' : 'a4'
setPaperSize(detectedSize)
}, [])
const handleGenerate = async () => {
setIsGenerating(true)
try {
@@ -95,7 +110,7 @@ export default function CalendarCreatorPage() {
color: 'yellow.400',
})}
>
Create Abacus Calendar
{t('pageTitle')}
</h1>
<p
className={css({
@@ -103,7 +118,7 @@ export default function CalendarCreatorPage() {
color: 'gray.300',
})}
>
Generate printable calendars with abacus date numbers
{t('pageSubtitle')}
</p>
</header>

View File

@@ -2,6 +2,7 @@
import { useAbacusConfig } from '@soroban/abacus-react'
import { useForm } from '@tanstack/react-form'
import { useTranslations } from 'next-intl'
import { useState } from 'react'
import { ConfigurationFormWithoutGenerate } from '@/components/ConfigurationFormWithoutGenerate'
import { GenerationProgress } from '@/components/GenerationProgress'
@@ -104,6 +105,7 @@ function validateAndCompleteConfig(formState: FlashcardFormState): FlashcardConf
type GenerationStatus = 'idle' | 'generating' | 'error'
export default function CreatePage() {
const t = useTranslations('create.flashcards')
const [generationStatus, setGenerationStatus] = useState<GenerationStatus>('idle')
const [error, setError] = useState<string | null>(null)
const globalConfig = useAbacusConfig()
@@ -184,7 +186,7 @@ export default function CreatePage() {
}
return (
<PageWithNav navTitle="Create Flashcards" navEmoji="✨">
<PageWithNav navTitle={t('navTitle')} navEmoji="✨">
<div className={css({ minHeight: '100vh', bg: 'gray.50' })}>
{/* Main Content */}
<div className={container({ maxW: '7xl', px: '4', py: '8' })}>
@@ -197,7 +199,7 @@ export default function CreatePage() {
color: 'gray.900',
})}
>
Create Your Flashcards
{t('pageTitle')}
</h1>
<p
className={css({
@@ -205,7 +207,7 @@ export default function CreatePage() {
color: 'gray.600',
})}
>
Configure content and style, preview instantly, then generate your flashcards
{t('pageSubtitle')}
</p>
</div>
</div>
@@ -248,7 +250,7 @@ export default function CreatePage() {
color: 'gray.900',
})}
>
🎨 Visual Style
{t('stylePanel.title')}
</h3>
<p
className={css({
@@ -256,7 +258,7 @@ export default function CreatePage() {
color: 'gray.600',
})}
>
See changes instantly in the preview
{t('stylePanel.subtitle')}
</p>
</div>
@@ -337,12 +339,12 @@ export default function CreatePage() {
animation: 'spin 1s linear infinite',
})}
/>
Generating Your Flashcards...
{t('generate.generating')}
</>
) : (
<>
<div className={css({ fontSize: 'xl' })}></div>
Generate Flashcards
{t('generate.button')}
</>
)}
</span>
@@ -374,7 +376,7 @@ export default function CreatePage() {
color: 'red.800',
})}
>
Generation Failed
{t('error.title')}
</h3>
</div>
<p
@@ -399,7 +401,7 @@ export default function CreatePage() {
_hover: { bg: 'red.700' },
})}
>
Try Again
{t('error.tryAgain')}
</button>
</div>
</div>

View File

@@ -1,10 +1,13 @@
'use client'
import Link from 'next/link'
import { useTranslations } from 'next-intl'
import { PageWithNav } from '@/components/PageWithNav'
import { css } from '../../../styled-system/css'
export default function CreateHubPage() {
const t = useTranslations('create.hub')
return (
<PageWithNav navTitle="Create" navEmoji="✨">
<div
@@ -81,7 +84,7 @@ export default function CreateHubPage() {
letterSpacing: 'tight',
})}
>
Create Your Learning Tools
{t('pageTitle')}
</h1>
<p
className={css({
@@ -93,8 +96,7 @@ export default function CreateHubPage() {
textShadow: '0 1px 3px rgba(0,0,0,0.1)',
})}
>
Design custom flashcards or 3D printable abacus models to enhance your learning
experience
{t('pageSubtitle')}
</p>
</div>
@@ -162,7 +164,7 @@ export default function CreateHubPage() {
letterSpacing: 'tight',
})}
>
Flashcard Creator
{t('flashcards.title')}
</h2>
{/* Description */}
@@ -174,8 +176,7 @@ export default function CreateHubPage() {
lineHeight: '1.7',
})}
>
Design custom flashcards with abacus visualizations. Perfect for learning and
teaching number recognition and arithmetic.
{t('flashcards.description')}
</p>
{/* Features */}
@@ -212,7 +213,7 @@ export default function CreateHubPage() {
>
</span>
Customizable number ranges
{t('flashcards.feature1')}
</li>
<li
className={css({
@@ -239,7 +240,7 @@ export default function CreateHubPage() {
>
</span>
Multiple styles and layouts
{t('flashcards.feature2')}
</li>
<li
className={css({
@@ -266,7 +267,7 @@ export default function CreateHubPage() {
>
</span>
Print-ready PDF generation
{t('flashcards.feature3')}
</li>
</ul>
@@ -296,7 +297,7 @@ export default function CreateHubPage() {
},
})}
>
<span>Create Flashcards</span>
<span>{t('flashcards.button')}</span>
<span className={css({ fontSize: 'lg' })}></span>
</div>
</div>
@@ -359,7 +360,7 @@ export default function CreateHubPage() {
letterSpacing: 'tight',
})}
>
3D Abacus Creator
{t('abacus.title')}
</h2>
{/* Description */}
@@ -371,8 +372,7 @@ export default function CreateHubPage() {
lineHeight: '1.7',
})}
>
Customize and download 3D printable abacus models. Choose your size, columns, and
colors for the perfect learning tool.
{t('abacus.description')}
</p>
{/* Features */}
@@ -409,7 +409,7 @@ export default function CreateHubPage() {
>
</span>
Adjustable size and columns
{t('abacus.feature1')}
</li>
<li
className={css({
@@ -436,7 +436,7 @@ export default function CreateHubPage() {
>
</span>
3MF color customization
{t('abacus.feature2')}
</li>
<li
className={css({
@@ -463,7 +463,7 @@ export default function CreateHubPage() {
>
</span>
Live 3D preview
{t('abacus.feature3')}
</li>
</ul>
@@ -493,7 +493,7 @@ export default function CreateHubPage() {
},
})}
>
<span>Create 3D Model</span>
<span>{t('abacus.button')}</span>
<span className={css({ fontSize: 'lg' })}></span>
</div>
</div>
@@ -556,7 +556,7 @@ export default function CreateHubPage() {
letterSpacing: 'tight',
})}
>
Abacus Calendar
{t('calendar.title')}
</h2>
{/* Description */}
@@ -568,8 +568,7 @@ export default function CreateHubPage() {
lineHeight: '1.7',
})}
>
Generate printable calendars where every date is shown as an abacus. Perfect for
teaching number representation.
{t('calendar.description')}
</p>
{/* Features */}
@@ -606,7 +605,7 @@ export default function CreateHubPage() {
>
</span>
Monthly or daily formats
{t('calendar.feature1')}
</li>
<li
className={css({
@@ -633,7 +632,7 @@ export default function CreateHubPage() {
>
</span>
Multiple paper sizes
{t('calendar.feature2')}
</li>
<li
className={css({
@@ -660,7 +659,7 @@ export default function CreateHubPage() {
>
</span>
Uses your abacus styling
{t('calendar.feature3')}
</li>
</ul>
@@ -690,7 +689,7 @@ export default function CreateHubPage() {
},
})}
>
<span>Create Calendar</span>
<span>{t('calendar.button')}</span>
<span className={css({ fontSize: 'lg' })}></span>
</div>
</div>

View File

@@ -26,8 +26,24 @@ function generateDayIcon(day: number): string {
return svg
}
export async function GET() {
const dayOfMonth = getDayOfMonth()
export async function GET(request: Request) {
// Parse query parameters for testing
const { searchParams } = new URL(request.url)
const dayParam = searchParams.get('day')
// Use override day if provided (for testing), otherwise use current day
let dayOfMonth: number
if (dayParam) {
const parsedDay = parseInt(dayParam, 10)
// Validate day is 1-31
if (parsedDay >= 1 && parsedDay <= 31) {
dayOfMonth = parsedDay
} else {
return new Response('Invalid day parameter. Must be 1-31.', { status: 400 })
}
} else {
dayOfMonth = getDayOfMonth()
}
// Check cache first
let svg = iconCache.get(dayOfMonth)
@@ -37,10 +53,12 @@ export async function GET() {
svg = generateDayIcon(dayOfMonth)
iconCache.set(dayOfMonth, svg)
// Clear old cache entries (keep only current day)
for (const [cachedDay] of iconCache) {
if (cachedDay !== dayOfMonth) {
iconCache.delete(cachedDay)
// Clear old cache entries (keep only current day, unless testing with override)
if (!dayParam) {
for (const [cachedDay] of iconCache) {
if (cachedDay !== dayOfMonth) {
iconCache.delete(cachedDay)
}
}
}
}
@@ -48,8 +66,10 @@ export async function GET() {
return new Response(svg, {
headers: {
'Content-Type': 'image/svg+xml',
// Cache for 1 hour so it updates throughout the day
'Cache-Control': 'public, max-age=3600, s-maxage=3600',
// Cache for 1 hour for current day, shorter cache for test overrides
'Cache-Control': dayParam
? 'public, max-age=60, s-maxage=60'
: 'public, max-age=3600, s-maxage=3600',
},
})
}

View File

@@ -0,0 +1,61 @@
{
"calendar": {
"pageTitle": "Abakus-Kalender erstellen",
"pageSubtitle": "Druckbare Kalender mit Abakus-Datumszahlen erstellen",
"format": {
"title": "Kalenderformat",
"monthly": "Monatskalender (eine Seite pro Monat)",
"daily": "Tageskalender (eine Seite pro Tag)"
},
"date": {
"title": "Datum",
"month": "Monat",
"year": "Jahr"
},
"paperSize": {
"title": "Papiergröße",
"usLetter": "US Letter (8,5\" × 11\")",
"a4": "A4 (210mm × 297mm)",
"a3": "A3 (297mm × 420mm)",
"tabloid": "Tabloid (11\" × 17\")"
},
"styling": {
"preview": "Kalender-Abakus-Stil Vorschau:"
},
"generate": {
"button": "PDF-Kalender erstellen",
"generating": "PDF wird erstellt..."
},
"preview": {
"loading": "Vorschau wird geladen...",
"noPreview": "Keine Vorschau verfügbar",
"generatedPdf": "Erstelltes PDF",
"livePreview": "Live-Vorschau",
"livePreviewFirstDay": "Live-Vorschau (Erster Tag)"
},
"months": {
"january": "Januar",
"february": "Februar",
"march": "März",
"april": "April",
"may": "Mai",
"june": "Juni",
"july": "Juli",
"august": "August",
"september": "September",
"october": "Oktober",
"november": "November",
"december": "Dezember"
},
"weekdays": {
"sunday": "Sonntag",
"monday": "Montag",
"tuesday": "Dienstag",
"wednesday": "Mittwoch",
"thursday": "Donnerstag",
"friday": "Freitag",
"saturday": "Samstag"
},
"notes": "Notizen:"
}
}

View File

@@ -0,0 +1,61 @@
{
"calendar": {
"pageTitle": "Create Abacus Calendar",
"pageSubtitle": "Generate printable calendars with abacus date numbers",
"format": {
"title": "Calendar Format",
"monthly": "Monthly Calendar (one page per month)",
"daily": "Daily Calendar (one page per day)"
},
"date": {
"title": "Date",
"month": "Month",
"year": "Year"
},
"paperSize": {
"title": "Paper Size",
"usLetter": "US Letter (8.5\" × 11\")",
"a4": "A4 (210mm × 297mm)",
"a3": "A3 (297mm × 420mm)",
"tabloid": "Tabloid (11\" × 17\")"
},
"styling": {
"preview": "Calendar abacus style preview:"
},
"generate": {
"button": "Generate PDF Calendar",
"generating": "Generating PDF..."
},
"preview": {
"loading": "Loading preview...",
"noPreview": "No preview available",
"generatedPdf": "Generated PDF",
"livePreview": "Live Preview",
"livePreviewFirstDay": "Live Preview (First Day)"
},
"months": {
"january": "January",
"february": "February",
"march": "March",
"april": "April",
"may": "May",
"june": "June",
"july": "July",
"august": "August",
"september": "September",
"october": "October",
"november": "November",
"december": "December"
},
"weekdays": {
"sunday": "Sunday",
"monday": "Monday",
"tuesday": "Tuesday",
"wednesday": "Wednesday",
"thursday": "Thursday",
"friday": "Friday",
"saturday": "Saturday"
},
"notes": "Notes:"
}
}

View File

@@ -0,0 +1,61 @@
{
"calendar": {
"pageTitle": "Crear Calendario de Ábaco",
"pageSubtitle": "Generar calendarios imprimibles con números de fecha de ábaco",
"format": {
"title": "Formato de Calendario",
"monthly": "Calendario Mensual (una página por mes)",
"daily": "Calendario Diario (una página por día)"
},
"date": {
"title": "Fecha",
"month": "Mes",
"year": "Año"
},
"paperSize": {
"title": "Tamaño de Papel",
"usLetter": "Carta US (8.5\" × 11\")",
"a4": "A4 (210mm × 297mm)",
"a3": "A3 (297mm × 420mm)",
"tabloid": "Tabloide (11\" × 17\")"
},
"styling": {
"preview": "Vista previa del estilo de ábaco del calendario:"
},
"generate": {
"button": "Generar Calendario PDF",
"generating": "Generando PDF..."
},
"preview": {
"loading": "Cargando vista previa...",
"noPreview": "No hay vista previa disponible",
"generatedPdf": "PDF Generado",
"livePreview": "Vista Previa en Vivo",
"livePreviewFirstDay": "Vista Previa en Vivo (Primer Día)"
},
"months": {
"january": "Enero",
"february": "Febrero",
"march": "Marzo",
"april": "Abril",
"may": "Mayo",
"june": "Junio",
"july": "Julio",
"august": "Agosto",
"september": "Septiembre",
"october": "Octubre",
"november": "Noviembre",
"december": "Diciembre"
},
"weekdays": {
"sunday": "Domingo",
"monday": "Lunes",
"tuesday": "Martes",
"wednesday": "Miércoles",
"thursday": "Jueves",
"friday": "Viernes",
"saturday": "Sábado"
},
"notes": "Notas:"
}
}

View File

@@ -0,0 +1,61 @@
{
"calendar": {
"pageTitle": "Abacus Kalender Giscaffan",
"pageSubtitle": "Drucchāri kalendera mit abacus tagozalun giskaffen",
"format": {
"title": "Kalenderart",
"monthly": "Mānoðkalender (ein sīta per mānoð)",
"daily": "Tagkalender (ein sīta per tag)"
},
"date": {
"title": "Tag",
"month": "Mānoð",
"year": "Jār"
},
"paperSize": {
"title": "Papiergrōzi",
"usLetter": "US Brief (8.5\" × 11\")",
"a4": "A4 (210mm × 297mm)",
"a3": "A3 (297mm × 420mm)",
"tabloid": "Tabloid (11\" × 17\")"
},
"styling": {
"preview": "Kalender abacus stil forasihti:"
},
"generate": {
"button": "PDF Kalender Giskaffen",
"generating": "PDF wirdit giskaffan..."
},
"preview": {
"loading": "Forasihti ladet...",
"noPreview": "Nein forasihti ferfuogbar",
"generatedPdf": "Giskaffan PDF",
"livePreview": "Lebenti Forasihti",
"livePreviewFirstDay": "Lebenti Forasihti (Ēristo Tag)"
},
"months": {
"january": "Hartmānot",
"february": "Hornung",
"march": "Lentzinmānot",
"april": "Ōstarmānot",
"may": "Winnemānot",
"june": "Brāhmānot",
"july": "Hewimānot",
"august": "Aranmānot",
"september": "Witumanot",
"october": "Windurmānot",
"november": "Herbistmānot",
"december": "Heilagmānot"
},
"weekdays": {
"sunday": "Sunnūntag",
"monday": "Mānetag",
"tuesday": "Ziostag",
"wednesday": "Mittawehha",
"thursday": "Donarestag",
"friday": "Frīatag",
"saturday": "Sambaztag"
},
"notes": "Notiziun:"
}
}

View File

@@ -0,0 +1,61 @@
{
"calendar": {
"pageTitle": "अबेकस कैलेंडर बनाएं",
"pageSubtitle": "अबेकस तिथि संख्याओं के साथ मुद्रण योग्य कैलेंडर उत्पन्न करें",
"format": {
"title": "कैलेंडर प्रारूप",
"monthly": "मासिक कैलेंडर (प्रति माह एक पृष्ठ)",
"daily": "दैनिक कैलेंडर (प्रति दिन एक पृष्ठ)"
},
"date": {
"title": "तिथि",
"month": "महीना",
"year": "वर्ष"
},
"paperSize": {
"title": "कागज का आकार",
"usLetter": "यूएस लेटर (8.5\" × 11\")",
"a4": "A4 (210mm × 297mm)",
"a3": "A3 (297mm × 420mm)",
"tabloid": "टैबलॉइड (11\" × 17\")"
},
"styling": {
"preview": "कैलेंडर अबेकस शैली पूर्वावलोकन:"
},
"generate": {
"button": "पीडीएफ कैलेंडर उत्पन्न करें",
"generating": "पीडीएफ उत्पन्न हो रहा है..."
},
"preview": {
"loading": "पूर्वावलोकन लोड हो रहा है...",
"noPreview": "कोई पूर्वावलोकन उपलब्ध नहीं",
"generatedPdf": "उत्पन्न पीडीएफ",
"livePreview": "लाइव पूर्वावलोकन",
"livePreviewFirstDay": "लाइव पूर्वावलोकन (पहला दिन)"
},
"months": {
"january": "जनवरी",
"february": "फरवरी",
"march": "मार्च",
"april": "अप्रैल",
"may": "मई",
"june": "जून",
"july": "जुलाई",
"august": "अगस्त",
"september": "सितंबर",
"october": "अक्टूबर",
"november": "नवंबर",
"december": "दिसंबर"
},
"weekdays": {
"sunday": "रविवार",
"monday": "सोमवार",
"tuesday": "मंगलवार",
"wednesday": "बुधवार",
"thursday": "गुरुवार",
"friday": "शुक्रवार",
"saturday": "शनिवार"
},
"notes": "नोट्स:"
}
}

View File

@@ -0,0 +1,61 @@
{
"calendar": {
"pageTitle": "そろばんカレンダーを作成",
"pageSubtitle": "そろばんの日付番号付き印刷可能なカレンダーを生成",
"format": {
"title": "カレンダー形式",
"monthly": "月間カレンダー月ごとに1ページ",
"daily": "日めくりカレンダー日ごとに1ページ"
},
"date": {
"title": "日付",
"month": "月",
"year": "年"
},
"paperSize": {
"title": "用紙サイズ",
"usLetter": "USレター (8.5\" × 11\")",
"a4": "A4 (210mm × 297mm)",
"a3": "A3 (297mm × 420mm)",
"tabloid": "タブロイド (11\" × 17\")"
},
"styling": {
"preview": "カレンダーそろばんスタイルプレビュー:"
},
"generate": {
"button": "PDFカレンダーを生成",
"generating": "PDFを生成中..."
},
"preview": {
"loading": "プレビューを読み込み中...",
"noPreview": "プレビューがありません",
"generatedPdf": "生成されたPDF",
"livePreview": "ライブプレビュー",
"livePreviewFirstDay": "ライブプレビュー(初日)"
},
"months": {
"january": "1月",
"february": "2月",
"march": "3月",
"april": "4月",
"may": "5月",
"june": "6月",
"july": "7月",
"august": "8月",
"september": "9月",
"october": "10月",
"november": "11月",
"december": "12月"
},
"weekdays": {
"sunday": "日曜日",
"monday": "月曜日",
"tuesday": "火曜日",
"wednesday": "水曜日",
"thursday": "木曜日",
"friday": "金曜日",
"saturday": "土曜日"
},
"notes": "メモ:"
}
}

View File

@@ -0,0 +1,61 @@
{
"calendar": {
"pageTitle": "Calendarium Abaci Creare",
"pageSubtitle": "Calendaria imprimibilia cum numeris diei abaci generare",
"format": {
"title": "Forma Calendarii",
"monthly": "Calendarium Mensuale (una pagina per mensem)",
"daily": "Calendarium Diurnum (una pagina per diem)"
},
"date": {
"title": "Dies",
"month": "Mensis",
"year": "Annus"
},
"paperSize": {
"title": "Magnitudo Chartae",
"usLetter": "US Epistula (8.5\" × 11\")",
"a4": "A4 (210mm × 297mm)",
"a3": "A3 (297mm × 420mm)",
"tabloid": "Tabloid (11\" × 17\")"
},
"styling": {
"preview": "Praevisio stili abaci calendarii:"
},
"generate": {
"button": "Calendarium PDF Generare",
"generating": "PDF Generatur..."
},
"preview": {
"loading": "Praevisio cargatur...",
"noPreview": "Nulla praevisio disponibilis",
"generatedPdf": "PDF Generatum",
"livePreview": "Praevisio Viva",
"livePreviewFirstDay": "Praevisio Viva (Primus Dies)"
},
"months": {
"january": "Ianuarius",
"february": "Februarius",
"march": "Martius",
"april": "Aprilis",
"may": "Maius",
"june": "Iunius",
"july": "Iulius",
"august": "Augustus",
"september": "September",
"october": "October",
"november": "November",
"december": "December"
},
"weekdays": {
"sunday": "Dies Solis",
"monday": "Dies Lunae",
"tuesday": "Dies Martis",
"wednesday": "Dies Mercurii",
"thursday": "Dies Iovis",
"friday": "Dies Veneris",
"saturday": "Dies Saturni"
},
"notes": "Notae:"
}
}

View File

@@ -0,0 +1,17 @@
import de from './de.json'
import en from './en.json'
import es from './es.json'
import goh from './goh.json'
import hi from './hi.json'
import ja from './ja.json'
import la from './la.json'
export const calendarMessages = {
en: en.calendar,
de: de.calendar,
ja: ja.calendar,
hi: hi.calendar,
es: es.calendar,
la: la.calendar,
goh: goh.calendar,
} as const

View File

@@ -0,0 +1,88 @@
{
"create": {
"hub": {
"pageTitle": "Erstellen Sie Ihre Lernwerkzeuge",
"pageSubtitle": "Entwerfen Sie individuelle Lernkarten oder 3D-druckbare Abakus-Modelle, um Ihr Lernerlebnis zu verbessern",
"flashcards": {
"title": "Lernkarten-Creator",
"description": "Entwerfen Sie individuelle Lernkarten mit Abakus-Visualisierungen. Perfekt zum Lernen und Lehren von Zahlenerkennung und Arithmetik.",
"feature1": "Anpassbare Zahlenbereiche",
"feature2": "Mehrere Stile und Layouts",
"feature3": "Druckfertige PDF-Generierung",
"button": "Lernkarten erstellen"
},
"abacus": {
"title": "3D-Abakus-Creator",
"description": "Passen Sie 3D-druckbare Abakus-Modelle an und laden Sie sie herunter. Wählen Sie Größe, Spalten und Farben für das perfekte Lernwerkzeug.",
"feature1": "Einstellbare Größe und Spalten",
"feature2": "3MF-Farbanpassung",
"feature3": "Live-3D-Vorschau",
"button": "3D-Modell erstellen"
},
"calendar": {
"title": "Abakus-Kalender",
"description": "Erstellen Sie druckbare Kalender, bei denen jedes Datum als Abakus angezeigt wird. Perfekt zum Lehren der Zahlendarstellung.",
"feature1": "Monatliche oder tägliche Formate",
"feature2": "Mehrere Papiergrößen",
"feature3": "Verwendet Ihren Abakus-Stil",
"button": "Kalender erstellen"
}
},
"abacus": {
"pageTitle": "Passen Sie Ihren 3D-druckbaren Abakus an",
"pageSubtitle": "Passen Sie die Parameter unten an, um Ihren Abakus anzupassen, und generieren und laden Sie dann die Datei für den 3D-Druck herunter.",
"customizationTitle": "Anpassungsparameter",
"columns": {
"label": "Anzahl der Spalten: {{count}}",
"help": "Gesamtanzahl der Spalten im Abakus (1-13)"
},
"scaleFactor": {
"label": "Skalierungsfaktor: {{factor}}x",
"help": "Gesamtgrößenmultiplikator (behält Seitenverhältnis bei, größere Werte = größere Dateigröße)"
},
"widthMm": {
"label": "Breite in mm (optional)",
"placeholder": "Leer lassen, um Skalierungsfaktor zu verwenden",
"help": "Geben Sie die genaue Breite in Millimetern an (überschreibt Skalierungsfaktor)"
},
"format": {
"label": "Ausgabeformat"
},
"colors": {
"title": "3MF-Farbanpassung",
"frame": "Rahmenfarbe",
"heavenBead": "Himmelsperlenfarbe",
"earthBead": "Erdperlenfarbe",
"decoration": "Dekorationsfarbe"
},
"generate": {
"button": "Datei generieren",
"generating": "Wird generiert..."
},
"download": "{{format}} herunterladen",
"preview": {
"title": "Vorschau",
"liveDescription": "Live-Vorschau: Die Vorschau wird automatisch aktualisiert, wenn Sie Parameter anpassen (mit 1 Sekunde Verzögerung). Dies zeigt das genaue gespiegelte Buchfalz-Design, das generiert wird.",
"note": "Hinweis: Die Vorschaugenerierung erfordert OpenSCAD. Wenn Sie einen Fehler sehen, funktioniert die Vorschaufunktion nur in der Produktion (Docker). Die Download-Funktionalität funktioniert weiterhin, wenn sie bereitgestellt wird.",
"instructions": "Verwenden Sie Ihre Maus, um das 3D-Modell zu drehen und zu zoomen."
}
},
"flashcards": {
"navTitle": "Lernkarten erstellen",
"pageTitle": "Erstellen Sie Ihre Lernkarten",
"pageSubtitle": "Konfigurieren Sie Inhalt und Stil, sehen Sie die Vorschau sofort und generieren Sie dann Ihre Lernkarten",
"stylePanel": {
"title": "🎨 Visueller Stil",
"subtitle": "Sehen Sie Änderungen sofort in der Vorschau"
},
"generate": {
"button": "Lernkarten generieren",
"generating": "Ihre Lernkarten werden generiert..."
},
"error": {
"title": "Generierung fehlgeschlagen",
"tryAgain": "Erneut versuchen"
}
}
}
}

View File

@@ -0,0 +1,88 @@
{
"create": {
"hub": {
"pageTitle": "Create Your Learning Tools",
"pageSubtitle": "Design custom flashcards or 3D printable abacus models to enhance your learning experience",
"flashcards": {
"title": "Flashcard Creator",
"description": "Design custom flashcards with abacus visualizations. Perfect for learning and teaching number recognition and arithmetic.",
"feature1": "Customizable number ranges",
"feature2": "Multiple styles and layouts",
"feature3": "Print-ready PDF generation",
"button": "Create Flashcards"
},
"abacus": {
"title": "3D Abacus Creator",
"description": "Customize and download 3D printable abacus models. Choose your size, columns, and colors for the perfect learning tool.",
"feature1": "Adjustable size and columns",
"feature2": "3MF color customization",
"feature3": "Live 3D preview",
"button": "Create 3D Model"
},
"calendar": {
"title": "Abacus Calendar",
"description": "Generate printable calendars where every date is shown as an abacus. Perfect for teaching number representation.",
"feature1": "Monthly or daily formats",
"feature2": "Multiple paper sizes",
"feature3": "Uses your abacus styling",
"button": "Create Calendar"
}
},
"abacus": {
"pageTitle": "Customize Your 3D Printable Abacus",
"pageSubtitle": "Adjust the parameters below to customize your abacus, then generate and download the file for 3D printing.",
"customizationTitle": "Customization Parameters",
"columns": {
"label": "Number of Columns: {{count}}",
"help": "Total number of columns in the abacus (1-13)"
},
"scaleFactor": {
"label": "Scale Factor: {{factor}}x",
"help": "Overall size multiplier (preserves aspect ratio, larger values = bigger file size)"
},
"widthMm": {
"label": "Width in mm (optional)",
"placeholder": "Leave empty to use scale factor",
"help": "Specify exact width in millimeters (overrides scale factor)"
},
"format": {
"label": "Output Format"
},
"colors": {
"title": "3MF Color Customization",
"frame": "Frame Color",
"heavenBead": "Heaven Bead Color",
"earthBead": "Earth Bead Color",
"decoration": "Decoration Color"
},
"generate": {
"button": "Generate File",
"generating": "Generating..."
},
"download": "Download {{format}}",
"preview": {
"title": "Preview",
"liveDescription": "Live Preview: The preview updates automatically as you adjust parameters (with a 1-second delay). This shows the exact mirrored book-fold design that will be generated.",
"note": "Note: Preview generation requires OpenSCAD. If you see an error, the preview feature only works in production (Docker). The download functionality will still work when deployed.",
"instructions": "Use your mouse to rotate and zoom the 3D model."
}
},
"flashcards": {
"navTitle": "Create Flashcards",
"pageTitle": "Create Your Flashcards",
"pageSubtitle": "Configure content and style, preview instantly, then generate your flashcards",
"stylePanel": {
"title": "🎨 Visual Style",
"subtitle": "See changes instantly in the preview"
},
"generate": {
"button": "Generate Flashcards",
"generating": "Generating Your Flashcards..."
},
"error": {
"title": "Generation Failed",
"tryAgain": "Try Again"
}
}
}
}

View File

@@ -0,0 +1,88 @@
{
"create": {
"hub": {
"pageTitle": "Crea Tus Herramientas de Aprendizaje",
"pageSubtitle": "Diseña tarjetas didácticas personalizadas o modelos de ábaco imprimibles en 3D para mejorar tu experiencia de aprendizaje",
"flashcards": {
"title": "Creador de Tarjetas Didácticas",
"description": "Diseña tarjetas didácticas personalizadas con visualizaciones de ábaco. Perfecto para aprender y enseñar reconocimiento de números y aritmética.",
"feature1": "Rangos de números personalizables",
"feature2": "Múltiples estilos y diseños",
"feature3": "Generación de PDF listo para imprimir",
"button": "Crear Tarjetas Didácticas"
},
"abacus": {
"title": "Creador de Ábaco 3D",
"description": "Personaliza y descarga modelos de ábaco imprimibles en 3D. Elige tu tamaño, columnas y colores para la herramienta de aprendizaje perfecta.",
"feature1": "Tamaño y columnas ajustables",
"feature2": "Personalización de color 3MF",
"feature3": "Vista previa 3D en vivo",
"button": "Crear Modelo 3D"
},
"calendar": {
"title": "Calendario de Ábaco",
"description": "Genera calendarios imprimibles donde cada fecha se muestra como un ábaco. Perfecto para enseñar representación numérica.",
"feature1": "Formatos mensuales o diarios",
"feature2": "Múltiples tamaños de papel",
"feature3": "Usa tu estilo de ábaco",
"button": "Crear Calendario"
}
},
"abacus": {
"pageTitle": "Personaliza Tu Ábaco Imprimible en 3D",
"pageSubtitle": "Ajusta los parámetros a continuación para personalizar tu ábaco, luego genera y descarga el archivo para impresión 3D.",
"customizationTitle": "Parámetros de Personalización",
"columns": {
"label": "Número de Columnas: {{count}}",
"help": "Número total de columnas en el ábaco (1-13)"
},
"scaleFactor": {
"label": "Factor de Escala: {{factor}}x",
"help": "Multiplicador de tamaño general (preserva la relación de aspecto, valores más grandes = mayor tamaño de archivo)"
},
"widthMm": {
"label": "Ancho en mm (opcional)",
"placeholder": "Dejar vacío para usar factor de escala",
"help": "Especificar ancho exacto en milímetros (anula el factor de escala)"
},
"format": {
"label": "Formato de Salida"
},
"colors": {
"title": "Personalización de Color 3MF",
"frame": "Color del Marco",
"heavenBead": "Color de Cuenta Celestial",
"earthBead": "Color de Cuenta Terrestre",
"decoration": "Color de Decoración"
},
"generate": {
"button": "Generar Archivo",
"generating": "Generando..."
},
"download": "Descargar {{format}}",
"preview": {
"title": "Vista Previa",
"liveDescription": "Vista previa en vivo: La vista previa se actualiza automáticamente a medida que ajustas los parámetros (con un retraso de 1 segundo). Esto muestra el diseño exacto de pliegue de libro espejo que se generará.",
"note": "Nota: La generación de vista previa requiere OpenSCAD. Si ves un error, la función de vista previa solo funciona en producción (Docker). La funcionalidad de descarga seguirá funcionando cuando se implemente.",
"instructions": "Usa tu ratón para rotar y hacer zoom en el modelo 3D."
}
},
"flashcards": {
"navTitle": "Crear Tarjetas Didácticas",
"pageTitle": "Crea Tus Tarjetas Didácticas",
"pageSubtitle": "Configura contenido y estilo, previsualiza instantáneamente, luego genera tus tarjetas didácticas",
"stylePanel": {
"title": "🎨 Estilo Visual",
"subtitle": "Ver cambios instantáneamente en la vista previa"
},
"generate": {
"button": "Generar Tarjetas Didácticas",
"generating": "Generando Tus Tarjetas Didácticas..."
},
"error": {
"title": "Generación Fallida",
"tryAgain": "Intentar de Nuevo"
}
}
}
}

View File

@@ -0,0 +1,88 @@
{
"create": {
"hub": {
"pageTitle": "Thīna Lernawerkzūg Giskaffen",
"pageSubtitle": "Anamahhōn fleissachartun odo 3D drucchāri abacusmodellun ze firbezzirungu thīnēro lernunga",
"flashcards": {
"title": "Fleissachartun Giskaffari",
"description": "Anamahhōn fleissachartun mit abacussihti. Folkomano ze lernenne inti lerenne zalakennunga inti rehnunga.",
"feature1": "Anamahhōn zalafristu",
"feature2": "Managfalti stili inti legari",
"feature3": "Drucchgareiti PDF giskaffunga",
"button": "Fleissachartun Giskaffen"
},
"abacus": {
"title": "3D Abacus Giskaffari",
"description": "Anamahhōn inti hladan 3D drucchāri abacusmodellun. Giweli thīna grōzi, spaltunga inti farawa fora folkomano lernawerkzūg.",
"feature1": "Gistellbāri grōzi inti spaltunga",
"feature2": "3MF farawaanamahhōn",
"feature3": "Libenti 3D forasihti",
"button": "3D Modellun Giskaffen"
},
"calendar": {
"title": "Abacuskalendarium",
"description": "Giskaffen drucchāri kalendariun wār iegilich tag als abacus gizeignit wirdit. Folkomano ze lerenne zalaforesteldunga.",
"feature1": "Mānotlīchi odo taglīchi formen",
"feature2": "Managfalti papirgrōzi",
"feature3": "Nuzzit thīnan abacusstil",
"button": "Kalendarium Giskaffen"
}
},
"abacus": {
"pageTitle": "Gianamahho Thīnan 3D Drucchāran Abacus",
"pageSubtitle": "Gistellōn thie parameterōn untanafora ze gianamahhōnne thīnan abacus, thanne giskaffo inti hlado thia datei fora 3D drucch.",
"customizationTitle": "Anamahhōnparameterōn",
"columns": {
"label": "Zala Spaltungo: {{count}}",
"help": "Allu zala spaltungo in abaco (1-13)"
},
"scaleFactor": {
"label": "Skālefaktor: {{factor}}x",
"help": "Allugrōzimultiplikator (gihaltet aspektaferhāltnissa, grōziri wertē = grōziri dateigr ōzi)"
},
"widthMm": {
"label": "Breiti in mm (wāllīg)",
"placeholder": "Lāzzilosun fora skālefaktor ze nuzzenne",
"help": "Spezifizieri genawe breiti in millimeterun (ūbarskrībit skālefaktor)"
},
"format": {
"label": "Ūzgangaforma"
},
"colors": {
"title": "3MF Farawaanamahhōn",
"frame": "Rāmafarawa",
"heavenBead": "Himilesglobulifarawa",
"earthBead": "Erdusglobulifarawa",
"decoration": "Zieratafarawa"
},
"generate": {
"button": "Datei Giskaffen",
"generating": "Wirdit giskaffan..."
},
"download": "{{format}} Hladan",
"preview": {
"title": "Forasihti",
"liveDescription": "Libenti forasihti: Thiu forasihti wirdit automatisch girēniwit sō du parameterōn gistellōst (mit 1 secunda firziagu). Thiz zeignit thaz genawe gespegelti buohfalzentuurf thaz giskaffan wirdit.",
"note": "Nota: Forasihtigiskaffunga bidarfit OpenSCAD. Oba thu errorem gisihist, thiu forasihtikunst arbeitet nur in productione (Docker). Thiu hladukunst arbeitet noch immir wanne gistellit wirdit.",
"instructions": "Nuzzi thīna mūs ze rōtenne inti zōmenne thaz 3D modellun."
}
},
"flashcards": {
"navTitle": "Fleissachartun Giskaffen",
"pageTitle": "Giskaffen Thīna Fleissachartun",
"pageSubtitle": "Gistellōn inhalt inti stil, forasih statim, thanne giskaffo thīna fleissachartun",
"stylePanel": {
"title": "🎨 Gisihtisstil",
"subtitle": "Gisih wihsala statim in forasihti"
},
"generate": {
"button": "Fleissachartun Giskaffen",
"generating": "Thīna Fleissachartun Werdent Giskaffan..."
},
"error": {
"title": "Giskaffunga Firzōganit",
"tryAgain": "Widar Firsuachen"
}
}
}
}

View File

@@ -0,0 +1,88 @@
{
"create": {
"hub": {
"pageTitle": "अपने सीखने के उपकरण बनाएं",
"pageSubtitle": "अपने सीखने के अनुभव को बढ़ाने के लिए कस्टम फ्लैशकार्ड या 3D प्रिंट करने योग्य अबेकस मॉडल डिजाइन करें",
"flashcards": {
"title": "फ्लैशकार्ड निर्माता",
"description": "अबेकस विज़ुअलाइज़ेशन के साथ कस्टम फ्लैशकार्ड डिज़ाइन करें। संख्या पहचान और अंकगणित सीखने और पढ़ाने के लिए बिल्कुल सही।",
"feature1": "अनुकूलन योग्य संख्या श्रेणियाँ",
"feature2": "एकाधिक शैलियाँ और लेआउट",
"feature3": "प्रिंट-रेडी पीडीएफ जनरेशन",
"button": "फ्लैशकार्ड बनाएं"
},
"abacus": {
"title": "3D अबेकस निर्माता",
"description": "3D प्रिंट करने योग्य अबेकस मॉडल को अनुकूलित करें और डाउनलोड करें। सही सीखने के उपकरण के लिए अपना आकार, कॉलम और रंग चुनें।",
"feature1": "समायोज्य आकार और कॉलम",
"feature2": "3MF रंग अनुकूलन",
"feature3": "लाइव 3D पूर्वावलोकन",
"button": "3D मॉडल बनाएं"
},
"calendar": {
"title": "अबेकस कैलेंडर",
"description": "प्रिंट करने योग्य कैलेंडर उत्पन्न करें जहां प्रत्येक तिथि को अबेकस के रूप में दिखाया गया है। संख्या प्रतिनिधित्व सिखाने के लिए बिल्कुल सही।",
"feature1": "मासिक या दैनिक प्रारूप",
"feature2": "एकाधिक कागज के आकार",
"feature3": "आपकी अबेकस स्टाइलिंग का उपयोग करता है",
"button": "कैलेंडर बनाएं"
}
},
"abacus": {
"pageTitle": "अपने 3D प्रिंट करने योग्य अबेकस को अनुकूलित करें",
"pageSubtitle": "अपने अबेकस को अनुकूलित करने के लिए नीचे दिए गए पैरामीटर समायोजित करें, फिर 3D प्रिंटिंग के लिए फ़ाइल उत्पन्न करें और डाउनलोड करें।",
"customizationTitle": "अनुकूलन पैरामीटर",
"columns": {
"label": "कॉलम की संख्या: {{count}}",
"help": "अबेकस में कुल कॉलम की संख्या (1-13)"
},
"scaleFactor": {
"label": "स्केल फैक्टर: {{factor}}x",
"help": "कुल आकार गुणक (पहलू अनुपात को संरक्षित करता है, बड़े मान = बड़ी फ़ाइल आकार)"
},
"widthMm": {
"label": "चौड़ाई मिमी में (वैकल्पिक)",
"placeholder": "स्केल फैक्टर का उपयोग करने के लिए खाली छोड़ें",
"help": "मिलीमीटर में सटीक चौड़ाई निर्दिष्ट करें (स्केल फैक्टर को ओवरराइड करता है)"
},
"format": {
"label": "आउटपुट प्रारूप"
},
"colors": {
"title": "3MF रंग अनुकूलन",
"frame": "फ्रेम रंग",
"heavenBead": "स्वर्ग मनका रंग",
"earthBead": "पृथ्वी मनका रंग",
"decoration": "सजावट रंग"
},
"generate": {
"button": "फ़ाइल उत्पन्न करें",
"generating": "उत्पन्न हो रहा है..."
},
"download": "{{format}} डाउनलोड करें",
"preview": {
"title": "पूर्वावलोकन",
"liveDescription": "लाइव पूर्वावलोकन: जैसे ही आप पैरामीटर समायोजित करते हैं, पूर्वावलोकन स्वचालित रूप से अपडेट होता है (1-सेकंड की देरी के साथ)। यह उत्पन्न होने वाले सटीक मिरर बुक-फोल्ड डिज़ाइन को दिखाता है।",
"note": "नोट: पूर्वावलोकन जनरेशन के लिए OpenSCAD की आवश्यकता होती है। यदि आप एक त्रुटि देखते हैं, तो पूर्वावलोकन सुविधा केवल उत्पादन (Docker) में काम करती है। डिप्लॉय होने पर डाउनलोड कार्यक्षमता अभी भी काम करेगी।",
"instructions": "3D मॉडल को घुमाने और ज़ूम करने के लिए अपने माउस का उपयोग करें।"
}
},
"flashcards": {
"navTitle": "फ्लैशकार्ड बनाएं",
"pageTitle": "अपने फ्लैशकार्ड बनाएं",
"pageSubtitle": "सामग्री और शैली को कॉन्फ़िगर करें, तुरंत पूर्वावलोकन करें, फिर अपने फ्लैशकार्ड उत्पन्न करें",
"stylePanel": {
"title": "🎨 दृश्य शैली",
"subtitle": "पूर्वावलोकन में तुरंत परिवर्तन देखें"
},
"generate": {
"button": "फ्लैशकार्ड उत्पन्न करें",
"generating": "आपके फ्लैशकार्ड उत्पन्न हो रहे हैं..."
},
"error": {
"title": "जनरेशन विफल",
"tryAgain": "फिर से कोशिश करें"
}
}
}
}

View File

@@ -0,0 +1,88 @@
{
"create": {
"hub": {
"pageTitle": "学習ツールを作成",
"pageSubtitle": "学習体験を向上させるカスタムフラッシュカードまたは3Dプリント可能なそろばんモデルをデザイン",
"flashcards": {
"title": "フラッシュカード作成",
"description": "そろばんの視覚化を使用したカスタムフラッシュカードをデザインします。数字の認識と算術の学習と教育に最適です。",
"feature1": "カスタマイズ可能な数値範囲",
"feature2": "複数のスタイルとレイアウト",
"feature3": "印刷可能なPDF生成",
"button": "フラッシュカードを作成"
},
"abacus": {
"title": "3Dそろばん作成",
"description": "3Dプリント可能なそろばんモデルをカスタマイズしてダウンロードします。完璧な学習ツールのためにサイズ、列、色を選択してください。",
"feature1": "調整可能なサイズと列",
"feature2": "3MF色のカスタマイズ",
"feature3": "ライブ3Dプレビュー",
"button": "3Dモデルを作成"
},
"calendar": {
"title": "そろばんカレンダー",
"description": "各日付がそろばんとして表示される印刷可能なカレンダーを生成します。数字の表現を教えるのに最適です。",
"feature1": "月次または日次形式",
"feature2": "複数の用紙サイズ",
"feature3": "そろばんスタイルを使用",
"button": "カレンダーを作成"
}
},
"abacus": {
"pageTitle": "3Dプリント可能そろばんをカスタマイズ",
"pageSubtitle": "以下のパラメータを調整してそろばんをカスタマイズし、3Dプリント用のファイルを生成してダウンロードします。",
"customizationTitle": "カスタマイズパラメータ",
"columns": {
"label": "列数:{{count}}",
"help": "そろばんの総列数1-13"
},
"scaleFactor": {
"label": "スケール係数:{{factor}}x",
"help": "全体サイズの乗数(アスペクト比を保持、値が大きいほどファイルサイズが大きくなります)"
},
"widthMm": {
"label": "幅mmオプション",
"placeholder": "空白のままでスケール係数を使用",
"help": "ミリメートル単位で正確な幅を指定(スケール係数を上書き)"
},
"format": {
"label": "出力形式"
},
"colors": {
"title": "3MF色のカスタマイズ",
"frame": "フレーム色",
"heavenBead": "天珠の色",
"earthBead": "地珠の色",
"decoration": "装飾色"
},
"generate": {
"button": "ファイルを生成",
"generating": "生成中..."
},
"download": "{{format}}をダウンロード",
"preview": {
"title": "プレビュー",
"liveDescription": "ライブプレビューパラメータを調整すると自動的に更新されます1秒の遅延。これにより、生成される正確なミラー折り返しデザインが表示されます。",
"note": "注プレビュー生成にはOpenSCADが必要です。エラーが表示される場合、プレビュー機能は本番環境Dockerでのみ動作します。デプロイ時にダウンロード機能は引き続き機能します。",
"instructions": "マウスを使用して3Dモデルを回転およびズームします。"
}
},
"flashcards": {
"navTitle": "フラッシュカードを作成",
"pageTitle": "フラッシュカードを作成",
"pageSubtitle": "コンテンツとスタイルを設定し、即座にプレビューして、フラッシュカードを生成します",
"stylePanel": {
"title": "🎨 ビジュアルスタイル",
"subtitle": "プレビューで変更を即座に確認"
},
"generate": {
"button": "フラッシュカードを生成",
"generating": "フラッシュカードを生成中..."
},
"error": {
"title": "生成失敗",
"tryAgain": "再試行"
}
}
}
}

View File

@@ -0,0 +1,88 @@
{
"create": {
"hub": {
"pageTitle": "Instrumenta Discendi Tua Crea",
"pageSubtitle": "Cartas memoriativas vel modulos abaci 3D imprimibiles designa ut experientiam discendi tuam augeas",
"flashcards": {
"title": "Creator Chartarum Memorativarum",
"description": "Cartas memoriativas cum visualizationibus abaci designa. Perfectus ad discendum et docendum recognitionem numerorum et arithmeticam.",
"feature1": "Limites numerorum configurabiles",
"feature2": "Multi styli et dispositiones",
"feature3": "Generatio PDF parata ad imprimendum",
"button": "Cartas Crea"
},
"abacus": {
"title": "Creator Abaci 3D",
"description": "Modulos abaci 3D imprimibiles configura et depone. Magnitudinem, columnas, colores tuos elige pro instrumento discendi perfecto.",
"feature1": "Magnitudo et columnae adaptabiles",
"feature2": "Configuratio colorum 3MF",
"feature3": "Praevisio 3D viva",
"button": "Modulum 3D Crea"
},
"calendar": {
"title": "Calendarium Abaci",
"description": "Calendaria imprimibilia genera ubi omnis dies ut abacus monstratur. Perfectus ad docendam repraesentationem numerorum.",
"feature1": "Formae mensuales vel diurnae",
"feature2": "Magnitudines chartae multiplices",
"feature3": "Stilum abaci tui utitur",
"button": "Calendarium Crea"
}
},
"abacus": {
"pageTitle": "Abacum Tuum 3D Imprimibilem Configura",
"pageSubtitle": "Parametros infra adapta ut abacum tuum configures, deinde fasciculum genera et depone pro impressione 3D.",
"customizationTitle": "Parametri Configurationis",
"columns": {
"label": "Numerus Columnarum: {{count}}",
"help": "Numerus totalis columnarum in abaco (1-13)"
},
"scaleFactor": {
"label": "Factor Scalae: {{factor}}x",
"help": "Multiplicator magnitudinis totalis (servat proportionem aspectus, valores maiores = magnitudo fasciculi maior)"
},
"widthMm": {
"label": "Latitudo in mm (optionalis)",
"placeholder": "Vacuum relinque ut factorem scalae utaris",
"help": "Latitudinem exactam in millimetris specifica (factorem scalae superat)"
},
"format": {
"label": "Forma Exitus"
},
"colors": {
"title": "Configuratio Colorum 3MF",
"frame": "Color Cornicis",
"heavenBead": "Color Globuli Caelestis",
"earthBead": "Color Globuli Terrae",
"decoration": "Color Ornamenti"
},
"generate": {
"button": "Fasciculum Genera",
"generating": "Generatur..."
},
"download": "{{format}} Depone",
"preview": {
"title": "Praevisio",
"liveDescription": "Praevisio viva: Praevisio automatice renovatur dum parametros adaptas (cum mora 1 secundi). Hoc designum exactum libri specularis plicati quod generabitur monstrat.",
"note": "Nota: Generatio praevisionis OpenSCAD requirit. Si errorem vides, facultas praevisionis solum in productione (Docker) operatur. Facultas deponendi adhuc operabitur cum explicatur.",
"instructions": "Mure tuo utere ut modulum 3D rotas et augeas."
}
},
"flashcards": {
"navTitle": "Cartas Crea",
"pageTitle": "Cartas Tuas Crea",
"pageSubtitle": "Contentum et stylum configura, statim praevide, deinde cartas tuas genera",
"stylePanel": {
"title": "🎨 Stilus Visualis",
"subtitle": "Mutationes statim in praevisione vide"
},
"generate": {
"button": "Cartas Genera",
"generating": "Cartae Tuae Generantur..."
},
"error": {
"title": "Generatio Defecit",
"tryAgain": "Iterum Tempta"
}
}
}
}

View File

@@ -0,0 +1,17 @@
import de from './de.json'
import en from './en.json'
import es from './es.json'
import goh from './goh.json'
import hi from './hi.json'
import ja from './ja.json'
import la from './la.json'
export const createMessages = {
en: en.create,
de: de.create,
ja: ja.create,
hi: hi.create,
es: es.create,
la: la.create,
goh: goh.create,
} as const

View File

@@ -1,4 +1,6 @@
import { rithmomachiaMessages } from '@/arcade-games/rithmomachia/messages'
import { calendarMessages } from '@/i18n/locales/calendar/messages'
import { createMessages } from '@/i18n/locales/create/messages'
import { gamesMessages } from '@/i18n/locales/games/messages'
import { guideMessages } from '@/i18n/locales/guide/messages'
import { homeMessages } from '@/i18n/locales/home/messages'
@@ -40,6 +42,8 @@ export async function getMessages(locale: Locale) {
{ games: gamesMessages[locale] },
{ guide: guideMessages[locale] },
{ tutorial: tutorialMessages[locale] },
{ calendar: calendarMessages[locale] },
{ create: createMessages[locale] },
rithmomachiaMessages[locale]
)
}

View File

@@ -117,6 +117,10 @@ export function generateCalendarComposite(options: CalendarCompositeOptions): st
showNumbers={false}
frameVisible={true}
compact={false}
hideInactiveBeads={true}
cropToActiveBeads={{
padding: { top: 8, bottom: 2, left: 5, right: 5 }
}}
/>
)
}
@@ -179,22 +183,41 @@ export function generateCalendarComposite(options: CalendarCompositeOptions): st
const cellX = MARGIN + col * CELL_WIDTH
const cellY = GRID_START_Y + WEEKDAY_ROW_HEIGHT + row * DAY_CELL_HEIGHT
// Render cropped abacus SVG
const abacusSVG = renderAbacusSVG(day, 2, 1)
// Extract viewBox and dimensions from the cropped SVG
const viewBoxMatch = abacusSVG.match(/viewBox="([^"]*)"/)
const widthMatch = abacusSVG.match(/width="?([0-9.]+)"?/)
const heightMatch = abacusSVG.match(/height="?([0-9.]+)"?/)
const croppedViewBox = viewBoxMatch ? viewBoxMatch[1] : '0 0 120 230'
const croppedWidth = widthMatch ? parseFloat(widthMatch[1]) : ABACUS_NATURAL_WIDTH
const croppedHeight = heightMatch ? parseFloat(heightMatch[1]) : ABACUS_NATURAL_HEIGHT
// Calculate scale to fit cropped abacus in cell
const MAX_SCALE_X = (CELL_WIDTH - CELL_PADDING * 2) / croppedWidth
const MAX_SCALE_Y = (DAY_CELL_HEIGHT - CELL_PADDING * 2) / croppedHeight
const fitScale = Math.min(MAX_SCALE_X, MAX_SCALE_Y) * 0.95 // 95% to leave breathing room
const scaledWidth = croppedWidth * fitScale
const scaledHeight = croppedHeight * fitScale
// Center abacus in cell
const abacusCenterX = cellX + CELL_WIDTH / 2
const abacusCenterY = cellY + DAY_CELL_HEIGHT / 2
// Offset to top-left corner of abacus (accounting for scaled size)
const abacusX = abacusCenterX - SCALED_ABACUS_WIDTH / 2
const abacusY = abacusCenterY - SCALED_ABACUS_HEIGHT / 2
// Offset to top-left corner of abacus
const abacusX = abacusCenterX - scaledWidth / 2
const abacusY = abacusCenterY - scaledHeight / 2
// Render at scale=1 and let the nested SVG handle scaling via viewBox
const abacusSVG = renderAbacusSVG(day, 2, 1)
// Extract SVG content (remove outer <svg> tags)
const svgContent = abacusSVG.replace(/<svg[^>]*>/, '').replace(/<\/svg>$/, '')
return `
<!-- Day ${day} (row ${row}, col ${col}) -->
<svg x="${abacusX}" y="${abacusY}" width="${SCALED_ABACUS_WIDTH}" height="${SCALED_ABACUS_HEIGHT}"
viewBox="0 0 ${ABACUS_NATURAL_WIDTH} ${ABACUS_NATURAL_HEIGHT}">
<svg x="${abacusX}" y="${abacusY}" width="${scaledWidth}" height="${scaledHeight}"
viewBox="${croppedViewBox}">
${svgContent}
</svg>`
})

View File

@@ -1,3 +1,18 @@
# [2.10.0](https://github.com/antialias/soroban-abacus-flashcards/compare/abacus-react-v2.9.0...abacus-react-v2.10.0) (2025-11-05)
### Bug Fixes
* replace regex HTML parsing with deterministic bead position calculations in icon generation ([41a3707](https://github.com/antialias/soroban-abacus-flashcards/commit/41a3707841595a74de56c6adf6d271237f81ee0e))
### Features
* add cropToActiveBeads prop to AbacusStatic and AbacusReact ([35b0824](https://github.com/antialias/soroban-abacus-flashcards/commit/35b0824fc4fb0b754e53b20a00541da1bf4b8434))
* **calendar:** add beautiful daily calendar with locale-based paper size detection ([bdca315](https://github.com/antialias/soroban-abacus-flashcards/commit/bdca3154f8336e17a7031be8d2917f9cf05f274a))
* **calendar:** add i18n support and cropped abacus day numbers ([5242f89](https://github.com/antialias/soroban-abacus-flashcards/commit/5242f890f725c872a74b6ee45cd611092628690a))
* **i18n:** add internationalization for all create pages ([b080970](https://github.com/antialias/soroban-abacus-flashcards/commit/b080970d7647c8286a713b05b772166c2d701c4c))
# [2.9.0](https://github.com/antialias/soroban-abacus-flashcards/compare/abacus-react-v2.8.3...abacus-react-v2.9.0) (2025-11-05)

View File

@@ -0,0 +1,435 @@
import type { Meta, StoryObj } from '@storybook/react'
import { AbacusStatic } from './AbacusStatic'
import { AbacusReact } from './AbacusReact'
/**
* Abacus Cropping - Automatic viewBox cropping to active beads
*
* ## Overview:
* The `cropToActiveBeads` prop automatically crops the SVG viewBox to show only active beads,
* making it perfect for:
* - Compact inline displays
* - Favicon generation (see /icon route)
* - Focus on active beads without distraction
* - Responsive layouts where space is limited
*
* ## Key Features:
* - ✅ Works with both AbacusStatic and AbacusReact
* - ✅ Configurable padding (top, bottom, left, right)
* - ✅ Maintains aspect ratio
* - ✅ Preserves frame elements (posts, bar) if enabled
* - ✅ Dynamic cropping based on value
*
* ## API:
* ```tsx
* // Simple boolean
* <AbacusStatic value={15} cropToActiveBeads />
*
* // With custom padding
* <AbacusStatic
* value={15}
* cropToActiveBeads={{
* padding: { top: 8, bottom: 2, left: 5, right: 5 }
* }}
* />
* ```
*/
const meta = {
title: 'AbacusStatic/Cropping',
component: AbacusStatic,
parameters: {
layout: 'centered',
},
tags: ['autodocs'],
} satisfies Meta<typeof AbacusStatic>
export default meta
type Story = StoryObj<typeof meta>
export const CroppedVsUncropped: Story = {
render: () => (
<div style={{ display: 'flex', gap: '40px', alignItems: 'flex-start' }}>
<div style={{ textAlign: 'center' }}>
<div style={{ border: '2px solid #e2e8f0', borderRadius: '8px', padding: '10px' }}>
<AbacusStatic value={15} hideInactiveBeads />
</div>
<p style={{ marginTop: '10px', color: '#64748b' }}>Without Cropping</p>
<p style={{ fontSize: '12px', color: '#94a3b8' }}>Full abacus frame shown</p>
</div>
<div style={{ textAlign: 'center' }}>
<div style={{ border: '2px solid #3b82f6', borderRadius: '8px', padding: '10px' }}>
<AbacusStatic value={15} hideInactiveBeads cropToActiveBeads />
</div>
<p style={{ marginTop: '10px', color: '#3b82f6', fontWeight: 'bold' }}>With Cropping</p>
<p style={{ fontSize: '12px', color: '#94a3b8' }}>Focused on active beads</p>
</div>
</div>
),
}
export const DifferentValues: Story = {
render: () => (
<div style={{ display: 'grid', gridTemplateColumns: 'repeat(4, 1fr)', gap: '20px' }}>
{[1, 5, 10, 15, 20, 25, 30, 31].map((value) => (
<div key={value} style={{ textAlign: 'center' }}>
<div style={{ border: '2px solid #e2e8f0', borderRadius: '8px', padding: '10px', minHeight: '100px', display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
<AbacusStatic
value={value}
columns={2}
hideInactiveBeads
cropToActiveBeads
scaleFactor={1.2}
/>
</div>
<p style={{ marginTop: '10px', fontSize: '16px', fontWeight: 'bold', color: '#475569' }}>{value}</p>
</div>
))}
</div>
),
}
export const CustomPadding: Story = {
render: () => (
<div style={{ display: 'flex', gap: '40px', flexWrap: 'wrap' }}>
<div style={{ textAlign: 'center' }}>
<div style={{ border: '2px solid #e2e8f0', borderRadius: '8px', padding: '10px' }}>
<AbacusStatic
value={15}
hideInactiveBeads
cropToActiveBeads
/>
</div>
<p style={{ marginTop: '10px', color: '#64748b' }}>Default Padding</p>
<p style={{ fontSize: '11px', color: '#94a3b8' }}>No custom padding</p>
</div>
<div style={{ textAlign: 'center' }}>
<div style={{ border: '2px solid #e2e8f0', borderRadius: '8px', padding: '10px' }}>
<AbacusStatic
value={15}
hideInactiveBeads
cropToActiveBeads={{ padding: { top: 20, bottom: 20, left: 20, right: 20 } }}
/>
</div>
<p style={{ marginTop: '10px', color: '#64748b' }}>Generous Padding</p>
<p style={{ fontSize: '11px', color: '#94a3b8' }}>20px all around</p>
</div>
<div style={{ textAlign: 'center' }}>
<div style={{ border: '2px solid #e2e8f0', borderRadius: '8px', padding: '10px' }}>
<AbacusStatic
value={15}
hideInactiveBeads
cropToActiveBeads={{ padding: { top: 2, bottom: 2, left: 2, right: 2 } }}
/>
</div>
<p style={{ marginTop: '10px', color: '#64748b' }}>Tight Crop</p>
<p style={{ fontSize: '11px', color: '#94a3b8' }}>2px minimal padding</p>
</div>
<div style={{ textAlign: 'center' }}>
<div style={{ border: '2px solid #e2e8f0', borderRadius: '8px', padding: '10px' }}>
<AbacusStatic
value={15}
hideInactiveBeads
cropToActiveBeads={{ padding: { top: 15, bottom: 2, left: 5, right: 5 } }}
/>
</div>
<p style={{ marginTop: '10px', color: '#64748b' }}>Asymmetric</p>
<p style={{ fontSize: '11px', color: '#94a3b8' }}>More top space</p>
</div>
</div>
),
}
export const WithColorSchemes: Story = {
render: () => (
<div style={{ display: 'flex', gap: '30px', flexWrap: 'wrap' }}>
{(['place-value', 'monochrome', 'heaven-earth', 'alternating'] as const).map((scheme) => (
<div key={scheme} style={{ textAlign: 'center' }}>
<div style={{ border: '2px solid #e2e8f0', borderRadius: '8px', padding: '10px', background: 'white' }}>
<AbacusStatic
value={123}
colorScheme={scheme}
hideInactiveBeads
cropToActiveBeads
scaleFactor={0.9}
/>
</div>
<p style={{ marginTop: '10px', color: '#64748b', fontSize: '14px' }}>
{scheme.split('-').map(w => w.charAt(0).toUpperCase() + w.slice(1)).join(' ')}
</p>
</div>
))}
</div>
),
}
export const DifferentColumnCounts: Story = {
render: () => (
<div style={{ display: 'flex', gap: '40px', flexWrap: 'wrap', alignItems: 'flex-start' }}>
<div style={{ textAlign: 'center' }}>
<div style={{ border: '2px solid #e2e8f0', borderRadius: '8px', padding: '15px', background: 'white' }}>
<AbacusStatic
value={9}
columns={1}
hideInactiveBeads
cropToActiveBeads
scaleFactor={1.5}
/>
</div>
<p style={{ marginTop: '10px', color: '#64748b' }}>1 Column</p>
<p style={{ fontSize: '12px', color: '#94a3b8' }}>Value: 9</p>
</div>
<div style={{ textAlign: 'center' }}>
<div style={{ border: '2px solid #e2e8f0', borderRadius: '8px', padding: '15px', background: 'white' }}>
<AbacusStatic
value={25}
columns={2}
hideInactiveBeads
cropToActiveBeads
scaleFactor={1.5}
/>
</div>
<p style={{ marginTop: '10px', color: '#64748b' }}>2 Columns</p>
<p style={{ fontSize: '12px', color: '#94a3b8' }}>Value: 25</p>
</div>
<div style={{ textAlign: 'center' }}>
<div style={{ border: '2px solid #e2e8f0', borderRadius: '8px', padding: '15px', background: 'white' }}>
<AbacusStatic
value={456}
columns={3}
hideInactiveBeads
cropToActiveBeads
scaleFactor={1.2}
/>
</div>
<p style={{ marginTop: '10px', color: '#64748b' }}>3 Columns</p>
<p style={{ fontSize: '12px', color: '#94a3b8' }}>Value: 456</p>
</div>
<div style={{ textAlign: 'center' }}>
<div style={{ border: '2px solid #e2e8f0', borderRadius: '8px', padding: '15px', background: 'white' }}>
<AbacusStatic
value={9876}
columns={4}
hideInactiveBeads
cropToActiveBeads
scaleFactor={1.0}
/>
</div>
<p style={{ marginTop: '10px', color: '#64748b' }}>4 Columns</p>
<p style={{ fontSize: '12px', color: '#94a3b8' }}>Value: 9876</p>
</div>
</div>
),
}
export const InlineEquation: Story = {
render: () => (
<div style={{ fontSize: '32px', display: 'flex', alignItems: 'center', gap: '15px', fontFamily: 'system-ui' }}>
<span>If</span>
<div style={{ border: '2px solid #e2e8f0', borderRadius: '6px', padding: '5px', background: 'white' }}>
<AbacusStatic value={5} columns={1} hideInactiveBeads cropToActiveBeads scaleFactor={1.2} />
</div>
<span>+</span>
<div style={{ border: '2px solid #e2e8f0', borderRadius: '6px', padding: '5px', background: 'white' }}>
<AbacusStatic value={3} columns={1} hideInactiveBeads cropToActiveBeads scaleFactor={1.2} />
</div>
<span>=</span>
<div style={{ border: '2px solid #10b981', borderRadius: '6px', padding: '5px', background: '#f0fdf4' }}>
<AbacusStatic value={8} columns={1} hideInactiveBeads cropToActiveBeads scaleFactor={1.2} />
</div>
<span>then what is</span>
<div style={{ border: '2px solid #e2e8f0', borderRadius: '6px', padding: '5px', background: 'white' }}>
<AbacusStatic value={10} columns={2} hideInactiveBeads cropToActiveBeads scaleFactor={1.0} />
</div>
<span>+</span>
<div style={{ border: '2px solid #e2e8f0', borderRadius: '6px', padding: '5px', background: 'white' }}>
<AbacusStatic value={15} columns={2} hideInactiveBeads cropToActiveBeads scaleFactor={1.0} />
</div>
<span>?</span>
</div>
),
}
export const FaviconStyle: Story = {
render: () => (
<div>
<p style={{ marginBottom: '20px', color: '#64748b', maxWidth: '600px' }}>
These examples show how cropping is used for the dynamic favicon (see <code>/icon</code> route).
Each day of the month gets its own cropped abacus icon.
</p>
<div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fill, minmax(80px, 1fr))', gap: '15px', maxWidth: '800px' }}>
{Array.from({ length: 31 }, (_, i) => i + 1).map((day) => (
<div key={day} style={{ textAlign: 'center' }}>
<div style={{
width: '64px',
height: '64px',
border: '2px solid #e2e8f0',
borderRadius: '8px',
padding: '4px',
background: 'white',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
margin: '0 auto'
}}>
<AbacusStatic
value={day}
columns={2}
hideInactiveBeads
cropToActiveBeads={{
padding: { top: 6, bottom: 2, left: 4, right: 4 }
}}
scaleFactor={0.8}
customStyles={{
columnPosts: { fill: '#1c1917', stroke: '#0c0a09', strokeWidth: 2 },
reckoningBar: { fill: '#1c1917', stroke: '#0c0a09', strokeWidth: 3 },
columns: {
0: { heavenBeads: { fill: '#fbbf24', stroke: '#f59e0b', strokeWidth: 2 }, earthBeads: { fill: '#fbbf24', stroke: '#f59e0b', strokeWidth: 2 } },
1: { heavenBeads: { fill: '#a855f7', stroke: '#7e22ce', strokeWidth: 2 }, earthBeads: { fill: '#a855f7', stroke: '#7e22ce', strokeWidth: 2 } },
},
}}
/>
</div>
<p style={{ marginTop: '8px', fontSize: '12px', color: '#64748b', fontWeight: 'bold' }}>{day}</p>
</div>
))}
</div>
</div>
),
}
export const AbacusReactCropping: Story = {
render: () => (
<div>
<p style={{ marginBottom: '20px', color: '#64748b', maxWidth: '600px' }}>
Cropping also works with <code>AbacusReact</code> (the interactive animated version).
This is useful for interactive tutorials where you want to focus on specific beads.
</p>
<div style={{ display: 'flex', gap: '40px', flexWrap: 'wrap' }}>
<div style={{ textAlign: 'center' }}>
<div style={{ border: '2px solid #e2e8f0', borderRadius: '8px', padding: '15px', background: 'white' }}>
<AbacusReact
value={15}
columns={2}
hideInactiveBeads
cropToActiveBeads
animated
interactive
scaleFactor={1.5}
/>
</div>
<p style={{ marginTop: '10px', color: '#64748b' }}>Interactive + Cropped</p>
<p style={{ fontSize: '12px', color: '#94a3b8' }}>Try clicking the beads!</p>
</div>
<div style={{ textAlign: 'center' }}>
<div style={{ border: '2px solid #e2e8f0', borderRadius: '8px', padding: '15px', background: 'white' }}>
<AbacusReact
value={9}
columns={1}
hideInactiveBeads
cropToActiveBeads={{ padding: { top: 10, bottom: 10, left: 10, right: 10 } }}
animated
interactive
scaleFactor={2.0}
/>
</div>
<p style={{ marginTop: '10px', color: '#64748b' }}>Single Column</p>
<p style={{ fontSize: '12px', color: '#94a3b8' }}>Value: 9</p>
</div>
<div style={{ textAlign: 'center' }}>
<div style={{ border: '2px solid #e2e8f0', borderRadius: '8px', padding: '15px', background: 'white' }}>
<AbacusReact
value={456}
columns={3}
hideInactiveBeads
cropToActiveBeads
animated
interactive
scaleFactor={1.2}
colorScheme="heaven-earth"
/>
</div>
<p style={{ marginTop: '10px', color: '#64748b' }}>Three Columns</p>
<p style={{ fontSize: '12px', color: '#94a3b8' }}>Heaven-Earth colors</p>
</div>
</div>
</div>
),
}
export const ComparisonGrid: Story = {
render: () => {
const testValues = [
{ value: 1, label: 'Minimal (1)' },
{ value: 5, label: 'Heaven only (5)' },
{ value: 4, label: 'Earth only (4)' },
{ value: 9, label: 'Maximum (9)' },
{ value: 15, label: 'Two columns (15)' },
{ value: 99, label: 'Two nines (99)' },
]
return (
<div>
<p style={{ marginBottom: '20px', color: '#64748b', maxWidth: '700px' }}>
Comparison showing how cropping adapts to different bead configurations.
Notice how the viewBox changes dynamically based on active beads.
</p>
<div style={{ display: 'grid', gridTemplateColumns: 'repeat(3, 1fr)', gap: '20px' }}>
{testValues.map(({ value, label }) => (
<div key={value}>
<div style={{ marginBottom: '15px' }}>
<h4 style={{ margin: '0 0 10px 0', color: '#475569' }}>{label}</h4>
<div style={{ display: 'flex', gap: '15px' }}>
<div style={{ flex: 1, textAlign: 'center' }}>
<div style={{ border: '2px solid #e2e8f0', borderRadius: '6px', padding: '10px', minHeight: '120px', display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
<AbacusStatic
value={value}
columns="auto"
hideInactiveBeads
scaleFactor={1.0}
/>
</div>
<p style={{ marginTop: '5px', fontSize: '11px', color: '#94a3b8' }}>Normal</p>
</div>
<div style={{ flex: 1, textAlign: 'center' }}>
<div style={{ border: '2px solid #3b82f6', borderRadius: '6px', padding: '10px', minHeight: '120px', display: 'flex', alignItems: 'center', justifyContent: 'center', background: '#eff6ff' }}>
<AbacusStatic
value={value}
columns="auto"
hideInactiveBeads
cropToActiveBeads
scaleFactor={1.0}
/>
</div>
<p style={{ marginTop: '5px', fontSize: '11px', color: '#3b82f6', fontWeight: 'bold' }}>Cropped</p>
</div>
</div>
</div>
</div>
))}
</div>
</div>
)
},
}
export const BeadShapesWithCropping: Story = {
render: () => (
<div style={{ display: 'flex', gap: '40px', flexWrap: 'wrap' }}>
{(['circle', 'diamond', 'square'] as const).map((shape) => (
<div key={shape} style={{ textAlign: 'center' }}>
<div style={{ border: '2px solid #e2e8f0', borderRadius: '8px', padding: '15px', background: 'white' }}>
<AbacusStatic
value={25}
columns={2}
beadShape={shape}
hideInactiveBeads
cropToActiveBeads
scaleFactor={1.5}
/>
</div>
<p style={{ marginTop: '10px', color: '#64748b', textTransform: 'capitalize' }}>{shape}</p>
</div>
))}
</div>
),
}

View File

@@ -7,7 +7,7 @@ import NumberFlow from "@number-flow/react";
import { useAbacusConfig, getDefaultAbacusConfig } from "./AbacusContext";
import { playBeadSound } from "./soundManager";
import * as Abacus3DUtils from "./Abacus3DUtils";
import { calculateStandardDimensions, calculateBeadPosition } from "./AbacusUtils";
import { calculateStandardDimensions, calculateBeadPosition, type CropPadding } from "./AbacusUtils";
import { AbacusSVGRenderer } from "./AbacusSVGRenderer";
import { AbacusAnimatedBead } from "./AbacusAnimatedBead";
import "./Abacus3D.css";
@@ -296,6 +296,9 @@ export interface AbacusConfig {
disabledColumns?: number[]; // Disable interaction on specific columns (legacy - array indices)
disabledBeads?: BeadHighlight[]; // Support both place-value and column-index based disabling
// Cropping
cropToActiveBeads?: boolean | { padding?: CropPadding }; // Crop viewBox to show only active beads
// Legacy callbacks for backward compatibility
onClick?: (bead: BeadConfig) => void;
onValueChange?: (newValue: number | bigint) => void;
@@ -1595,6 +1598,8 @@ export const AbacusReact: React.FC<AbacusConfig> = ({
showDirectionIndicators = false,
disabledColumns = [],
disabledBeads = [],
// Cropping
cropToActiveBeads,
// Legacy callbacks
onClick,
onValueChange,
@@ -2215,6 +2220,7 @@ export const AbacusReact: React.FC<AbacusConfig> = ({
interactive={finalConfig.interactive}
highlightColumns={highlightColumns}
columnLabels={columnLabels}
cropToActiveBeads={cropToActiveBeads}
defsContent={defsContent}
BeadComponent={AbacusAnimatedBead}
getBeadColor={getBeadColor}

View File

@@ -34,7 +34,7 @@
import React from 'react'
import type { AbacusLayoutDimensions } from './AbacusUtils'
import type { BeadConfig, AbacusCustomStyles, ValidPlaceValues } from './AbacusReact'
import { numberToAbacusState, calculateBeadPosition, type AbacusState } from './AbacusUtils'
import { numberToAbacusState, calculateBeadPosition, calculateAbacusCrop, type AbacusState, type CropPadding } from './AbacusUtils'
/**
* Props that bead components must accept
@@ -83,6 +83,9 @@ export interface AbacusSVGRendererProps {
customStyles?: AbacusCustomStyles
interactive?: boolean // Enable interactive CSS styles
// Cropping
cropToActiveBeads?: boolean | { padding?: CropPadding }
// Tutorial features
highlightColumns?: number[]
columnLabels?: string[]
@@ -127,6 +130,7 @@ export function AbacusSVGRenderer({
showNumbers,
customStyles,
interactive = false,
cropToActiveBeads,
highlightColumns = [],
columnLabels = [],
defsContent,
@@ -141,12 +145,26 @@ export function AbacusSVGRenderer({
}: AbacusSVGRendererProps) {
const { width, height, rodSpacing, barY, beadSize, barThickness, labelHeight, numbersHeight } = dimensions
// Calculate crop viewBox if enabled
let viewBox = `0 0 ${width} ${height}`
let svgWidth = width
let svgHeight = height
if (cropToActiveBeads) {
const padding = typeof cropToActiveBeads === 'object' ? cropToActiveBeads.padding : undefined
// Use the actual scaleFactor so crop calculations match the rendered abacus size
const crop = calculateAbacusCrop(Number(value), columns, scaleFactor, padding)
viewBox = crop.viewBox
svgWidth = crop.width
svgHeight = crop.height
}
return (
<svg
xmlns="http://www.w3.org/2000/svg"
width={width * scaleFactor}
height={height * scaleFactor}
viewBox={`0 0 ${width} ${height}`}
width={svgWidth}
height={svgHeight}
viewBox={viewBox}
className={`abacus-svg ${hideInactiveBeads ? 'hide-inactive-mode' : ''} ${interactive ? 'interactive' : ''}`}
style={{ overflow: 'visible', display: 'block' }}
>

View File

@@ -7,7 +7,7 @@
* Different: No hooks, no animations, no interactions, simplified bead rendering
*/
import { numberToAbacusState, calculateStandardDimensions } from './AbacusUtils'
import { numberToAbacusState, calculateStandardDimensions, type CropPadding } from './AbacusUtils'
import { AbacusSVGRenderer } from './AbacusSVGRenderer'
import { AbacusStaticBead } from './AbacusStaticBead'
import type {
@@ -30,6 +30,7 @@ export interface AbacusStaticConfig {
customStyles?: AbacusCustomStyles
highlightColumns?: number[]
columnLabels?: string[]
cropToActiveBeads?: boolean | { padding?: CropPadding }
}
// Shared color logic (matches AbacusReact)
@@ -106,6 +107,7 @@ export function AbacusStatic({
customStyles,
highlightColumns = [],
columnLabels = [],
cropToActiveBeads,
}: AbacusStaticConfig) {
// Calculate columns
const valueStr = value.toString().replace('-', '')
@@ -175,6 +177,7 @@ export function AbacusStatic({
customStyles={customStyles}
highlightColumns={highlightColumns}
columnLabels={columnLabels}
cropToActiveBeads={cropToActiveBeads}
BeadComponent={AbacusStaticBead}
getBeadColor={getBeadColor}
/>

View File

@@ -5,6 +5,38 @@
import type { ValidPlaceValues, BeadHighlight } from './AbacusReact'
/**
* Calculate the actual rendered dimensions of a bead based on its shape
* These values match the exact rendering in AbacusStaticBead and AbacusAnimatedBead
*
* @param size - The base bead size parameter
* @param shape - The bead shape ('circle', 'diamond', or 'square')
* @returns Object with width and height of the rendered bead
*/
export function calculateBeadDimensions(
size: number,
shape: 'circle' | 'diamond' | 'square' = 'diamond'
): { width: number; height: number } {
switch (shape) {
case 'diamond':
// Diamond polygon: points=`${size*0.7},0 ${size*1.4},${size/2} ${size*0.7},${size} 0,${size/2}`
// Spans from x=0 to x=size*1.4, y=0 to y=size
return { width: size * 1.4, height: size }
case 'circle':
// Circle with radius=size/2, so diameter=size
return { width: size, height: size }
case 'square':
// Square with width=size, height=size
return { width: size, height: size }
default:
// Default to diamond (most common/largest)
return { width: size * 1.4, height: size }
}
}
/**
* Represents the state of beads in a single column
*/
@@ -515,7 +547,7 @@ export function calculateBeadPosition(
dimensions: AbacusLayoutDimensions,
columnState?: ColumnStateForPositioning
): { x: number; y: number } {
const { beadSize, rodSpacing, heavenEarthGap, barThickness, activeGap, inactiveGap, adjacentSpacing, totalColumns } = dimensions
const { beadSize, rodSpacing, heavenEarthGap, barThickness, activeGap, inactiveGap, adjacentSpacing, totalColumns, labelHeight } = dimensions
// X position based on place value (rightmost = ones place)
const columnIndex = totalColumns - 1 - bead.placeValue
@@ -523,14 +555,15 @@ export function calculateBeadPosition(
// Y position based on bead type and active state
// These formulas match the original Typst implementation exactly
// NOTE: All Y positions are offset by labelHeight to match absolute SVG coordinates
if (bead.type === 'heaven') {
if (bead.active) {
// Active heaven bead: positioned close to reckoning bar (Typst line 175)
const y = heavenEarthGap - beadSize / 2 - activeGap
const y = labelHeight + heavenEarthGap - beadSize / 2 - activeGap
return { x, y }
} else {
// Inactive heaven bead: positioned away from reckoning bar (Typst line 178)
const y = heavenEarthGap - inactiveGap - beadSize / 2
const y = labelHeight + heavenEarthGap - inactiveGap - beadSize / 2
return { x, y }
}
} else {
@@ -539,7 +572,7 @@ export function calculateBeadPosition(
if (bead.active) {
// Active beads: positioned near reckoning bar, adjacent beads touch (Typst line 251)
const y = heavenEarthGap + barThickness + activeGap + beadSize / 2 +
const y = labelHeight + heavenEarthGap + barThickness + activeGap + beadSize / 2 +
bead.position * (beadSize + adjacentSpacing)
return { x, y }
} else {
@@ -547,16 +580,194 @@ export function calculateBeadPosition(
let y: number
if (earthActive > 0) {
// Position after the last active bead + gap, then adjacent inactive beads touch (Typst line 256)
y = heavenEarthGap + barThickness + activeGap + beadSize / 2 +
y = labelHeight + heavenEarthGap + barThickness + activeGap + beadSize / 2 +
(earthActive - 1) * (beadSize + adjacentSpacing) +
beadSize / 2 + inactiveGap + beadSize / 2 +
(bead.position - earthActive) * (beadSize + adjacentSpacing)
} else {
// No active beads: position after reckoning bar + gap, adjacent inactive beads touch (Typst line 259)
y = heavenEarthGap + barThickness + inactiveGap + beadSize / 2 +
y = labelHeight + heavenEarthGap + barThickness + inactiveGap + beadSize / 2 +
bead.position * (beadSize + adjacentSpacing)
}
return { x, y }
}
}
}
/**
* Padding configuration for cropping
*/
export interface CropPadding {
top?: number
bottom?: number
left?: number
right?: number
}
/**
* Bounding box for crop area
*/
export interface BoundingBox {
minX: number
minY: number
maxX: number
maxY: number
width: number
height: number
}
/**
* Complete crop calculation result
*/
export interface CropResult extends BoundingBox {
viewBox: string // SVG viewBox attribute value
scaledWidth: number // Width after scaling to fit target
scaledHeight: number // Height after scaling to fit target
}
/**
* Calculate bounding box around active beads for a given value
* Uses the same position calculations as the rendering engine
*
* @param value - The number to display
* @param columns - Number of columns
* @param scaleFactor - Scale factor for the abacus
* @returns Bounding box containing all active beads
*/
export function calculateActiveBeadsBounds(
value: number,
columns: number,
scaleFactor: number = 1
): BoundingBox {
// Get which beads are active for this value
const abacusState = numberToAbacusState(value, columns)
// Get layout dimensions
const dimensions = calculateStandardDimensions({
columns,
scaleFactor,
showNumbers: false,
columnLabels: [],
})
// Calculate positions of all active beads
const activeBeadPositions: Array<{ x: number; y: number }> = []
for (let placeValue = 0; placeValue < columns; placeValue++) {
const columnState = abacusState[placeValue]
if (!columnState) continue
// Heaven bead
if (columnState.heavenActive) {
const bead: BeadPositionConfig = {
type: 'heaven',
active: true,
position: 0,
placeValue,
}
const pos = calculateBeadPosition(bead, dimensions, { earthActive: columnState.earthActive })
activeBeadPositions.push(pos)
}
// Earth beads
for (let earthPos = 0; earthPos < columnState.earthActive; earthPos++) {
const bead: BeadPositionConfig = {
type: 'earth',
active: true,
position: earthPos,
placeValue,
}
const pos = calculateBeadPosition(bead, dimensions, { earthActive: columnState.earthActive })
activeBeadPositions.push(pos)
}
}
if (activeBeadPositions.length === 0) {
// Fallback if no active beads - show full abacus
return {
minX: 0,
minY: 0,
maxX: dimensions.width,
maxY: dimensions.height,
width: dimensions.width,
height: dimensions.height,
}
}
// Calculate bounding box from active bead positions
// Use diamond dimensions (largest bead shape) for consistent cropping across all shapes
const { width: beadWidth, height: beadHeight } = calculateBeadDimensions(dimensions.beadSize, 'diamond')
let minX = Infinity
let maxX = -Infinity
let minY = Infinity
let maxY = -Infinity
for (const pos of activeBeadPositions) {
// Bead center is at pos.x, pos.y
// Calculate bounding box for diamond shape
minX = Math.min(minX, pos.x - beadWidth / 2)
maxX = Math.max(maxX, pos.x + beadWidth / 2)
minY = Math.min(minY, pos.y - beadHeight / 2)
maxY = Math.max(maxY, pos.y + beadHeight / 2)
}
// HORIZONTAL BOUNDS: Always show full width of all columns (consistent across all values)
// Use rod positions for consistent horizontal bounds
const rodSpacing = dimensions.rodSpacing
minX = rodSpacing / 2 - beadWidth / 2
maxX = (columns - 0.5) * rodSpacing + beadWidth / 2
return {
minX,
minY,
maxX,
maxY,
width: maxX - minX,
height: maxY - minY,
}
}
/**
* Calculate crop parameters with padding for SVG viewBox
*
* @param value - The number to display
* @param columns - Number of columns
* @param scaleFactor - Scale factor for the abacus
* @param padding - Padding to add around the crop area
* @returns Complete crop result with viewBox and dimensions
*/
export function calculateAbacusCrop(
value: number,
columns: number,
scaleFactor: number = 1,
padding: CropPadding = {}
): CropResult {
const bbox = calculateActiveBeadsBounds(value, columns, scaleFactor)
// Apply padding
const paddingTop = padding.top ?? 0
const paddingBottom = padding.bottom ?? 0
const paddingLeft = padding.left ?? 0
const paddingRight = padding.right ?? 0
const cropX = bbox.minX - paddingLeft
const cropY = bbox.minY - paddingTop
const cropWidth = bbox.width + paddingLeft + paddingRight
const cropHeight = bbox.height + paddingTop + paddingBottom
// Create viewBox string
const viewBox = `${cropX} ${cropY} ${cropWidth} ${cropHeight}`
return {
minX: cropX,
minY: cropY,
maxX: cropX + cropWidth,
maxY: cropY + cropHeight,
width: cropWidth,
height: cropHeight,
viewBox,
scaledWidth: cropWidth,
scaledHeight: cropHeight,
}
}

View File

@@ -50,6 +50,9 @@ export {
calculateAbacusDimensions,
calculateStandardDimensions, // NEW: Shared layout calculator
calculateBeadPosition, // NEW: Bead position calculator
calculateBeadDimensions, // NEW: Calculate exact bead dimensions by shape
calculateActiveBeadsBounds, // NEW: Calculate bounding box for active beads
calculateAbacusCrop, // NEW: Calculate crop parameters with padding
} from "./AbacusUtils";
export type {
BeadState,
@@ -59,6 +62,9 @@ export type {
PlaceValueBasedBead,
AbacusLayoutDimensions, // NEW: Complete layout dimensions type
BeadPositionConfig, // NEW: Bead config for position calculation
CropPadding, // NEW: Padding config for cropping
BoundingBox, // NEW: Bounding box type
CropResult, // NEW: Complete crop calculation result
} from "./AbacusUtils";
export { useAbacusDiff, useAbacusState } from "./AbacusHooks";