No description
  • TypeScript 86.7%
  • HTML 8.3%
  • CSS 2.9%
  • JavaScript 2%
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
2026-07-13 14:59:00 +02:00
.forgejo/workflows chore(deploy): Cloudflare Pages deploy + Forgejo Actions CI 2026-06-30 11:02:51 +02:00
android chore(android): strip inert google-services Gradle hook (V1 = no analytics SDK) 2026-06-30 15:57:32 +02:00
docs feat(enemies): complete the Deathless roster to the doc contract (TV1-3) 2026-07-12 14:40:09 +02:00
e2e feat(gear): the healer is not a tank — mitigation cut, HP confined to chest+legs (TV1-9/P3) 2026-07-12 16:28:44 +02:00
src feat(run): report what a run actually paid out — every clear AND every wipe 2026-07-13 14:58:09 +02:00
vendor docs: seal Pre-0.K UI/UX/VFX direction (A·Stone) + canonical battle-board & dungeon mockups 2026-06-30 00:03:00 +02:00
.gitignore chore: stop tracking agent worktree gitlink (committed by mistake) 2026-06-30 14:26:10 +02:00
.prettierignore feat(ui): procedural faction standards on boss node + dungeon-select node 2026-07-06 22:18:56 +02:00
.prettierrc chore: scaffold Vite + TS strict workspace + code-quality tooling 2026-06-30 08:00:26 +02:00
.stylelintignore feat(ui): re-skin to Reign UI (blue-glass + stone + gold) with player/enemy split 2026-07-06 16:21:02 +02:00
capacitor.config.ts feat(app): Capacitor Android wrap (non-monetized) + project scaffold 2026-06-30 15:32:34 +02:00
CLAUDE.md feat(gear): the healer is not a tank — mitigation cut, HP confined to chest+legs (TV1-9/P3) 2026-07-12 16:28:44 +02:00
eslint.config.js feat(ui): procedural faction standards on boss node + dungeon-select node 2026-07-06 22:18:56 +02:00
healie-battle-pixi.html docs: seal Pre-0.K UI/UX/VFX direction (A·Stone) + canonical battle-board & dungeon mockups 2026-06-30 00:03:00 +02:00
healie-ui-v05.html docs: seal Pre-0.K UI/UX/VFX direction (A·Stone) + canonical battle-board & dungeon mockups 2026-06-30 00:03:00 +02:00
index.html chore: scaffold Vite + TS strict workspace + code-quality tooling 2026-06-30 08:00:26 +02:00
LICENSES.md feat(ui): re-skin to Reign UI (blue-glass + stone + gold) with player/enemy split 2026-07-06 16:21:02 +02:00
package.json feat(ui,sim): main menu + CAMP hub + Manage Party + merged Healer gear screen to mockup parity 2026-07-02 00:22:16 +02:00
playwright.config.ts test(e2e): extended hub→spokes→battle flow + DOM-screen visual regression 2026-06-30 16:33:58 +02:00
pnpm-lock.yaml feat(ui,sim): main menu + CAMP hub + Manage Party + merged Healer gear screen to mockup parity 2026-07-02 00:22:16 +02:00
pnpm-workspace.yaml chore(deploy): Cloudflare Pages deploy + Forgejo Actions CI 2026-06-30 11:02:51 +02:00
PRODUCT.md feat(party): real hero armouries + per-weapon baselines & hero crit (TV1-10) 2026-07-12 17:12:24 +02:00
README.md docs: Android build/sign/Play flow + mid-range perf notes in README 2026-06-30 15:33:08 +02:00
stylelint.config.js chore: scaffold Vite + TS strict workspace + code-quality tooling 2026-06-30 08:00:26 +02:00
TODO.md docs(todo): TV1-14 + TV1-13 done, TV1-12 mostly done — seventh handover; next task is TV1-11 (simultaneity) 2026-07-13 14:59:00 +02:00
tsconfig.json chore: scaffold Vite + TS strict workspace + code-quality tooling 2026-06-30 08:00:26 +02:00
vite.config.ts chore: scaffold Vite + TS strict workspace + code-quality tooling 2026-06-30 08:00:26 +02:00
vitest.config.ts chore(sim): harden purity guard (Date/perf/globalThis/crypto/dynamic-import) + loop non-finite-dt + rng fixes 2026-06-30 08:48:23 +02:00
wrangler.jsonc chore(deploy): Cloudflare Pages deploy + Forgejo Actions CI 2026-06-30 11:02:51 +02:00

Healie

An endless auto-battler healer RPG for Android. You control only the healer of a fantasy party — the one role that can never go AFK or the whole party dies.

The full game design lives in PRODUCT.md; the phased build plan in TODO.md; the engineering contract (stack, architecture, guardrails) in CLAUDE.md.

Tech stack

TypeScript (strict) · Vite · PixiJS v8 (WebGPU → WebGL2) · Lottie · Capacitor (Android) · deterministic fixed-timestep sim. Package manager: pnpm. Runtime: Node 24+.

Architecture

One-way data flow across onion-style layers under src/:

  • sim/pure game logic. No Pixi, no DOM, no window, no Math.random. Deterministic, unit-testable, seeded RNG. (The ESLint config mechanically enforces this purity.)
  • render/ — PixiJS scene graph. Reads sim state, draws the board + VFX.
  • ui/ — DOM / HTML + CSS + Lottie HUD and menus.
  • data/ — tuning curves & content tables (the balance knobs).
  • app/ — bootstrap, asset loading, scene routing.

Build / Run / Deploy

Command What it does
pnpm install install deps (pnpm only)
pnpm dev Vite dev server — play in browser
pnpm build type-check (tsc --noEmit) then production web build → dist/
pnpm test unit tests (sim/ must pass headless)
pnpm test:watch unit tests in watch mode
pnpm coverage unit tests with v8 coverage report
pnpm lint ESLint + Prettier (check) + Stylelint
pnpm format Prettier write
pnpm verify lint + test + build (the green-gate)

Web demo (Cloudflare Pages)

Live at https://healie.pages.dev (Cloudflare Pages project healie, production branch main).

The current build renders the static A·Stone battle board; live auto-battle + smart-cast input land in later commits. The deploy auto-updates as main advances.

Auto-deploy (CI): every push to main runs .forgejo/workflows/deploy.yml on the self-hosted Forgejo Actions runner (node:24-bookworm): pnpm install --frozen-lockfilepnpm buildpnpm run deploy. Requires the repo Forgejo Actions secrets CF_API_TOKEN and CF_ACCOUNT_ID (both already set).

Manual deploy (from a clean local build):

pnpm build                                   # -> dist/
CLOUDFLARE_API_TOKEN=CLOUDFLARE_ACCOUNT_ID=… pnpm run deploy
# pnpm run deploy == wrangler pages deploy --branch=main
# target (project name = healie, output dir = dist) comes from wrangler.jsonc

Cloudflare credentials live in ~/.claude/secrets/cloudflare.env (CF_API_TOKEN, CF_ACCOUNT_ID); map them to the CLOUDFLARE_* env vars wrangler reads. Rollback: wrangler pages deployment list --project-name=healie then redeploy a prior good build, or roll back from the Cloudflare Pages dashboard.

Android (Capacitor → Google Play)

V1 wraps the exact same web build into a native Android app with Capacitor — a thin WebView shell, NON-MONETIZED (NO AdMob / Play Billing / analytics plugins; those are the Post-1.0 backlog). Config lives in capacitor.config.ts:

  • appId: eu.treefolk.healie · appName: Healie · webDir: dist
  • near-black launch/background #0d0d0f (no white flash), androidScheme: https, no cleartext.

The android/ native project is committed; its build outputs + the synced web-asset copy are gitignored (and signing keys are never committed).

Prerequisites for the native build (the developer's machine, not CI): a JDK 21+, Android Studio with the Android SDK, and ANDROID_HOME set. The scaffold and asset sync below need none of that; only the final assemble/sign/upload (done in Android Studio) does.

# One-time (already done): scaffold the native project
npx cap add android

# Each release: build the web bundle, copy it into android/, open Android Studio
pnpm cap:sync           # == pnpm build && cap sync android  (copies dist/ into the native project)
pnpm cap:open           # == cap open android                (Android Studio)

In Android Studio (the developer's manual steps):

  1. Build → Generate Signed Bundle / APK → Android App Bundle (.aab).
  2. Create / select a signing keystore (keep it OUTSIDE the repo — *.keystore / *.jks are gitignored as a safety net; store it in your password manager / secure backup).
  3. Build the release bundle.
  4. Upload the .aab to the Google Play Console as a FREE app (slug/title healie), with no monetization disclosures (no ads, no IAP in V1).

If npx cap add android ever needs re-running on a machine without the Android SDK, it still scaffolds the project (config + Gradle wrapper); only cap:open + the signed build require the full Android toolchain.

Performance / quality (mid-range Android)

Targets 60fps on mid-range Android: WebGPU with a clean WebGL2 fallback, pooled + hard-capped particles, no per-frame redraws of static chrome, and no stencil masks in the hot path (portraits are texture-cropped, cooldown sweeps are geometry). The Settings → Graphics toggles drive a real auto-degrade (knobs in src/data/perf.ts, applied by src/app/perf-controller.ts):

  • Low-end mode → fewer particles (cap + spray scale), soft glows off, DPR capped at 1.5, FPS capped at 60, antialiasing off.
  • Reduce motion → disables screen-shake + struck jitter and further thins particle churn (heal glow + floating numbers stay fully readable), on top of the global no-animation CSS class.