You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Typo fixes no longer nuke saves. Editing dialogue text (fixing a
typo, rewording a line) used to silently invalidate every player's save,
because the old text was baked into the save's "did the script change?"
check. That's fixed — only structural stuff (who's speaking, jumps,
labels, choices, etc.) is checked now, not the words themselves.
One-time heads up: because of how this fix works internally, saves
made before this update will show the normal "Save may be out of
date" prompt one last time on load, then behave correctly from then
on.
Players can no longer bold/color/italicize their own name. If
someone enters [b]Bob as their name, it now shows literally as [b]Bob instead of rendering as Bob. Markup tags ([b], [i], [c=...]) written by you in story.js still work exactly as before —
this only strips them out of player-typed names and set() variables.
Docs fixed: removed two keyboard shortcuts from VNEngine.md
(auto-advance's A key, skip's Ctrl/Tab) that were documented but
never actually existed in the engine — the engine has always been
buttons + Space/Enter/number-keys only.
Docs added:VNEngine.md now says plainly that rollback history (the
"back one line" buffer) and the backlog/history overlay are memory
only — they reset on reload. Only checkpoints/auto-save/seen-tracking
survive a reload.
Topbar buttons are now screen-reader friendly (aria-labels added,
visuals unchanged).
Renamed to "VNEngine" (capital E) in the visible/branded spots:
page title, title-screen logo, README heading, and the manual — which is
now template/VNEngine.md (was VNengine.md).
For coders
engine.js → save-resolve.js extraction. Pulled the DOM-free save
logic (digestOps, hashStr, buildLabels, segmentNameAt, posFromPtr, resolvePos) out into template/js/save-resolve.js — a
small UMD module (window.VNSaveResolve in the browser, module.exports
in Node). engine.js now calls into it via a local SR alias. Loaded in index.html right before engine.js.
The fix itself:digestOps's say case dropped o.text, kept o.who. Save format bumped v: 2 → v: 3; applySnapshot now checks s.v === 3. Anything else (v1's raw ptr, or v2 — whose hash can't be
trusted anymore since it included text) falls into the legacy/mismatch
path, but still resolves pos when the save has one instead of just
resetting to line 0.
segmentNameAt is now binary search, not Object.keys().forEach. buildLabels() returns a pre-sorted [index, name] array once at boot;
lookup is O(log labels) instead of O(labels), called on every line of
dialogue.
Tests:template/tools/tests/save-resolve.test.js — plain Node, no
framework, 14 cases covering hashStr, digestOps (incl. the "text
change → same digest" regression lock), buildLabels/segmentNameAt,
and posFromPtr/resolvePos round-trips (including "insert lines in an
earlier label → save still resolves correctly," and a documented edge
case for inserting within the same segment before the saved line).
Run: node template/tools/tests/save-resolve.test.js.
Location note: lives under template/tools/tests/, not a
repo-root tests/ — repo root is just the setup scaffolder, template/
is the actual engine project, and tools/ is where the other
dev-only/never-shipped tooling already lives (packager, devlog.js). projectpackager-windows.py's ARCHIVE_DIRS = (css, js, src) confirms tools/ never ships in a built game.
CI added:.github/workflows/ci.yml, on push/PR — py_compiles setup.py, template/playtest.py, template/tools/*.py, and runs the
test file above.
setup.py rmtree hardened (~line 471, now main()'s overwrite
block + new _looks_like_vnengine_project() helper): refuses to touch a
non-empty destination unless it contains a project.json with "engine": "VNengine"; shows file count in the confirmation prompt;
renames the old folder to <name>.bak-<timestamp> instead of shutil.rmtree-ing it.
fmt() in engine.js: added stripMarkup(), applied to player.first, player.last, and each interpolated state.vars[k]
before substitution (not to the final string — writer-authored markup
elsewhere in the line is untouched).
Rename:template/VNengine.md → template/VNEngine.md via a
two-commit-safe git mv (staged as a rename, not yet committed — Windows
git needs the two-step dance for a pure case change).