v0.4.0: Foundry v13/v14 rewrite — release to main - #4
Merged
Conversation
Adds CLAUDE.md with repository overview, build commands, architecture details, and coding conventions for AI assistant context. References it via AGENTS.md.
Ground-up rebuild against current Foundry idioms, using the legacy
0.7-era code as the behavioral spec (extracted to z/SPEC.md):
- Zero build steps: repo root is the system directory; plain JS ES
modules + JSDoc, plain CSS with native nesting. Old gulp/rollup/
TypeScript/Tailwind toolchain and committed release zips removed.
- Modern manifest: id/compatibility {13.347 -> 14}, documentTypes for
character + 5 item types; template.json replaced by TypeDataModel
schemas with presence-guarded migrateData (node smoke tests in
tools/test-migrations.mjs).
- Documents & rolls: HellasActor/HellasItem replace the legacy Proxy
polymorphism; async dice; DialogV2 modifier prompt; omega-table
outcomes; skill names synced in _preCreate/_preUpdate instead of
writes during prepareData.
- Sheets on ApplicationV2 + HandlebarsApplicationMixin: one item sheet
for all five types, four-tab actor sheet; all actions (incl. rolls)
gated on isEditable; core data-tooltip-html replaces vendored
tooltipster; no jQuery, no custom Handlebars helpers.
- Compendia: NeDB journals deduped and converted to per-document JSON
sources (packs/_source), compiled to LevelDB via foundryvtt-cli
(tools/build-packs.mjs); document ids preserved.
- 19 legacy bugs fixed rather than ported (z/SPEC.md fix-don't-port
list), incl. fate points never persisting, sxithborn data-key typo
(with migration), and DB writes during render/prepare.
- Verification: tools/audit.mjs static cross-reference audit (actions,
i18n incl. composed key families, form paths vs schemas, template
paths, packs, manifest) is clean; manual checklist in z/CHECKLIST.md.
- Release: GitHub Actions on v* tag push; tombstone manifest kept at
src/system.json for the legacy raw-GitHub update channel.
Legacy source stays under src/ as reference until the manual checklist
passes; z/ holds the rewrite plan, spec, and review ledger.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- Persist normalized skill selectors in _preCreate/_preUpdate and reset the name when skill is cleared (devin D1, major). Normalization stays out of migrateData: update deltas lack whole-document context. - Gate #onItemEdit on isEditable like every other action (devin D2). - Ledger in z/PLAN.md records all findings incl. rejected codex P1 (scrollable [""] is the documented v13 idiom) and the verified NumberField integer-rounding behavior. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- Remove the <form> nested inside DialogV2 content (devin D6, major): DialogV2 supplies its own form; per the AppV2 conversion guide a nested form risks button.form missing the inputs entirely. - Number()-parse dialog modifiers so exponent forms survive (codex C2). - Clear dependent skill selectors when skill is emptied (devin D8). - Fate label tooltip now uses the purpose-built fatepoints.title key — legacy formatted args into the placeholder-less description (devin D10, logged as legacy bug F20). - Ledger updated; D7 recorded as accepted-by-design, D9 rejected with reason (core requires a name at Item.create). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Both reviewers clean on the rev-2 folds (codex: no regression; devin: all four folds sound, fresh sweep empty). Review loop terminal state recorded in the z/PLAN.md ledger; only the execution-gated tombstone check (D4) remains, carried to the manual checklist. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Droid verified the full v13 API surface, data-prep ordering, roll pipeline, templates, tools, and manifests: no blockers or majors. Folds: STR-shortfall arithmetic uses one guarded minStr (droid's NaN scenario disproven by execution — null coerces to 0 — folded for clarity only); dead || true removed from audit.mjs; three unused legacy i18n short-name keys carried wrong "Fate Points" values, corrected. Adds the best-practices comparison report (z/BEST-PRACTICES.md). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…plan - Ledger rev 5: droid round 2 clean — all three model families converged. - z/FOUNDRY-BEST-PRACTICES.md: repo-agnostic v13/v14 best-practices reference (raw material behind the z/BEST-PRACTICES.md comparison). - z/phase-9-plan.md: two-phase plan for the best-practices updates (9a pre-tag: migration runner, bundled fonts, manifest polish, Package Release API; 9b post-release: AE visibility, a11y, LOCALIZATION_PREFIXES, enum choices, form helpers). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Remove the 2021-era .nvmrc (node v12); mise.toml now pins node 24 and the release workflow builds on node 24 to match. All tooling verified under 24.12.0: migration smoke tests, static audit, pack build and round-trip. README dev setup mentions mise install. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Two plan-review rounds (codex + devin): rev 1 folded recursive:false, zero-failure stamping + activeGM gate, effects stripping, scope cut of the unlinked-token pass (delta-override hazard), shell-script secret guard (resolves a reviewer dispute over Actions env/if semantics), scripted font fetching, jq -er guards; rev 2 confirmed with mechanical i18n/checklist alignments. Ledger inside the plan doc. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Setup-screen media and world-login background reuse the credited marble photo; flags.hotReload uses the documented paths-only shape (the extensions key does not exist in the official flag structure — verified against the configuration article, resolving the plan's impl-time check); changelog now points at a real CHANGELOG.md, shipped in the release zip. Audit verifies media/background paths exist. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Roboto (variable woff2 covering weights 300-500 — Google serves one identical file per weight, verified by checksum) and Caesar Dressing now ship in fonts/ with their OFL license texts, fetched reproducibly by tools/fetch-fonts.mjs (magic-byte + size verified). Offline/LAN installs keep the full visual identity and clients no longer call a third-party CDN. Synthetic bold remains, matching what the legacy import produced. README credits the fonts; release zip ships fonts/; audit verifies the files exist and no googleapis reference remains. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
module/migrations/world.mjs: version-gated blanket re-save of world
actors and items so migrateData's in-memory normalizations (sxithborn
rename, blank-string -> null) finally reach the DB. Runs once per
NEEDS_MIGRATION_VERSION from the single active GM, stamps the
systemMigrationVersion world setting only after a zero-failure pass
(failures retry next launch; re-saving is idempotent). toObject(true)
+ {diff:false, recursive:false} keeps derived values out of the DB and
drops removed legacy keys; item/actor effects payloads stripped;
unlinked-token deltas and compendia deliberately out of scope (see
file header). SYSTEM_ID moved to module/config.mjs to keep the module
importable in bare node (7/7 smoke tests incl. the version gate).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
POSTs each release to foundryvtt.com per the official Package Release API (version-specific manifest asset URL, compatibility read from the stamped system.json via jq -er guards, maximum:"" as in the official example). Shell-level secret guard skips cleanly until the package is registered and FOUNDRY_PACKAGE_TOKEN exists. Body construction dry-verified locally. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Restore the required hotReload extensions key (codex P2 — the core design issue foundryvtt#9027 marks extensions required; the configuration article's paths-only snippet is a simplification, and dnd5e ships both keys). Harden the fetch-fonts url() regex (devin nit). Devin's effects-preservation question is reasoned in the ledger and pinned to a new manual-checklist row for execution confirmation. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
en.json carried a dotted-key expansion collision (skill.specifier.title both a string and a prefix of the stray ...title.label): v13 merges translations via setProperty, which throws on strict-mode string property assignment, aborting the ENTIRE language file — every UI string rendered as its raw key. Stray key removed; the audit now fails on any expansion collision. Setup-tile media switched to brushed gold (white marble washed out at tile size). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Tables now paint their own light background and ink instead of tinting whatever core's theme put underneath (dark slabs in dark mode), and the two-column layout uses minmax(0,1fr) so grid children can shrink instead of pushing the right column past the window edge. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
window-content becomes an overflow-hidden flex column; the active tab section flexes to the remaining height and scrolls itself. PARTS' scrollable [""] only preserves scroll positions across re-renders — the actual overflow behavior is system CSS, which was missing. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Core dark-theme headings are pale cream for dark grounds and vanished on the marble; all headings now take the sheet ink. Default document icons are white-line SVGs — a dark chip behind .profile-img keeps them visible while raster portraits cover it entirely. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The input+hint cells become flex rows: the hint text gets its own flexible column next to the input and wraps within that column. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
v13 icon-font checkbox states were illegible on the marble ground (unchecked rendered as a solid dark block). Suppress core's glyph pseudo-elements and draw the box + check with our own styles: empty light box unchecked, dark check when checked, dimmed when disabled. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Rewrite system from scratch for Foundry VTT v13/v14
The 0.7-era source served as the rewrite's behavioral spec and is now fully captured by the shipped system and git history. src/system.json remains as the tombstone manifest for the legacy update channel. The z/ plan/spec/ledger docs and the one-time NeDB converter (whose input no longer exists and whose output is committed under packs/_source) retire with it. CLAUDE.md rewritten for the current architecture; stale gitignore entry dropped. Audit, smoke tests, and pack round-trip all green after removal. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Brings the complete v13/v14 rewrite (merged to
developin #3) tomain, plus the final retirement step:src/removed — the 0.7-era source served as the rewrite's behavioral spec and lives on in git history.src/system.jsonstays as the tombstone manifest: legacy installs pollraw.githubusercontent.com/snorith/hellas/master/src/system.json(served frommainvia the branch-rename redirect), and the tombstone points them at the new GitHub-Releases channel with dual legacy/modern keys.z/working docs dropped (plan, spec, review ledgers — all in history), along with the one-time NeDB→JSON converter whose input no longer exists.CLAUDE.mdrewritten for the current architecture; stale.gitignoreentries cleaned.Merging this makes the tombstone live for legacy update channels. It does NOT publish a release — that happens on the
v0.4.0tag push, ideally after the remaining manual checklist items (rolls, legacy-world migration) are done.Verification
Static audit + migration smoke tests green after the removal. (Pack compilation is verified in CI at release time; local LevelDB rebuilds require Foundry to be closed — single-writer lock.)
🤖 Generated with Claude Code