Core
The core plugin is the foundation every other plugin is built on. It bootstraps the application, registers the service worker that serves your novel’s assets on the web, and starts the Unity host on desktop.
On its own, core does very little. Its real job is to define the application’s lifecycle: the moments when the novel starts, is torn down, and comes back. It exposes these moments as commands so that other plugins can decorate them and hook their own behavior into the lifecycle. Novel, for example, decorates suspendSession and resumeSession to preserve your place across a hot reload.
Core provides a single collection of commands. They’re intentionally minimal, and most are empty on their own. Think of them as extension points that mark when something happens, leaving the what to the plugins layered on top.
Commands
Section titled “Commands”Runs once when the application starts. This is the entry point for the entire novel.
init(): Promise<void>Core’s own init is empty. It exists so that other plugins can decorate it to do their startup work. Web UI, for instance, decorates init to mount the React application.
Example
decorateCommand("init", (context, next) => { console.log("Starting up..."); return next(context);});resumeSession
Section titled “resumeSession”Runs when a suspended session is being restored, such as after the workspace is rebuilt during development.
resumeSession(): Promise<void>Pairs with suspendSession. Core’s implementation is empty; Novel decorates it to reload the bookmark saved on suspend and replay the reader back to their exact position.
Example
decorateCommand("resumeSession", async (context, next) => { await restoreMyState(); return next(context);});suspendSession
Section titled “suspendSession”Runs when the current session is being torn down, for example because the workspace was updated and the novel needs to reload.
suspendSession(ctx: SuspendSessionContext): Promise<void>
interface SuspendSessionContext { reason: "workspace-updated";}The reason tells you why the session is being suspended. Core’s implementation reloads the page; plugins decorate it beforehand to persist anything they’ll want back when resumeSession runs.
Example
decorateCommand("suspendSession", async (context, next) => { await saveMyState(); return next(context);});