Commit Graph
63 Commits
Author SHA1 Message Date
slaguru666andClaude Opus 4.8 3bd85dd9c7 fix: generate the missing seed art images (broken thumbnails)
The art manifest referenced /art/*.png files that never existed; the SPA
fallback returned index.html for them, so the library thumbnails rendered
as broken images. Generate 5 atmospheric B&W placeholder scenes
(tools/gen-art-placeholders.mjs, npm run gen:art) into public/art/.
tests/tools/art-assets.test.js ties every manifest entry to a real PNG.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-21 13:14:33 +01:00
slaguru666andClaude Opus 4.8 529911dc12 fix: service worker network-first for the page so deploys reach devices
The cache-first SW never revalidated the HTML, so a device that loaded the
app once kept serving the old bundle forever (new deploys never landed).
Now: network-first for navigations/HTML (fresh on every online load, cached
shell as offline fallback), cache-first only for immutable hashed assets.
Bumped CACHE to director-v2 so the stale v1 cache is purged on activate.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-21 11:42:55 +01:00
slaguru666andClaude Opus 4.8 0ec09290ea fix: iPad layout — clamp rail labels, fill the stage with a run-board
The rail was a fixed 64px bar cramming 3 info cells against 9 chips, so
long beat/trigger labels wrapped and clipped ('bled'), and trays were thin
top strips leaving the iPad screen mostly empty.

- Rail: min-height + 2-line clamp on the beat/trigger labels (no bleed),
  nowrap 'Reached it', slimmer chips, tabular clock.
- Trays now fill the stage as solid panels (inset:0) instead of a strip.
- New <run-board>: the whole run at a glance behind the trays — every beat
  with target time, done beats stamped/dimmed, next beat highlighted, hard
  triggers + drift. Fills the previously-empty stage with the most useful
  GM view.
- @media (min-width:1024px/1366px): larger type, roomier rows, more art
  columns — uses the tablet space.

tests/components/run-board.test.js. 219 tests pass; build clean.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-21 11:41:03 +01:00
slaguru666andClaude Opus 4.8 1d6e1f4b62 chore: add proxy-network compose for reverse-proxy deploys
docker-compose.proxy.yml runs the container on a shared external 'proxy'
network with no published ports, for hosting behind an existing edge
proxy (Caddy/Traefik/etc.) that routes <sub>.domain -> the-director:80.
This is how it's deployed at apps.timevans.uk.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-21 11:21:16 +01:00
slaguru666andClaude Opus 4.8 89b89572b5 chore: containerized static deploy (Docker + Caddy) for self-hosting
Serve the built PWA behind your own domain: multi-stage Dockerfile builds
dist/ and serves it with Caddy on :80 (TLS terminated at your Cloudflare
edge). Caddyfile sets no-cache on sw.js/index/manifest and immutable on
hashed assets; SPA fallback to index.html. docker-compose maps :8087.

Verified locally: image builds, container serves 200s with correct cache
headers and SPA fallback.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-21 11:11:37 +01:00
slaguru666andClaude Opus 4.8 8f807d50b5 feat: placeholder app icons (clock-with-target motif)
Generate the manifest/PWA + native-wrapper icons that were referenced but
missing (icon-192/512 were 404). A reproducible pure-Node generator
(tools/gen-icons.mjs, npm run gen:icons) draws a clock ring with amber
hands + a green target dot in the app palette — no image deps, hand-rolled
PNG encoder with analytic anti-aliasing.

- public/icons/icon-192, -512, -180 (apple-touch); linked in index.html.
- resources/icon.png (1024) + splash.png (2732) for @capacitor/assets.
- tests/tools/icons.test.js ties every manifest icon to a real PNG of the
  declared size. 213 tests pass; icons now serve 200.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-21 09:29:57 +01:00
slaguru666andClaude Opus 4.8 e79f643409 feat: native iPad wrapper — Capacitor iOS scaffold
Wrap the PWA in a thin native iOS shell (Capacitor 8):
- capacitor.config.json (webDir dist, appId uk.timevans.thedirector,
  iOS safe-area contentInset + theme background).
- @capacitor/{core,cli,ios} as devDependencies (web app keeps zero
  runtime deps); ios:add / ios:sync / ios:open / ios npm scripts.
- main.js skips service-worker registration under Capacitor
  (window.Capacitor.isNativePlatform) — assets are already local.
- iOS <meta> hints in index.html; .gitignore for native build output.
- docs/native-ipad-wrapper.md: full Xcode + CocoaPods build guide,
  incl. the keep-awake plugin note for the wake toggle in WKWebView.

The iOS project generation/build (npx cap add ios → Xcode) needs a Mac
with full Xcode + CocoaPods, which this env lacks; it is documented for
the user to run. tests/tools/capacitor-config.test.js guards the config.
211 tests pass; build clean.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-20 23:55:20 +01:00
slaguru666andClaude Opus 4.8 028dcb5e4e feat: online art Generate — configured endpoint, cached into the library
Add the art tray's online Generate: prompt → a GM-configured image-gen
endpoint → new pencil image cached into a persisted, searchable library
(offline thereafter). No endpoint or key is hardcoded — the GM pastes
their gen URL (⚙ field, persisted). Degrades gracefully: unconfigured or
offline → Generate disabled, library search fully works; network is never
load-bearing.

- src/art/generate.js: createArtGenerator (injectable fetch/navigator).
- src/art/library.js: pure addGenerated (dedupe + cap 24).
- art-tray: generate row, endpoint config, generated cache (gmd.art.*).

Tests: generate.test.js, library.test.js, art-tray-generate.test.js;
existing art-tray tests unchanged. 206 tests pass; build clean.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-20 23:48:05 +01:00
slaguru666andClaude Opus 4.8 7c6ee3eecc feat: markdown → scenario-data generator (tools/)
Add a deterministic authoring tool that turns a structured scenario
markdown file into a validated scenario-data module:
- tools/scenario-md.js: pure parseScenarioMarkdown + emitScenarioModule
  (frontmatter → meta; ## Timeline/## Clues/## Cast lists → the arrays;
  auto-slugged ids; validated via validateScenario before emit).
- tools/md-to-scenario.mjs: CLI (npm run gen:scenario), file or stdout.
- tools/example-scenario.md: documented format example.

Parses a defined format, not freeform con prose. tools/ is dev-only and
never bundled. tests/tools/scenario-md.test.js round-trips + validates.
187 tests pass; build clean.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-20 23:33:28 +01:00
slaguru666andClaude Opus 4.8 6d529c9799 feat: parking-lot note + wake-lock tray tools
Add the last two design-§5 tray tools:
- <parking-lot>: one-tap capture of a thread to return to, stamped with
  the session time, persisted per-scenario (parkingLot store key), 📝 chip.
- src/core/wake-lock.js: injectable Screen Wake Lock controller (keeps the
  tablet awake, re-acquires on foreground, graceful no-op where the API is
  absent). Toggled by a 💡 rail chip that lights when active.

Tests: parking-lot.test.js, wake-lock.test.js, gm-shell-parking.test.js,
gm-shell-wake.test.js. 179 tests pass; build clean.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-20 23:15:14 +01:00
slaguru666andClaude Opus 4.8 73a7ea72ad feat: break timer — pause the session clock so breaks don't poison drift
Add <break-timer> tray: pick a duration, Start break pauses the session
clock (reusing clock.pause/resume), End break resumes it — so meal/comfort
break time is excluded from elapsed and drift stays honest. The shell owns
pause/resume + persistence (break store key); the rail shows a on-break
badge and gains a coffee chip. fmtCountdown (M:SS) added to format.js.

tests/components/break-timer.test.js + gm-shell-break.test.js (incl. the
30-play/20-break/10-play drift-honesty case) + fmtCountdown. 159 tests pass.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-20 23:00:17 +01:00
slaguru666andClaude Opus 4.8 49e9dcda46 feat: dedicated BRP dice pack; Day One uses it instead of coc-d100
Add brp-d100 rule-pack (Basic Roleplaying roll-under): fumble on 100,
critical <= skill/20, special <= skill/5, success <= skill — bands
transcribed from the Continuum Day One console's verdict() logic.
Register it and switch day-one meta.system from coc-d100 to brp-d100.

tests/dice/brp-d100.test.js covers the ladder, low-skill rounding, and
the fumble-only-on-100 edge. 147 tests pass.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-20 22:48:28 +01:00
slaguru666andClaude Opus 4.8 9d0e6c7ec4 feat: cast tray — surface scenario.cast rosters in a session
Add <cast-tray>: renders scenario.cast (name + one-line note) with each
NPC secret behind a tap-to-reveal so spoilers stay off-screen at the
table. Wired into the shell as the 'cast' tool with a 👥 rail chip;
reveal state is ephemeral component state. Now the 57 ported NPCs are
visible in a running session.

tests/components/cast-tray.test.js + gm-shell-cast.test.js. 141 tests pass.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-20 22:34:38 +01:00
slaguru666andClaude Opus 4.8 4096291b1d feat: port all six scenarios' NPC cast rosters into the data model
Populate cast[] (kind:'npc') for every Continuum scenario, transcribed
from the gm-utility NPC sources — normalising the two schemas (console
{id,name,ess,sec} and module {name,tag,secret}) into
{ id, name, kind, note, secret? }. 57 NPCs total. Pregens/PCs excluded
(separate character-sheet system).

No cast UI consumer yet — the design reserves scenario.cast for a future
cast dashboard, so this is a data-model port guarded by
tests/scenarios/cast.test.js (shape + unique ids). 131 tests pass.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-20 22:18:52 +01:00
slaguru666andClaude Opus 4.8 ce91b4ce98 feat: port all six scenarios' clue trails into the data model
Populate clues[] for every Continuum scenario (afterimage, day-one,
vain-crown, silvery-moon, chopper, princes-bride), transcribed faithfully
from the gm-utility console sources (CLUES arrays, gbclue GM-brief spines,
and the princes-bride module). The Slice 4 clue safety-net now works
against real content — essential-gap banner, act labels, and fallbacks.

day-one and princes-bride carry the source's own essential/optional split;
the four GM-brief spines mark each tracked clue essential (single curated
list, no optional tier in-source).

tests/scenarios/clues.test.js guards shape, unique ids, and solvability.
129 tests pass; build clean.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-20 22:12:39 +01:00
slaguru666andClaude Opus 4.8 b4d797b52d feat: port all six Continuum 2026 slots + real schedule times
Rewrite continuum-2026.js from the authoritative con-desk.html SLOTS
array: six real slots with days/times/systems/players and startsAt set,
so the hub's live-now/up-next follows the real convention clock.

Add five scenario modules (day-one, vain-crown, silvery-moon, chopper,
princes-bride) transcribed from the existing gm-utility console
timelines, and register them so every slot is tappable. Day One (BRP)
borrows the coc-d100 pack; the others map to their own systems.

Corrections found while porting: the slate is six slots (Slot 5 Silvery
Moon was missing) and s6 is 'Get to the Chopper — Another Fine Mess'.

tests/con/continuum-2026.test.js guards slot resolvability, valid dice
packs, and schedule status. 125 tests pass; build clean.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-20 21:52:53 +01:00
slaguru666andClaude Opus 4.8 b57880d630 feat: Slice 5 — convention hub (live now / up next, deep-links)
Add the convention hub landing screen: a pure schedule engine
(analyzeSchedule) classifies each slot as live/next/done/upcoming from an
injected now; <con-hub> renders the slate + summary and emits open-scenario;
a scenario registry resolves a slot's scenarioId to its module; gm-shell
routes hub<->session (hiding/restoring the Rail) with a home rail chip.

Ships continuum-2026.js with the real slate (only AFTERIMAGE ported;
others scenarioId:null, start-times TBC) and a fully-timed example-con.js
template/fixture. 122 tests pass; build clean.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-20 21:35:47 +01:00
tevans a7a7870a76 docs: README roadmap + architecture reflect Slices 3-4 (rule-packs, clue safety-net) 2026-07-20 16:59:18 +01:00
tevans 3089233e02 feat: wire clue safety-net into shell + rail; add example scenario 2026-07-20 16:54:25 +01:00
tevans 77148bf0f8 feat: <clue-net> essential-gap tracker component 2026-07-20 16:47:49 +01:00
tevans f89a218eae feat: clue safety-net engine (essential-gap + solvability) 2026-07-20 16:44:44 +01:00
tevansandClaude Opus 4.8 bc8e23c5f6 Plan: The Director Slice 4 (clue safety-net)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-20 16:43:19 +01:00
tevans 8f659181e2 fix: dice-tray re-syncs params on programmatic systemId change 2026-07-20 16:38:22 +01:00
tevans 47cb9c3b3f feat: dice-tray rule-pack selector + per-pack param inputs 2026-07-20 16:33:40 +01:00
tevans 01a279798b feat: Dee Sanction challenge/verdict rule-pack 2026-07-20 16:28:37 +01:00
tevans d64fbc02bf feat: Panic & Glory rule-pack 2026-07-20 16:25:52 +01:00
tevans 95833bd2c1 feat: VANITY d6-pool rule-pack 2026-07-20 16:22:13 +01:00
tevans 605b107c77 feat: CoC 7e d100 rule-pack 2026-07-20 16:18:27 +01:00
tevans 4ebf8d3994 feat: rule-pack contract v2 (params + summary) and registry listing 2026-07-20 16:15:02 +01:00
tevansandClaude Opus 4.8 fee86b8dd1 Plan: The Director Slice 3 (dice rule-packs: CoC d100, VANITY d6, Panic & Glory, Dee Sanction + tray selector)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-20 16:13:06 +01:00
tevans 8a6de064ad chore: gitignore dist/ build output 2026-07-20 15:57:04 +01:00
tevans 21d261cc2d feat: wire NPC + art trays and prop viewer into the shell 2026-07-20 15:51:58 +01:00
tevans e648c17e79 refactor: dedupe art-tray thumbnail template; test real escaping path 2026-07-20 15:47:06 +01:00
tevans 13c71c5aae feat: <art-tray> pencil-art library search UI with HTML escaping 2026-07-20 15:38:47 +01:00
tevans 5bdeef654e refactor: shared escapeHtml util; escape prop-viewer src/alt 2026-07-20 15:35:57 +01:00
tevansandClaude Opus 4.8 9a5e4c4ce4 feat: <prop-viewer> fullscreen prop overlay
Implements fullscreen image overlay component for displaying art to players.
Methods: show(src, label), dismiss(), isOpen(). Starts hidden. Clicking
overlay dismisses. Strict TDD: 3 tests passing.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-20 15:30:56 +01:00
tevans e58d833ba2 feat: seed pencil-art manifest + validator 2026-07-20 15:27:59 +01:00
tevans 6b88e0fa76 feat: pure tag-ranked art library search 2026-07-20 15:24:34 +01:00
tevans f61eb48038 fix: HTML-escape seed + NPC fields in <npc-tray> to prevent markup breakage 2026-07-20 15:21:59 +01:00
tevans cb86a780b9 feat: <npc-tray> seed-to-character generator UI 2026-07-20 15:17:30 +01:00
tevans 2819305b56 feat: pure NPC generator over genre tables 2026-07-20 15:13:57 +01:00
tevansandClaude Opus 4.8 03ce5e1606 feat: NPC noir genre table pack + genre registry
Implements Slice 2 Task 1: Noir/Blade Runner genre pack with curated
string tables (names, looks, manners, wants, secrets, voices) and a
registry mapping id->pack for use by offline NPC generator.

Tests: 2/2 pass (noir structure + registry resolution).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-20 15:10:35 +01:00
tevansandClaude Opus 4.8 61fb2228b9 Plan: The Director Slice 2 (NPC generator + offline art library)
8 TDD tasks: noir genre pack + registry, pure NPC generator, <npc-tray>,
art search, art manifest, <prop-viewer>, <art-tray>, and shell/rail wiring
(open-tool for npc/art, keep-npc persistence, show-prop fullscreen).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-20 15:07:48 +01:00
tevans d967eb6a88 docs: proper README (overview, quick start, architecture, scenario model, roadmap) 2026-07-20 14:55:34 +01:00
tevans 9ad51a3a0c Merge initial GitHub repo commit (README) 2026-07-20 14:46:03 +01:00
tevans 083549a7db first commit 2026-07-20 14:43:31 +01:00
tevans d0c9378c40 fix: precache only stable shell paths so SW install survives a production build 2026-07-20 14:31:26 +01:00
tevans a78f8e9a3a chore: commit package-lock.json for reproducible installs 2026-07-20 14:30:53 +01:00
tevans b4fdb969a1 fix: guard service-worker runtime cache on res.ok/basic + waitUntil 2026-07-20 14:25:07 +01:00
tevans 539798f8d0 feat: installable offline PWA (manifest + service worker) 2026-07-20 14:21:56 +01:00