4.1 KiB
Agent Handoff Notes
This file is for future coding agents continuing work on the Forge Master Strategy Optimizer.
Do not duplicate game rules, formulas, stat caps, or gameplay assumptions here. Use GAME.md as the source of truth for those details. Use README.md for the player-facing overview.
Project shape
This is a dependency-free static web app:
index.html: page markup and templates.styles.css: responsive styling.app.js: all state, rendering, calculations, import/export, save slots, and comparison logic.README.md: concise player guide.GAME.md: game mechanics and formulas.
There is no build system, package manager, or test runner currently configured.
Development workflow
- Read
GAME.mdbefore changing calculations. - Keep
README.mdplayer-facing. Avoid implementation or formula detail there unless linking toGAME.md. - Keep
AGENTS.mdimplementation-focused. Avoid repeating game mechanics fromGAME.md. - Prefer small, self-contained commits.
- Validate with headless Firefox after UI changes:
firefox --headless --screenshot /tmp/forge-master-check.png file://$PWD/index.html
- Also grep for accidental debug markers:
grep -R "TO[D]O\|FIX[M]E\|console[.]log" -n . --exclude-dir=.git
State and persistence
The app stores state in browser localStorage:
- named save slots use
forgeMasterOptimizer.v1, - the autosaved current draft uses
forgeMasterOptimizer.draft.v1.
Import/export uses a wrapped JSON payload with app, version, exportedAt, and build. Raw build objects are also accepted. Keep import normalization backward-compatible when changing state shape.
Important state paths in app.js:
createDefaultState()defines new blank state.normalizeState()handles imported/draft/saved state migration.createDefaultPiece()defines normal equipment entries.createDefaultNewItem()defines the New item comparison entry.
Rendering structure
Rendering is manual DOM construction, not a framework.
Important functions:
render()orchestrates full rendering.renderControls()updates strategy and combat-style controls.renderGear()renders current equipment cards.renderNewItemComparison()renders the replacement comparison card.renderEffectTotals()renders the total effect tags and marginal max-roll values.renderSacrifices()renders sacrifice candidates.
Event binding is centralized in bindEvents(). Current equipment edits go through handleGearInput(). New item edits go through handleNewItemInput().
Calculation entry points
Use the function names below rather than adding duplicate calculation logic:
calculateTotals()sums base stats and effects.calculateDamageDetails()returns single hit, crit hit, and DPS.calculateDps()returns DPS only.calculateRegenDetails()returns health-regen healing, lifesteal healing, and total Regen.calculateSurvivability()is used for defensive marginal effect comparison.replacePieceInTotals()creates totals after replacing one piece.renderReplacementComparison()displays New item DPS/Regen deltas.
If a calculation changes, update GAME.md first or in the same commit.
Replacement comparison behavior
The New item panel compares one hypothetical roll against a selected current target.
Target behavior is implemented by:
getReplacementOptions()getFixedReplacementTarget()getReplacementTargetPiece()createNewItemCandidate()
When the target is Pet, getReplacementTargetPiece() chooses the lowest-scoring current pet.
Validation expectations
Before reporting completion:
- load the page with headless Firefox,
- confirm no obvious render errors in stderr,
- run the debug-marker grep from the workflow section,
- check
git diff --stat, - commit changes unless explicitly asked not to.
Style constraints
- Keep the app dependency-free unless the user explicitly approves adding tooling.
- Keep controls usable in narrow cards and small screens.
- Prefer readable helper functions over inline formula duplication.
- Preserve backward compatibility for saved/imported JSON whenever practical.