**Download Link**: [monogatari-v2.8.0.zip](https://storage.monogatari.io/releases/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](https://github.com/sponsors/Hyuchia)
- 🧡 [Patreon](https://www.patreon.com/Hyuchia)
- ☕ [Ko-fi](https://ko-fi.com/hyuchia)

### 📰 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`](https://www.npmjs.com/package/@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`](https://monogatari.io/v2/script-actions/preload) pre-caches music, sounds, voices, scenes, images, and character sprites before you need them; [`unload`](https://monogatari.io/v2/script-actions/unload) frees them when you don't.

```javascript
// 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:

```javascript
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:

```javascript
monogatari.settings({
    'Screenshots': true,
});
```

When enabled, the engine captures the game screen (via [`modern-screenshot`](https://github.com/qq15725/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](https://monogatari.io/v2/configuration-options/game-configuration/saving).

**💾 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:

```javascript
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:

```javascript
'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](https://monogatari.io/v2/script-actions/show-textbox) · [hide textbox](https://monogatari.io/v2/script-actions/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}`:

```javascript
'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:

```javascript
'{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:

```css
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](https://monogatari.io/v2/script-actions/dialogs) and [Type Writer](https://monogatari.io/v2/components/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`:

```html
<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`](https://www.npmjs.com/package/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](https://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](https://www.npmjs.com/package/@monogatari/core) 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](https://monogatari.io/v2/upgrading-from-v1-4-1) first — the jump to v2 is a big one.
