**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.

### 📰 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.
