Document markup and improve choice tags
This commit is contained in:
@@ -20,6 +20,9 @@ The web app starts on `http://localhost:3000` when launched through `src/index.t
|
||||
|
||||
```powershell
|
||||
npm run dev # Start the web UI through ts-node/nodemon
|
||||
npm run dev:ink # Start the Ink engine server, watch ink source, compile on restart
|
||||
npm run dev:yaml # Start the YAML engine server
|
||||
npm run dev:zork # Start the Z-code/Zork engine server
|
||||
npm run start # Run the compiled web server from dist/
|
||||
npm run build # Compile TypeScript
|
||||
npm run test # Run Jest tests
|
||||
@@ -28,6 +31,8 @@ npm run start:cli # Run the CLI interface
|
||||
npm run dev:cli # Run the CLI interface through ts-node/nodemon
|
||||
```
|
||||
|
||||
Each game engine also has an inspect command for debugger work: `npm run dev:ink:inspect`, `npm run dev:yaml:inspect`, and `npm run dev:zork:inspect`.
|
||||
|
||||
## Configuration
|
||||
|
||||
Environment variables are loaded from `.env`.
|
||||
@@ -67,6 +72,7 @@ Major modules:
|
||||
- `tts-factory-module.js` plus provider modules: TTS provider selection, voice settings, speed mapping, caching, and playback.
|
||||
- `audio-manager-module.js`: master, speech, music, and sound effect volume, music playback, sound effects, and music ducking.
|
||||
- `ui-controller-module.js`, `ui-display-handler-module.js`, `ui-input-handler-module.js`, `options-ui-module.js`: book UI, command input, options, top-bar controls, and game API calls.
|
||||
- `choice-display-module.js`: choice-mode UI, click selection, keyboard-letter assignment, and future choice-template routing.
|
||||
|
||||
The static server sends no-cache headers for local development so stale ES modules do not mask changes. If the browser console shows `onpage-dialog.preload.js:121 Uncaught ReferenceError: browser is not defined`, ignore it; that comes from the installed ad blocker, not this project.
|
||||
|
||||
@@ -82,7 +88,18 @@ Inline Markdown emphasis:
|
||||
***bold italic*** or ___bold italic___
|
||||
```
|
||||
|
||||
Canonical block/media tags use Ink-style `#` syntax. In Ink these are real Ink tags. In YAML and Zork narrative output, leading `#...` lines are parsed by the server into the same structured `StoryTag` objects before reaching the client. The browser only consumes structured `TurnResult` objects.
|
||||
Canonical block/media/control tags use Ink-style `#` syntax. In Ink these are real Ink tags. In YAML and Zork narrative output, leading `#...` lines are parsed by the server into the same structured `StoryTag` objects before reaching the client. The browser only consumes structured `TurnResult` objects.
|
||||
|
||||
Tag format:
|
||||
|
||||
```text
|
||||
#key
|
||||
#key[value]
|
||||
#key[value](options)
|
||||
#key:value
|
||||
```
|
||||
|
||||
For Ink choices, put choice-local tags under the choice they belong to. Explicit keyboard letters are supported with `# letter[x]`, `#letter[x]`, or the colon form `#key:x`; the client reserves those letters first, then assigns the remaining visible choices from `A` through `Z` in order. `# action[name]` or `#action:name` is parsed as a category/template hint for future choice layouts, although the current UI displays all choices in one list.
|
||||
|
||||
Chapter:
|
||||
|
||||
@@ -108,23 +125,25 @@ The following paragraph returns to the normal indent.
|
||||
|
||||
`#textblock` is treated the same way. The first paragraph after the marker is separated from previous content by one line of vertical space.
|
||||
|
||||
Images are parsed for future rendering:
|
||||
Images are story blocks:
|
||||
|
||||
```text
|
||||
#image[mansion-rain.jpg](landscape)
|
||||
#image[portrait-letter.jpg](portrait pause=2)
|
||||
#image[seal.png](square lead=1.5)
|
||||
```
|
||||
|
||||
Image file names are relative to `public/images/`. `widescreen` is accepted as an alias for `landscape`.
|
||||
Image file names are relative to `public/images/`. `landscape`/`widescreen` and `square` images are centered, near full page width, and line-snapped. `portrait` images sit beside prose at half page width. Image pauses (`pause=`, `delay=`, `lead=`, or a bare `2s`) are skippable and do not block background TTS preparation.
|
||||
|
||||
Sound effects are story tags:
|
||||
|
||||
```text
|
||||
#sfx[squeaky-door.ogg]
|
||||
#sfx[church-bells.ogg](max=8 fade fade-duration=2)
|
||||
The door opens and the hall exhales.
|
||||
```
|
||||
|
||||
The tag is parsed by the server into a `StoryTag` object. Sound effect paths are relative to `public/sounds/`.
|
||||
The tag is parsed by the server into a `StoryTag` object. Sound effect paths are relative to `public/sounds/`. Optional parameters can limit playback (`max=`, `duration=`, `stop-after=`, `fade-after=`), choose the end mode (`fade` or `stop`/`cut`), and set `fade-duration=`.
|
||||
|
||||
Music can be placed as a block:
|
||||
|
||||
@@ -134,6 +153,17 @@ Music can be placed as a block:
|
||||
|
||||
Music paths are relative to `public/music/`. Supported modes are `queue`, `crossfade`, and `cut`. Use `loop` or `once` to control repetition. `lead=<seconds>` delays the following text/TTS paragraph so the music can play alone before narration continues. To place that pause between a chapter heading and the dropcapped first paragraph, put the music tag after the chapter tag and before the first prose paragraph; TTS generation for the next spoken paragraph continues during the lead pause.
|
||||
|
||||
Game-state and player-message tags:
|
||||
|
||||
```text
|
||||
#score[You found the quiet ending.]
|
||||
#error[Ink story ended without an explicit ending tag.]
|
||||
#achievement[First Steps]
|
||||
#alert[Try examining objects before using them.]
|
||||
```
|
||||
|
||||
`#score[...]` marks an intended ending and opens a localized ending popup when the turn reaches `inputMode: end`. `#error[...]` marks an unrecoverable ending and opens an error popup. If an Ink story runs out of content without an explicit `#score[...]` or `#error[...]`, the Ink engine emits an `#error[...]` tag. `#achievement[...]` and `#alert[...]` open localized queued popups while the game continues.
|
||||
|
||||
## Assets
|
||||
|
||||
- `public/sounds/`: sound effects referenced by `#sfx[file]` tags.
|
||||
@@ -160,8 +190,20 @@ When real TTS audio is available, animation duration is driven by measured audio
|
||||
|
||||
Fast-forwarding by page click or space completes the active animation and fades/stops current TTS playback so queued content can proceed.
|
||||
|
||||
The right page history is line-addressed rather than natively scrolled. The page has a fixed line count, all block heights snap to whole lines, and the custom scrollbar represents virtual history line position. The DOM keeps a moving window of history blocks around the active line instead of paginating the story.
|
||||
|
||||
## Changelog
|
||||
|
||||
### 2026-05-17
|
||||
|
||||
- Added Ink engine support with source compilation, engine config files, game metadata, locale-driven UI text, choice mode, keyboard choice letters, and one-list choice rendering.
|
||||
- Added line-addressed right-page history, save/load reconstruction, image restoration, custom scrollbar plumbing, and virtual block-window rendering.
|
||||
- Added story image rendering for landscape, portrait, and square images, including line-snapped sizing and portrait text exclusion.
|
||||
- Added localized popups for endings, errors, achievements, and alerts through the tag channel.
|
||||
- Added credits and third-party license UI.
|
||||
- Added per-volume mute toggles and configurable music ducking amount.
|
||||
- Added German typography handling for dialogue guillemets based on game metadata language.
|
||||
|
||||
### 2026-05-14
|
||||
|
||||
- Consolidated usage, markup, and architecture documentation into `README.md` and `CLIENT_TODO.md`.
|
||||
|
||||
Reference in New Issue
Block a user