19 Commits
Author SHA1 Message Date
ddidderr 3fc1096500 fmt: README.md files and .cargo/config.toml 2026-09-01 05:27:10 +02:00
ddidderr a5f2aab005 chore(release): prepare v1.2.1
Bump the package version to 1.2.1 for multiball Greifarm capture preservation and scoping fixes. Update CHANGELOG.md and refresh the tracked web WASM artifact.

Test Plan:
- `just test` -- passed (152 game tests and 8 service tests)
- `just clippy` -- passed
- `just build-production` -- passed
- `just web-build` -- passed
- `cargo +nightly fmt --all -- --check` -- passed
- `rumdl check --flavor commonmark CHANGELOG.md` -- passed
- `cargo metadata --locked --format-version 1 --no-deps` -- passed
- `git diff --cached --check` -- passed
2026-09-01 05:22:59 +02:00
ddidderr 71e5450a84 fix(divergence): scope claw latch to captured slot
The Greifarm entry restriction was still shared across both multiball slots.
An unrelated upper-playfield ball could clear the entering ball's latch during
its own record-89 scan, while a shallow aborted entry could retain a stale
choice. Store the latch owner with the capture-time restriction, permit only
that slot to clear it when leaving the deep capture zone, and migrate the owner
when a held secondary ball becomes primary.

Test Plan:
- `just --justfile tdkpin-rs/justfile test` -- passed (151 game, 8 service tests)
- `just --justfile tdkpin-rs/justfile clippy` -- passed
- `just --justfile tdkpin-rs/justfile build-production` -- passed
- `just --justfile tdkpin-rs/justfile web-build` -- passed
- `cargo +nightly fmt --manifest-path tdkpin-rs/Cargo.toml --all -- --check` -- passed
- `rumdl check --flavor commonmark tdkpin-rs/CHANGELOG.md tdkpin-rs/AGENTS.md` -- passed
- `git diff --cached --check` -- passed
2026-08-31 23:27:15 +02:00
ddidderr 26a2567c91 fix(divergence): latch multiball claw capture state
A multiball Greifarm capture could lose its two-ball restriction while the
ball was still being pulled: capture age remains zero during nonstationary
pulling, so a later callback with one remaining ball rewrote the decision.
Represent the capture decision as an explicit optional latch and clear it only
when that entry exits or the claw state resets. When a held secondary ball is
promoted after the primary drains or is captured, migrate record 89 ownership
to ball one as well, so the released ball can clear its contact normally.

Test Plan:
- `just --justfile tdkpin-rs/justfile test` -- passed (149 game/service tests)
- `just --justfile tdkpin-rs/justfile clippy` -- passed
- `just --justfile tdkpin-rs/justfile build-production` -- passed
- `just --justfile tdkpin-rs/justfile web-build` -- passed
- `cargo +nightly fmt --manifest-path tdkpin-rs/Cargo.toml --all -- --check` -- passed
- `rumdl check --flavor commonmark tdkpin-rs/CHANGELOG.md tdkpin-rs/AGENTS.md` -- passed
- `git diff --cached --check` -- passed
2026-08-31 23:11:00 +02:00
ddidderr 25147ad58e fix(divergence): preserve multiball Greifarm captures
The original port consumed a ball as soon as record 89 completed during
multiball, which skipped the Greifarm animation and lost the ball permanently.
Keep the captured slot through the full animation instead, latch whether the
capture began with two live balls, and exclude the launcher release (frame 18)
for that capture. The surviving slot continues physics, scoring, nudging, and
flipper responses while the held slot is suspended; drain and promotion paths
also preserve the held ball. A later Greifarm entry makes a fresh ball-count
decision. Update slot-aware rendering and refresh the browser WASM artifact.

Test Plan:
- `just --justfile tdkpin-rs/justfile test` -- passed (149 game/service tests)
- `just --justfile tdkpin-rs/justfile clippy` -- passed
- `just --justfile tdkpin-rs/justfile build-production` -- passed
- `just --justfile tdkpin-rs/justfile web-build` -- passed
- `cargo +nightly fmt --manifest-path tdkpin-rs/Cargo.toml --all -- --check` -- passed
- `rumdl check --flavor commonmark tdkpin-rs/CHANGELOG.md tdkpin-rs/AGENTS.md` -- passed
- `git diff --cached --check` -- passed
2026-08-31 22:15:39 +02:00
ddidderr c4fb345197 chore(release): prepare v1.2.0
Bump the package version to 1.2.0 for the high-score demo database seeding, service hardening, web retry bounds, and multiball parity and divergence fixes. Update CHANGELOG.md and refresh the tracked web WASM artifact.

Test Plan:
- `just test` -- passed (142 game tests and 8 service tests)
- `just clippy` -- passed
- `just build-production` -- passed
- `just web-build` -- passed
- `cargo +nightly fmt --all -- --check` -- passed
- `rumdl check --flavor commonmark tdkpin-rs/CHANGELOG.md` -- passed
- `cargo metadata --locked --format-version 1 --no-deps` -- passed
- `git diff --cached --check` -- passed
2026-08-31 20:48:59 +02:00
ddidderr 4385a661b3 web 2026-08-31 20:46:20 +02:00
ddidderr 9023af7e7e fix(web): define high-score retry bounds
The browser storage plugin initializes and updates its high-score retry
backoff, but the constants supplying its initial and maximum delays were
lost during the merge that combined the retry and relative-endpoint fixes.
Define the intended 250 ms initial delay and 30 s cap so the plugin can load
and retain bounded retry behavior after transient submission failures.

Test Plan:
- `node --check tdkpin-rs/web/storage.js` -- passed
- Node VM top-level load harness -- passed
- `prettier --check tdkpin-rs/web/storage.js` -- passed
- `cargo +nightly fmt --all -- --check` -- passed
- `just test` -- passed (144 tests)
- `just clippy` -- passed
- `git diff --cached --check` -- passed
2026-08-29 20:18:53 +02:00
ddidderr 12d1ec0aab Merge branch 'tomerge' 2026-08-29 20:11:13 +02:00
ddidderr 9c5b033c0a fix(web): use relative path for high-score API endpoint
Change the high-score endpoint URL in storage.js from "/api/highscores" to
"./api/highscores". When serving the web build from a subpath rather than the
domain root, an absolute path sends fetch requests to the domain root instead
of the nested application path. Using a relative URL ensures requests resolve
relative to the active document path while still working when hosted at root.

Test Plan:
- `node --check tdkpin-rs/web/storage.js` -- passed
- `npx prettier --check tdkpin-rs/web/storage.js` -- passed
- `just test` -- passed (138 game tests, 3 highscore-server tests)
- `just clippy` -- passed
- `git diff --cached --check` -- passed
2026-08-29 20:08:15 +02:00
ddidderr bc1ebcaaaa fix(web): back off high-score retries
The browser previously retried every failed shared high-score submission on the
50 ms polling interval. With server-side rate limiting and database load
shedding, immediate 429 and 503 responses could create a tight retry loop.
Add a bounded exponential delay with jitter, honor Retry-After on transient
responses, and reset the delay after a successful submission. Keep the pending
revision retryable without allowing overlapping requests.

Test Plan:
- `node --check tdkpin-rs/web/storage.js` -- passed
- `prettier --check tdkpin-rs/web/storage.js` -- passed
- Node VM retry timing harness covering Retry-After, backoff, and reset -- passed
- `git diff --cached --check` -- passed
2026-08-29 19:49:49 +02:00
ddidderr 7ee2e71bc7 fix: relative api/highscores path 2026-08-29 18:46:10 +02:00
ddidderr 51502ef92f chore(release): prepare v1.1.0
Build TDK Pinball / build (macos-latest) (push) Canceled after 0s
Build TDK Pinball / build (ubuntu-latest) (push) Canceled after 0s
Build TDK Pinball / build (windows-latest) (push) Canceled after 0s
Bump the package version to 1.1.0 for the web port, optional shared high-score service, and post-1.0 parity and edge fixes. Update CHANGELOG.md and refresh the tracked web WASM artifact.

Test Plan:
- `just test` -- passed (138 game tests, 3 highscore-server tests)
- `just clippy` -- passed
- `just build-production` -- passed
- `just web-build` -- passed
- `cargo metadata --locked --format-version 1 --no-deps` -- passed
- `git diff --cached --check` -- passed
2026-08-29 17:52:53 +02:00
ddidderr f9063bd2ff chore(web): regenerate browser artifact
Build TDK Pinball / build (macos-latest) (push) Canceled after 0s
Build TDK Pinball / build (ubuntu-latest) (push) Canceled after 0s
Build TDK Pinball / build (windows-latest) (push) Canceled after 0s
2026-08-29 17:50:49 +02:00
ddidderr acb0c20b59 fix(web): vendor the Macroquad browser loader
The page depended on the externally hosted miniquad bundle, which violates a
same-origin `script-src 'self'` policy and makes the game depend on a third
party at runtime. Vendor the current official loader alongside the web assets
and move the WASM `load` call into a local bootstrap script, preserving plugin
registration order without inline JavaScript.

Document the CSP requirement for WebAssembly compilation and same-origin
connections. The vendored bundle is the current response from the official
Macroquad loader URL and was syntax-checked before committing.

Test Plan:
- `just web-build` -- passed
- `node --check web/mq_js_bundle.js web/storage.js web/bootstrap.js` -- passed
- `prettier --check web/storage.js web/bootstrap.js` -- passed
- Browser smoke test with `script-src 'self' 'wasm-unsafe-eval'` and `connect-src 'self'` -- passed; 640x460 canvas and no CSP/script errors
- `git diff --cached --check` -- passed
2026-08-29 17:12:43 +02:00
ddidderr 5dd7f38450 feat(web): use the shared high-score service
Keep browser settings and the existing local save fallback, but route the
browser high-score table through the same-origin service when it is available.
The WASM storage bridge now accepts fetched score JSON and queues one validated
submission at a time. The JavaScript plugin fetches the canonical table,
submits accepted name-entry scores, ignores stale responses, retries failures,
and feeds successful responses back into the running game.

Update the web and project documentation to describe the optional shared
leaderboard and regenerate the tracked browser artifact. A missing service
continues to leave the local table usable; the service documentation records
that anonymous client scores are intentionally not tamper-resistant.

Test Plan:
- `just test` -- passed (3 service tests and 137 game tests)
- `just clippy` -- passed
- `just web-build` -- passed
- `cargo +nightly fmt -- --check` -- passed
- `node --check web/storage.js` and `prettier --check web/storage.js` -- passed
- `rumdl check --flavor commonmark CHANGELOG.md README.md web/README.md highscore-server/README.md` -- passed
- Browser WASM load through same-origin API proxy -- passed
- `git diff --cached --check` -- passed
2026-08-29 15:55:15 +02:00
ddidderr 8fe9431989 fix(game): restore startup and multiball edge behavior
Build TDK Pinball / build (macos-latest) (push) Canceled after 0s
Build TDK Pinball / build (ubuntu-latest) (push) Canceled after 0s
Build TDK Pinball / build (windows-latest) (push) Canceled after 0s
The interactive build inherited Macroquad's fixed zero random state, making
maximum-power launcher shots repeat across fresh runs. Seed the platform
generator from the startup clock before taking the program-global gameplay
seed. Require record 148's still-live contact before the effect-seven special
respawn and clear active multiball state on an ordinary ball drain, so a
released reserve ball cannot be recreated after both slots are lost.

Type-4 target and effect handlers now honor each record's predicted broadphase
before changing its entry latch. This preserves the latch while another
multiball slot is elsewhere, preventing repeated upper-left corridor scoring.
The regressions and regenerated browser artifact stay with the implementation.

Test Plan:
- `just test` -- passed (137 tests)
- `just clippy` -- passed
- `cargo build --profile production` -- passed
- `just web-build` -- passed
- `cargo +nightly fmt --check` -- passed
- `rumdl check --flavor commonmark CHANGELOG.md` -- passed
- `git diff --cached --check` -- passed
2026-08-29 15:27:28 +02:00
ddidderr a21f01c02d fix(web): keep game at original canvas size
Build TDK Pinball / build (macos-latest) (push) Canceled after 0s
Build TDK Pinball / build (ubuntu-latest) (push) Canceled after 0s
Build TDK Pinball / build (windows-latest) (push) Canceled after 0s
The browser shell previously sized the canvas to the full viewport, causing
Macroquad to scale the 640x460 game presentation as the website changed size.
Keep the canvas at the original 640x460 CSS-pixel dimensions and center it on
a black page instead. A minimum page size and scrolling preserve access to the
fixed canvas on viewports smaller than the original presentation.

Test Plan:
- `just web-build` -- passed
- `git diff --check` -- passed
- Browser smoke test -- canvas measured 640x460 and was centered at (320,130)
  in a 1280x720 viewport; the rendered game remained at the intended fixed
  presentation size with no runtime errors
2026-08-29 14:49:37 +02:00
ddidderr b079cfa196 feat(web): add browser build for TDK Pinball
Expose the existing Macroquad game as a static WASM website while preserving
native desktop behavior. Native-only simulation/file-export code and the
per-user filesystem save path are now separated from the browser build.

The browser version uses a small WASM-only storage support crate and a
Macroquad-compatible JavaScript plugin to persist the same JSON settings and
high scores in localStorage. Browser audio decoding starts in an owned
background coroutine so the game can render its original loading/attract
screens while the embedded sounds finish loading. The checked-in web bundle
contains the optimized WASM, centered black HTML shell, and build/serve
instructions.

Test Plan:
- `just test` -- passed, 135 tests
- `just clippy` -- passed
- `cargo clippy --target wasm32-unknown-unknown -- -D warnings` -- passed
- `cargo +nightly fmt --check` and web-storage format check -- passed
- `just web-build` -- passed; packaged WASM matches the production artifact
- Browser smoke test at `http://127.0.0.1:8000/` -- rendered the centered
  game, started gameplay, opened settings, and restored a changed language
  from browser storage in a fresh page with no runtime errors
2026-08-29 14:32:41 +02:00