Monogatari v2.8.0

June 17, 2026

Hyuchia

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, the main entry 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 cache

You 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 (plus shake-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 0 on fade-in instead of fading from the configured level.
  • Fixed word-wrap making text “jump” mid-typewriter β€” unrevealed characters now use opacity instead of visibility.
  • 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 Message actions soft-locking the screen and blocking progress.
  • Fixed AutoPlaySpeed flipping to the opposite value every time the player changed it and refreshed the game.
  • Fixed the selector parameter not being passed to init() 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/hide image, 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 tsParticles for legacy compatibility.

πŸ“¦ Misc#

  • Added the modern-screenshot dependency 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.ts web 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.0 and 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 static blocking property plus a shouldProceed() 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 the script-src directive of your Content-Security-Policy (the template’s script-src-elem already allows blob:; modern-screenshot also needs it in script-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.js with the new one, which skips caching opaque responses.

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.

Tags: #monogatari #visual #novel #engine #typescript #release