1123 lines
33 KiB
Svelte
1123 lines
33 KiB
Svelte
<script lang="ts">
|
||
import PseudoScript from '$lib/components/PseudoScript.svelte';
|
||
import { TRIGGER_ACTION_REGISTRY } from '$lib/calculations/conditional';
|
||
import {
|
||
MECHANIC_COMBAT_REFERENCE_REGISTRY,
|
||
MECHANIC_EVENT_REGISTRY
|
||
} from '$lib/calculations/mechanic';
|
||
|
||
type AttributeVariable = {
|
||
id: string;
|
||
name: string;
|
||
description?: string | null;
|
||
unit?: string | null;
|
||
type?: string | null;
|
||
category?: string | null;
|
||
calculation_type?: string | null;
|
||
cap_value?: number | null;
|
||
gear_min?: number | null;
|
||
gear_max?: number | null;
|
||
weapon_min?: number | null;
|
||
weapon_max?: number | null;
|
||
skill_chip_min?: number | null;
|
||
skill_chip_max?: number | null;
|
||
};
|
||
|
||
let { data } = $props();
|
||
let variableSearch = $state('');
|
||
const normalizedVariableSearch = $derived(variableSearch.trim().toLocaleLowerCase());
|
||
const matchingAttributes = $derived((data.attributes as AttributeVariable[]).filter((attribute) => {
|
||
if (!normalizedVariableSearch) return true;
|
||
return [
|
||
attribute.name,
|
||
attribute.description,
|
||
attribute.unit,
|
||
attribute.type,
|
||
attribute.category,
|
||
attribute.calculation_type
|
||
].some((value) => String(value ?? '').toLocaleLowerCase().includes(normalizedVariableSearch));
|
||
}));
|
||
|
||
const sections = [
|
||
{ id: 'reading-scripts', label: 'READING SCRIPTS' },
|
||
{ id: 'events', label: 'EVENTS' },
|
||
{ id: 'action-families', label: 'ACTION FAMILIES' },
|
||
{ id: 'values', label: 'VALUES + CONDITIONS' },
|
||
{ id: 'attribute-variables', label: 'ATTRIBUTE VARIABLES' },
|
||
{ id: 'reducers', label: 'REDUCERS' },
|
||
{ id: 'state', label: 'STATE' },
|
||
{ id: 'outcomes', label: 'OUTCOMES' },
|
||
{ id: 'scenarios', label: 'SCENARIOS' },
|
||
{ id: 'examples', label: 'WORKED EXAMPLES' }
|
||
];
|
||
|
||
const statements = [
|
||
{ token: 'MECHANIC', meaning: 'Names one complete mechanic program.' },
|
||
{ token: 'STATE', meaning: 'Declares an Agent- or target-scoped value that branches can share.' },
|
||
{ token: 'WHEN', meaning: 'Selects the normalized combat event that starts a branch.' },
|
||
{ token: 'IF', meaning: 'Tests event, Agent, target, team, encounter, or state values.' },
|
||
{ token: 'COUNT / EVERY / AFTER / DERIVE', meaning: 'Reduces matching events or scenario data into an activation value.' },
|
||
{ token: 'COOLDOWN', meaning: 'Blocks that branch from activating again for the configured duration.' },
|
||
{ token: 'WEIGHT', meaning: 'Applies a scenario-dependent contribution to a branch.' },
|
||
{ token: 'ADD / SET / CONSUME / CLEAR / TRANSFER', meaning: 'Changes a named state pool.' },
|
||
{ token: 'APPLY / RELOAD', meaning: 'Emits an Attribute modifier, damage, restoration, resource cost, weapon action, or marker.' }
|
||
];
|
||
|
||
const valueSources = [
|
||
{ syntax: 'EVENT.<path>', use: 'A value carried by the current event, such as target distance or critical state.' },
|
||
{ syntax: 'SCENARIO.<key>', use: 'A builder assumption supplied by Maximum Potential or Custom Scenario mode.' },
|
||
{ syntax: 'COMBAT.currentHealth', use: MECHANIC_COMBAT_REFERENCE_REGISTRY.currentHealth.description },
|
||
{ syntax: 'COMBAT.currentHealthPercent', use: `${MECHANIC_COMBAT_REFERENCE_REGISTRY.currentHealthPercent.description} “Below” conditions use a strict < comparison.` },
|
||
{ syntax: 'PRE-EVENT COMBAT.<path>', use: 'Combat state captured before the current branch changes it.' },
|
||
{ syntax: 'ATTRIBUTE[<id>]', use: 'The authoritative loadout total for a stable Attribute ID. Percentage Attributes use their displayed percentage value.' },
|
||
{ syntax: 'EQUIPMENT.<path>', use: 'A value from the equipped item, including OS Protocol talent upgrades.' },
|
||
{ syntax: 'REDUCER VALUE', use: 'The number produced by the branch reducer.' },
|
||
{ syntax: '<pool> FOR AGENT / EVENT TARGET', use: 'The current value in an Agent- or target-scoped state pool.' }
|
||
];
|
||
|
||
const predicateOperators = [
|
||
{ syntax: '== / !=', use: 'Equality and inequality.' },
|
||
{ syntax: '> / >= / < / <=', use: 'Numeric threshold comparisons.' },
|
||
{ syntax: 'AND / OR / NOT', use: 'Combines or negates conditions.' },
|
||
{ syntax: 'EXISTS', use: 'Requires an event, scenario, combat, equipment, or state value.' }
|
||
];
|
||
|
||
const reducers = [
|
||
{ syntax: 'COUNT n MATCHES', use: 'Activates after a configured number of matching events.' },
|
||
{ syntax: 'EVERY n MATCHES', use: 'Activates on every nth match, such as every ten shots.' },
|
||
{ syntax: 'COUNT n MATCHES WITHIN xs', use: 'Counts events inside a sliding time window.' },
|
||
{ syntax: 'AFTER CONDITION HOLDS FOR xs', use: 'Activates after a condition remains true for a duration.' },
|
||
{ syntax: 'EVERY <expression>s WHILE TRUE', use: 'Runs on an explicit periodic cadence while its condition remains true.' },
|
||
{ syntax: 'DERIVE <expression>', use: 'Calculates a scalar from current event, scenario, combat, equipment, or state values.' }
|
||
];
|
||
|
||
const mutations = [
|
||
{ syntax: 'ADD value TO pool FOR EVENT TARGET', use: 'Increases one enemy’s target-scoped state, respecting the pool maximum.' },
|
||
{ syntax: 'SET value AS pool', use: 'Replaces the current pool value.' },
|
||
{ syntax: 'CONSUME value FROM pool', use: 'Spends available state without falling below the pool minimum.' },
|
||
{ syntax: 'CLEAR pool', use: 'Resets the selected state pool.' },
|
||
{ syntax: 'TRANSFER value pool FROM target TO target', use: 'Moves target-scoped state between entities.' }
|
||
];
|
||
|
||
const phases = [
|
||
{ syntax: 'ON_EVENT', use: 'Applies against combat state as the event arrives.' },
|
||
{ syntax: 'AFTER_EVENT', use: 'Applies after branch mutations and resource costs.' },
|
||
{ syntax: 'ON_ENTER', use: 'Applies when tracked state enters an active range.' },
|
||
{ syntax: 'ON_EXIT', use: 'Applies when tracked state leaves an active range, using its final pre-exit value for stack thresholds and scaling.' },
|
||
{ syntax: 'WHILE_ACTIVE', use: 'Remains active while the referenced state satisfies its stack range.' }
|
||
];
|
||
|
||
const outcomeKinds = [
|
||
{ token: 'ATTRIBUTE MODIFIER', detail: 'Adds or multiplies a referenced Attribute.' },
|
||
{ token: 'DIRECT DAMAGE', detail: 'Deals damage from a flat value or a configured percentage basis.' },
|
||
{ token: 'RESTORATION', detail: 'Restores Health from a flat value or Health basis.' },
|
||
{ token: 'RESOURCE COST', detail: 'Consumes Health or another modeled resource in branch order.' },
|
||
{ token: 'WEAPON RELOAD', detail: 'Reloads the inactive weapon after the configured delay. A new activation refreshes a pending reload timer.' },
|
||
{ token: 'MARKER', detail: 'Emits a typed state marker without changing a numeric Attribute.' }
|
||
];
|
||
|
||
const bases = [
|
||
'FLAT',
|
||
'MAX HEALTH PERCENT',
|
||
'CURRENT HEALTH PERCENT',
|
||
'WEAPON BASE PERCENT'
|
||
];
|
||
|
||
const valueRange = (minimum: number | null | undefined, maximum: number | null | undefined) => {
|
||
if (minimum === null || minimum === undefined || maximum === null || maximum === undefined) return null;
|
||
return `${minimum}–${maximum}`;
|
||
};
|
||
|
||
const sourceRanges = (attribute: AttributeVariable) => [
|
||
{ label: 'GEAR', value: valueRange(attribute.gear_min, attribute.gear_max) },
|
||
{ label: 'WEAPON', value: valueRange(attribute.weapon_min, attribute.weapon_max) },
|
||
{ label: 'SKILL CHIP', value: valueRange(attribute.skill_chip_min, attribute.skill_chip_max) }
|
||
].filter((source) => source.value);
|
||
|
||
const superiorFirepower = [
|
||
'MECHANIC SUPERIOR FIREPOWER',
|
||
'STATE relentless [AGENT] 0..10; EXPIRES 10s AFTER WRITE',
|
||
'',
|
||
'WHEN WEAPON HIT // Build Relentless',
|
||
'COUNT 9 MATCHES WITHIN 3s PER EVENT.targetId',
|
||
'ADD 1 TO relentless FOR AGENT',
|
||
'WHILE_ACTIVE: APPLY 3% FLAT weapon_damage PER STACK // Weapon Damage',
|
||
'WHILE_ACTIVE: APPLY 1% FLAT critical_damage PER STACK // Critical Damage'
|
||
];
|
||
|
||
const happySurvival = [
|
||
'MECHANIC HAPPY SURVIVAL',
|
||
'',
|
||
'WHEN PROXIMITY SNAPSHOT // Count nearby enemies',
|
||
'DERIVE MIN(EVENT.enemiesWithin10m, 5)',
|
||
'SET REDUCER VALUE AS nearby_enemies FOR AGENT',
|
||
'',
|
||
'WHEN SIMULATION TICK // Restore Health on an explicit cadence',
|
||
'EVERY SCENARIO.restorationIntervalSeconds WHILE TRUE',
|
||
'AFTER_EVENT: APPLY (0.5 * (1 + (EQUIPMENT.protocolTalentUpgrades / 5))) MAX_HEALTH_PERCENT PER STACK // Restore Health',
|
||
'',
|
||
'WHEN SHOT FIRED // Pay Health, then calculate damage',
|
||
'ON_EVENT: APPLY 2 CURRENT_HEALTH_PERCENT // Health cost',
|
||
'AFTER_EVENT: APPLY (0.6 * (1 + (EQUIPMENT.protocolTalentUpgrades / 5))) CURRENT_HEALTH_PERCENT USING CURRENT HEALTH // Additional damage'
|
||
];
|
||
|
||
const preciseTrauma = [
|
||
'MECHANIC PRECISE TRAUMA',
|
||
'STATE trauma [TARGET] 0..10; EXPIRES 1s AFTER WRITE',
|
||
'',
|
||
'WHEN WEAPON HIT // Body shot',
|
||
'IF EVENT.targetId EXISTS AND EVENT.values.headshot == false',
|
||
'ADD 1 TO trauma FOR EVENT TARGET',
|
||
'',
|
||
'WHEN WEAPON HIT // Headshot',
|
||
'IF EVENT.targetId EXISTS AND EVENT.values.headshot == true',
|
||
'ADD 2 TO trauma FOR EVENT TARGET',
|
||
'',
|
||
'WHEN SIMULATION TICK // Shared refreshed expiry',
|
||
'ON_EXIT: APPLY (1 * ATTRIBUTE[skill-damage-id]) FLAT DIRECT_DAMAGE PER STACK TO EVENT TARGET'
|
||
];
|
||
</script>
|
||
|
||
<svelte:head>
|
||
<title>Mechanic script reference — SHD.build ISAC</title>
|
||
<meta
|
||
name="description"
|
||
content="Reference for the generated mechanic language used by SHD.build combat calculations."
|
||
/>
|
||
</svelte:head>
|
||
|
||
<div class="reference-toolbar">
|
||
<div>
|
||
<p class="eyebrow">CALCULATION MODEL REFERENCE</p>
|
||
<h2>MECHANIC SCRIPT LANGUAGE</h2>
|
||
<p>Read the generated scripts used to explain combat mechanics. ISAC stores and evaluates typed data; displayed scripts are read-only.</p>
|
||
</div>
|
||
<div class="reference-actions">
|
||
<a class="secondary" href="/isac/talents">TALENT MECHANICS</a>
|
||
<a class="secondary" href="/isac/calculations">COMBAT CALCULATIONS</a>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="reference-layout">
|
||
<nav class="reference-index" aria-label="Mechanic reference sections">
|
||
<strong>REFERENCE INDEX</strong>
|
||
{#each sections as section, index}
|
||
<a href={`#${section.id}`}><span>{String(index + 1).padStart(2, '0')}</span>{section.label}</a>
|
||
{/each}
|
||
</nav>
|
||
|
||
<main class="reference-content">
|
||
<section id="reading-scripts" class="reference-section lead-section">
|
||
<header>
|
||
<div><span>01</span><h3>READING GENERATED SCRIPTS</h3></div>
|
||
<b>READ ONLY</b>
|
||
</header>
|
||
<p>Editors create structured events, conditions, state changes, and outcomes. ISAC transcribes those records into a compact script so you can inspect calculation order without reading JSON or application code.</p>
|
||
<div class="reference-matrix statement-matrix">
|
||
{#each statements as statement}
|
||
<div><code>{statement.token}</code><span>{statement.meaning}</span></div>
|
||
{/each}
|
||
</div>
|
||
</section>
|
||
|
||
<section id="events" class="reference-section">
|
||
<header>
|
||
<div><span>02</span><h3>NORMALIZED COMBAT EVENTS</h3></div>
|
||
<b>{Object.keys(MECHANIC_EVENT_REGISTRY).length} EVENTS</b>
|
||
</header>
|
||
<p>Each branch begins with one event. Event values carry details such as target identity, distance, critical state, movement state, and nearby entity counts.</p>
|
||
<div class="event-registry">
|
||
{#each Object.values(MECHANIC_EVENT_REGISTRY) as event}
|
||
<article>
|
||
<div><strong>{event.label}</strong><code>{event.key}</code></div>
|
||
<p>{event.description}</p>
|
||
{#if event.fields?.length}
|
||
<ul aria-label={`${event.label} typed fields`}>
|
||
{#each event.fields as field}
|
||
<li><code>{field.path}</code><span>{field.label} · {field.type.toUpperCase()}</span></li>
|
||
{/each}
|
||
</ul>
|
||
{/if}
|
||
</article>
|
||
{/each}
|
||
</div>
|
||
</section>
|
||
|
||
<section id="action-families" class="reference-section">
|
||
<header>
|
||
<div><span>03</span><h3>ACTION FAMILY RECIPES</h3></div>
|
||
<b>{Object.keys(TRIGGER_ACTION_REGISTRY).length} RECIPES</b>
|
||
</header>
|
||
<p>Action Families seed common mechanic shapes. They map familiar game language to normalized events and validated parameters, then copy an editable branch into the source item.</p>
|
||
<div class="action-registry">
|
||
{#each Object.values(TRIGGER_ACTION_REGISTRY) as action}
|
||
<div><strong>{action.label}</strong><code>{action.key}</code></div>
|
||
{/each}
|
||
</div>
|
||
</section>
|
||
|
||
<section id="values" class="reference-section">
|
||
<header><div><span>04</span><h3>VALUES, EXPRESSIONS, AND CONDITIONS</h3></div></header>
|
||
<p>Expressions combine numbers with references through addition, subtraction, multiplication, division, minimum, maximum, and clamp operations.</p>
|
||
<div class="split-reference">
|
||
<div>
|
||
<h4>VALUE SOURCES</h4>
|
||
<div class="reference-matrix">
|
||
{#each valueSources as item}<div><code>{item.syntax}</code><span>{item.use}</span></div>{/each}
|
||
</div>
|
||
</div>
|
||
<div>
|
||
<h4>CONDITION OPERATORS</h4>
|
||
<div class="reference-matrix">
|
||
{#each predicateOperators as item}<div><code>{item.syntax}</code><span>{item.use}</span></div>{/each}
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
<section id="attribute-variables" class="reference-section attribute-variable-section">
|
||
<header>
|
||
<div><span>05</span><h3>ISAC ATTRIBUTE VARIABLES</h3></div>
|
||
<b>{data.attributeSummary.documented}/{data.attributeSummary.total} DOCUMENTED</b>
|
||
</header>
|
||
<p>Attribute outcomes reference the current ISAC Attribute registry. Names and descriptions below update with that data, so improving an Attribute description improves this reference.</p>
|
||
<div class="variable-controls">
|
||
<label>
|
||
<span>SEARCH VARIABLES</span>
|
||
<input
|
||
type="search"
|
||
bind:value={variableSearch}
|
||
placeholder="Search name, description, type, or category…"
|
||
autocomplete="off"
|
||
/>
|
||
</label>
|
||
<strong>{matchingAttributes.length} OF {data.attributeSummary.total} SHOWN</strong>
|
||
</div>
|
||
<div class="attribute-variable-list" aria-live="polite">
|
||
{#each matchingAttributes as attribute (attribute.id)}
|
||
<article>
|
||
<header>
|
||
<div>
|
||
<strong>{attribute.name}{attribute.unit ? ` (${attribute.unit})` : ''}</strong>
|
||
<code>{attribute.id}</code>
|
||
</div>
|
||
<div class="variable-classification">
|
||
<span>{String(attribute.category ?? 'UNCATEGORIZED').toLocaleUpperCase()}</span>
|
||
<span>{String(attribute.type ?? 'UNCLASSIFIED').toLocaleUpperCase()}</span>
|
||
<span>{String(attribute.calculation_type ?? 'UNSPECIFIED').toLocaleUpperCase()}</span>
|
||
</div>
|
||
</header>
|
||
<p class:missing-description={!String(attribute.description ?? '').trim()}>
|
||
{String(attribute.description ?? '').trim() || 'DESCRIPTION NEEDED · Add calculation guidance in the ISAC Attribute editor.'}
|
||
</p>
|
||
{#if sourceRanges(attribute).length || attribute.cap_value !== null}
|
||
<footer>
|
||
{#each sourceRanges(attribute) as source}
|
||
<span><b>{source.label}</b>{source.value}{attribute.unit ?? ''}</span>
|
||
{/each}
|
||
{#if attribute.cap_value !== null}
|
||
<span><b>CAP</b>{attribute.cap_value}{attribute.unit ?? ''}</span>
|
||
{/if}
|
||
</footer>
|
||
{/if}
|
||
</article>
|
||
{:else}
|
||
<div class="variable-empty">
|
||
<strong>NO ATTRIBUTE VARIABLES MATCH</strong>
|
||
<span>Change the search terms to inspect another Attribute.</span>
|
||
</div>
|
||
{/each}
|
||
</div>
|
||
</section>
|
||
|
||
<section id="reducers" class="reference-section">
|
||
<header><div><span>06</span><h3>EVENT REDUCERS</h3></div></header>
|
||
<p>Reducers turn matching event history or current scenario data into an activation. A periodic reducer must name its interval; ISAC excludes a branch when its cadence is unknown.</p>
|
||
<div class="reference-matrix">
|
||
{#each reducers as item}<div><code>{item.syntax}</code><span>{item.use}</span></div>{/each}
|
||
</div>
|
||
</section>
|
||
|
||
<section id="state" class="reference-section">
|
||
<header><div><span>07</span><h3>TRACKED STATE</h3></div></header>
|
||
<p>State pools track stacks, counts, scalars, marks, or resources. Agent pools belong to the build; target pools keep separate values for each enemy.</p>
|
||
<div class="reference-matrix">
|
||
{#each mutations as item}<div><code>{item.syntax}</code><span>{item.use}</span></div>{/each}
|
||
</div>
|
||
<aside class="contract">
|
||
<strong>EXPIRY CONTRACT</strong>
|
||
<span>A pool can expire after its last write. Each write refreshes its timer. Target pools maintain independent values and timers for each bound enemy.</span>
|
||
</aside>
|
||
</section>
|
||
|
||
<section id="outcomes" class="reference-section">
|
||
<header><div><span>08</span><h3>OUTCOMES AND ORDER</h3></div></header>
|
||
<p>Outcome phases control calculation order. This distinction matters when one event changes Health before another outcome reads current Health.</p>
|
||
<div class="outcome-grid">
|
||
<div>
|
||
<h4>PHASES</h4>
|
||
<div class="reference-matrix">
|
||
{#each phases as item}<div><code>{item.syntax}</code><span>{item.use}</span></div>{/each}
|
||
</div>
|
||
</div>
|
||
<div>
|
||
<h4>RESULT TYPES</h4>
|
||
<div class="result-types">
|
||
{#each outcomeKinds as item}<div><strong>{item.token}</strong><span>{item.detail}</span></div>{/each}
|
||
</div>
|
||
<h4>VALUE BASES</h4>
|
||
<div class="basis-list">{#each bases as basis}<code>{basis}</code>{/each}</div>
|
||
</div>
|
||
</div>
|
||
<aside class="contract">
|
||
<strong>CONTINUOUS RESTORATION</strong>
|
||
<span><code>DELIVER TOTAL CONTINUOUSLY OVER xs</code> distributes one resolved restoration total at a constant rate. Overlapping activations add independently, and excess restoration is lost when it reaches the resource maximum.</span>
|
||
</aside>
|
||
<aside class="contract">
|
||
<strong>LIVE ATTRIBUTE VALUES</strong>
|
||
<span><code>ATTRIBUTE[<id>]</code> reads the current loadout value by stable Attribute ID. For a displayed percentage, divide by 100 before applying a flat coefficient: <code>240 * (ATTRIBUTE[<id>] / 100)</code>.</span>
|
||
</aside>
|
||
</section>
|
||
|
||
<section id="scenarios" class="reference-section">
|
||
<header><div><span>09</span><h3>PLANNED BUILDER SCENARIOS</h3></div></header>
|
||
<div class="scenario-grid">
|
||
<article>
|
||
<strong>MAXIMUM POTENTIAL</strong>
|
||
<p>The planned mode uses each mechanic’s configured best-case values to calculate a ceiling. It applies peak stacks and maximum supported target or ally counts.</p>
|
||
</article>
|
||
<article>
|
||
<strong>CUSTOM SCENARIO</strong>
|
||
<p>The planned mode uses player-selected toggles, counts, percentages, and cadence inputs to model a specific combat situation.</p>
|
||
</article>
|
||
</div>
|
||
<aside class="contract">
|
||
<strong>REQUIRES ASSUMPTIONS</strong>
|
||
<span>The runtime withholds a branch when the mechanic needs an undefined scenario value. An author or future scenario control must supply it before the runtime includes that contribution.</span>
|
||
</aside>
|
||
<aside class="contract protocol-contract">
|
||
<strong>OS PROTOCOL TALENT UPGRADES</strong>
|
||
<span><code>EQUIPMENT.protocolTalentUpgrades</code> supplies a value from 0 through 5. Each outcome decides whether that value scales its effect. Rank 5 can reach double the base value while costs and other fixed values remain unchanged.</span>
|
||
</aside>
|
||
</section>
|
||
|
||
<section id="examples" class="reference-section examples-section">
|
||
<header><div><span>10</span><h3>WORKED MECHANICS</h3></div></header>
|
||
<div class="example-intro">
|
||
<div>
|
||
<h4>PRECISE TRAUMA</h4>
|
||
<p>Body shots add one target-bound stack and headshots add two. Each hit refreshes that enemy’s shared one-second expiry; the expiry deals one live Skill Damage value per final stack.</p>
|
||
</div>
|
||
<div>
|
||
<h4>SUPERIOR FIREPOWER</h4>
|
||
<p>Nine hits on one target add a Relentless stack. Each write refreshes the ten-second pool timer.</p>
|
||
</div>
|
||
<div>
|
||
<h4>HAPPY SURVIVAL</h4>
|
||
<p>A periodic branch restores Health from nearby-enemy count. Each shot pays its Health cost before calculating additional damage from current Health.</p>
|
||
</div>
|
||
</div>
|
||
<div class="example-scripts">
|
||
<PseudoScript title="PRECISE TRAUMA · GENERATED EXAMPLE" lines={preciseTrauma} readiness="READY" />
|
||
<PseudoScript title="SUPERIOR FIREPOWER · GENERATED EXAMPLE" lines={superiorFirepower} readiness="READY" />
|
||
<PseudoScript title="HAPPY SURVIVAL · GENERATED EXAMPLE" lines={happySurvival} readiness="REQUIRES ASSUMPTIONS" />
|
||
</div>
|
||
</section>
|
||
</main>
|
||
</div>
|
||
|
||
<style>
|
||
.reference-toolbar {
|
||
display: flex;
|
||
align-items: end;
|
||
justify-content: space-between;
|
||
gap: var(--shd-gap-lg);
|
||
padding-bottom: var(--shd-gap-md);
|
||
border-bottom: 1px solid var(--shd-border);
|
||
}
|
||
|
||
.reference-toolbar h2,
|
||
.reference-toolbar p {
|
||
margin: 0;
|
||
}
|
||
|
||
.reference-toolbar h2 {
|
||
margin-top: 2px;
|
||
font-size: clamp(1.55rem, 2vw, 2.25rem);
|
||
letter-spacing: -0.02em;
|
||
}
|
||
|
||
.reference-toolbar > div:first-child > p:last-child {
|
||
max-width: 72ch;
|
||
margin-top: 7px;
|
||
color: var(--shd-text-muted);
|
||
line-height: 1.5;
|
||
}
|
||
|
||
.reference-actions {
|
||
display: flex;
|
||
gap: var(--shd-gap-sm);
|
||
flex: 0 0 auto;
|
||
}
|
||
|
||
.reference-actions a {
|
||
display: inline-flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
min-height: 40px;
|
||
padding: 0 13px;
|
||
}
|
||
|
||
.reference-layout {
|
||
display: grid;
|
||
grid-template-columns: 190px minmax(0, 1fr);
|
||
gap: var(--shd-gap-md);
|
||
align-items: start;
|
||
padding-top: var(--shd-gap-md);
|
||
}
|
||
|
||
.reference-index {
|
||
position: sticky;
|
||
top: 82px;
|
||
display: grid;
|
||
border: 1px solid var(--shd-border);
|
||
background: var(--shd-surface);
|
||
}
|
||
|
||
.reference-index > strong {
|
||
padding: 10px;
|
||
border-bottom: 1px solid var(--shd-border);
|
||
color: var(--shd-orange);
|
||
font-size: var(--shd-type-telemetry);
|
||
letter-spacing: 0.08em;
|
||
}
|
||
|
||
.reference-index a {
|
||
display: grid;
|
||
grid-template-columns: 28px 1fr;
|
||
gap: 8px;
|
||
align-items: center;
|
||
min-height: 39px;
|
||
padding: 6px 8px;
|
||
border-bottom: 1px solid var(--shd-border-soft);
|
||
color: var(--shd-text-muted);
|
||
font-size: var(--shd-type-telemetry);
|
||
font-weight: 900;
|
||
letter-spacing: 0.05em;
|
||
}
|
||
|
||
.reference-index a:last-child {
|
||
border-bottom: 0;
|
||
}
|
||
|
||
.reference-index a:hover,
|
||
.reference-index a:focus-visible {
|
||
background: var(--shd-surface-raised);
|
||
color: var(--shd-orange);
|
||
}
|
||
|
||
.reference-index a:focus-visible {
|
||
outline: 2px solid var(--shd-focus-ring);
|
||
outline-offset: -2px;
|
||
}
|
||
|
||
.reference-index a span {
|
||
color: var(--shd-text-dim);
|
||
font-variant-numeric: tabular-nums;
|
||
}
|
||
|
||
.reference-content {
|
||
display: grid;
|
||
gap: var(--shd-gap-md);
|
||
min-width: 0;
|
||
}
|
||
|
||
.reference-section {
|
||
scroll-margin-top: 90px;
|
||
border: 1px solid var(--shd-border);
|
||
background: var(--shd-surface);
|
||
}
|
||
|
||
.reference-section > header {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
gap: var(--shd-gap-md);
|
||
min-height: 52px;
|
||
padding: 9px 12px;
|
||
border-bottom: 1px solid var(--shd-border);
|
||
background: var(--shd-surface-raised);
|
||
}
|
||
|
||
.reference-section > header > div {
|
||
display: flex;
|
||
align-items: baseline;
|
||
gap: 10px;
|
||
}
|
||
|
||
.reference-section > header span {
|
||
color: var(--shd-text-dim);
|
||
font-size: var(--shd-type-telemetry);
|
||
font-weight: 900;
|
||
}
|
||
|
||
.reference-section h3,
|
||
.reference-section h4,
|
||
.reference-section > p,
|
||
.scenario-grid p,
|
||
.example-intro p {
|
||
margin: 0;
|
||
}
|
||
|
||
.reference-section h3 {
|
||
font-size: var(--shd-type-title);
|
||
letter-spacing: 0.03em;
|
||
}
|
||
|
||
.reference-section h4 {
|
||
color: var(--shd-text-muted);
|
||
font-size: var(--shd-type-telemetry);
|
||
letter-spacing: 0.08em;
|
||
}
|
||
|
||
.reference-section > header > b {
|
||
padding: 5px 7px;
|
||
border: 1px solid var(--shd-border);
|
||
color: var(--shd-info);
|
||
font-size: var(--shd-type-telemetry);
|
||
letter-spacing: 0.06em;
|
||
}
|
||
|
||
.reference-section > p {
|
||
max-width: 76ch;
|
||
padding: 12px;
|
||
color: var(--shd-text-muted);
|
||
line-height: 1.55;
|
||
}
|
||
|
||
.lead-section {
|
||
border-top: 2px solid var(--shd-info);
|
||
}
|
||
|
||
.reference-matrix {
|
||
display: grid;
|
||
margin: 0 12px 12px;
|
||
border: 1px solid var(--shd-border-soft);
|
||
}
|
||
|
||
.reference-matrix > div {
|
||
display: grid;
|
||
grid-template-columns: minmax(185px, 0.62fr) minmax(0, 1.38fr);
|
||
gap: 12px;
|
||
align-items: start;
|
||
padding: 9px;
|
||
border-bottom: 1px solid var(--shd-border-soft);
|
||
background: var(--shd-bg);
|
||
}
|
||
|
||
.reference-matrix > div:last-child {
|
||
border-bottom: 0;
|
||
}
|
||
|
||
code {
|
||
color: var(--shd-success);
|
||
font-family: var(--shd-font-mono);
|
||
font-size: var(--shd-type-supporting);
|
||
font-weight: 900;
|
||
overflow-wrap: anywhere;
|
||
}
|
||
|
||
.reference-matrix span,
|
||
.result-types span {
|
||
color: var(--shd-text-muted);
|
||
font-size: var(--shd-type-supporting);
|
||
line-height: 1.45;
|
||
}
|
||
|
||
.statement-matrix {
|
||
grid-template-columns: repeat(3, minmax(0, 1fr));
|
||
}
|
||
|
||
.statement-matrix > div {
|
||
grid-template-columns: 1fr;
|
||
align-content: start;
|
||
}
|
||
|
||
.event-registry {
|
||
display: grid;
|
||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||
margin: 0 12px 12px;
|
||
border: 1px solid var(--shd-border-soft);
|
||
}
|
||
|
||
.event-registry article {
|
||
display: grid;
|
||
gap: 6px;
|
||
padding: 10px;
|
||
border-right: 1px solid var(--shd-border-soft);
|
||
border-bottom: 1px solid var(--shd-border-soft);
|
||
background: var(--shd-bg);
|
||
}
|
||
|
||
.event-registry article:nth-child(2n) {
|
||
border-right: 0;
|
||
}
|
||
|
||
.event-registry article:nth-last-child(-n + 2) {
|
||
border-bottom: 0;
|
||
}
|
||
|
||
.event-registry article > div {
|
||
display: flex;
|
||
flex-wrap: wrap;
|
||
justify-content: space-between;
|
||
gap: 7px;
|
||
}
|
||
|
||
.event-registry strong {
|
||
font-size: var(--shd-type-supporting);
|
||
}
|
||
|
||
.event-registry p {
|
||
margin: 0;
|
||
color: var(--shd-text-muted);
|
||
font-size: var(--shd-type-supporting);
|
||
line-height: 1.45;
|
||
}
|
||
|
||
.event-registry ul {
|
||
display: grid;
|
||
gap: 4px;
|
||
margin: 2px 0 0;
|
||
padding: 0;
|
||
list-style: none;
|
||
}
|
||
|
||
.event-registry li {
|
||
display: flex;
|
||
flex-wrap: wrap;
|
||
justify-content: space-between;
|
||
gap: 6px;
|
||
padding-top: 5px;
|
||
border-top: 1px solid var(--shd-border-soft);
|
||
color: var(--shd-text-muted);
|
||
font-size: var(--shd-type-telemetry);
|
||
}
|
||
|
||
.action-registry {
|
||
display: grid;
|
||
grid-template-columns: repeat(3, minmax(0, 1fr));
|
||
margin: 0 12px 12px;
|
||
border: 1px solid var(--shd-border-soft);
|
||
}
|
||
|
||
.action-registry > div {
|
||
display: grid;
|
||
gap: 4px;
|
||
min-width: 0;
|
||
padding: 9px;
|
||
border-right: 1px solid var(--shd-border-soft);
|
||
border-bottom: 1px solid var(--shd-border-soft);
|
||
background: var(--shd-bg);
|
||
}
|
||
|
||
.action-registry > div:nth-child(3n) {
|
||
border-right: 0;
|
||
}
|
||
|
||
.action-registry strong {
|
||
font-size: var(--shd-type-supporting);
|
||
}
|
||
|
||
.split-reference,
|
||
.outcome-grid {
|
||
display: grid;
|
||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||
gap: 1px;
|
||
margin: 0 12px 12px;
|
||
background: var(--shd-border);
|
||
}
|
||
|
||
.split-reference > div,
|
||
.outcome-grid > div {
|
||
min-width: 0;
|
||
padding-top: 10px;
|
||
background: var(--shd-surface-raised);
|
||
}
|
||
|
||
.split-reference h4,
|
||
.outcome-grid h4 {
|
||
padding: 0 12px 8px;
|
||
}
|
||
|
||
.contract {
|
||
display: grid;
|
||
grid-template-columns: 190px minmax(0, 1fr);
|
||
gap: 12px;
|
||
margin: 0 12px 12px;
|
||
padding: 10px;
|
||
border: 1px solid var(--shd-model-border);
|
||
background: var(--shd-model-surface);
|
||
}
|
||
|
||
.contract strong {
|
||
color: var(--shd-info);
|
||
font-size: var(--shd-type-telemetry);
|
||
letter-spacing: 0.07em;
|
||
}
|
||
|
||
.contract span {
|
||
color: var(--shd-text-muted);
|
||
font-size: var(--shd-type-supporting);
|
||
line-height: 1.45;
|
||
}
|
||
|
||
.result-types {
|
||
display: grid;
|
||
margin: 0 12px 14px;
|
||
border: 1px solid var(--shd-border-soft);
|
||
}
|
||
|
||
.result-types > div {
|
||
display: grid;
|
||
grid-template-columns: 145px 1fr;
|
||
gap: 10px;
|
||
padding: 9px;
|
||
border-bottom: 1px solid var(--shd-border-soft);
|
||
background: var(--shd-bg);
|
||
}
|
||
|
||
.result-types > div:last-child {
|
||
border-bottom: 0;
|
||
}
|
||
|
||
.result-types strong {
|
||
color: var(--shd-text);
|
||
font-size: var(--shd-type-telemetry);
|
||
}
|
||
|
||
.basis-list {
|
||
display: flex;
|
||
flex-wrap: wrap;
|
||
gap: 5px;
|
||
padding: 0 12px 12px;
|
||
}
|
||
|
||
.basis-list code {
|
||
padding: 5px 7px;
|
||
border: 1px solid var(--shd-border);
|
||
background: var(--shd-bg);
|
||
}
|
||
|
||
.scenario-grid,
|
||
.example-intro {
|
||
display: grid;
|
||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||
gap: 1px;
|
||
margin: 12px;
|
||
background: var(--shd-border);
|
||
}
|
||
|
||
.scenario-grid article,
|
||
.example-intro > div {
|
||
display: grid;
|
||
align-content: start;
|
||
gap: 6px;
|
||
padding: 12px;
|
||
background: var(--shd-bg);
|
||
}
|
||
|
||
.scenario-grid strong {
|
||
color: var(--shd-orange);
|
||
font-size: var(--shd-type-supporting);
|
||
}
|
||
|
||
.scenario-grid p,
|
||
.example-intro p {
|
||
color: var(--shd-text-muted);
|
||
line-height: 1.5;
|
||
}
|
||
|
||
.protocol-contract code {
|
||
font-size: inherit;
|
||
}
|
||
|
||
.variable-controls {
|
||
display: flex;
|
||
align-items: end;
|
||
justify-content: space-between;
|
||
gap: var(--shd-gap-md);
|
||
margin: 0 12px 8px;
|
||
}
|
||
|
||
.variable-controls label {
|
||
display: grid;
|
||
gap: 5px;
|
||
width: min(620px, 100%);
|
||
color: var(--shd-text-muted);
|
||
font-size: var(--shd-type-telemetry);
|
||
font-weight: 900;
|
||
letter-spacing: 0.07em;
|
||
}
|
||
|
||
.variable-controls input {
|
||
width: 100%;
|
||
min-height: 42px;
|
||
}
|
||
|
||
.variable-controls > strong {
|
||
padding-bottom: 11px;
|
||
color: var(--shd-info);
|
||
font-size: var(--shd-type-telemetry);
|
||
letter-spacing: 0.06em;
|
||
white-space: nowrap;
|
||
}
|
||
|
||
.attribute-variable-list {
|
||
display: grid;
|
||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||
gap: 1px;
|
||
margin: 0 12px 12px;
|
||
border: 1px solid var(--shd-border-soft);
|
||
background: var(--shd-border-soft);
|
||
}
|
||
|
||
.attribute-variable-list article {
|
||
display: grid;
|
||
grid-template-rows: auto 1fr auto;
|
||
min-width: 0;
|
||
background: var(--shd-bg);
|
||
}
|
||
|
||
.attribute-variable-list article > header {
|
||
display: grid;
|
||
gap: 7px;
|
||
padding: 10px;
|
||
border-bottom: 1px solid var(--shd-border-soft);
|
||
}
|
||
|
||
.attribute-variable-list article > header > div:first-child {
|
||
display: flex;
|
||
align-items: baseline;
|
||
justify-content: space-between;
|
||
gap: 9px;
|
||
min-width: 0;
|
||
}
|
||
|
||
.attribute-variable-list article > header strong {
|
||
font-size: var(--shd-type-body);
|
||
}
|
||
|
||
.attribute-variable-list article > header code {
|
||
max-width: 45%;
|
||
overflow: hidden;
|
||
color: var(--shd-text-dim);
|
||
font-size: var(--shd-type-telemetry);
|
||
text-overflow: ellipsis;
|
||
white-space: nowrap;
|
||
}
|
||
|
||
.variable-classification {
|
||
display: flex;
|
||
flex-wrap: wrap;
|
||
gap: 4px;
|
||
}
|
||
|
||
.variable-classification span {
|
||
padding: 3px 5px;
|
||
border: 1px solid var(--shd-border);
|
||
color: var(--shd-text-muted);
|
||
font-size: var(--shd-type-telemetry);
|
||
font-weight: 900;
|
||
letter-spacing: 0.04em;
|
||
}
|
||
|
||
.attribute-variable-list article > p {
|
||
margin: 0;
|
||
padding: 10px;
|
||
color: var(--shd-text-muted);
|
||
line-height: 1.5;
|
||
}
|
||
|
||
.attribute-variable-list article > p.missing-description {
|
||
color: var(--shd-danger);
|
||
font-size: var(--shd-type-supporting);
|
||
font-weight: 700;
|
||
}
|
||
|
||
.attribute-variable-list article > footer {
|
||
display: flex;
|
||
flex-wrap: wrap;
|
||
gap: 5px;
|
||
padding: 8px 10px;
|
||
border-top: 1px solid var(--shd-border-soft);
|
||
}
|
||
|
||
.attribute-variable-list article > footer span {
|
||
display: inline-flex;
|
||
gap: 5px;
|
||
padding: 3px 5px;
|
||
border: 1px solid var(--shd-border);
|
||
color: var(--shd-text-muted);
|
||
font-size: var(--shd-type-telemetry);
|
||
font-variant-numeric: tabular-nums;
|
||
}
|
||
|
||
.attribute-variable-list article > footer b {
|
||
color: var(--shd-text);
|
||
}
|
||
|
||
.variable-empty {
|
||
display: grid;
|
||
grid-column: 1 / -1;
|
||
gap: 5px;
|
||
place-items: center;
|
||
min-height: 150px;
|
||
padding: 24px;
|
||
background: var(--shd-bg);
|
||
text-align: center;
|
||
}
|
||
|
||
.variable-empty strong {
|
||
color: var(--shd-text);
|
||
font-size: var(--shd-type-supporting);
|
||
}
|
||
|
||
.variable-empty span {
|
||
color: var(--shd-text-muted);
|
||
}
|
||
|
||
.example-scripts {
|
||
display: grid;
|
||
grid-template-columns: repeat(3, minmax(0, 1fr));
|
||
gap: 8px;
|
||
padding: 0 12px 12px;
|
||
}
|
||
|
||
.example-scripts > :global(*) {
|
||
min-width: 0;
|
||
}
|
||
|
||
@media (max-width: 1000px) {
|
||
.reference-layout {
|
||
grid-template-columns: 1fr;
|
||
}
|
||
|
||
.reference-index {
|
||
position: static;
|
||
grid-template-columns: repeat(3, minmax(0, 1fr));
|
||
}
|
||
|
||
.reference-index > strong {
|
||
grid-column: 1 / -1;
|
||
}
|
||
|
||
.reference-index a {
|
||
border-right: 1px solid var(--shd-border-soft);
|
||
}
|
||
|
||
.statement-matrix,
|
||
.action-registry {
|
||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||
}
|
||
|
||
.action-registry > div:nth-child(3n) {
|
||
border-right: 1px solid var(--shd-border-soft);
|
||
}
|
||
|
||
.action-registry > div:nth-child(2n) {
|
||
border-right: 0;
|
||
}
|
||
|
||
.example-scripts {
|
||
grid-template-columns: 1fr;
|
||
}
|
||
|
||
.attribute-variable-list {
|
||
grid-template-columns: 1fr;
|
||
}
|
||
}
|
||
|
||
@media (max-width: 680px) {
|
||
.reference-toolbar,
|
||
.reference-actions {
|
||
display: grid;
|
||
align-items: stretch;
|
||
}
|
||
|
||
.reference-actions a {
|
||
min-height: 44px;
|
||
}
|
||
|
||
.reference-index {
|
||
grid-template-columns: 1fr;
|
||
}
|
||
|
||
.reference-index > strong {
|
||
grid-column: 1;
|
||
}
|
||
|
||
.reference-index a {
|
||
min-height: 44px;
|
||
border-right: 0;
|
||
}
|
||
|
||
.statement-matrix,
|
||
.event-registry,
|
||
.action-registry,
|
||
.split-reference,
|
||
.outcome-grid,
|
||
.scenario-grid,
|
||
.example-intro {
|
||
grid-template-columns: 1fr;
|
||
}
|
||
|
||
.event-registry article,
|
||
.event-registry article:nth-child(2n),
|
||
.event-registry article:nth-last-child(-n + 2),
|
||
.action-registry > div,
|
||
.action-registry > div:nth-child(2n),
|
||
.action-registry > div:nth-child(3n) {
|
||
border-right: 0;
|
||
border-bottom: 1px solid var(--shd-border-soft);
|
||
}
|
||
|
||
.event-registry article:last-child,
|
||
.action-registry > div:last-child {
|
||
border-bottom: 0;
|
||
}
|
||
|
||
.reference-matrix > div,
|
||
.result-types > div,
|
||
.contract {
|
||
grid-template-columns: 1fr;
|
||
gap: 5px;
|
||
}
|
||
|
||
.reference-section > header {
|
||
align-items: start;
|
||
}
|
||
|
||
.reference-section > header > div {
|
||
align-items: start;
|
||
}
|
||
|
||
.variable-controls {
|
||
display: grid;
|
||
align-items: stretch;
|
||
}
|
||
|
||
.variable-controls > strong {
|
||
padding-bottom: 0;
|
||
}
|
||
|
||
.attribute-variable-list article > header > div:first-child {
|
||
display: grid;
|
||
}
|
||
|
||
.attribute-variable-list article > header code {
|
||
max-width: 100%;
|
||
}
|
||
}
|
||
</style>
|