Monogatari v2.8.0
Download Link: monogatari-v2.8.0.zip
v2.8.0 is the largest release since v2.6.0. Under the hood, the entire engine has been rewritten in TypeScript and broken apart into focused modules; on the surface, you get explicit asset management, save screenshots, native desktop storage, a big library of dialogue text effects, and a long list of fixes. Here’s everything that changed and how to take advantage of it.
π Support Monogatari
Monogatari is free, open source, and built in the open β releases like this one are powered by the people who chip in to keep it going. If the engine helps you bring your stories to life, please consider sponsoring its development:
- β€οΈ GitHub Sponsors
- π§‘ Patreon
- β Ko-fi
π° Release Change Log
π New Features
π§ A Full TypeScript Rewrite
The core engine, every built-in action, and every component have been migrated to TypeScript. The @monogatari/core package now ships its own type definitions, so whether you’re writing custom actions and components or just scripting your game in an editor, you get full autocomplete and type-checking for the engine API, game settings, and the new typewriter effects.
π§© The Engine, Split Into Modules
The old ~3,500-line monogatari.ts “god object” has been split into focused modules β assets, characters, i18n, input, lifecycle, persistence, and ui. The build now produces two clearly separated targets:
lib/monogatari.module.jsβ an ES module, themainentry of the npm package, ideal for bundlers (Parcel, Vite, webpack, etc.).dist/engine/core/monogatari.jsβ a self-contained browser bundle, the one used by the classic drop-in game template.
Nothing changes about how you write a game, but the engine is now far easier to maintain and to load from a bundler.
π¦ Preload & Unload Actions
Two new script actions give you explicit control over when assets live in memory. preload pre-caches music, sounds, voices, scenes, images, and character sprites before you need them; unload frees them when you don’t.
// Single assets
'preload music main_theme',
'preload scene classroom',
'preload character y happy',
// Wait until the asset is ready before continuing
'preload scene boss_room blocking',
// Free memory again
'unload scene classroom',
'unload music', // a whole category
'unload all permanent', // memory *and* the IndexedDB cacheYou can also group assets into named blocks and load or free them in a single statement β great for per-chapter management:
monogatari.action('Preload').blocks({
'Chapter1': {
music: ['theme_song', 'battle_music'],
scenes: ['school_gate', 'classroom'],
characters: { 'y': ['happy', 'sad', 'normal'] },
},
});
// ...later in your script
'preload block Chapter1 blocking',
// ...and at the end of the chapter
'unload block Chapter1',Audio is decoded once and persisted in IndexedDB, so re-preloading across sessions is instant β unless you unload ... permanent, which clears the persistent cache too.
πΈ Save Screenshots
Save slots can now show a screenshot of the exact moment a save was made instead of a generic scene image. Turn it on with a single setting:
monogatari.settings({
'Screenshots': true,
});When enabled, the engine captures the game screen (via modern-screenshot) as you save and stores it in a dedicated IndexedDB database, kept separate from your save data so it never bloats the save object. Slots then render that screenshot as their thumbnail. β οΈ Screenshots have a couple of requirements around CSP and cross-origin assets β see the upgrade notes below and the Saving documentation.
πΎ File System Storage
For games packaged as desktop apps (Electron / Electrobun), there’s a new FileSystem storage adapter that writes saves straight to disk through a desktop bridge instead of the browser’s IndexedDB:
monogatari.settings({
'Storage': {
'Adapter': 'FileSystem',
'Store': 'SaveData',
},
});If the same build is opened on the web (no desktop bridge present), it automatically falls back to IndexedDB, so it keeps working everywhere.
π Show & Hide Textbox
Two tiny but frequently requested actions to get the dialog UI out of the way β perfect for showing off a CG or a scene:
'show scene cg_sunset with fadeIn',
'hide textbox',
'wait 2000',
'show textbox',
'e ...beautiful, right?',Visibility is part of the saved state, so it survives save/load and rollback. One thing to remember: once hidden, the box stays hidden for every following line until you show textbox again β so always bring it back before a line you want the player to read. Docs: show textbox Β· hide textbox.
β¨ A Big Library of Text Effects
Dialogue now supports inline text effects with a simple {effect}β¦{/effect} markup. Open with {effect} and close with {/effect}:
'y I am {angry}absolutely furious{/angry}! {pause:500}{whisper}...but I will be okay{/whisper}.',
'narrator The {glitch}corrupted{/glitch} signal pointed somewhere {mysterious}strange{/mysterious}.',There are 40+ effects across several families:
- Movement β
shake(plusshake-hard,shake-slow,shake-little,shake-horizontal,shake-vertical),wave/wave-slow/wave-fast - Reveal β
fade,blur,scale,scale-bounce,slide-up,slide-down,redacted,invisible-ink,handwriting,flicker - Glitch β
glitch,glitch-hard,glitch-slow - Style β
bold,italic,big,small,impact,rainbow,glow - Emotion presets that bundle several of the above into one keyword β
angry,scared,happy,sad,mysterious,excited,whisper,shout,dizzy,dreamy,robotic,static
Effects nest, so you can combine them:
'{shake}{angry}STOP{/angry}{/shake} right there!',β¦and they’re all driven by CSS custom properties, so you can re-tune them globally without touching the engine:
type-character[data-component] {
--effect-shake-intensity: 4px;
--effect-wave-amplitude: 0.5em;
--effect-wave-speed: 0.6s;
--effect-glitch-color-1: #ff00ff;
--effect-glitch-color-2: #00ff00;
}The full list and details live in the Dialogs and Type Writer docs.
β© Semi-Instant Skipping
If you keep InstantText off β so finishing a line rushes the typewriter while keeping its effects, rather than dumping the whole line at once β you can now also let players make that rush genuinely fast. Set the min value of the text-speed slider in your settings screen below 0:
<input type="range" min="-100" max="50" step="1" data-action="set-text-speed">Players who drag the slider into the negative range get a near-instant fast-forward that still respects formatting and effects.
π¦ A Proper Action-Blocking API
Actions that need to pause the story until they finish β waiting on a choice, a notification permission, an async load β now declare a static blocking flag and a shouldProceed() check instead of toggling a global. The old block / executing sub action globals still work for now but are deprecated; if you maintain custom actions, see the upgrade notes below.
π Bug Fixes
- Fixed audio volume being reset to
0on fade-in instead of fading from the configured level. - Fixed word-wrap making text “jump” mid-typewriter β unrevealed characters now use
opacityinstead ofvisibility. - Text speed now updates live from the settings slider (previously it only took effect after a refresh), and the slider shows the correct value on reload.
- Fixed
Messageactions soft-locking the screen and blocking progress. - Fixed
AutoPlaySpeedflipping to the opposite value every time the player changed it and refreshed the game. - Fixed the
selectorparameter not being passed toinit()in actions and components. - Fixed the page not centering correctly when aspect-ratio enforcement was active.
- Fixed dialog-log and text-box scrolling behavior.
- Made visual actions (
show/hideimage, character, layer, canvas, video, etc.) record state and history consistently, for more reliable rollback. - Fixed a recursive-call bug in the engine core.
- Re-exported
tsParticlesfor legacy compatibility.
π¦ Misc
- Added the
modern-screenshotdependency that powers the screenshots feature. - New service-worker caching strategy: network-first for navigations (so fresh CSP and markup reach players immediately), stale-while-revalidate for your JS/CSS (instant load, updated on the next visit), and cache-first for everything under
assets/. Opaque cross-origin responses are no longer cached β this is what keeps screenshots from coming out black. - Documentation has moved into the main repository and now lives at monogatari.io/v2.
- The development toolchain now runs on Bun, with a custom dev server (WebSocket live-reload), a
build-web.tsweb build, and Electrobun scripts for desktop distribution. None of this is required to ship a game β the downloadable template is still a static site you can serve any way you like. - Removed the old Parcel / Yarn toolchain, cleaned up leftover debug logs, added missing debug-mode error messages, and updated the CI lint/test tasks.
- The npm package has been updated to
2.8.0and now ships TypeScript types.
How To Upgrade
If you’re on a v2.x.x version
For most games, upgrading is the usual drill: replace the files in your engine directory with the new ones from the download. A few things are worth double-checking:
- Custom dialog markup: if you use inline text effects, make sure your closing tags are
{/effect}(for example,{shake}boom{/shake}). - Custom actions: if you wrote actions that called
engine.global('block', β¦)or relied on_executing_sub_action, migrate them to the new pattern β a staticblockingproperty plus ashouldProceed()that throws while the action is blocking. The old globals are still honored, but deprecated. - Turning on screenshots: besides
Screenshots: true, you’ll need to:- add
blob:to thescript-srcdirective of yourContent-Security-Policy(the template’sscript-src-elemalready allowsblob:;modern-screenshotalso needs it inscript-src), - serve any cross-origin assets (for example, from a CDN) with CORS headers (
Access-Control-Allow-Origin), otherwise the browser taints the canvas and your thumbnails come out black, and - replace your
service-worker.jswith the new one, which skips caching opaque responses.
- add
If you’re on v1.4.1 (stable) or below
If you’re upgrading from a game built on v1.4.1, we recommend reading the Upgrade Guide first β the jump to v2 is a big one.