Files
storybook/docs/book/reference/14-schedules.html
Sienna Meridian Satterwhite 16deb5d237 release: Storybook v0.2.0 - Major syntax and features update
BREAKING CHANGES:
- Relationship syntax now requires blocks for all participants
- Removed self/other perspective blocks from relationships
- Replaced 'guard' keyword with 'if' for behavior tree decorators

Language Features:
- Add tree-sitter grammar with improved if/condition disambiguation
- Add comprehensive tutorial and reference documentation
- Add SBIR v0.2.0 binary format specification
- Add resource linking system for behaviors and schedules
- Add year-long schedule patterns (day, season, recurrence)
- Add behavior tree enhancements (named nodes, decorators)

Documentation:
- Complete tutorial series (9 chapters) with baker family examples
- Complete reference documentation for all language features
- SBIR v0.2.0 specification with binary format details
- Added locations and institutions documentation

Examples:
- Convert all examples to baker family scenario
- Add comprehensive working examples

Tooling:
- Zed extension with LSP integration
- Tree-sitter grammar for syntax highlighting
- Build scripts and development tools

Version Updates:
- Main package: 0.1.0 → 0.2.0
- Tree-sitter grammar: 0.1.0 → 0.2.0
- Zed extension: 0.1.0 → 0.2.0
- Storybook editor: 0.1.0 → 0.2.0
2026-02-13 21:52:03 +00:00

866 lines
32 KiB
HTML

<!DOCTYPE HTML>
<html lang="en" class="light sidebar-visible" dir="ltr">
<head>
<!-- Book generated using mdBook -->
<meta charset="UTF-8">
<title>Schedules - Storybook Language Guide</title>
<!-- Custom HTML head -->
<meta name="description" content="Comprehensive documentation for the Storybook narrative simulation language">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="theme-color" content="#ffffff">
<link rel="icon" href="../favicon.svg">
<link rel="shortcut icon" href="../favicon.png">
<link rel="stylesheet" href="../css/variables.css">
<link rel="stylesheet" href="../css/general.css">
<link rel="stylesheet" href="../css/chrome.css">
<link rel="stylesheet" href="../css/print.css" media="print">
<!-- Fonts -->
<link rel="stylesheet" href="../FontAwesome/css/font-awesome.css">
<link rel="stylesheet" href="../fonts/fonts.css">
<!-- Highlight.js Stylesheets -->
<link rel="stylesheet" href="../highlight.css">
<link rel="stylesheet" href="../tomorrow-night.css">
<link rel="stylesheet" href="../ayu-highlight.css">
<!-- Custom theme stylesheets -->
<!-- Provide site root to javascript -->
<script>
var path_to_root = "../";
var default_theme = window.matchMedia("(prefers-color-scheme: dark)").matches ? "navy" : "light";
</script>
<!-- Start loading toc.js asap -->
<script src="../toc.js"></script>
</head>
<body>
<div id="body-container">
<!-- Work around some values being stored in localStorage wrapped in quotes -->
<script>
try {
var theme = localStorage.getItem('mdbook-theme');
var sidebar = localStorage.getItem('mdbook-sidebar');
if (theme.startsWith('"') && theme.endsWith('"')) {
localStorage.setItem('mdbook-theme', theme.slice(1, theme.length - 1));
}
if (sidebar.startsWith('"') && sidebar.endsWith('"')) {
localStorage.setItem('mdbook-sidebar', sidebar.slice(1, sidebar.length - 1));
}
} catch (e) { }
</script>
<!-- Set the theme before any content is loaded, prevents flash -->
<script>
var theme;
try { theme = localStorage.getItem('mdbook-theme'); } catch(e) { }
if (theme === null || theme === undefined) { theme = default_theme; }
const html = document.documentElement;
html.classList.remove('light')
html.classList.add(theme);
html.classList.add("js");
</script>
<input type="checkbox" id="sidebar-toggle-anchor" class="hidden">
<!-- Hide / unhide sidebar before it is displayed -->
<script>
var sidebar = null;
var sidebar_toggle = document.getElementById("sidebar-toggle-anchor");
if (document.body.clientWidth >= 1080) {
try { sidebar = localStorage.getItem('mdbook-sidebar'); } catch(e) { }
sidebar = sidebar || 'visible';
} else {
sidebar = 'hidden';
}
sidebar_toggle.checked = sidebar === 'visible';
html.classList.remove('sidebar-visible');
html.classList.add("sidebar-" + sidebar);
</script>
<nav id="sidebar" class="sidebar" aria-label="Table of contents">
<!-- populated by js -->
<mdbook-sidebar-scrollbox class="sidebar-scrollbox"></mdbook-sidebar-scrollbox>
<noscript>
<iframe class="sidebar-iframe-outer" src="../toc.html"></iframe>
</noscript>
<div id="sidebar-resize-handle" class="sidebar-resize-handle">
<div class="sidebar-resize-indicator"></div>
</div>
</nav>
<div id="page-wrapper" class="page-wrapper">
<div class="page">
<div id="menu-bar-hover-placeholder"></div>
<div id="menu-bar" class="menu-bar sticky">
<div class="left-buttons">
<label id="sidebar-toggle" class="icon-button" for="sidebar-toggle-anchor" title="Toggle Table of Contents" aria-label="Toggle Table of Contents" aria-controls="sidebar">
<i class="fa fa-bars"></i>
</label>
<button id="theme-toggle" class="icon-button" type="button" title="Change theme" aria-label="Change theme" aria-haspopup="true" aria-expanded="false" aria-controls="theme-list">
<i class="fa fa-paint-brush"></i>
</button>
<ul id="theme-list" class="theme-popup" aria-label="Themes" role="menu">
<li role="none"><button role="menuitem" class="theme" id="light">Light</button></li>
<li role="none"><button role="menuitem" class="theme" id="rust">Rust</button></li>
<li role="none"><button role="menuitem" class="theme" id="coal">Coal</button></li>
<li role="none"><button role="menuitem" class="theme" id="navy">Navy</button></li>
<li role="none"><button role="menuitem" class="theme" id="ayu">Ayu</button></li>
</ul>
<button id="search-toggle" class="icon-button" type="button" title="Search. (Shortkey: s)" aria-label="Toggle Searchbar" aria-expanded="false" aria-keyshortcuts="S" aria-controls="searchbar">
<i class="fa fa-search"></i>
</button>
</div>
<h1 class="menu-title">Storybook Language Guide</h1>
<div class="right-buttons">
<a href="../print.html" title="Print this book" aria-label="Print this book">
<i id="print-button" class="fa fa-print"></i>
</a>
<a href="https://github.com/r3t-studios/storybook" title="Git repository" aria-label="Git repository">
<i id="git-repository-button" class="fa fa-github"></i>
</a>
</div>
</div>
<div id="search-wrapper" class="hidden">
<form id="searchbar-outer" class="searchbar-outer">
<input type="search" id="searchbar" name="searchbar" placeholder="Search this book ..." aria-controls="searchresults-outer" aria-describedby="searchresults-header">
</form>
<div id="searchresults-outer" class="searchresults-outer hidden">
<div id="searchresults-header" class="searchresults-header"></div>
<ul id="searchresults">
</ul>
</div>
</div>
<!-- Apply ARIA attributes after the sidebar and the sidebar toggle button are added to the DOM -->
<script>
document.getElementById('sidebar-toggle').setAttribute('aria-expanded', sidebar === 'visible');
document.getElementById('sidebar').setAttribute('aria-hidden', sidebar !== 'visible');
Array.from(document.querySelectorAll('#sidebar a')).forEach(function(link) {
link.setAttribute('tabIndex', sidebar === 'visible' ? 0 : -1);
});
</script>
<div id="content" class="content">
<main>
<h1 id="schedules"><a class="header" href="#schedules">Schedules</a></h1>
<p>Schedules define time-based routines for characters and institutions. They specify what activities occur during specific time ranges, support seasonal variations, recurring events, and template composition. Schedules enable rich temporal behavior from simple daily routines to complex year-long patterns.</p>
<h2 id="what-is-a-schedule"><a class="header" href="#what-is-a-schedule">What is a Schedule?</a></h2>
<p>A schedule is a collection of time blocks that define activities throughout a day, week, season, or year:</p>
<ul>
<li><strong>Blocks</strong>: Time ranges (e.g., <code>06:00 - 14:00</code>) with associated activities/behaviors</li>
<li><strong>Temporal constraints</strong>: When blocks apply (season, day of week, month)</li>
<li><strong>Recurrence patterns</strong>: Repeating events (e.g., “Market Day every Earthday”)</li>
<li><strong>Composition</strong>: Schedules can extend and override other schedules</li>
</ul>
<pre><code>Schedule: BakerySchedule
├─ Block: 06:00 - 08:00 → prepare_dough
├─ Block: 08:00 - 14:00 → serve_customers
├─ Recurrence: Market Day (on Earthday) → special_market_hours
└─ Extends: BaseBusiness (inherits closing hours)
</code></pre>
<h2 id="syntax"><a class="header" href="#syntax">Syntax</a></h2>
<pre><code class="language-bnf">&lt;schedule-decl&gt; ::= "schedule" &lt;identifier&gt; &lt;extends-clause&gt;? &lt;body&gt;
&lt;extends-clause&gt; ::= "extends" &lt;identifier&gt;
&lt;body&gt; ::= "{" &lt;schedule-item&gt;* "}"
&lt;schedule-item&gt; ::= &lt;schedule-block&gt;
| &lt;recurrence-pattern&gt;
&lt;schedule-block&gt; ::= "block" &lt;block-name&gt;? "{" &lt;block-content&gt;+ "}"
&lt;block-name&gt; ::= &lt;identifier&gt;
&lt;block-content&gt; ::= &lt;time-range&gt;
| "action" ":" &lt;qualified-path&gt;
| &lt;temporal-constraint&gt;
| &lt;field&gt;
&lt;time-range&gt; ::= &lt;time&gt; "-" &lt;time&gt;
&lt;temporal-constraint&gt; ::= "on" &lt;temporal-spec&gt;
&lt;temporal-spec&gt; ::= "season" &lt;identifier&gt;
| "day" &lt;identifier&gt;
| "month" &lt;identifier&gt;
| "dates" &lt;string&gt; ".." &lt;string&gt;
&lt;recurrence-pattern&gt; ::= "recurs" &lt;identifier&gt; &lt;temporal-constraint&gt; "{" &lt;schedule-block&gt;+ "}"
</code></pre>
<h2 id="schedule-blocks"><a class="header" href="#schedule-blocks">Schedule Blocks</a></h2>
<p>A schedule block defines an activity during a specific time range.</p>
<h3 id="basic-block"><a class="header" href="#basic-block">Basic Block</a></h3>
<pre><code class="language-storybook">schedule SimpleBaker {
block {
06:00 - 14:00
action: baking::prepare_and_sell
}
}
</code></pre>
<h3 id="named-block"><a class="header" href="#named-block">Named Block</a></h3>
<p>Named blocks support the override system:</p>
<pre><code class="language-storybook">schedule BakeryBase {
block work {
09:00 - 17:00
action: baking::standard_work
}
}
schedule EarlyBaker extends BakeryBase {
block work { // Override by name
05:00 - 13:00
action: baking::early_shift
}
}
</code></pre>
<h3 id="block-content"><a class="header" href="#block-content">Block Content</a></h3>
<p>Blocks can contain:</p>
<ol>
<li><strong>Time range</strong> (required): <code>HH:MM - HH:MM</code></li>
<li><strong>Action</strong> (optional): Behavior tree reference</li>
<li><strong>Temporal constraint</strong> (optional): When the block applies</li>
<li><strong>Fields</strong> (optional): Additional metadata</li>
</ol>
<pre><code class="language-storybook">schedule CompleteBlock {
block morning_work {
06:00 - 12:00
action: work::morning_routine
on season summer
location: "Outdoor Market"
}
}
</code></pre>
<h2 id="time-ranges"><a class="header" href="#time-ranges">Time Ranges</a></h2>
<p>Time ranges use 24-hour clock format.</p>
<h3 id="syntax-1"><a class="header" href="#syntax-1">Syntax</a></h3>
<pre><code class="language-storybook">HH:MM - HH:MM
</code></pre>
<ul>
<li><strong>HH</strong>: Hour (00-23)</li>
<li><strong>MM</strong>: Minute (00-59)</li>
<li>Optional seconds: <code>HH:MM:SS - HH:MM:SS</code></li>
</ul>
<h3 id="examples"><a class="header" href="#examples">Examples</a></h3>
<pre><code class="language-storybook">schedule Examples {
block early { 05:00 - 08:00, action: prep }
block midday { 12:00 - 13:00, action: lunch }
block late { 20:00 - 23:59, action: closing }
}
</code></pre>
<h3 id="overnight-ranges"><a class="header" href="#overnight-ranges">Overnight Ranges</a></h3>
<p>Blocks can span midnight:</p>
<pre><code class="language-storybook">schedule NightShift {
block night_work {
22:00 - 06:00 // 10 PM to 6 AM next day
action: security::patrol
}
}
</code></pre>
<p>The system interprets this as 22:00-24:00 (day 1) + 00:00-06:00 (day 2).</p>
<h2 id="actions"><a class="header" href="#actions">Actions</a></h2>
<p>The <code>action</code> field links a schedule block to a behavior tree.</p>
<h3 id="syntax-2"><a class="header" href="#syntax-2">Syntax</a></h3>
<pre><code class="language-storybook">action: &lt;qualified-path&gt;
</code></pre>
<h3 id="examples-1"><a class="header" href="#examples-1">Examples</a></h3>
<pre><code class="language-storybook">schedule BakerSchedule {
block morning {
05:00 - 08:00
action: baking::prepare_dough
}
block sales {
08:00 - 14:00
action: baking::serve_customers
}
block cleanup {
14:00 - 15:00
action: baking::close_shop
}
}
</code></pre>
<h3 id="qualified-paths"><a class="header" href="#qualified-paths">Qualified Paths</a></h3>
<p>Actions can reference behaviors from other modules:</p>
<pre><code class="language-storybook">schedule GuardSchedule {
block patrol {
08:00 - 16:00
action: behaviors::guards::patrol_route
}
block training {
16:00 - 18:00
action: combat::training::drills
}
}
</code></pre>
<h2 id="temporal-constraints"><a class="header" href="#temporal-constraints">Temporal Constraints</a></h2>
<p>Temporal constraints specify when a block applies (season, day of week, month, date range).</p>
<h3 id="season-constraint"><a class="header" href="#season-constraint">Season Constraint</a></h3>
<pre><code class="language-storybook">schedule SeasonalHours {
block summer_hours {
06:00 - 20:00
action: work::long_day
on season summer
}
block winter_hours {
07:00 - 18:00
action: work::short_day
on season winter
}
}
</code></pre>
<p><strong>Season values</strong> are defined by enums in your storybook:</p>
<pre><code class="language-storybook">enum Season {
spring
summer
fall
winter
}
</code></pre>
<h3 id="day-of-week-constraint"><a class="header" href="#day-of-week-constraint">Day of Week Constraint</a></h3>
<pre><code class="language-storybook">schedule WeeklyPattern {
block weekday_work {
09:00 - 17:00
action: work::standard
on day monday // Also: tuesday, wednesday, thursday, friday, saturday, sunday
}
block weekend_rest {
10:00 - 16:00
action: leisure::relax
on day saturday
}
}
</code></pre>
<p><strong>Day values</strong> are typically defined by a <code>DayOfWeek</code> enum:</p>
<pre><code class="language-storybook">enum DayOfWeek {
monday
tuesday
wednesday
thursday
friday
saturday
sunday
}
</code></pre>
<h3 id="month-constraint"><a class="header" href="#month-constraint">Month Constraint</a></h3>
<pre><code class="language-storybook">schedule AnnualPattern {
block harvest {
06:00 - 20:00
action: farming::harvest_crops
on month october
}
block spring_planting {
07:00 - 19:00
action: farming::plant_seeds
on month april
}
}
</code></pre>
<h3 id="date-range-constraint"><a class="header" href="#date-range-constraint">Date Range Constraint</a></h3>
<pre><code class="language-storybook">schedule TouristSeason {
block high_season {
08:00 - 22:00
action: tourism::busy_service
on dates "Jun 1" .. "Sep 1"
}
}
</code></pre>
<p><strong>Note</strong>: Date format is implementation-specific. Check your runtime for supported formats.</p>
<h2 id="recurrence-patterns"><a class="header" href="#recurrence-patterns">Recurrence Patterns</a></h2>
<p>Recurrence patterns define recurring events that modify the schedule.</p>
<h3 id="syntax-3"><a class="header" href="#syntax-3">Syntax</a></h3>
<pre><code class="language-storybook">recurs EventName on &lt;temporal-constraint&gt; {
&lt;schedule-block&gt;+
}
</code></pre>
<h3 id="examples-2"><a class="header" href="#examples-2">Examples</a></h3>
<h4 id="weekly-recurring-event"><a class="header" href="#weekly-recurring-event">Weekly Recurring Event</a></h4>
<pre><code class="language-storybook">schedule MarketSchedule {
// Regular daily hours
block work {
08:00 - 17:00
action: shop::regular_sales
}
// Market day every saturday
recurs MarketDay on day saturday {
block setup {
06:00 - 08:00
action: market::setup_stall
}
block busy_market {
08:00 - 18:00
action: market::busy_sales
}
block teardown {
18:00 - 20:00
action: market::pack_up
}
}
}
</code></pre>
<h4 id="monthly-recurring-event"><a class="header" href="#monthly-recurring-event">Monthly Recurring Event</a></h4>
<pre><code class="language-storybook">schedule TownSchedule {
recurs CouncilMeeting on month first_monday {
block meeting {
18:00 - 21:00
action: governance::council_session
}
}
}
</code></pre>
<h4 id="seasonal-recurring-event"><a class="header" href="#seasonal-recurring-event">Seasonal Recurring Event</a></h4>
<pre><code class="language-storybook">schedule FarmSchedule {
recurs SpringPlanting on season spring {
block planting {
06:00 - 18:00
action: farming::plant_all_fields
}
}
recurs FallHarvest on season fall {
block harvest {
06:00 - 20:00
action: farming::harvest_all_crops
}
}
}
</code></pre>
<h2 id="schedule-composition"><a class="header" href="#schedule-composition">Schedule Composition</a></h2>
<p>Schedules can extend other schedules using <code>extends</code>, inheriting and overriding blocks.</p>
<h3 id="extends-clause"><a class="header" href="#extends-clause">Extends Clause</a></h3>
<pre><code class="language-storybook">schedule Base {
block work {
09:00 - 17:00
action: work::standard
}
}
schedule Extended extends Base {
block work { // Override inherited block
05:00 - 13:00
action: work::early_shift
}
}
</code></pre>
<h3 id="override-semantics"><a class="header" href="#override-semantics">Override Semantics</a></h3>
<p>When extending a schedule:</p>
<ol>
<li><strong>Named blocks</strong> with matching names override base blocks</li>
<li><strong>Unnamed blocks</strong> are appended</li>
<li><strong>Time range</strong> can change</li>
<li><strong>Action</strong> can change</li>
<li><strong>Constraints</strong> can be added/changed</li>
</ol>
<h3 id="multiple-levels"><a class="header" href="#multiple-levels">Multiple Levels</a></h3>
<pre><code class="language-storybook">schedule BaseWork {
block work {
09:00 - 17:00
action: work::standard
}
}
schedule BakerWork extends BaseWork {
block work {
05:00 - 13:00 // Earlier hours
action: baking::work
}
}
schedule MasterBaker extends BakerWork {
block work {
03:00 - 11:00 // Even earlier!
action: baking::master_work
}
block teaching {
14:00 - 16:00
action: baking::teach_apprentice
}
}
</code></pre>
<p><strong>Resolution:</strong></p>
<ul>
<li><code>work</code> block: 03:00-11:00 with <code>baking::master_work</code> (MasterBaker overrides BakerWork overrides BaseWork)</li>
<li><code>teaching</code> block: 14:00-16:00 with <code>baking::teach_apprentice</code> (from MasterBaker)</li>
</ul>
<h2 id="complete-examples"><a class="header" href="#complete-examples">Complete Examples</a></h2>
<h3 id="simple-daily-schedule"><a class="header" href="#simple-daily-schedule">Simple Daily Schedule</a></h3>
<pre><code class="language-storybook">schedule SimpleFarmer {
block sleep {
22:00 - 05:00
action: rest::sleep
}
block morning_chores {
05:00 - 08:00
action: farming::feed_animals
}
block fieldwork {
08:00 - 17:00
action: farming::tend_crops
}
block evening_chores {
17:00 - 19:00
action: farming::evening_tasks
}
block leisure {
19:00 - 22:00
action: social::family_time
}
}
</code></pre>
<h3 id="seasonal-variation"><a class="header" href="#seasonal-variation">Seasonal Variation</a></h3>
<pre><code class="language-storybook">schedule SeasonalBaker {
block summer_work {
06:00 - 20:00
action: baking::long_shift
on season summer
}
block winter_work {
07:00 - 18:00
action: baking::short_shift
on season winter
}
block spring_work {
06:30 - 19:00
action: baking::medium_shift
on season spring
}
block fall_work {
06:30 - 19:00
action: baking::medium_shift
on season fall
}
}
</code></pre>
<h3 id="weekly-pattern-with-recurrence"><a class="header" href="#weekly-pattern-with-recurrence">Weekly Pattern with Recurrence</a></h3>
<pre><code class="language-storybook">schedule InnkeeperSchedule {
// Weekday routine
block weekday_service {
08:00 - 22:00
action: inn::regular_service
on day monday // Repeat for each weekday
}
block weekday_service {
08:00 - 22:00
action: inn::regular_service
on day tuesday
}
// ... (wednesday, thursday, friday)
// Weekend hours
block weekend_service {
10:00 - 24:00
action: inn::busy_service
on day saturday
}
block weekend_service {
10:00 - 24:00
action: inn::busy_service
on day sunday
}
// Weekly market day
recurs MarketDay on day wednesday {
block market_prep {
06:00 - 08:00
action: inn::prepare_market_goods
}
block market_rush {
08:00 - 16:00
action: inn::market_day_chaos
}
}
}
</code></pre>
<h3 id="extended-schedule"><a class="header" href="#extended-schedule">Extended Schedule</a></h3>
<pre><code class="language-storybook">schedule BaseShopkeeper {
block open {
09:00 - 17:00
action: shop::standard_hours
}
}
schedule BlacksmithSchedule extends BaseShopkeeper {
block open { // Override
06:00 - 18:00 // Longer hours
action: smithing::work
}
block forge_heat { // New block
05:00 - 06:00
action: smithing::heat_forge
}
}
</code></pre>
<h3 id="complex-year-round-schedule"><a class="header" href="#complex-year-round-schedule">Complex Year-Round Schedule</a></h3>
<pre><code class="language-storybook">schedule MasterBakerYear {
// Daily base pattern
block prep {
04:00 - 06:00
action: baking::prepare
}
block baking {
06:00 - 10:00
action: baking::bake
}
block sales {
10:00 - 16:00
action: baking::serve
}
block cleanup {
16:00 - 17:00
action: baking::clean
}
// Seasonal variations
block summer_hours {
10:00 - 20:00 // Extended sales
action: baking::busy_summer
on season summer
}
// Weekly market
recurs MarketDay on day saturday {
block market_prep {
02:00 - 04:00
action: baking::market_prep
}
block market_sales {
08:00 - 18:00
action: baking::market_rush
}
}
// Annual events
recurs HarvestFestival on dates "Sep 20" .. "Sep 25" {
block festival {
06:00 - 23:00
action: baking::festival_mode
}
}
}
</code></pre>
<h2 id="integration-with-characters"><a class="header" href="#integration-with-characters">Integration with Characters</a></h2>
<p>Characters link to schedules using the <code>uses schedule</code> clause:</p>
<pre><code class="language-storybook">character Martha {
uses schedule: BakerySchedule
}
</code></pre>
<p><strong>Multiple schedules:</strong></p>
<pre><code class="language-storybook">character Innkeeper {
uses schedules: [WeekdaySchedule, WeekendSchedule]
}
</code></pre>
<p>See <a href="./10-characters.html#schedule-integration">Characters</a> for complete integration syntax.</p>
<h2 id="execution-semantics"><a class="header" href="#execution-semantics">Execution Semantics</a></h2>
<h3 id="time-based-selection"><a class="header" href="#time-based-selection">Time-Based Selection</a></h3>
<p>At any given time, the runtime:</p>
<ol>
<li><strong>Evaluates temporal constraints</strong>: Which blocks apply right now?</li>
<li><strong>Selects matching block</strong>: First block whose time range and constraint match</li>
<li><strong>Executes action</strong>: Runs the associated behavior tree</li>
<li><strong>Repeats next tick</strong></li>
</ol>
<h3 id="priority-order"><a class="header" href="#priority-order">Priority Order</a></h3>
<p>When multiple blocks could apply:</p>
<ol>
<li><strong>Recurrences</strong> take priority over regular blocks</li>
<li><strong>Constraints</strong> filter blocks (season, day, month)</li>
<li><strong>Time ranges</strong> must overlap current time</li>
<li><strong>First match</strong> wins (declaration order)</li>
</ol>
<h3 id="block-overlap"><a class="header" href="#block-overlap">Block Overlap</a></h3>
<p>Blocks can overlap in time. The runtime selects the first matching block.</p>
<p><strong>Example:</strong></p>
<pre><code class="language-storybook">schedule Overlapping {
block general {
08:00 - 17:00
action: work::general
}
block specialized {
10:00 - 12:00 // Overlaps with general
action: work::specialized
on day wednesday
}
}
</code></pre>
<p>On Wednesday at 11:00, <code>specialized</code> block is selected (more specific constraint).</p>
<h2 id="validation-rules"><a class="header" href="#validation-rules">Validation Rules</a></h2>
<ol>
<li><strong>Time format</strong>: Times must be valid HH:MM or HH:MM:SS (24-hour)</li>
<li><strong>Time order</strong>: Start time must be before end time (unless spanning midnight)</li>
<li><strong>Extends exists</strong>: If using <code>extends</code>, base schedule must be defined</li>
<li><strong>No circular extends</strong>: Cannot form circular dependency chains</li>
<li><strong>Named blocks unique</strong>: Block names must be unique within a schedule</li>
<li><strong>Action exists</strong>: Action references must resolve to defined behaviors</li>
<li><strong>Constraint values</strong>: Temporal constraint values must reference defined enums</li>
<li><strong>Recurrence names unique</strong>: Recurrence names must be unique within a schedule</li>
</ol>
<h2 id="best-practices"><a class="header" href="#best-practices">Best Practices</a></h2>
<h3 id="1-use-named-blocks-for-overrides"><a class="header" href="#1-use-named-blocks-for-overrides">1. Use Named Blocks for Overrides</a></h3>
<p><strong>Avoid:</strong></p>
<pre><code class="language-storybook">schedule Extended extends Base {
block { 05:00 - 13:00, action: work } // Appends instead of overriding
}
</code></pre>
<p><strong>Prefer:</strong></p>
<pre><code class="language-storybook">schedule Extended extends Base {
block work { 05:00 - 13:00, action: early_work } // Overrides by name
}
</code></pre>
<h3 id="2-group-related-blocks"><a class="header" href="#2-group-related-blocks">2. Group Related Blocks</a></h3>
<pre><code class="language-storybook">schedule DailyRoutine {
// Sleep blocks
block night_sleep { 22:00 - 05:00, action: sleep }
// Morning blocks
block wake_up { 05:00 - 06:00, action: morning_routine }
block breakfast { 06:00 - 07:00, action: eat_breakfast }
// Work blocks
block commute { 07:00 - 08:00, action: travel_to_work }
block work { 08:00 - 17:00, action: work }
}
</code></pre>
<h3 id="3-use-recurrences-for-special-events"><a class="header" href="#3-use-recurrences-for-special-events">3. Use Recurrences for Special Events</a></h3>
<p><strong>Avoid:</strong> Duplicating blocks manually</p>
<p><strong>Prefer:</strong></p>
<pre><code class="language-storybook">recurs MarketDay on day saturday {
block market { 08:00 - 16:00, action: market_work }
}
</code></pre>
<h3 id="4-extend-for-variations"><a class="header" href="#4-extend-for-variations">4. Extend for Variations</a></h3>
<p><strong>Avoid:</strong> Duplicating entire schedules</p>
<p><strong>Prefer:</strong></p>
<pre><code class="language-storybook">schedule WorkerBase { ... }
schedule EarlyWorker extends WorkerBase { ... }
schedule NightWorker extends WorkerBase { ... }
</code></pre>
<h3 id="5-use-temporal-constraints-for-clarity"><a class="header" href="#5-use-temporal-constraints-for-clarity">5. Use Temporal Constraints for Clarity</a></h3>
<pre><code class="language-storybook">block summer_hours {
06:00 - 20:00
action: long_shift
on season summer // Explicit and readable
}
</code></pre>
<h2 id="cross-references"><a class="header" href="#cross-references">Cross-References</a></h2>
<ul>
<li><a href="./10-characters.html">Characters</a> - Linking schedules to characters</li>
<li><a href="./11-behavior-trees.html">Behavior Trees</a> - Actions reference behavior trees</li>
<li><a href="./18-value-types.html">Value Types</a> - Time and duration literals</li>
<li><a href="../reference/16-other-declarations.html#enums">Enums</a> - Defining seasons, days, months</li>
</ul>
<h2 id="related-concepts"><a class="header" href="#related-concepts">Related Concepts</a></h2>
<ul>
<li><strong>Time-based AI</strong>: Schedules drive time-dependent behavior</li>
<li><strong>Template inheritance</strong>: <code>extends</code> enables schedule reuse</li>
<li><strong>Temporal constraints</strong>: Filter blocks by season, day, month</li>
<li><strong>Recurrence patterns</strong>: Define repeating events</li>
<li><strong>Composition</strong>: Build complex schedules from simple parts</li>
</ul>
</main>
<nav class="nav-wrapper" aria-label="Page navigation">
<!-- Mobile navigation buttons -->
<a rel="prev" href="../reference/13-life-arcs.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
<i class="fa fa-angle-left"></i>
</a>
<a rel="next prefetch" href="../reference/15-relationships.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<i class="fa fa-angle-right"></i>
</a>
<div style="clear: both"></div>
</nav>
</div>
</div>
<nav class="nav-wide-wrapper" aria-label="Page navigation">
<a rel="prev" href="../reference/13-life-arcs.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
<i class="fa fa-angle-left"></i>
</a>
<a rel="next prefetch" href="../reference/15-relationships.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<i class="fa fa-angle-right"></i>
</a>
</nav>
</div>
<!-- Livereload script (if served using the cli tool) -->
<script>
const wsProtocol = location.protocol === 'https:' ? 'wss:' : 'ws:';
const wsAddress = wsProtocol + "//" + location.host + "/" + "__livereload";
const socket = new WebSocket(wsAddress);
socket.onmessage = function (event) {
if (event.data === "reload") {
socket.close();
location.reload();
}
};
window.onbeforeunload = function() {
socket.close();
}
</script>
<script>
window.playground_copyable = true;
</script>
<script src="../elasticlunr.min.js"></script>
<script src="../mark.min.js"></script>
<script src="../searcher.js"></script>
<script src="../clipboard.min.js"></script>
<script src="../highlight.js"></script>
<script src="../book.js"></script>
<!-- Custom JS scripts -->
</div>
</body>
</html>