Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Screenplay, sections, and events

One spoken line spans three native objects. The screenplay item says who speaks and which localization ID to resolve. A timed event schedules that item. A section owns the event and determines when graph flow can leave.

screenplayStore.lines[0]
  scnscreenplayDialogLine item 1
          ^
          | screenplayLineId 1
  scnDialogLineEvent, start 0, duration 2598 ms
          |
          v
  scnSectionNode 2, sectionDuration 2998 ms

Removing any layer produces a different resource: a screenplay row alone is not scheduled, an event with an unresolved item ID has no line definition, and a section duration that ends too early can cut off its event.

The screenplay line

First Contact’s scnscreenplayStore.lines contains exactly one scnscreenplayDialogLine; its options array is empty:

{
  "$type": "scnscreenplayDialogLine",
  "itemId": { "$type": "scnscreenplayItemId", "id": 1 },
  "speaker": { "$type": "scnActorId", "id": 0 },
  "addressee": { "$type": "scnActorId", "id": 1 },
  "locstringId": {
    "$type": "scnlocLocstringId",
    "ruid": "9638591835734011695"
  },
  "usage": {
    "$type": "scnscreenplayLineUsage",
    "playerGenderMask": { "$type": "scnGenderMask", "mask": 3 }
  }
}

Actor 0 is the contact and actor 1 is V. Gender mask 3 is the exact line-usage value in this checkpoint. It sits beside male and female lipsync animation names set to None; it does not select the subtitle resource or replace the actor definitions.

The line stores no English sentence. Its RUID 9638591835734011695 resolves to All clear. Keep moving. through external subtitle and VO resources. Consequently the scene’s scnlocLocStoreEmbedded can remain typed and empty. Embedded locStore payloads are for scene-owned localized data such as choice labels, not this line’s external spoken-text path.

For custom clips, those two animation-name fields need their own lookup check: confirm the selected CName exists in the intended animset. See Custom clip checks before replacing None; a valid RUID or WEM does not validate an animation.

The timed line event

Section node 2 contains exactly one handled scnDialogLineEvent:

PropertyExact value
screenplayLineIdscnscreenplayItemId 1
idscnSceneEventId 8646165628675208917
startTime0
duration2598 ms
visualStyleregular
voContextVo_Context_Quest
voExpressionVo_Expression_Spoken
additionalSpeakers.speakers[]

The event points to screenplay item 1; it does not point directly to the locstring. Event ID 8646165628675208917 and locstring RUID 9638591835734011695 are intentionally different unsigned identifiers. Keep both as unsigned decimal values through tooling and comparison. Do not derive one from the other, reuse a graph node ID, or truncate either to 32 bits.

The event duration is aligned to the supplied audio’s measured duration for this fixture. It is not inferred from subtitle character count.

The section

scnSectionNode 2 owns the event and two output sockets:

Section 2
├── actorBehaviors
│   ├── actor 0: OnlyIfAlive
│   └── actor 1: OnlyIfAlive
├── events
│   └── DialogLineEvent: item 1, 2598 ms
├── sectionDuration: scnSceneTime(stu = 2998)
├── output stamp name 0 / ordinal 0 -> End 3 input 0 / 0
└── output stamp name 1 / ordinal 0 -> no destination

For First Contact, the section-duration contract is:

2598 ms line duration + 400 ms tail = 2998 ms section duration

The 400 ms tail is a deliberate lab value that lets the line finish before the section reaches End. It is not claimed as a universal engine constant. For multiple or overlapping events, calculate the latest event end and add an appropriate tested tail instead of adding 400 ms blindly to every line.

Output stamp 0/0 is the normal completed route. Output stamp 1/0 is an explicit cancel-shaped socket with no destination in this minimal scene. A named quest exit is attached to End node 3, not to the screenplay line or event itself.

Keep the ID domains separate

Typed domainFirst Contact valueIdentifies
scnActorId0, 1Contact and V
scnPerformerId1, 257Debug performer symbols
scnNodeId1, 2, 3, 4Start, Section, End, PuppetAI wrapper
scnscreenplayItemId1The line definition and event-to-line join
scnSceneEventId8646165628675208917The timed event instance
scnlocLocstringId9638591835734011695External subtitle and voice lookup
scnLipsyncAnimSetSRRefId0Index into the lipsync resource-reference array

The repeated integer 1 across several rows is coincidence plus a deliberately small fixture. See Identifier domains before comparing raw exports.