Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
87 changes: 65 additions & 22 deletions docs/RouteEngine.md
Original file line number Diff line number Diff line change
Expand Up @@ -655,22 +655,22 @@ Built-in effect handling notes:

Actions that can be attached to lines to control presentation:

| Action | Properties | Description |
| ------------ | ---------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------- |
| `screen` | `{ opacity?, blur?, animations? }` | Set whole-screen appearance or transition. `opacity`/`blur` apply to the composed story frame |
| `background` | `{ resourceId?, colorId?, transformId?, opacity?, blur?, animations? }` | Set background/CG. `opacity` maps to renderer alpha; `blur: null` clears background blur |
| `dialogue` | `{ characterId?, character?, character.sprite?, persistCharacter?, content, append?, mode?, ui?, clear? }` | Display dialogue |
| `character` | `{ items }` | Display character sprites. Each item can set transform overrides, `opacity`, and `blur` |
| `visual` | `{ items }` | Display visual elements. Each item can set `layer`, transform overrides, `opacity`, and `blur` |
| `bgm` | `{ resourceId, volume?, loop?, startDelayMs? }` | Play background music |
| `sfx` | `{ items }` | Play sound effects. Each item can include `volume`, `loop`, and `startDelayMs` |
| `voice` | `{ resourceId, volume?, loop?, startDelayMs? }` | Play voice audio from `resources.voices[currentSceneId][resourceId]` |
| `animation` | `{ ... }` | Apply animations |
| `layout` | `{ resourceId }` | Display layout |
| `control` | `{ resourceId }` | Activate control bindings and control UI |
| `choice` | `{ resourceId, items }` | Display choice menu |
| `form` | `{ resourceId, fields, submitActions?, cancelActions? }` | Display a blocking multi-input form |
| `cleanAll` | `true` | Clear all presentation state |
| Action | Properties | Description |
| ------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------- |
| `screen` | `{ opacity?, blur?, animations? }` | Set whole-screen appearance or transition. `opacity`/`blur` apply to the composed story frame |
| `background` | `{ resourceId?, colorId?, transformId?, x?, y?, anchorX?, anchorY?, scaleX?, scaleY?, rotation?, originX?, originY?, opacity?, blur?, animations? }` | Set background/CG. Transform fields are renderer pixels/unitless multipliers/degrees; `blur: null` clears background blur |
| `dialogue` | `{ characterId?, character?, character.sprite?, persistCharacter?, content, append?, mode?, ui?, clear? }` | Display dialogue |
| `character` | `{ items }` | Display character sprites. Each item can set transform overrides, `opacity`, and `blur` |
| `visual` | `{ items }` | Display visual elements. Each item can set `layer`, transform overrides, `opacity`, and `blur` |
| `bgm` | `{ resourceId, volume?, loop?, startDelayMs? }` | Play background music |
| `sfx` | `{ items }` | Play sound effects. Each item can include `volume`, `loop`, and `startDelayMs` |
| `voice` | `{ resourceId, volume?, loop?, startDelayMs? }` | Play voice audio from `resources.voices[currentSceneId][resourceId]` |
| `animation` | `{ ... }` | Apply animations |
| `layout` | `{ resourceId }` | Display layout |
| `control` | `{ resourceId }` | Activate control bindings and control UI |
| `choice` | `{ resourceId, items }` | Display choice menu |
| `form` | `{ resourceId, fields, submitActions?, cancelActions? }` | Display a blocking multi-input form |
| `cleanAll` | `true` | Clear all presentation state |

Animation selections use `animations.resourceId` plus optional
`animations.playback`. `playback.speed` is a unitless multiplier: `1` is normal,
Expand Down Expand Up @@ -715,12 +715,55 @@ callers can use the exported `RENDER_LAYER`, `VISUAL_LAYER`, and
### Item Transform Overrides

`resources.transforms` can define `x`, `y`, `anchorX`, `anchorY`, `scaleX`,
`scaleY`, `rotation`, `originX`, and `originY`. Character and visual items can
override any of those transform fields for a single item. `originX` and
`originY` are passed through to the renderer as the transform origin fields.
New character sprite items still require `transformId`; after an item exists, a
later line can provide only `id` and transform fields to patch that item without
restating its sprites or visual resource.
`scaleY`, `rotation`, `originX`, and `originY`. `x` and `y` use renderer pixels,
anchors are normalized unitless values, scale fields are multipliers, and
`rotation` is degrees. Character and visual items can override any of those
transform fields for a single item. `originX` and `originY` are passed through
to the renderer as the transform origin fields. New character sprite items still
require `transformId`; after an item exists, a later line can provide only `id`
and transform fields to patch that item without restating its sprites or visual
resource.

Background actions can also set `x`, `y`, `anchorX`, `anchorY`, `scaleX`,
`scaleY`, `rotation`, `originX`, and `originY` at the top level. These fields
can override selected values from `transformId`, or position the background
without any `transformId`. Image and video backgrounds default to centered
placement, computed as `x = screen.width / 2` and `y = screen.height / 2`, with
`anchorX: 0.5`, `anchorY: 0.5`, `rotation: 0`, `scaleX: 1`, and `scaleY: 1`.
Layout backgrounds use top-left defaults when a background transform is
authored.

Background transforms support three authoring modes:

| Mode | Behavior |
| --------------------------------- | ---------------------------------------------------------------------- |
| `transformId` only | Use the complete transform resource |
| `transformId` plus inline fields | Start from the transform resource, then override the provided fields |
| inline fields without transformId | Apply the provided fields over the background type's default transform |

```yaml
background:
resourceId: bg_school
transformId: fullscreen

background:
resourceId: bg_school
transformId: fullscreen
scaleX: 1.1
scaleY: 1.1

background:
resourceId: bg_school
x: 960
y: 540
anchorX: 0.5
anchorY: 0.5
rotation: 0
scaleX: 1
scaleY: 1
originX: 960
originY: 540
```

```yaml
character:
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "route-engine-js",
"version": "1.21.0",
"version": "1.22.0",
"description": "A lightweight Visual Novel engine built in JavaScript for creating interactive narrative games with branching storylines",
"repository": {
"type": "git",
Expand Down
20 changes: 19 additions & 1 deletion spec/projectDataSchema.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -191,7 +191,7 @@ describe("projectData schema", () => {
);
});

it("accepts background transformId in presentation actions", () => {
it("accepts background transformId and inline transform fields in presentation actions", () => {
expect(
validatePresentationActions({
background: {
Expand All @@ -202,6 +202,24 @@ describe("projectData schema", () => {
).toBe(true);
expect(validatePresentationActions.errors).toBeNull();

expect(
validatePresentationActions({
background: {
resourceId: "bg1",
x: 100,
y: 120,
anchorX: 0,
anchorY: 1,
scaleX: 1.2,
scaleY: 0.8,
rotation: -8,
originX: 64,
originY: 128,
},
}),
).toBe(true);
expect(validatePresentationActions.errors).toBeNull();

expect(
validatePresentationActions({
character: {
Expand Down
38 changes: 38 additions & 0 deletions spec/system/constructPresentationState.spec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,44 @@ out:
transformId: "centered"
colorId: "backdrop"
---
case: background inline transform update keeps the current background resource
in:
- - background:
resourceId: "mainBackground"
transformId: "centered"
x: 960
y: 540
anchorX: 0.5
anchorY: 0.5
scaleX: 1
scaleY: 1
rotation: 0
originX: 960
originY: 540
- background:
x: 100
y: 120
anchorX: 0
anchorY: 1
scaleX: 1.2
scaleY: 0.8
rotation: -8
originX: 64
originY: 128
out:
background:
resourceId: "mainBackground"
transformId: "centered"
x: 100
y: 120
anchorX: 0
anchorY: 1
scaleX: 1.2
scaleY: 0.8
rotation: -8
originX: 64
originY: 128
---
case: background opacity and blur update keeps the current background resource
in:
- - background:
Expand Down
189 changes: 189 additions & 0 deletions spec/system/renderState/addBackgroundOrCg.spec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -422,6 +422,129 @@ out:
height: 1080
animations: []
---
case: add background image with inline transform to story container
in:
- elements:
- id: "story"
type: "container"
x: 0
y: 0
children: []
animations: []
- presentationState:
background:
resourceId: "bg1"
x: 100
y: 120
anchorX: 0
anchorY: 1
scaleX: 1.2
scaleY: 0.8
rotation: -8
originX: 64
originY: 128
resources:
images:
bg1:
fileId: "image1.png"
width: 1920
height: 1080
out:
elements:
- id: "story"
type: "container"
x: 0
y: 0
children:
- id: "bg-cg-background-color"
type: "rect"
x: 0
y: 0
width: 1920
height: 1080
fill: "#000000"
- id: "bg-cg-background-sprite"
type: "sprite"
alpha: 1
anchorX: 0
anchorY: 1
rotation: -8
scaleX: 1.2
scaleY: 0.8
originX: 64
originY: 128
x: 100
y: 120
src: "image1.png"
width: 1920
height: 1080
animations: []
---
case: background inline transform overrides transform resource fields
in:
- elements:
- id: "story"
type: "container"
x: 0
y: 0
children: []
animations: []
- presentationState:
background:
resourceId: "bg1"
transformId: "bgTransform"
x: 500
scaleY: 0.75
rotation: 22
originX: 32
originY: 96
resources:
images:
bg1:
fileId: "image1.png"
width: 1920
height: 1080
transforms:
bgTransform:
x: 200
y: 300
anchorX: 0
anchorY: 1
scaleX: 1.25
scaleY: 1
originX: 64
originY: 128
out:
elements:
- id: "story"
type: "container"
x: 0
y: 0
children:
- id: "bg-cg-background-color"
type: "rect"
x: 0
y: 0
width: 1920
height: 1080
fill: "#000000"
- id: "bg-cg-background-sprite"
type: "sprite"
alpha: 1
anchorX: 0
anchorY: 1
rotation: 22
scaleX: 1.25
scaleY: 0.75
originX: 32
originY: 96
x: 500
y: 300
src: "image1.png"
width: 1920
height: 1080
animations: []
---
case: unknown background transformId should throw clear error
in:
- elements:
Expand Down Expand Up @@ -1596,6 +1719,72 @@ out:
fill: "#000000"
animations: []
---
case: add background layout with inline transform
in:
- elements:
- id: "story"
type: "container"
x: 0
y: 0
children: []
animations: []
- presentationState:
background:
resourceId: "bgLayout"
x: 400
y: 250
anchorX: 0
anchorY: 0
rotation: 12
scaleX: 0.75
scaleY: 1.1
originX: 64
originY: 128
resources:
layouts:
bgLayout:
elements:
- id: "bg-panel"
type: "rect"
width: 100
height: 50
colorId: "panel"
colors:
panel:
hex: "#000000"
out:
elements:
- id: "story"
type: "container"
x: 0
y: 0
children:
- id: "bg-cg-background-color"
type: "rect"
x: 0
y: 0
width: 1920
height: 1080
fill: "#000000"
- id: "bg-cg-background-container"
type: "container"
x: 400
y: 250
anchorX: 0
anchorY: 0
rotation: 12
scaleX: 0.75
scaleY: 1.1
originX: 64
originY: 128
children:
- id: "bg-panel"
type: "rect"
width: 100
height: 50
fill: "#000000"
animations: []
---
case: resolves colorId in background layout elements
in:
- elements:
Expand Down
Loading
Loading