No description
  • JavaScript 87.9%
  • CSS 6.8%
  • C++ 5.2%
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
2026-10-22 20:12:42 +02:00
.voidbot Record Sai identity and Eve bond 2026-05-31 13:19:47 +01:00
dist Make speaker continue a canvas prompt 2026-06-04 21:13:52 +01:00
docs Serve Sai plugin ABI over CultNet 2026-07-10 11:31:15 +01:00
examples/static-site Add visual novel sprite staging 2026-05-31 00:41:14 +01:00
plugins Serve Sai plugin ABI over CultNet 2026-07-10 11:31:15 +01:00
scripts Serve Sai plugin ABI over CultNet 2026-07-10 11:31:15 +01:00
src Serve Sai plugin ABI over CultNet 2026-07-10 11:31:15 +01:00
.gitignore Add Sai VoidBot face state 2026-05-31 13:00:37 +01:00
.prettierignore Extract Sai Ink embedder 2026-05-27 14:07:23 +01:00
LICENSE Extract Sai Ink embedder 2026-05-27 14:07:23 +01:00
package-lock.json Serve Sai plugin ABI over CultNet 2026-07-10 11:31:15 +01:00
package.json Serve Sai plugin ABI over CultNet 2026-07-10 11:31:15 +01:00
README.md README: status line with live scope and entry points 2026-10-22 20:12:30 +02:00

Sai

Ink stories that wake up inside static sites.

Sai is a small browser embedder for compiled Ink stories. It is not an Ink engine; it uses inkjs for that. Sai owns the article-shaped part: loading a story into an existing page, reading a visual manifest, rendering transcript, visual-novel, or cinematic layouts, and staying pleasant to drop into Quartz, Eleventy, Astro, Hugo, plain HTML, or whatever shrine of markup you dragged home at midnight.

The name is the pitch: ink that becomes a living scene.

Status: @gamecult/sai 0.1.0. Live: the transcript (default), visual-novel and cinematic formats, the visual manifest, the portable Eve surface module (src/eve.js) and the Eve playback sidecars (src/eve-cultnet-sidecar.cjs, src/eve-sidecar.cjs). Not planned here: Ink authoring or compilation, Eve transport, and a full game loop (see Boundary). Entry points: dist/sai.js and dist/sai.css for pages, src/sai.js for source, docs/manifest.md and docs/eve.md for the contracts, examples/static-site/ for a working page, and npm run build then npm run check to verify.

Why Sai Exists

Most Ink web players answer: "Can I play this story in a browser?"

Sai answers: "Can this story become part of a page?"

It is for interactive essays, lore posts, documentation rituals, cheap visual novels, pitch decks, character sermons, branching articles, and other story objects that want to live inside a site instead of becoming a separate web app.

Quick Start

Copy the built files from dist/ into your site's static assets:

sai.js
sai.css
ink.js

Add the assets to a page:

<link rel="stylesheet" href="/static/sai/sai.css" />
<script defer src="/static/sai/sai.js"></script>

Embed a story:

<div
  class="sai-player"
  data-ink-format="visual-novel"
  data-ink-story="/stories/agora/story.ink.json"
  data-visual-manifest="/stories/agora/visual-manifest.json"
  data-scene-label="The Aquarium Agora"
></div>

Sai auto-initialises every .sai-player when the document loads. It also listens for Quartz-style nav events after client-side page swaps.

Formats

Raven

<div class="sai-player" data-ink-story="/story.ink.json"></div>

The default format is a compact interactive-fiction transcript. It is the simplest Raven Collective-style shape: text, choices, variables when useful, and no stage machinery.

Visual Novel

<div
  class="sai-player"
  data-ink-format="visual-novel"
  data-ink-story="/story.ink.json"
  data-visual-manifest="/visual-manifest.json"
></div>

Visual-novel mode renders one scene image, a fixed dialogue bar, speaker avatar, speaker name, line text, optional character sprites, optional DOM cards, and a right-side option rail. Ink tags drive the speaker, scene, staged sprites, and staged page elements:

# speaker: Void
# scene: agora
# avatar: void
# sprite: welcome@left
# sprites: Void.welcome@left, Aqua.listen@right
# dom: roadmap, receipts
The world is full of systems that say one thing and reward another.

If a speaker has sprites in the visual manifest, Sai shows the speaker's default sprite automatically. Use # sprite: none for lines that should stage only background, DOM cards, and dialogue.

The dom tag reads card definitions from the visual manifest and clones matching page DOM into the scene stage. This is for static-site tours where the story frames canonical Quartz/HTML content without making the story file a second source of truth.

Cinematic

<div
  class="sai-player"
  data-ink-format="cinematic"
  data-ink-story="/deck.ink.json"
  data-visual-manifest="/deck.visual-manifest.json"
></div>

Cinematic mode is for slide/deck-like fragments: background plates, captions, references, and short blocks of text.

Data Attributes

  • data-ink-story: required URL for compiled Ink JSON.
  • data-ink-format: raven, visual-novel, or cinematic.
  • data-visual-manifest: optional visual manifest URL.
  • data-scene-label: optional fallback scene label for visual-novel mode.
  • data-ink-title: optional player title/status text.
  • data-ink-runtime: optional URL for ink.js.
  • data-sai-runtime: alias for data-ink-runtime.
  • data-show-variables="true": show Ink variables in visual modes.

Legacy .aetheria-ink-player containers are still initialised so existing GameCult pages can migrate without ritual screaming. New work should use .sai-player.

JavaScript API

window.Sai.init(document.querySelector(".sai-player"));
window.Sai.initAll();
console.log(window.Sai.version);

By default, sai.js loads ink.js from the same directory as itself. Override that with data-ink-runtime, data-sai-runtime, or window.Sai.runtimeSrc.

Visual Manifest

See docs/manifest.md.

Eve Surface Module

Sai also ships eve.js, a portable projection module for Eve/CultMesh clients. It turns Sai visual-novel state into a retained gamecult.eve.surface.v1 component tree instead of browser DOM. Browser, iOS, Android, Direct2D, and future renderers can consume the same tree and send back story.* or style.patch commands.

See docs/eve.md.

Sai also publishes a retained Ink playback sidecar for runtime-independent Eve clients. See docs/eve-sidecar.md.

Development

npm install
npm run build
npm run check

Compile the example story after dependencies are installed:

npm run compile:example

Open examples/static-site/index.html through a local static server. Browsers are right to dislike fetch() from file://; do not take it personally.

Boundary

Sai owns:

  • browser-side Ink loading through inkjs
  • player DOM and mode rendering
  • visual manifest interpretation
  • Eve surface projection for portable renderers
  • default CSS and theme variables
  • static-site auto-init

Sai does not own:

  • authoring Ink
  • compiling .ink to .ink.json
  • Eve/CultMesh transport or provider command acceptance
  • Quartz page chrome
  • GameCult-specific assets, lore, or characters
  • a full VN/game engine loop

The brush is sharp. The painting is yours.