# nte-optimizer Gear optimizer for *Neverness to Everness*. Static site, no server, no account. It imports the JSON that [`nte-exporter`](../nte-exporter) writes during a normal capture run, and recommends what to equip on whom — drawn onto each character's console grid. ## Running it ```sh npm ci npm run dev # development npm run build # dist/index.html — the normal build npm run build:single # dist/nte.html — one file, works over file:// npm test ``` `dist/` is **committed on purpose**. In three years, when `npm ci` fails on some transitive native module, `python3 -m http.server -d dist` will still work. The source build is the convenience; the committed output is the artifact. ## Layout | path | what lives there | |---|---| | `data-src/` | raw everness mirrors, Arc classifications, guide data. Committed, not shipped. | | `tools/` | build-time scripts. Output goes to `src/generated/`, also committed. | | `src/domain/` | **pure.** No DOM, no IndexedDB, no imports from `ui/`, `db/` or `state/`. | | `src/solver/` | same rule. Chunked generators, so they run in a worker or inline unchanged. | | `src/db/` | schema, migrations, import, persistence adapters. | | `src/ui/` | React. Four tabs and a hash router. | The `domain/` and `solver/` rule is what makes them worker-safe, Node-testable and diffable against the Python they were ported from. Keep it. ## Two things that are easy to get wrong **Ported rules were expensive to derive and break in ways that still look plausible.** Before touching anything in `domain/`, read `~/Apps/nte-research/WIREFORMAT.md` and the "facts worth not re-deriving" section of `RESUME.md`. Builds are 6, 7 or 8 modules and never always 7; the console trait is not always CRIT DMG or Type III; a transposed board renders correctly on a symmetric grid. **The model has measured gaps, and the app is built to show them rather than hide them.** Set bonus values are unknown and contribute nothing. The base-stat multiplier has never been read at level 80. A `proven` build is optimal for its packing and cartridge, not globally. Every one of those is surfaced in the UI on purpose — if you find yourself replacing one with a plausible number, don't. ## Degraded modes Opening `dist/nte.html` from the filesystem gives the page an opaque origin, so IndexedDB, workers, `fetch` and module scripts are all unavailable. The app handles this behind two interfaces it never sees through — `PersistenceAdapter` (IndexedDB → localStorage → memory) and `SolverHost` (worker → inline) — and shows a banner when storage is not durable. Artwork is not carried in that build. ## Deploying `npm run deploy` builds both targets and publishes to **[removed]**. The homelab has no `rsync`, so the tree goes over as a tar stream, and the destination is wiped first: a stale content-hashed chunk left behind would be served forever, since `/assets/*` is cached as immutable. Caddy serves `/mnt/docker/appdata/caddy/sites/[removed]` as `/srv/[removed]` via a read-only bind mount, which is why a deploy needs no container restart — but adding a *new* site does, and recreating that container briefly drops every other site behind Caddy. `[removed]` is the single-file offline build, shipped alongside the app. `dist/` is not in git. The deploy builds from source.