Docs Examples

Examples

Copy-paste patterns for the most common structures. Swap in the character names, asset filenames and variable names you’ve registered in your project.

A full chapter

Backgrounds, dialogue, choices, variables, conditionals, jumps and endings working together.

chapter_one.omi
## The Message
// Register 'stranger' in Studio → Characters, 'city_night' in Assets → Backgrounds,
// and '$met_stranger' (boolean) in Studio → Variables before running this script.

@bg city_night

// Narration — no speaker, shown as prose overlay
"It was 2 AM when the phone buzzed."

// Dialogue — speaker must be registered in Studio → Characters
player: "Who texts at this hour?"
stranger: "Turn around."

// Choice gate — player picks one branch; the engine waits here
? "What do you do?"
  - "Turn around slowly"
    player: "My hands are shaking."
    stranger: "Smart choice."
    // Session variable assignment — saved with save slots
    $met_stranger = true
    -> The Reveal

  - "Ignore it"
    player: "Probably spam."
    "She put the phone down. Big mistake."
    -> Bad End

## The Reveal
@bg alley_night

"The figure stepped into the light."

// Conditional — branches on a session variable value
? if $met_stranger:
  stranger: "I knew you'd come."
? else:
  stranger: "You shouldn't be here."

stranger: "We need to talk. Not here."

// @end — chapter complete, engine loads the next published chapter
@end

## Bad End
@bg city_night

"Three hours later, she was gone."

// @fin ends the entire story, not just the chapter
@fin

Branching choices

branching.omi
// Choices can be conditional — an option only appears when its [$condition] is true.
// Conditions read session variables ($var) declared in Studio → Variables.

? "What do you say?"
  - "I believe you" [$trust >= 1]
    // This option only shows if $trust is at least 1
    player: "I believe you."
    sarah: "Thank you. Really."
    $route = "friendship"
    -> Good Path

  - "I don't trust you"
    // No condition — always visible
    player: "I don't trust you."
    sarah: "That's fair. But you're wrong."
    $route = "tense"
    -> Tense Path

  - "Stay quiet" [$met_sarah == false]
    // Only available if the player hasn't met sarah yet
    "You said nothing. Safer that way."
    -> Quiet Path

Messenger scene

messenger.omi
// Switch to a messenger-type app registered in Studio → Apps.
// All @chat content is deposited into that chat's message log.
@app chatter

// Open a specific chat — chatId must be registered under this app in Studio.
@chat chat_sarah
  // Messages drip in one at a time as the engine runs
  sarah: "hey, you there?"
  sarah: "hello??"

  // Reply gate — the player picks one option to send as their message
  ? reply:
    - "sorry, was asleep"
      player: "sorry just woke up lol"
      sarah: "okay good, we need to talk"
      // Track that the player replied — useful for branching later
      $replied_sarah = true
      -> Replied

    - "leave on read"
      // No player message — sarah gets no response
      -> Left On Read

## Replied
sarah: "meet me at the usual spot. 20 mins."
@end

## Left On Read
// Push a notification into the player's notification shade
@notify chatter "Sarah" "is waiting for your reply..."
@end

Conditional branching

conditional.omi
// ? if / ? elif / ? else — conditional blocks.
// Evaluates against session ($var) or persistent ($$var) variables.
// Only the first matching branch executes.

? if $route == "friendship":
  sarah: "I'm glad we talked."
  player: "Me too."
? elif $route == "tense":
  sarah: "I hope you change your mind."
  player: "Maybe."
? else:
  // Fallback — runs when no other branch matched
  "They stood in silence."

// Comparison operators: ==  !=  >  <  >=  <=
// Logical: and  or  not
// Example multi-condition: ? if $score >= 10 and $met_sarah:

Phone call (SimOS)

phone.omi
## The Call
// Switch to a phone-type app registered in Studio → Apps
@app phone

// Incoming call gate — the player picks Answer, Decline, or another branch.
// Dialogue inside a branch becomes the in-call conversation in the Phone app.
? call from sarah:
  - "answer"
    sarah: "Hey. Are you alone?"
    player: "Yeah, why?"
    sarah: "I need you to listen carefully."
    sarah: "Don't come to the office tomorrow."
    -> After Call

  - "decline"
    // No in-call dialogue — goes straight to the branch body
    -> Missed Call

  // 'hang up' is a special branch — runs when the player taps End Call mid-conversation
  - "hang up"
    sarah: "...hello?"
    -> Hung Up

## After Call
"She hung up before you could ask anything."
@end

## Missed Call
// Voicemail — deposited into the phone app's voicemail inbox
@voicemail vm_sarah_001
  from: sarah
  duration: 0:12
  transcript: "It's me. Call me back. Please."
@end

## Hung Up
"You stared at the phone. Had that been a mistake?"
@end

Social feed (SimOS)

social.omi
## The Post
// Switch to a social_feed-type app registered in Studio → Apps
@app social_feed

// Posts deposit into the feed as the engine runs — displayed newest-first in the UI.
// 'image' is a logical name from Studio → Assets → CGs (no file extension).
@post post_morning
  by: sarah
  text: "Another late night at the office. Someone send help ☕"
  image: sarah_office
  likes: 12
  likeable: true

// Comment gate — the player picks a reply to a specific post.
// appId and postId must reference what's already been deposited above.
? comment on social_feed post_morning:
  - "Hang in there!"
    player: "Hang in there, you've got this!"
    sarah: "Aw, thanks 🥺"
    -> After Comment

  - "Say nothing"
    -> After Comment

## After Comment
// Push a banner notification into the player's notification shade
@notify social_feed "Sarah" "liked your comment"
"Your notification lit up a moment later."
@end

Premium feed with subscription (SimOS)

premium.omi
## The Exclusive
// Premium feed — requires a premium_feed-type app in Studio → Apps
@app vip_feed

// free: true — always visible regardless of subscription status
@post post_free_001
  by: creator
  text: "Hey everyone, big news coming soon 👀"
  likes: 204
  likeable: true
  free: true

// locked_until — the post is blurred with a lock overlay until the condition is true.
// player_subscribed_to(appId, userId) is a built-in engine expression.
@post post_locked_001
  by: creator
  text: "Here's the full behind-the-scenes video from last night."
  image: bts_video_thumb
  locked_until: player_subscribed_to(vip_feed, creator)
  teaser: "Subscribe to unlock exclusive content 🔒"

// ? subscribe to — narrative-driven subscription gate.
? subscribe to vip_feed creator:
  - "Subscribe"
    creator: "Thank you so much! 🥺"
    // Persistent — survives across playthroughs, so future chapters know
    $$subscribed_vip = true
    -> Subscribed
  - "Maybe later"
    -> Skipped

## Subscribed
"The locked post shimmered and revealed itself."
@end

## Skipped
"The blurred post remained. For now."
@end

Character sprites

sprites.omi
## The Confrontation
// 'rooftop_night' is a logical name from Studio → Assets → Backgrounds
@bg rooftop_night

// Auto-stage: speaking with () triggers automatic sprite placement.
// The first speaker goes center; the second speaker pushes the first aside.
sarah (): "You followed me up here."
player (): "You left me no choice."

// Named expression — registered in the character's sprite map in Studio.
// Use () for the default expression, (name) for a registered variant.
sarah (angry): "Don't make this harder than it has to be."

// Explicit placement — overrides auto-staging, puts marcus in the left slot.
@sprite left marcus

marcus: "Nobody's going anywhere."

// Clear a slot — removes the sprite visually when a character exits.
@sprite left clear

// sarah and player remain staged in their auto-assigned slots.
sarah: "It's just us now."

// @end — chapter complete. Use @fin to end the entire story.
@end

Storyomi Creator Docs

Back to Storyomi