Skip to content

Latest commit

 

History

History
478 lines (384 loc) · 17.7 KB

File metadata and controls

478 lines (384 loc) · 17.7 KB

RouteEngine API Reference

The RouteEngine is the core runtime for RVN visual novels. It manages state, processes actions, and coordinates rendering.

Creating an Engine Instance

import createRouteEngine from "rvn-temp";

const engine = createRouteEngine({
  handlePendingEffects: (effects) => {
    // Process side effects (render, timers, etc.)
    effects.forEach((effect) => {
      switch (effect.name) {
        case "render":
          renderToScreen(engine.selectRenderState());
          break;
        case "handleLineActions":
          engine.handleLineActions();
          break;
        // ... handle other effects
      }
    });
  },
});

Initialization

init({ initialState })

Initializes the engine with project data and global settings.

engine.init({
  initialState: {
    projectData: {
      resources: {
        /* images, audio, etc */
      },
      story: {
        initialSceneId: "scene1",
        scenes: {
          scene1: {
            initialSectionId: "section1",
            sections: {
              section1: {
                initialLineId: "line1", // optional, otherwise first line is used
                lines: [
                  /* section lines */
                ],
              },
            },
          },
        },
      },
    },
  },
});

Localization is not implemented in the current runtime. The planned patch-based l10n model is documented in L10n.md.

The engine will:

  1. Create the system store with initial state
  2. Append a render effect
  3. Execute any actions on the initial line
  4. Trigger pending effects handler
  5. Clear pending effects

Methods

selectSystemState()

Returns a cloned snapshot of the full internal system state.

This is intended for tooling, debugging, capture harnesses, and devtools-style inspection. It should not be treated as the primary gameplay-facing API for normal runtime integration.

The returned value is a snapshot, not the live mutable store object.

const systemState = engine.selectSystemState();

console.log(systemState.global.nextLineConfig);
console.log(systemState.contexts.at(-1)?.pointers);

Utilities

resolveLayoutReferences(value, { resources })

Resolves authored layout references into renderer-facing fields without mutating the input value.

It resolves:

  • textStyleId into textStyle
  • colorId into fill
  • imageId into src
  • nested interaction references such as hover.colorId, clickImageId, and rightClick.colorId

It uses the same strict rules as the engine render-state pipeline, so inline authored textStyle, fill, and sprite src fields still throw.

import { resolveLayoutReferences } from "rvn-temp";

const resolvedElements = resolveLayoutReferences(layout.elements, {
  resources: projectData.resources,
});

handleAction(actionType, payload)

Dispatches a single action to the system store.

// Advance to next line
engine.handleAction("nextLine");

// Jump to specific section
engine.handleAction("sectionTransition", { sectionId: "chapter_2" });

// Toggle auto mode
engine.handleAction("toggleAutoMode");

handleActions(actions, eventContext?)

Dispatches multiple actions from an object. Optionally accepts event context for _event.* payload bindings.

// Basic usage
engine.handleActions({
  setNextLineConfig: {
    manual: { enabled: false },
    auto: { enabled: true, trigger: "fromComplete", delay: 2000 },
  },
  markLineCompleted: {},
});

// With event context (for slider/input events)
// Bindings like _event.value in action payloads get resolved
engine.handleActions(payload.actions, { _event: payload._event });

Event Templating

When eventContext is provided, action payloads can use _event.* bindings to reference event values. Action payloads can also reference ${variables.*} and they will be resolved at runtime. eventContext only supports _event for event data; using event will throw. Invalid _event.* bindings fail fast with an explicit error.

# In YAML layout definition
- id: volumeSlider
  type: slider
  min: 0
  max: 100
  change:
    payload:
      actions:
        updateVariable:
          id: setVolume
          operations:
            - variableId: volume
              op: set
              value: "_event.value" # Resolved to slider's current value

The integration layer should pass event context when handling events:

eventHandler: (eventName, payload) => {
  if (payload.actions) {
    engine.handleActions(
      payload.actions,
      payload._event ? { _event: payload._event } : undefined,
    );
  }
};

Layout Resource References

Layout authoring uses project resource references, not the renderer-facing fields that RouteGraphics consumes directly.

  • textStyleId resolves through resources.textStyles to renderer textStyle
  • imageId / hoverImageId / clickImageId resolve through resources.images to renderer src, hover.src, and click.src
  • colorId / hover.colorId / click.colorId / rightClick.colorId resolve through resources.colors to renderer fill

This resolution happens during render-state construction, before RouteGraphics parses the layout tree.

Layout Text Styles

Layout text should be authored with textStyleId and resolved through resources.textStyles. Authored inline textStyle objects in layout elements are rejected at render-state construction. Text transparency should be authored on the text style resource with colorAlpha and strokeAlpha, not baked into the shared color resource itself. Whole-node transparency still uses the element alpha. resources.colors[*].hex must be opaque hex only.

resources:
  fonts:
    fontDefault:
      fileId: Arial
  colors:
    colorPrimary:
      hex: "#FFFFFF"
  textStyles:
    body:
      fontId: fontDefault
      colorId: colorPrimary
      colorAlpha: 0.9
      fontSize: 24
      fontWeight: "400"
      fontStyle: normal
      lineHeight: 1.2
      strokeColorId: colorPrimary
      strokeAlpha: 0.35
      strokeWidth: 2
  layouts:
    dialogueLayout:
      elements:
        - id: dialogue-text
          type: text
          content: "${dialogue.content[0].text}"
          textStyleId: body

Layout Sprite Images

Layout sprite elements should be authored with imageId and optional hoverImageId / clickImageId. Authored inline sprite src and interaction hover.src / click.src fields are rejected at render-state construction. Legacy url, hoverUrl, and clickUrl fields are also rejected.

If resources.images[imageId] exists, the engine resolves the sprite to that image resource's fileId. Otherwise, the rendered imageId string is passed through directly, which allows dynamic values such as save preview image keys. Before RouteGraphics parses the layout, the engine resolves these IDs to sprite-facing src, hover.src, and click.src fields.

resources:
  images:
    buttonIdle:
      fileId: button-idle.png
      width: 400
      height: 80
    buttonHover:
      fileId: button-hover.png
      width: 400
      height: 80
  layouts:
    titleLayout:
      elements:
        - id: start-button
          type: sprite
          imageId: buttonIdle
          hoverImageId: buttonHover

Layout Rect Colors

Layout rect elements should be authored with colorId and optional hover.colorId / click.colorId / rightClick.colorId. Authored inline rect fill and interaction hover.fill / click.fill / rightClick.fill fields are rejected at render-state construction. Before RouteGraphics parses the layout, the engine resolves these IDs to rect-facing fill fields.

resources:
  colors:
    panelBg:
      hex: "#000000"
    panelBgHover:
      hex: "#141414"
  layouts:
    menuLayout:
      elements:
        - id: menu-panel
          type: rect
          width: 900
          height: 420
          opacity: 0.85
          colorId: panelBg
          hover:
            colorId: panelBgHover
            opacity: 0.9

handleLineActions()

Processes actions attached to the current line. Called automatically on line changes.

// Line data structure
const line = {
  id: "line_1",
  actions: {
    background: { resourceId: "bg_school" },
    dialogue: { characterId: "protagonist", content: [{ text: "Hello!" }] },
    bgm: { resourceId: "music_1" },
  },
};

selectRenderState()

Returns the current render state for the renderer.

const renderState = engine.selectRenderState();
// {
//   elements: [{ id: 'story', type: 'container', children: [...] }],
//   animations: [...],
//   audio: [...]
// }

selectPresentationState()

Returns the current presentation state.

const presentationState = engine.selectPresentationState();
// {
//   background: { resourceId: 'bg_school' },
//   dialogue: { characterId: 'protagonist', content: [...] },
//   bgm: { resourceId: 'music_1', loop: true }
// }

Available Actions

Navigation Actions

Action Payload Description
nextLine - Advance to the next line (respects nextLineConfig.manual)
prevLine { sectionId } Navigate to previous line (enters history mode)
jumpToLine { sectionId?, lineId } Jump to specific line
sectionTransition { sectionId } Transition to a different section

Playback Mode Actions

Action Payload Description
startAutoMode - Enable auto-advance mode
stopAutoMode - Disable auto-advance mode
toggleAutoMode - Toggle auto-advance mode
startSkipMode - Enable skip mode
stopSkipMode - Disable skip mode
toggleSkipMode - Toggle skip mode

Playback timing semantics:

  • Global autoMode waits for the current line to complete before starting its _autoForwardTime delay.
  • That completion is driven by Route Graphics renderComplete, so revealing text and other tracked render work finish first.
  • Global skipMode does not use that completion gate; it advances on its own fast timer.
  • nextLineConfig.auto is separate and may use trigger: "fromStart" or trigger: "fromComplete" depending on authored behavior.

UI Actions

Action Payload Description
showDialogueUI - Show the dialogue UI
hideDialogueUI - Hide the dialogue UI
toggleDialogueUI - Toggle dialogue UI visibility

State Management Actions

Action Payload Description
markLineCompleted - Mark current line as completed
setNextLineConfig { manual?, auto? } Configure line advancement
updateProjectData { projectData } Replace project data

Registry Actions

Action Payload Description
addViewedLine { sectionId, lineId } Mark line as viewed
addViewedResource { resourceId } Mark resource as viewed
addToHistory { item } Add entry to history sequence

Seen-line semantics:

  • The engine stores seen progress per section as a single frontier: { sectionId, lastLineId }.
  • The frontier line itself counts as seen.
  • Any earlier line in the same section also counts as seen.
  • The frontier is updated when a line is completed and when progression moves away from the current line.

Save System Actions

Action Payload Description
saveSlot { slotId, thumbnailImage? } Save game to a slot
loadSlot { slotId } Load game from a slot

Save/load design, requirements, and storage boundaries are documented in SaveLoad.md.

Notes:

  • slotId is the public action field; storage stringification is internal
  • save/load UIs can bind slotId directly from layout templates such as ${slot.slotId}
  • if slot identity comes from event data, use _event.* bindings such as slotId: "_event.slotId"
  • example save/load UI copy should stay terse; prefer short labels like Save, Load, Page 1, Saved, Empty, and Image
  • thumbnailImage is integration-provided; the engine does not capture screenshots by itself
  • if a save action appears inside a multi-action event payload, the host should prepare/augment the actions object and still call handleActions(...) once for the whole batch

Effect Actions

Action Payload Description
appendPendingEffect { name, ...options } Queue a side effect
clearPendingEffects - Clear the effect queue

Available Selectors

The system store exposes these selectors (called internally):

Selector Parameters Returns
selectPendingEffects - Array of pending effects
selectCurrentPointer - { currentPointerMode, pointer }
selectCurrentLine - Current line object
selectSection { sectionId } Section object
selectAutoMode - Boolean
selectSkipMode - Boolean
selectDialogueUIHidden - Boolean
selectIsLineViewed { sectionId, lineId } Boolean
selectIsResourceViewed { resourceId } Boolean
selectNextLineConfig - Config object
selectSaveSlotMap - Save slots object map
selectSaveSlot { slotId } Save slot data
selectSaveSlotPage { slotsPerPage? } Paged save slot list for UI

Pending Effects

Effects queued by actions for external handling:

Effect Description
render Re-render the current state
handleLineActions Process current line's actions

Line Actions (Presentation)

Actions that can be attached to lines to control presentation:

Action Properties Description
background { resourceId, animations? } Set background/CG
dialogue { characterId?, character?, content, mode?, ui?, clear? } Display dialogue
character { items } Display character sprites. Each item can have optional x and y to override transform position
visual { items } Display visual elements
bgm { resourceId, loop?, volume?, delay? } Play background music
sfx { items } Play sound effects
voice { fileId, volume?, loop? } Play voice audio
animation { ... } Apply animations
layout { resourceId } Display layout
control { resourceId } Activate control bindings and control UI
choice { resourceId, items } Display choice menu
cleanAll true Clear all presentation state