narraleaf-studio 0.6.0 → 0.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/_api.d.ts CHANGED
@@ -11,7 +11,6 @@
11
11
  // Generated by dts-bundle-generator v9.5.1
12
12
 
13
13
  import { LucideIcon } from 'lucide-react';
14
- import { TextGlyphOrientation, TextWritingMode as NlrTextWritingMode } from 'narraleaf-react';
15
14
  import React$1 from 'react';
16
15
  import { ComponentType, InputHTMLAttributes, ReactElement, ReactNode, RefObject } from 'react';
17
16
 
@@ -1422,260 +1421,6 @@ type StoryAlignPositionValue = {
1422
1421
  xoffset?: number;
1423
1422
  yoffset?: number;
1424
1423
  };
1425
- type GameBuildPlatform = "windows" | "macos" | "linux" | "web" | "android" | "ios";
1426
- type PluginPermissionPersistence = "temporary" | "permanent";
1427
- type PluginFileSystemPermissionMode = "read" | "write" | "readwrite";
1428
- /**
1429
- * Install-time permissions split into two families, and the split is the whole
1430
- * point:
1431
- *
1432
- * - **Author-declared** (`filesystem`, `api`) — privileged Studio controls the
1433
- * plugin asks for explicitly in `permissions[]`.
1434
- * - **Derived** (`runtime`, `sidecar`, `buildDependency`, `externalLink`,
1435
- * `network`) — computed from `contributes` by {@link validatePluginManifest}
1436
- * and *rejected* if written by
1437
- * hand. A capability is declared in exactly one place, so what the prompt shows
1438
- * and what the plugin can actually reach cannot drift apart. Adding a
1439
- * capability widens the permission set, which makes the update re-prompt for
1440
- * free (see `isPermissionSubset`).
1441
- */
1442
- export type PluginInstallPermission = {
1443
- kind: "filesystem";
1444
- path: string;
1445
- mode: PluginFileSystemPermissionMode;
1446
- recursive: boolean;
1447
- } | {
1448
- kind: "api";
1449
- capability: string;
1450
- } | {
1451
- /** Derived from `contributes.runtimeCapabilities`. */
1452
- kind: "runtime";
1453
- capability: PluginRuntimeCapability;
1454
- } | {
1455
- /** Derived from `contributes.sidecars`: a native child process shipped inside the author's game. */
1456
- kind: "sidecar";
1457
- id: string;
1458
- /**
1459
- * Which of the two sidecar shapes this is, carried through from the manifest because the
1460
- * two are different promises: `executable` starts a separate binary, `node` runs the
1461
- * plugin's own JavaScript under the game's Electron as Node. An author told only "this
1462
- * ships a helper program" has not been told which one they are approving.
1463
- *
1464
- * Named apart from `kind` above on purpose - that one says which permission this is, this
1465
- * one says what the sidecar runs.
1466
- */
1467
- sidecarKind: PluginSidecarKind;
1468
- /** `<platform>-<arch>` keys the sidecar ships binaries for. */
1469
- platforms: string[];
1470
- } | {
1471
- /** Derived from `contributes.buildDependencies`: binaries downloaded at build time. */
1472
- kind: "buildDependency";
1473
- id: string;
1474
- /** Distinct hostnames the binaries are fetched from. */
1475
- hosts: string[];
1476
- } | {
1477
- /**
1478
- * Derived from `contributes.externalLinks`: addresses outside the game this plugin may open
1479
- * in the player's browser or platform handler.
1480
- *
1481
- * One permission carrying every pattern rather than one permission each, because what the
1482
- * author is deciding is a single question - "may this plugin send the player out to these
1483
- * places" - and a prompt that asked it four times would be four chances to stop reading.
1484
- * `isPermissionSubset` still compares the patterns one by one, so adding one to a later
1485
- * version widens the set and re-prompts.
1486
- *
1487
- * The patterns are the author's own strings, unrewritten: this list is what the prompt
1488
- * shows, and normalizing a permission before showing it to the person approving it would
1489
- * make the prompt and the manifest two slightly different documents.
1490
- */
1491
- kind: "externalLink";
1492
- patterns: string[];
1493
- } | {
1494
- /**
1495
- * Derived from `contributes.network`: hosts this plugin's runtime code requests bytes from.
1496
- *
1497
- * A separate question from `externalLink` and never folded into it. Opening a page hands an
1498
- * address to the browser the player already uses and nothing comes back; this fetches, and
1499
- * what comes back runs inside the game. An author deciding about one has not decided about
1500
- * the other.
1501
- *
1502
- * The patterns are also what a project's network allowlist shows attributed to this plugin,
1503
- * which is the point of declaring them: a build narrowed to a list still reaches what the
1504
- * author approved here, and the list can say so rather than silently making room.
1505
- */
1506
- kind: "network";
1507
- patterns: string[];
1508
- };
1509
- type PluginSidecarKind = "executable" | "node";
1510
- declare const PluginRuntimeCapability: {
1511
- /** `app.game.store` — plugin-scoped persistent key/value storage. */
1512
- readonly Store: "store";
1513
- /** `app.game.events` — game lifecycle and engine event subscription. */
1514
- readonly Events: "events";
1515
- /** `app.game.state.get` — read story variables. */
1516
- readonly StateRead: "state.read";
1517
- /** `app.game.state.set` — write story variables. */
1518
- readonly StateWrite: "state.write";
1519
- /** `app.game.saves` — list and read save metadata. */
1520
- readonly SavesRead: "saves.read";
1521
- /**
1522
- * `app.game.saves.write` / `.load` — overwrite a save slot and load one.
1523
- *
1524
- * Separate from (and heavier than) `saves.read`: this can destroy a
1525
- * playthrough. It exists because quick-save/quick-load is an ordinary thing
1526
- * for a visual novel to ship — the built-in Quick Save plugin is exactly
1527
- * this — and a capability model that cannot express a feature the product
1528
- * already has would just push authors back around it.
1529
- */
1530
- readonly SavesWrite: "saves.write";
1531
- /** `app.game.ui.overlay` — draw on top of the game. */
1532
- readonly UiOverlay: "ui.overlay";
1533
- /** `app.game.assets` — resolve packaged asset URLs. */
1534
- readonly Assets: "assets";
1535
- /**
1536
- * `app.game.locale` — read and observe the game language, and read the project's own
1537
- * localized text through the same table and fallback chain the `Get Text` node uses.
1538
- */
1539
- readonly Locale: "locale";
1540
- /**
1541
- * `app.game.menu` — own the menu bar above the game.
1542
- *
1543
- * Its own capability rather than part of anything else, because what it grants is *the chrome
1544
- * the player reads the game through*: every row on that bar, and what each one does, is this
1545
- * plugin's to decide. The rows still act through the game's own vocabulary (see
1546
- * `@shared/types/gameMenu`) - nothing here reaches past what a blueprint could already do - but
1547
- * an author approving this is handing over a surface their players will read as the game's own,
1548
- * which is worth a name at install rather than arriving with something else.
1549
- *
1550
- * Absent on shells with no bar to give (the web export, Dev Mode), which is reported the way
1551
- * every environment difference is: the member is not there.
1552
- */
1553
- readonly Menu: "menu";
1554
- /**
1555
- * `app.game.story` — register a compile pass that observes each scene and injects engine
1556
- * actions around its rows.
1557
- *
1558
- * The heaviest of the ten to read, and the one whose weight is easiest to miss: nothing here
1559
- * touches the player's files, and the author still sees only their own document — but a pass
1560
- * runs over *every* scene of the project, sees who speaks in each, and can put actions around
1561
- * lines it did not write. That is a plugin editing the story, at the last moment before it
1562
- * plays, and it is worth a name the author approves at install.
1563
- *
1564
- * It is not `state.write` in disguise and does not imply it: a pass builds actions, it does not
1565
- * run them, and the one piece of runtime state it can touch is a scene-local flag the compiler
1566
- * creates and owns (`SceneCompileContext.runtimeFlag`), never a story variable the author
1567
- * declared.
1568
- */
1569
- readonly StoryCompile: "story.compile";
1570
- };
1571
- type PluginRuntimeCapability = typeof PluginRuntimeCapability[keyof typeof PluginRuntimeCapability];
1572
- /**
1573
- * `app.game.sidecar` has no entry here on purpose: it exists exactly when
1574
- * `contributes.sidecars` is non-empty. Declaring the sidecar *is* the request.
1575
- */
1576
- export interface PluginIdentity {
1577
- id: string;
1578
- name?: string;
1579
- version?: string;
1580
- publisher?: string;
1581
- }
1582
- interface PluginPermissionRequestBase {
1583
- requestId: string;
1584
- plugin: PluginIdentity;
1585
- reason?: string;
1586
- requestedAt?: number;
1587
- }
1588
- export type PluginPermissionRequest = (PluginPermissionRequestBase & {
1589
- kind: "trust";
1590
- persistence?: PluginPermissionPersistence;
1591
- }) | (PluginPermissionRequestBase & {
1592
- kind: "filesystem";
1593
- path: string;
1594
- mode: PluginFileSystemPermissionMode;
1595
- recursive: boolean;
1596
- persistence: PluginPermissionPersistence;
1597
- }) | (PluginPermissionRequestBase & {
1598
- kind: "install";
1599
- source: string;
1600
- permissions?: PluginInstallPermission[];
1601
- persistence?: PluginPermissionPersistence;
1602
- }) | (PluginPermissionRequestBase & {
1603
- kind: "api";
1604
- capability: string;
1605
- persistence?: PluginPermissionPersistence;
1606
- });
1607
- interface PluginPermissionGrantResult {
1608
- requestId: string;
1609
- pluginId: string;
1610
- kind: PluginPermissionRequest["kind"];
1611
- approved: boolean;
1612
- persistence: PluginPermissionPersistence;
1613
- grantedAt?: number;
1614
- }
1615
- export type PluginPermissionPromptResult = PluginPermissionGrantResult | null;
1616
- type BlueprintDebugEvent = {
1617
- type: "execution.started";
1618
- executionId: string;
1619
- blueprintId: string;
1620
- } | {
1621
- type: "execution.finished";
1622
- executionId: string;
1623
- blueprintId: string;
1624
- } | {
1625
- type: "execution.cancelled";
1626
- executionId: string;
1627
- blueprintId?: string;
1628
- eventId?: string;
1629
- graphId?: string;
1630
- nodeId?: string;
1631
- reason?: string;
1632
- } | {
1633
- type: "node.enter";
1634
- executionId: string;
1635
- nodeId: string;
1636
- } | {
1637
- type: "node.exit";
1638
- executionId: string;
1639
- nodeId: string;
1640
- } | {
1641
- type: "state.read";
1642
- scope: string;
1643
- key: string;
1644
- } | {
1645
- type: "state.write";
1646
- scope: string;
1647
- key: string;
1648
- } | {
1649
- type: "binding.evaluated";
1650
- bindingId: string;
1651
- } | {
1652
- type: "function.call";
1653
- functionId: string;
1654
- } | {
1655
- type: "function.return";
1656
- functionId: string;
1657
- } | {
1658
- type: "devtools.log";
1659
- level: string;
1660
- message: string;
1661
- } | {
1662
- type: "execution.error";
1663
- executionId: string;
1664
- message: string;
1665
- blueprintId?: string;
1666
- eventId?: string;
1667
- graphId?: string;
1668
- nodeId?: string;
1669
- /**
1670
- * The UI surface whose graph failed, when the failure happened on one.
1671
- *
1672
- * The rest of this event names OUR ids - a blueprint, a graph, a node - none of which an
1673
- * author can find their way back from. A surface id resolves against the document they
1674
- * drew, which is what lets a host say "the Quick Menu" rather than "bp:8f2c1a…". Absent on
1675
- * the global blueprint, which belongs to no surface.
1676
- */
1677
- surfaceId?: string;
1678
- };
1679
1424
  type BlueprintOwnerRef = {
1680
1425
  kind: "globalMain";
1681
1426
  } | {
@@ -1694,9 +1439,6 @@ type BlueprintOwnerRef = {
1694
1439
  kind: "componentWidgetMain";
1695
1440
  componentId: string;
1696
1441
  elementId: string;
1697
- } | {
1698
- kind: "sharedAsset";
1699
- assetId: string;
1700
1442
  }
1701
1443
  /**
1702
1444
  * Story Action Blueprint: an implicit project resource bound 1:1 to a single story action.
@@ -1717,17 +1459,22 @@ type BlueprintOwnerRef = {
1717
1459
  blueprintId: string;
1718
1460
  mode?: "action" | "value" | "condition";
1719
1461
  };
1720
- type BlueprintFrontendKind = "visual" | "typescript";
1721
- type BlueprintProgramKind = "graph" | "scriptModule";
1722
1462
  type Blueprint = {
1723
1463
  id: string;
1724
1464
  name: string;
1725
1465
  owner: BlueprintOwnerRef;
1726
- frontend: BlueprintFrontendKind;
1727
- programKind: BlueprintProgramKind;
1728
1466
  members?: BlueprintMemberIndex;
1729
1467
  bindings?: Record<string, BindingDefinition>;
1730
- program: BlueprintProgram;
1468
+ /**
1469
+ * The layers this slot runs, in the order the author arranged them.
1470
+ *
1471
+ * Reached directly rather than through a `program: { kind }` wrapper. The wrapper existed to
1472
+ * separate a graph blueprint from a script one, and there is no such division any more: a
1473
+ * blueprint is a container of layers, and each layer says for itself whether it is a graph or a
1474
+ * file. Three fields used to answer the same question - `frontend`, `programKind` and
1475
+ * `program.kind` - and none of them could answer it for a blueprint holding one of each.
1476
+ */
1477
+ graphs: BlueprintGraphIndex;
1731
1478
  meta?: Record<string, unknown>;
1732
1479
  };
1733
1480
  type BlueprintMemberIndex = {
@@ -1779,12 +1526,10 @@ type BlueprintFunctionSignature = {
1779
1526
  returnType?: string;
1780
1527
  meta?: Record<string, unknown>;
1781
1528
  };
1782
- type BlueprintProgram = {
1783
- kind: "graph";
1784
- graphs: BlueprintGraphIndex;
1785
- } | {
1786
- kind: "scriptModule";
1787
- source: TypeScriptBlueprintSource;
1529
+ type BlueprintLayerScript = {
1530
+ scriptRef: string;
1531
+ /** What the last compile of {@link scriptRef} said. Absent until one has run. */
1532
+ diagnostics?: BlueprintDiagnostic[];
1788
1533
  };
1789
1534
  type BlueprintGraphIndex = {
1790
1535
  /**
@@ -1803,7 +1548,7 @@ type BlueprintGraphIndex = {
1803
1548
  * listed. Write it through the service, never by hand.
1804
1549
  */
1805
1550
  eventIds?: string[];
1806
- events: Record<string, BlueprintEventGraph>;
1551
+ events: Record<string, BlueprintLayer>;
1807
1552
  /**
1808
1553
  * Authored order of {@link functions}, on the same terms as {@link eventIds}.
1809
1554
  *
@@ -1861,11 +1606,13 @@ type BlueprintGraphEdge = {
1861
1606
  port: string;
1862
1607
  };
1863
1608
  };
1864
- type BlueprintEventGraph = {
1609
+ type BlueprintLayer = {
1865
1610
  id: string;
1866
1611
  name?: string;
1867
1612
  /** Event execution graph - may contain effectful nodes */
1868
1613
  graph?: BlueprintGraphIr;
1614
+ /** The author's file this layer runs, when it is a script layer rather than a graph one. */
1615
+ script?: BlueprintLayerScript;
1869
1616
  meta?: Record<string, unknown>;
1870
1617
  };
1871
1618
  type BlueprintFunctionGraph = {
@@ -1880,13 +1627,6 @@ type BlueprintMacroGraph = {
1880
1627
  graph?: BlueprintGraphIr;
1881
1628
  meta?: Record<string, unknown>;
1882
1629
  };
1883
- type TypeScriptBlueprintSource = {
1884
- language: "typescript";
1885
- code: string;
1886
- compiledModuleId?: string;
1887
- outputPath?: string;
1888
- diagnostics?: BlueprintDiagnostic[];
1889
- };
1890
1630
  type LiteralValue = string | number | boolean | null | LiteralValue[] | {
1891
1631
  [key: string]: LiteralValue;
1892
1632
  };
@@ -1920,166 +1660,243 @@ type BlueprintDiagnostic = {
1920
1660
  /** Source span or module location; M1 opaque */
1921
1661
  location?: Record<string, unknown>;
1922
1662
  };
1923
- type SharedBlueprintAsset = {
1924
- assetId: string;
1925
- name: string;
1926
- frontend: BlueprintFrontendKind;
1927
- blueprint: Blueprint;
1928
- meta?: {
1929
- tags?: string[];
1930
- category?: string;
1931
- };
1663
+ type AudioClipRegion = {
1664
+ /** Offset from the start of the clip, in milliseconds. Where playback starts. */
1665
+ inMs?: number;
1666
+ /** Offset from the start of the clip, in milliseconds. Where playback stops, or where a loop turns around. */
1667
+ outMs?: number;
1668
+ /**
1669
+ * Offset from the start of the clip, in milliseconds. Where each repeat returns to.
1670
+ *
1671
+ * Absent means "return to {@link inMs}" - a plain loop, and exactly what every record written
1672
+ * before this field existed means. Set past the in point it describes the standard VN
1673
+ * **intro→loop**: `inMs..loopStartMs` plays once, then `loopStartMs..outMs` repeats forever.
1674
+ *
1675
+ * Constrained to `inMs <= loopStartMs < outMs`. A value outside that window is dropped rather
1676
+ * than clamped: clamping would invent a loop point the author never marked, while dropping
1677
+ * degrades to the plain loop the two other markers already describe.
1678
+ */
1679
+ loopStartMs?: number;
1932
1680
  };
1933
- type LocaleCode = string;
1934
- type LocalizationLocaleEntry = {
1935
- code: LocaleCode;
1936
- /** Author-facing autonym shown to players (e.g. "日本語", never "Japanese"). */
1937
- displayName: string;
1938
- /** Optional intermediate fallback locale tried before the source locale. */
1939
- fallback?: LocaleCode;
1681
+ type BlueprintOpenExternalRequest = {
1682
+ url: string;
1683
+ };
1684
+ type BlueprintOpenExternalOutcome = "opened" | "refused" | "failed";
1685
+ type BlueprintOpenExternalResult = {
1686
+ outcome: BlueprintOpenExternalOutcome;
1687
+ /** Human-readable reason, null when the page was handed over. */
1688
+ error: string | null;
1940
1689
  };
1941
- type GameLocalizationBundle = {
1942
- sourceLocale: LocaleCode;
1943
- locales: LocalizationLocaleEntry[];
1944
- tables: Record<LocaleCode, Record<string, string>>;
1945
- /** Named-key source texts (key name → source-language text). */
1946
- keys?: Record<string, string>;
1690
+ type BlueprintGraphKind = "event" | "function" | "macro";
1691
+ type GameBuildPlatform = "windows" | "macos" | "linux" | "web" | "android" | "ios";
1692
+ type PluginPermissionPersistence = "temporary" | "permanent";
1693
+ type PluginFileSystemPermissionMode = "read" | "write" | "readwrite";
1694
+ /**
1695
+ * Install-time permissions split into two families, and the split is the whole
1696
+ * point:
1697
+ *
1698
+ * - **Author-declared** (`filesystem`, `api`) — privileged Studio controls the
1699
+ * plugin asks for explicitly in `permissions[]`.
1700
+ * - **Derived** (`runtime`, `sidecar`, `buildDependency`, `externalLink`,
1701
+ * `network`) — computed from `contributes` by {@link validatePluginManifest}
1702
+ * and *rejected* if written by
1703
+ * hand. A capability is declared in exactly one place, so what the prompt shows
1704
+ * and what the plugin can actually reach cannot drift apart. Adding a
1705
+ * capability widens the permission set, which makes the update re-prompt for
1706
+ * free (see `isPermissionSubset`).
1707
+ */
1708
+ export type PluginInstallPermission = {
1709
+ kind: "filesystem";
1710
+ path: string;
1711
+ mode: PluginFileSystemPermissionMode;
1712
+ recursive: boolean;
1713
+ } | {
1714
+ kind: "api";
1715
+ capability: string;
1716
+ } | {
1717
+ /** Derived from `contributes.runtimeCapabilities`. */
1718
+ kind: "runtime";
1719
+ capability: PluginRuntimeCapability;
1720
+ } | {
1721
+ /** Derived from `contributes.sidecars`: a native child process shipped inside the author's game. */
1722
+ kind: "sidecar";
1723
+ id: string;
1724
+ /**
1725
+ * Which of the two sidecar shapes this is, carried through from the manifest because the
1726
+ * two are different promises: `executable` starts a separate binary, `node` runs the
1727
+ * plugin's own JavaScript under the game's Electron as Node. An author told only "this
1728
+ * ships a helper program" has not been told which one they are approving.
1729
+ *
1730
+ * Named apart from `kind` above on purpose - that one says which permission this is, this
1731
+ * one says what the sidecar runs.
1732
+ */
1733
+ sidecarKind: PluginSidecarKind;
1734
+ /** `<platform>-<arch>` keys the sidecar ships binaries for. */
1735
+ platforms: string[];
1736
+ } | {
1737
+ /** Derived from `contributes.buildDependencies`: binaries downloaded at build time. */
1738
+ kind: "buildDependency";
1739
+ id: string;
1740
+ /** Distinct hostnames the binaries are fetched from. */
1741
+ hosts: string[];
1742
+ } | {
1743
+ /**
1744
+ * Derived from `contributes.externalLinks`: addresses outside the game this plugin may open
1745
+ * in the player's browser or platform handler.
1746
+ *
1747
+ * One permission carrying every pattern rather than one permission each, because what the
1748
+ * author is deciding is a single question - "may this plugin send the player out to these
1749
+ * places" - and a prompt that asked it four times would be four chances to stop reading.
1750
+ * `isPermissionSubset` still compares the patterns one by one, so adding one to a later
1751
+ * version widens the set and re-prompts.
1752
+ *
1753
+ * The patterns are the author's own strings, unrewritten: this list is what the prompt
1754
+ * shows, and normalizing a permission before showing it to the person approving it would
1755
+ * make the prompt and the manifest two slightly different documents.
1756
+ */
1757
+ kind: "externalLink";
1758
+ patterns: string[];
1759
+ } | {
1760
+ /**
1761
+ * Derived from `contributes.network`: hosts this plugin's runtime code requests bytes from.
1762
+ *
1763
+ * A separate question from `externalLink` and never folded into it. Opening a page hands an
1764
+ * address to the browser the player already uses and nothing comes back; this fetches, and
1765
+ * what comes back runs inside the game. An author deciding about one has not decided about
1766
+ * the other.
1767
+ *
1768
+ * The patterns are also what a project's network allowlist shows attributed to this plugin,
1769
+ * which is the point of declaring them: a build narrowed to a list still reaches what the
1770
+ * author approved here, and the list can say so rather than silently making room.
1771
+ */
1772
+ kind: "network";
1773
+ patterns: string[];
1774
+ };
1775
+ type PluginSidecarKind = "executable" | "node";
1776
+ declare const PluginRuntimeCapability: {
1777
+ /** `app.game.store` — plugin-scoped persistent key/value storage. */
1778
+ readonly Store: "store";
1779
+ /** `app.game.events` — game lifecycle and engine event subscription. */
1780
+ readonly Events: "events";
1781
+ /** `app.game.state.get` — read story variables. */
1782
+ readonly StateRead: "state.read";
1783
+ /** `app.game.state.set` — write story variables. */
1784
+ readonly StateWrite: "state.write";
1785
+ /** `app.game.saves` — list and read save metadata. */
1786
+ readonly SavesRead: "saves.read";
1947
1787
  /**
1948
- * Scene-name source texts (scene id → source-language name), for the scenes this build ships.
1788
+ * `app.game.saves.write` / `.load` — overwrite a save slot and load one.
1949
1789
  *
1950
- * The same job `keys` does for named keys: a translation table only holds the *target* side, so
1951
- * without this a `scene:` reference read while the game is in the source language has nothing to
1952
- * render but the id. Assembled from the story documents the bundle carries, so a scene a variant
1953
- * dropped is absent here too.
1790
+ * Separate from (and heavier than) `saves.read`: this can destroy a
1791
+ * playthrough. It exists because quick-save/quick-load is an ordinary thing
1792
+ * for a visual novel to ship — the built-in Quick Save plugin is exactly
1793
+ * this — and a capability model that cannot express a feature the product
1794
+ * already has would just push authors back around it.
1954
1795
  */
1955
- scenes?: Record<string, string>;
1956
- };
1957
- type VariableRegistryScope = "saved" | "persistent";
1958
- type VariableRegistryEntry = {
1959
- id: string;
1960
- /** Author-facing, proper-case label. Displayed to users; the id/storageKey are never shown. */
1961
- name: string;
1796
+ readonly SavesWrite: "saves.write";
1797
+ /** `app.game.ui.overlay` — draw on top of the game. */
1798
+ readonly UiOverlay: "ui.overlay";
1799
+ /** `app.game.assets` — resolve packaged asset URLs. */
1800
+ readonly Assets: "assets";
1962
1801
  /**
1963
- * Which project scope this definition belongs to. Decides which runtime table it lands in and
1964
- * which channel reads it - the two never mix, so no consumer may treat the registry as one flat
1965
- * list of persistent variables.
1802
+ * `app.game.locale` — read and observe the game language, and read the project's own
1803
+ * localized text through the same table and fallback chain the `Get Text` node uses.
1966
1804
  */
1967
- scope: VariableRegistryScope;
1968
- valueType: StoryVariableValueType;
1969
- defaultValue?: StoryLiteralValue;
1970
- /** Stable save-file / host-persistence key; defaults to `id`, unchanged on rename. */
1971
- storageKey: string;
1972
- description?: string;
1973
- };
1974
- type PersistentVariableRuntimeTable = Record<string, VariableRegistryEntry>;
1975
- type SaveRecordTimes = {
1976
- /** When this slot was last written, epoch milliseconds; 0 when the record carries no stamp. */
1977
- savedAt: number;
1978
- /** When this slot was first written, epoch milliseconds; 0 when the record carries no stamp. */
1979
- createdAt: number;
1980
- };
1981
- type SaveRecordPlaytime = {
1982
- /** Seconds of play behind the slot; 0 when nothing was recorded. */
1983
- seconds: number;
1984
- /** False when the slot carries no reading at all. */
1985
- recorded: boolean;
1986
- };
1987
- type SaveRecordLine = {
1988
- /** The last sentence shown, or "" when the record carries none. */
1989
- line: string;
1990
- /** Who spoke it, or "" when the record carries no speaker (narration, or none yet). */
1991
- speaker: string;
1992
- };
1993
- type AutoSaveEntry = {
1994
- id: string;
1995
- /** Slot index within the ring. */
1996
- slot: number;
1997
- /** When this slot was last written, epoch milliseconds. */
1998
- timestamp: number;
1999
- /** When this slot was first written, epoch milliseconds. */
2000
- createdAt: number;
2001
- /** Whatever the writer attached as user metadata (null when none). */
2002
- metadata: unknown;
2003
- };
2004
- type VoiceLocaleEntry = {
2005
- code: LocaleCode;
2006
- /** Author-facing autonym shown for this voice language (e.g. "日本語"). */
2007
- displayName: string;
2008
- };
2009
- type AudioClipRegion = {
2010
- /** Offset from the start of the clip, in milliseconds. Where playback starts. */
2011
- inMs?: number;
2012
- /** Offset from the start of the clip, in milliseconds. Where playback stops, or where a loop turns around. */
2013
- outMs?: number;
1805
+ readonly Locale: "locale";
2014
1806
  /**
2015
- * Offset from the start of the clip, in milliseconds. Where each repeat returns to.
1807
+ * `app.game.menu` — own the menu bar above the game.
2016
1808
  *
2017
- * Absent means "return to {@link inMs}" - a plain loop, and exactly what every record written
2018
- * before this field existed means. Set past the in point it describes the standard VN
2019
- * **intro→loop**: `inMs..loopStartMs` plays once, then `loopStartMs..outMs` repeats forever.
1809
+ * Its own capability rather than part of anything else, because what it grants is *the chrome
1810
+ * the player reads the game through*: every row on that bar, and what each one does, is this
1811
+ * plugin's to decide. The rows still act through the game's own vocabulary (see
1812
+ * `@shared/types/gameMenu`) - nothing here reaches past what a blueprint could already do - but
1813
+ * an author approving this is handing over a surface their players will read as the game's own,
1814
+ * which is worth a name at install rather than arriving with something else.
2020
1815
  *
2021
- * Constrained to `inMs <= loopStartMs < outMs`. A value outside that window is dropped rather
2022
- * than clamped: clamping would invent a loop point the author never marked, while dropping
2023
- * degrades to the plain loop the two other markers already describe.
1816
+ * Absent on shells with no bar to give (the web export, Dev Mode), which is reported the way
1817
+ * every environment difference is: the member is not there.
2024
1818
  */
2025
- loopStartMs?: number;
2026
- };
2027
- type BlueprintOpenExternalRequest = {
2028
- url: string;
2029
- };
2030
- type BlueprintOpenExternalOutcome = "opened" | "refused" | "failed";
2031
- type BlueprintOpenExternalResult = {
2032
- outcome: BlueprintOpenExternalOutcome;
2033
- /** Human-readable reason, null when the page was handed over. */
2034
- error: string | null;
2035
- };
2036
- type BlueprintPointerMoveOutcome =
2037
- /** The cursor is now at the requested point. */
2038
- "moved"
2039
- /** This shell cannot move the cursor: a web export, or a host with no platform support. */
2040
- | "unsupported"
2041
- /** The move was attempted and failed. */
2042
- | "failed";
2043
- type BlueprintPointerMoveResult = {
2044
- outcome: BlueprintPointerMoveOutcome;
2045
- error?: string;
2046
- };
2047
- declare const BLUEPRINT_POINTER_MOVE_EASINGS: readonly [
2048
- "linear",
2049
- "easeIn",
2050
- "easeOut",
2051
- "easeInOut"
2052
- ];
2053
- type BlueprintPointerMoveEasing = (typeof BLUEPRINT_POINTER_MOVE_EASINGS)[number];
2054
- type BlueprintGraphKind = "event" | "function" | "macro";
2055
- declare const BLUEPRINT_NETWORK_METHODS: readonly [
2056
- "GET",
2057
- "POST",
2058
- "PUT",
2059
- "PATCH",
2060
- "DELETE",
2061
- "HEAD"
2062
- ];
2063
- type BlueprintNetworkMethod = typeof BLUEPRINT_NETWORK_METHODS[number];
2064
- type BlueprintNetworkFetchRequest = {
2065
- url: string;
2066
- method: BlueprintNetworkMethod;
2067
- /** Header name -> value. Null and `{}` both mean "send none". */
2068
- headers: Record<string, string> | null;
2069
- /** Request body, for the methods that carry one. */
2070
- body: string | null;
2071
- timeoutMs: number;
2072
- };
2073
- type BlueprintNetworkFetchOutcome = "success" | "httpError" | "networkError" | "timeout";
2074
- type BlueprintNetworkFetchResult = {
2075
- outcome: BlueprintNetworkFetchOutcome;
2076
- /** HTTP status, or 0 when no response was received. */
2077
- status: number;
2078
- /** Response body text, present whenever a response arrived. */
2079
- body: string | null;
2080
- /** Human-readable failure reason, null on success. */
2081
- error: string | null;
1819
+ readonly Menu: "menu";
1820
+ /**
1821
+ * `app.game.story` — register a compile pass that observes each scene and injects engine
1822
+ * actions around its rows.
1823
+ *
1824
+ * The heaviest of the ten to read, and the one whose weight is easiest to miss: nothing here
1825
+ * touches the player's files, and the author still sees only their own document — but a pass
1826
+ * runs over *every* scene of the project, sees who speaks in each, and can put actions around
1827
+ * lines it did not write. That is a plugin editing the story, at the last moment before it
1828
+ * plays, and it is worth a name the author approves at install.
1829
+ *
1830
+ * It is not `state.write` in disguise and does not imply it: a pass builds actions, it does not
1831
+ * run them, and the one piece of runtime state it can touch is a scene-local flag the compiler
1832
+ * creates and owns (`SceneCompileContext.runtimeFlag`), never a story variable the author
1833
+ * declared.
1834
+ */
1835
+ readonly StoryCompile: "story.compile";
1836
+ /**
1837
+ * `app.game.diagnostics` — read what the player's caches are holding.
1838
+ *
1839
+ * The lightest of the list to grant and the easiest to misread as heavier than it is. Nothing
1840
+ * here is authored data: it reports how many images the engine is holding, how many bytes those
1841
+ * cost, and what budgets they are being held against. It reads no story, no save and no
1842
+ * variable, and every member is a read - there is nothing to set.
1843
+ *
1844
+ * It is its own capability rather than free like `data` and `config` because a plugin that
1845
+ * watches memory is a plugin that runs continuously and reports numbers about the player's
1846
+ * machine, and an author should see that named at install. The performance inspector is the
1847
+ * plugin this exists for.
1848
+ *
1849
+ * Absent until a game session is live, which is the same rule every other engine-backed member
1850
+ * follows: a plugin's `setup()` runs during boot, and asking then answers null rather than
1851
+ * throwing.
1852
+ */
1853
+ readonly Diagnostics: "diagnostics";
2082
1854
  };
1855
+ type PluginRuntimeCapability = typeof PluginRuntimeCapability[keyof typeof PluginRuntimeCapability];
1856
+ /**
1857
+ * `app.game.sidecar` has no entry here on purpose: it exists exactly when
1858
+ * `contributes.sidecars` is non-empty. Declaring the sidecar *is* the request.
1859
+ */
1860
+ export interface PluginIdentity {
1861
+ id: string;
1862
+ name?: string;
1863
+ version?: string;
1864
+ publisher?: string;
1865
+ }
1866
+ interface PluginPermissionRequestBase {
1867
+ requestId: string;
1868
+ plugin: PluginIdentity;
1869
+ reason?: string;
1870
+ requestedAt?: number;
1871
+ }
1872
+ export type PluginPermissionRequest = (PluginPermissionRequestBase & {
1873
+ kind: "trust";
1874
+ persistence?: PluginPermissionPersistence;
1875
+ }) | (PluginPermissionRequestBase & {
1876
+ kind: "filesystem";
1877
+ path: string;
1878
+ mode: PluginFileSystemPermissionMode;
1879
+ recursive: boolean;
1880
+ persistence: PluginPermissionPersistence;
1881
+ }) | (PluginPermissionRequestBase & {
1882
+ kind: "install";
1883
+ source: string;
1884
+ permissions?: PluginInstallPermission[];
1885
+ persistence?: PluginPermissionPersistence;
1886
+ }) | (PluginPermissionRequestBase & {
1887
+ kind: "api";
1888
+ capability: string;
1889
+ persistence?: PluginPermissionPersistence;
1890
+ });
1891
+ interface PluginPermissionGrantResult {
1892
+ requestId: string;
1893
+ pluginId: string;
1894
+ kind: PluginPermissionRequest["kind"];
1895
+ approved: boolean;
1896
+ persistence: PluginPermissionPersistence;
1897
+ grantedAt?: number;
1898
+ }
1899
+ export type PluginPermissionPromptResult = PluginPermissionGrantResult | null;
2083
1900
  declare const PluginManifestVersion = 2;
2084
1901
  /**
2085
1902
  * Per-target plugin entry files. Each entry is a prebundled ESM file relative
@@ -2387,11 +2204,6 @@ export type RuntimePluginDescriptor = {
2387
2204
  */
2388
2205
  buildConfig?: Record<string, string>;
2389
2206
  };
2390
- type GameProgressImportOutcome = {
2391
- outcome: "found" | "missing" | "failed";
2392
- sceneId: string;
2393
- error: string;
2394
- };
2395
2207
  type GameMenuLabel = {
2396
2208
  readonly key?: string | null;
2397
2209
  readonly text: string;
@@ -2501,13 +2313,6 @@ type GameMenuSpecMenu = {
2501
2313
  type GameMenuSpec = {
2502
2314
  readonly menus: readonly GameMenuSpecMenu[];
2503
2315
  };
2504
- type UIInputActionSource = "pointer" | "key" | "gamepad" | "touch";
2505
- type UIInputActionEventPayload = {
2506
- actionId: string;
2507
- source: UIInputActionSource;
2508
- x?: number;
2509
- y?: number;
2510
- };
2511
2316
  declare const UI_INPUT_POINTER_GESTURES: readonly [
2512
2317
  "click",
2513
2318
  "doubleClick",
@@ -2813,72 +2618,6 @@ type UILayout = {
2813
2618
  lockAspectRatio?: boolean;
2814
2619
  };
2815
2620
  type UIStyle = Record<string, unknown>;
2816
- type GameStorageDurability = "durable" | "evictable" | "unknown";
2817
- type UIGraphId = string;
2818
- type UIGraph = {
2819
- id: UIGraphId;
2820
- name?: string;
2821
- entries: Record<string, UIGraphEntry>;
2822
- nodes: Record<string, UIGraphNode>;
2823
- edges: UIGraphEdge[];
2824
- variables?: Record<string, unknown>;
2825
- meta?: Record<string, unknown>;
2826
- /**
2827
- * M2+ optional link: id of a Blueprint in `blueprintDocument.blueprints` that owns this graph IR.
2828
- */
2829
- blueprintId?: string;
2830
- /** M2+ optional owner context for instance main blueprints */
2831
- ownerRef?: BlueprintOwnerRef;
2832
- };
2833
- type UIGraphEntry = {
2834
- start: {
2835
- nodeId: string;
2836
- port: string;
2837
- };
2838
- inputs?: Record<string, unknown>;
2839
- meta?: Record<string, unknown>;
2840
- };
2841
- type UIGraphNode = {
2842
- id: string;
2843
- type: string;
2844
- params?: Record<string, unknown>;
2845
- ports?: Record<string, UIGraphPort>;
2846
- meta?: Record<string, unknown>;
2847
- /**
2848
- * What each asset set this node's stored params name resolves to, per locale.
2849
- *
2850
- * The same field `BlueprintGraphNode` declares, and the same object: `adaptBlueprintGraphIr`
2851
- * hands the executor the bundle's own nodes rather than copies, so a node running here is
2852
- * carrying whatever the package wrote onto it. Declared on both because a node reads it from
2853
- * whichever of the two types its caller happens to hold.
2854
- *
2855
- * Never authored and never on disk under `editor/`.
2856
- */
2857
- assetVariants?: AssetVariantMap;
2858
- };
2859
- type UIGraphPort = {
2860
- kind: "input" | "output";
2861
- type?: string;
2862
- label?: string;
2863
- };
2864
- type UIGraphEdge = {
2865
- from: {
2866
- nodeId: string;
2867
- port: string;
2868
- };
2869
- to: {
2870
- nodeId: string;
2871
- port: string;
2872
- };
2873
- };
2874
- type DevModeStartStoryRequest = {
2875
- storyId: StoryId;
2876
- sceneId: string;
2877
- /** Row-precise "play from here": enter the game pre-posed at this block and play forward. */
2878
- startBlockId?: string;
2879
- /** Scene Snapshot (变量快照) whose variable overrides seed the launch. */
2880
- snapshotId?: string;
2881
- };
2882
2621
  type GameTestLogLevel = "verbose" | "info" | "success" | "warning" | "error";
2883
2622
  type GameTestExitReason =
2884
2623
  /** Closed from inside the game - the window's own close, or the engine quitting itself. */
@@ -3465,6 +3204,10 @@ declare const en: {
3465
3204
  readonly keybindings: {
3466
3205
  readonly label: "Keyboard shortcuts";
3467
3206
  };
3207
+ readonly projectTrust: {
3208
+ readonly label: "Trusted projects";
3209
+ readonly description: "Projects that Studio did not create, and whether they may run.";
3210
+ };
3468
3211
  readonly cacheInventory: {
3469
3212
  readonly label: "Cached files";
3470
3213
  };
@@ -3567,6 +3310,23 @@ declare const en: {
3567
3310
  };
3568
3311
  };
3569
3312
  readonly data: {
3313
+ readonly projectTrust: {
3314
+ readonly loading: "Reading\u2026";
3315
+ readonly empty: "Every project opened so far was created by Studio.";
3316
+ readonly waiting: "Waiting for a decision";
3317
+ readonly granted: "Trusted";
3318
+ readonly trust: "Trust";
3319
+ readonly remove: "Remove";
3320
+ readonly reloadNote: "A project that is open reloads when its trust changes.";
3321
+ readonly origin: {
3322
+ readonly package: "From a package";
3323
+ readonly remote: "From a remote source";
3324
+ readonly opened: "Opened from a folder";
3325
+ readonly created: "Created by Studio";
3326
+ readonly recent: "Opened before";
3327
+ readonly commandLine: "From the command line";
3328
+ };
3329
+ };
3570
3330
  readonly cache: {
3571
3331
  readonly measuring: "Measuring\u2026";
3572
3332
  readonly unavailable: "Not available";
@@ -4091,6 +3851,10 @@ declare const en: {
4091
3851
  readonly entry: {
4092
3852
  readonly edit: "edit";
4093
3853
  readonly storyEdit: "story edit";
3854
+ readonly storyMoveRowsToScene: "move to another scene";
3855
+ readonly storySplitScene: "scene split";
3856
+ readonly storyMergeScenes: "scene merge";
3857
+ readonly storySpeakerChange: "speaker change";
4094
3858
  readonly storyMotionEdit: "motion edit";
4095
3859
  readonly audioMarkers: "marker change";
4096
3860
  readonly surfaceEdit: "interface edit";
@@ -4212,6 +3976,9 @@ declare const en: {
4212
3976
  readonly errorOpenFailed: "Could not open that folder: {error}";
4213
3977
  readonly notAProjectTitle: "This folder is not a NarraLeaf project";
4214
3978
  readonly notAProjectDetail: "No .nlproj file was found.";
3979
+ readonly projectLockedTitle: "This project is open in another NarraLeaf Studio";
3980
+ readonly projectLockedHere: "Open on this computer since {time}. Retry once it has been closed there.";
3981
+ readonly projectLockedElsewhere: "Open on {host} since {time}. Retry once it has been closed there.";
4215
3982
  readonly openLauncher: "Open launcher";
4216
3983
  readonly panelRenderError: "This panel hit a rendering error";
4217
3984
  readonly mainEditorRegion: "Main editor";
@@ -4245,8 +4012,10 @@ declare const en: {
4245
4012
  };
4246
4013
  };
4247
4014
  readonly panelMenu: {
4248
- readonly removeItem: "Remove this item";
4015
+ readonly hideItem: "Hide this item";
4249
4016
  readonly collapseItem: "Collapse into group";
4017
+ readonly resetLayout: "Reset to default layout";
4018
+ readonly resetLayoutDisabled: "Already in the default layout.";
4250
4019
  };
4251
4020
  readonly panelGroup: {
4252
4021
  readonly title: "Collapsed panels";
@@ -4323,11 +4092,16 @@ declare const en: {
4323
4092
  };
4324
4093
  };
4325
4094
  readonly statusBar: {
4095
+ readonly distrusted: {
4096
+ readonly label: "Not trusted";
4097
+ readonly tooltip: "This project cannot run until it is trusted. Click to trust it.";
4098
+ };
4326
4099
  readonly devMode: "Dev Mode";
4327
4100
  readonly preview: "Preview";
4328
4101
  readonly production: "Production";
4329
4102
  readonly phase: {
4330
4103
  readonly starting: "Starting\u2026";
4104
+ readonly checking: "Checking\u2026";
4331
4105
  readonly preparing: "Preparing\u2026";
4332
4106
  readonly compiling: "Compiling\u2026";
4333
4107
  readonly launching: "Launching\u2026";
@@ -4357,6 +4131,7 @@ declare const en: {
4357
4131
  readonly entries: {
4358
4132
  readonly team: "NarraLeaf Team";
4359
4133
  readonly runStatus: "Run status";
4134
+ readonly projectTrust: "Project trust";
4360
4135
  readonly studioTasks: "Background work";
4361
4136
  readonly unsavedChanges: "Unsaved changes";
4362
4137
  readonly wordCount: "Story stats";
@@ -4409,6 +4184,7 @@ declare const en: {
4409
4184
  readonly characters: "characters";
4410
4185
  readonly project: "project settings";
4411
4186
  readonly assets: "asset library";
4187
+ readonly openEditors: "the open editor";
4412
4188
  };
4413
4189
  };
4414
4190
  readonly reload: {
@@ -4427,6 +4203,10 @@ declare const en: {
4427
4203
  readonly unavailable: "Unavailable while the project is frozen. Unfreeze the project to use it.";
4428
4204
  readonly unavailableLive: "Unavailable during a live session. Leave the session to use it.";
4429
4205
  };
4206
+ readonly distrust: {
4207
+ readonly unavailable: "Unavailable until this project is trusted. Click Not trusted in the status bar to trust it.";
4208
+ readonly refusedTitle: "This project is not trusted";
4209
+ };
4430
4210
  readonly revisionView: {
4431
4211
  readonly showPrevious: "Show the Previous Version (Read-Only)";
4432
4212
  readonly leave: "Stop Viewing History";
@@ -4475,6 +4255,7 @@ declare const en: {
4475
4255
  readonly committing: "Submitting this version\u2026";
4476
4256
  readonly nothingToCommit: "Nothing has changed since the last version.";
4477
4257
  readonly closingWithApp: "Studio is closing. Try again after it restarts.";
4258
+ readonly repositoryLocked: "Another program has this project's version history open. Close it to use versions here.";
4478
4259
  readonly commitBeforeSync: "Submit a version before getting the server's.";
4479
4260
  readonly branchDiverged: "This project and the server have both changed. Get the server's versions first, then send yours.";
4480
4261
  readonly changesUnknown: "Not checked";
@@ -6119,6 +5900,12 @@ declare const en: {
6119
5900
  readonly other: "Link speaker on {count} lines";
6120
5901
  };
6121
5902
  readonly playFromHere: "Play from here";
5903
+ readonly moveToScene: "Move to scene";
5904
+ readonly splitScene: "Split scene here\u2026";
5905
+ readonly mergeWithNext: "Merge with next scene";
5906
+ readonly mergeIntoPrevious: "Merge into previous scene";
5907
+ readonly changeSpeaker: "Change speaker";
5908
+ readonly speakerNameOnly: "{name} (name only)";
6122
5909
  readonly openInspector: "Open inspector";
6123
5910
  readonly delete: "Delete";
6124
5911
  };
@@ -6130,6 +5917,50 @@ declare const en: {
6130
5917
  readonly moveScene: "move scene {name}";
6131
5918
  readonly moveChapter: "move chapter {name}";
6132
5919
  };
5920
+ readonly structuralOps: {
5921
+ readonly moveRows: {
5922
+ readonly done: {
5923
+ readonly one: "{count} row moved to {scene}";
5924
+ readonly other: "{count} rows moved to {scene}";
5925
+ };
5926
+ readonly refused: "Not available during a live session";
5927
+ };
5928
+ readonly splitScene: {
5929
+ readonly title: "Split Scene";
5930
+ readonly description: "The rows from here to the end become this scene.";
5931
+ readonly placeholder: "Enter scene name";
5932
+ readonly namePattern: "{name} {index}";
5933
+ readonly done: {
5934
+ readonly one: "{count} row moved to {scene}";
5935
+ readonly other: "{count} rows moved to {scene}";
5936
+ };
5937
+ readonly jumpAdded: "jump added";
5938
+ readonly refused: "The rows after this one still need what comes before it";
5939
+ readonly refusedDetail: "Still in use after this row: {names}";
5940
+ };
5941
+ readonly mergeScenes: {
5942
+ readonly confirm: "Merge \"{merged}\" into \"{surviving}\"?";
5943
+ readonly detail: {
5944
+ readonly one: "Its {count} row moves to the end of {surviving}.";
5945
+ readonly other: "Its {count} rows move to the end of {surviving}.";
5946
+ };
5947
+ readonly done: {
5948
+ readonly one: "{count} row merged into {scene}";
5949
+ readonly other: "{count} rows merged into {scene}";
5950
+ };
5951
+ readonly refused: "\"{name}\" is still named elsewhere";
5952
+ readonly refusedDetail: "Named by: {referrers}";
5953
+ readonly referrerJump: "{scene} \u00B7 row {row}";
5954
+ readonly referrerEntryScene: "the story's entry scene";
5955
+ readonly noNeighbour: "There is no scene to merge with";
5956
+ };
5957
+ readonly speaker: {
5958
+ readonly done: {
5959
+ readonly one: "Speaker changed on {count} line";
5960
+ readonly other: "Speaker changed on {count} lines";
5961
+ };
5962
+ };
5963
+ };
6133
5964
  readonly keybindings: {
6134
5965
  readonly find: "Find and replace";
6135
5966
  readonly deleteRows: "Delete selected story rows";
@@ -6182,6 +6013,7 @@ declare const en: {
6182
6013
  };
6183
6014
  reason: {
6184
6015
  unknownCommand: string;
6016
+ unknownCommandNear: string;
6185
6017
  unknownParam: string;
6186
6018
  duplicateParam: string;
6187
6019
  extraPositional: string;
@@ -6700,6 +6532,7 @@ declare const en: {
6700
6532
  readonly xOffset: "X offset";
6701
6533
  readonly yOffset: "Y offset";
6702
6534
  readonly params: "Params";
6535
+ readonly fromCharacter: "From the character";
6703
6536
  };
6704
6537
  readonly background: {
6705
6538
  readonly image: "Image";
@@ -6813,7 +6646,6 @@ declare const en: {
6813
6646
  readonly audio: "Audio";
6814
6647
  readonly video: "Videos";
6815
6648
  readonly json: "JSON Files";
6816
- readonly blueprint: "Blueprints";
6817
6649
  readonly font: "Fonts";
6818
6650
  readonly model: "Models";
6819
6651
  readonly other: "Other";
@@ -6830,6 +6662,11 @@ declare const en: {
6830
6662
  readonly one: "{count} item";
6831
6663
  readonly other: "{count} items";
6832
6664
  };
6665
+ readonly unreadable: {
6666
+ readonly category: "This category could not be read. Its file is unchanged.";
6667
+ readonly notSaved: "Changes are not being saved";
6668
+ readonly notSavedDetail: "{file} could not be read. Nothing is written over it.";
6669
+ };
6833
6670
  readonly overview: {
6834
6671
  readonly loading: "Reading the asset library\u2026";
6835
6672
  readonly failed: "Could not read the asset library.";
@@ -7210,11 +7047,6 @@ declare const en: {
7210
7047
  readonly paste: "Paste assets";
7211
7048
  readonly rename: "Rename selected asset or group";
7212
7049
  };
7213
- readonly lockReason: {
7214
- readonly character: "Asset is used by a character";
7215
- readonly scene: "Asset is used by a scene";
7216
- readonly editor: "Asset is used by the Editor";
7217
- };
7218
7050
  readonly previewEditor: {
7219
7051
  readonly loadFailed: "Failed to load this asset.";
7220
7052
  };
@@ -7405,7 +7237,9 @@ declare const en: {
7405
7237
  readonly node: {
7406
7238
  readonly contextInvalid: "Node \"{name}\" is not allowed in this {ownerKind} {graphKind} graph.{hint}";
7407
7239
  readonly contextValueReturnHint: " Return Value only belongs in Blueprint Value graphs.";
7240
+ readonly contextListItemHint: " It reads the list row it runs for, and nothing here draws one.";
7408
7241
  readonly noRuntime: "Node \"{node}\": no runtime for type \"{type}\".";
7242
+ readonly inputMissing: "\"{node}\" has nothing connected to \"{pin}\".";
7409
7243
  readonly unknownType: "Node \"{node}\": unknown type \"{type}\". Its plugin may be uninstalled or disabled.";
7410
7244
  readonly variableIdInvalid: "Node \"{node}\": pick a variable.";
7411
7245
  readonly persistentVariableIdInvalid: "Node \"{node}\": pick a persistent variable.";
@@ -7445,12 +7279,22 @@ declare const en: {
7445
7279
  readonly selectDataType: "Select data type";
7446
7280
  };
7447
7281
  readonly eventLayer: {
7448
- readonly createTitle: "Create event layer";
7449
- readonly createInvalid: "Select an event and name the layer before creating it.";
7450
- readonly event: "Event";
7282
+ readonly createTitle: "Add layer";
7283
+ readonly createInvalid: "Name the layer before creating it.";
7451
7284
  readonly layerName: "Layer name";
7452
7285
  readonly defaultName: "Layer {index}";
7453
7286
  };
7287
+ readonly layerDialog: {
7288
+ readonly graphDescription: "Wire nodes together on the canvas.";
7289
+ readonly scriptDescription: "Run one of your own files.";
7290
+ readonly scriptPickerLabel: "Which file this layer runs";
7291
+ readonly newScript: "New script\u2026";
7292
+ readonly newScriptDetail: "Writes a starter file under scripts/";
7293
+ readonly alreadyRun: {
7294
+ readonly one: "Already run by {count} layer";
7295
+ readonly other: "Already run by {count} layers";
7296
+ };
7297
+ };
7454
7298
  readonly owner: {
7455
7299
  readonly global: "Global";
7456
7300
  readonly storyAction: "Story Action";
@@ -7467,6 +7311,7 @@ declare const en: {
7467
7311
  readonly renameLayerTitle: "Rename layer";
7468
7312
  readonly layerNamePlaceholder: "Layer name";
7469
7313
  readonly deleteLayer: "Delete layer\u2026";
7314
+ readonly deleteScriptLayer: "Remove layer (the file stays)";
7470
7315
  readonly deleteLayerConfirm: "Delete this layer?";
7471
7316
  readonly deleteLayerDetail: "Linked UI events will be cleared.";
7472
7317
  readonly deleteVariableLabel: "Delete variable \"{name}\"";
@@ -7490,16 +7335,9 @@ declare const en: {
7490
7335
  readonly defaultVariableName: "Variable";
7491
7336
  readonly defaultPersistentName: "Persistent";
7492
7337
  };
7493
- readonly revisions: {
7494
- readonly sharedAssetSingle: "One revision per shared asset.";
7495
- readonly title: "Revisions";
7496
- readonly active: "\u00B7 active";
7497
- readonly unnamed: "Revision {index}";
7498
- readonly newTypeScript: "New TypeScript revision";
7499
- readonly newVisual: "New Visual revision";
7500
- };
7501
7338
  readonly frontend: {
7502
- readonly visual: "Visual";
7339
+ readonly visual: "Blueprint";
7340
+ readonly script: "Script";
7503
7341
  };
7504
7342
  readonly literal: {
7505
7343
  readonly string: "String";
@@ -7661,9 +7499,22 @@ declare const en: {
7661
7499
  readonly unnamedInputAction: "Unnamed action";
7662
7500
  readonly missingInputAction: "Missing action";
7663
7501
  };
7664
- readonly tsPane: {
7665
- readonly importHint: "Allowed import: \"narraleaf-studio\"";
7666
- readonly sourceLabel: "TypeScript blueprint source";
7502
+ readonly script: {
7503
+ readonly fileLabel: "Script file";
7504
+ readonly open: "Open in editor";
7505
+ readonly openIn: "Open in {editor}";
7506
+ readonly reveal: "Show in file manager";
7507
+ readonly openFolder: "Open scripts folder";
7508
+ readonly missing: "This file is missing.";
7509
+ readonly changeFile: "Use another file";
7510
+ readonly changeFileEmpty: "No other file under scripts/";
7511
+ readonly readOnly: "Scripts are edited in your own editor.";
7512
+ readonly sectionTitle: "Scripts";
7513
+ readonly tabTitle: "Script";
7514
+ readonly sectionEmpty: "No scripts yet. Open the logic of a page or a component, add a layer, and choose Script.";
7515
+ readonly unbound: "Nothing runs this file";
7516
+ readonly boundTo: "Runs as {name}";
7517
+ readonly boundToMany: "Runs as {name} and {count} more";
7667
7518
  };
7668
7519
  readonly tool: {
7669
7520
  readonly select: "Select tool";
@@ -7890,6 +7741,7 @@ declare const en: {
7890
7741
  readonly isEntering: "Is Entering";
7891
7742
  readonly isExiting: "Is Exiting";
7892
7743
  readonly isFullscreen: "Is Fullscreen";
7744
+ readonly isFocused: "Is Focused";
7893
7745
  readonly isPicked: "Is Picked";
7894
7746
  readonly isRead: "Is Read";
7895
7747
  readonly isInstalled: "Is Installed";
@@ -7979,6 +7831,7 @@ declare const en: {
7979
7831
  readonly skipDelay: "Skip Delay";
7980
7832
  readonly skipInterval: "Skip Interval";
7981
7833
  readonly skipReadText: "Skip Read Text";
7834
+ readonly muteWhenUnfocused: "Mute When Unfocused";
7982
7835
  readonly skipping: "Skipping";
7983
7836
  readonly slider: "Slider";
7984
7837
  readonly sound: "Sound";
@@ -7988,6 +7841,7 @@ declare const en: {
7988
7841
  readonly status: "Status";
7989
7842
  readonly step: "Step";
7990
7843
  readonly story: "Story";
7844
+ readonly storyName: "Story Name";
7991
7845
  readonly success: "Success";
7992
7846
  readonly string: "String";
7993
7847
  readonly switch: "Switch";
@@ -8146,6 +8000,7 @@ declare const en: {
8146
8000
  readonly getSkipDelay: "Get Skip Delay";
8147
8001
  readonly getSkipInterval: "Get Skip Interval";
8148
8002
  readonly getSkipReadText: "Get Skip Read Text";
8003
+ readonly getMuteWhenUnfocused: "Get Mute When Unfocused";
8149
8004
  readonly getSkipping: "Get Skipping";
8150
8005
  readonly getSliderEnabled: "Get Slider Enabled";
8151
8006
  readonly getSliderVisible: "Get Slider Visible";
@@ -8193,6 +8048,7 @@ declare const en: {
8193
8048
  readonly setSkipDelay: "Set Skip Delay";
8194
8049
  readonly setSkipInterval: "Set Skip Interval";
8195
8050
  readonly setSkipReadText: "Set Skip Read Text";
8051
+ readonly setMuteWhenUnfocused: "Set Mute When Unfocused";
8196
8052
  readonly setSkipping: "Set Skipping";
8197
8053
  readonly setSliderEnabled: "Set Slider Enabled";
8198
8054
  readonly setSliderVisible: "Set Slider Visible";
@@ -8457,11 +8313,15 @@ declare const en: {
8457
8313
  readonly onGameReady: "On Game Ready";
8458
8314
  readonly onFullscreenChanged: "On Fullscreen Changed";
8459
8315
  readonly onWindowCloseRequested: "On Window Close Requested";
8316
+ readonly onWindowFocusChanged: "On Window Focus Changed";
8460
8317
  readonly onAction: "On Action";
8461
8318
  readonly onKeyDown: "On Key Down";
8462
8319
  readonly onKeyUp: "On Key Up";
8463
8320
  readonly onPreferenceChanged: "On Preference Changed";
8464
8321
  readonly openLink: "Open Link";
8322
+ readonly openScreenshotsFolder: "Open Screenshots Folder";
8323
+ readonly saveScreenshot: "Save Screenshot";
8324
+ readonly isWindowFocused: "Is Window Focused";
8465
8325
  readonly openPage: "Open page";
8466
8326
  readonly or: "Or";
8467
8327
  readonly padEnd: "Pad End";
@@ -8599,6 +8459,7 @@ declare const en: {
8599
8459
  readonly getTimeZone: "Get Time Zone";
8600
8460
  readonly getSaveTime: "Get Save Time";
8601
8461
  readonly getSaveLine: "Get Save Line";
8462
+ readonly getSaveStory: "Get Save Story";
8602
8463
  readonly getSavePlaytime: "Get Save Playtime";
8603
8464
  readonly getPlaytime: "Get Playtime";
8604
8465
  readonly getTotalPlaytime: "Get Total Playtime";
@@ -8631,12 +8492,18 @@ declare const en: {
8631
8492
  readonly namePlaceholder: "Enter character name";
8632
8493
  readonly groupNamePlaceholder: "Enter group name";
8633
8494
  readonly deleteCharacterConfirm: "Delete character \"{name}\"?";
8495
+ readonly renameSpokenRowsConfirm: {
8496
+ readonly one: "Also rename {count} line that speaks as \"{name}\"?";
8497
+ readonly other: "Also rename {count} lines that speak as \"{name}\"?";
8498
+ };
8499
+ readonly renameSpokenRowsDetail: "Those lines carry the name, not the character. They become \"{name}\".";
8634
8500
  readonly deleteCharacterDetail: "Its dialogue keeps the name. Rows that place it on stage stop resolving.";
8635
8501
  readonly deleteGroupConfirm: "Delete group \"{name}\"?";
8636
8502
  readonly deleteGroupDetail: "Characters in this group will be unassigned.";
8637
8503
  };
8638
8504
  readonly history: {
8639
8505
  readonly deleteCharacter: "delete character {name}";
8506
+ readonly renameCharacter: "rename character {name}";
8640
8507
  readonly deleteGroup: "delete group {name}";
8641
8508
  };
8642
8509
  readonly create: {
@@ -8682,6 +8549,7 @@ declare const en: {
8682
8549
  readonly describeNoModel: "No model to read";
8683
8550
  readonly describeNoBackend: "No runtime chosen";
8684
8551
  readonly describeBackendMissing: "Runtime not installed here";
8552
+ readonly describeDistrusted: "Project not trusted";
8685
8553
  readonly describeNotSupported: "This runtime lists nothing";
8686
8554
  readonly describeFailed: "The model could not be read";
8687
8555
  readonly redescribe: "Read the model again";
@@ -8834,6 +8702,10 @@ declare const en: {
8834
8702
  readonly voiceTrack: "Voice bus";
8835
8703
  readonly voiceTrackMissing: "Missing bus";
8836
8704
  readonly voiceTrackEmpty: "Add a bus under Voice in Project \u25B8 Game to give this character its own volume control.";
8705
+ readonly entrance: "Entrance defaults";
8706
+ readonly entranceEmpty: "Entrance rows use the stage's own values until this is set.";
8707
+ readonly entranceDrag: "Drag to place";
8708
+ readonly entranceZoom: "Drag to scale";
8837
8709
  readonly select: "Select";
8838
8710
  readonly thumbnailAlt: "thumbnail";
8839
8711
  readonly color: "Color";
@@ -9096,6 +8968,9 @@ declare const en: {
9096
8968
  readonly refresh: "Check for Updates";
9097
8969
  readonly refreshFailedTitle: "Could not check the source";
9098
8970
  };
8971
+ readonly local: {
8972
+ readonly origin: "The project holds a copy of a file on this machine. Studio does not track that file; Replace File imports it again.";
8973
+ };
9099
8974
  readonly image: {
9100
8975
  readonly title: "Image Properties";
9101
8976
  readonly info: "Image Information";
@@ -9412,7 +9287,8 @@ declare const en: {
9412
9287
  };
9413
9288
  readonly storySnapshot: {
9414
9289
  readonly empty: "Open a story scene to manage its snapshots.";
9415
- readonly getStarted: "Add a snapshot to set launch values.";
9290
+ readonly defaults: "Defaults";
9291
+ readonly defaultsDetail: "Every variable starts at the value declared for it.";
9416
9292
  readonly noVariables: "No variables in scope for this scene.";
9417
9293
  readonly add: "Add snapshot";
9418
9294
  readonly delete: "Delete snapshot";
@@ -9422,11 +9298,6 @@ declare const en: {
9422
9298
  readonly true: "True";
9423
9299
  readonly false: "False";
9424
9300
  };
9425
- readonly launch: {
9426
- readonly needSnapshot: "A snapshot is needed to start the game here";
9427
- readonly needSnapshotDetail: "Playing from a row requires concrete variable values. Create a scene snapshot first.";
9428
- readonly createAction: "Create snapshot";
9429
- };
9430
9301
  };
9431
9302
  readonly uiEditor: {
9432
9303
  readonly surfaceKind: {
@@ -9441,7 +9312,6 @@ declare const en: {
9441
9312
  readonly surfaceMain: "Page logic";
9442
9313
  readonly widgetMain: "Component logic";
9443
9314
  readonly widgetValue: "Component value";
9444
- readonly sharedAsset: "Shared blueprint";
9445
9315
  readonly storyAction: "Story action";
9446
9316
  };
9447
9317
  readonly stageSlot: {
@@ -9581,6 +9451,10 @@ declare const en: {
9581
9451
  };
9582
9452
  readonly refs: "{count} refs";
9583
9453
  };
9454
+ readonly canvas: {
9455
+ readonly unknownWidget: "Unknown widget";
9456
+ readonly widgetRenderFailed: "Widget failed to draw";
9457
+ };
9584
9458
  readonly editor: {
9585
9459
  readonly componentNotFound: "Component not found";
9586
9460
  readonly interfaceNotFound: "Interface not found";
@@ -9745,7 +9619,7 @@ declare const en: {
9745
9619
  readonly interaction: "Interaction";
9746
9620
  };
9747
9621
  readonly blueprint: {
9748
- readonly controlLabel: "Control blueprint";
9622
+ readonly controlLabel: "Component logic";
9749
9623
  };
9750
9624
  readonly appearance: {
9751
9625
  readonly title: "Appearance";
@@ -9757,6 +9631,7 @@ declare const en: {
9757
9631
  readonly horizontal: "Horizontal";
9758
9632
  readonly vertical: "Vertical";
9759
9633
  readonly gap: "Gap";
9634
+ readonly wrap: "Wrap";
9760
9635
  readonly perSidePx: "Per side (px)";
9761
9636
  readonly sides: {
9762
9637
  readonly top: "Top";
@@ -9924,6 +9799,10 @@ declare const en: {
9924
9799
  readonly title: "Text";
9925
9800
  readonly localizeText: "Localize text";
9926
9801
  };
9802
+ readonly textMarks: {
9803
+ readonly title: "Marks";
9804
+ readonly selectHint: "Select the text to mark";
9805
+ };
9927
9806
  readonly frame: {
9928
9807
  readonly title: "Page";
9929
9808
  readonly page: "Page";
@@ -10037,6 +9916,7 @@ declare const en: {
10037
9916
  readonly describeNoModel: "Pick a model bundle to list its names.";
10038
9917
  readonly describeNoBackend: "Pick a runtime to list the model's names.";
10039
9918
  readonly describeBackendMissing: "That runtime is not installed in this project, so names must be typed.";
9919
+ readonly describeDistrusted: "This project is not trusted, so its runtimes do not run. Trust it from the status bar.";
10040
9920
  readonly describeNotSupported: "This runtime does not describe its models. Type the names.";
10041
9921
  readonly describeFailed: "Could not read the model; type names by hand.";
10042
9922
  readonly redescribe: "Re-read";
@@ -10047,6 +9927,7 @@ declare const en: {
10047
9927
  readonly placeholderUnconfigured: "Select a model bundle and a runtime.";
10048
9928
  readonly placeholderNoModel: "The model bundle is not available here.";
10049
9929
  readonly placeholderBackendMissing: "No runtime named \u201C{backend}\u201D is installed in this project.";
9930
+ readonly placeholderDistrusted: "Not drawn: this project is not trusted, so its runtime is not run.";
10050
9931
  readonly placeholderLoading: "Loading the model\u2026";
10051
9932
  readonly placeholderError: "The runtime failed: {error}";
10052
9933
  readonly placeholderBudget: "Not drawn: {drawn} models are already drawn in this window.";
@@ -10418,6 +10299,7 @@ declare const en: {
10418
10299
  readonly insert: "Insert {name}";
10419
10300
  readonly drawing: "Drawing {name}: drag on canvas to create";
10420
10301
  readonly moreInsertElements: "More insert elements";
10302
+ readonly fromPlugin: "From {plugin}";
10421
10303
  readonly components: "Components";
10422
10304
  readonly openComponentLibrary: "Open Component Library";
10423
10305
  readonly componentLibrary: "Component Library";
@@ -10864,6 +10746,10 @@ declare const en: {
10864
10746
  readonly title: "Voice fade";
10865
10747
  readonly description: "How long the fade lasts. Only used when the clip fades out.";
10866
10748
  };
10749
+ readonly muteOnWindowBlur: {
10750
+ readonly title: "Mute when unfocused";
10751
+ readonly description: "Silences the game while another window is in front.";
10752
+ };
10867
10753
  };
10868
10754
  readonly audio: {
10869
10755
  readonly add: "Add track";
@@ -10946,8 +10832,8 @@ declare const en: {
10946
10832
  readonly sidecarNote: "A program a plugin ships runs outside the game process and is not covered by the allowlist.";
10947
10833
  };
10948
10834
  readonly encryptAssetsTitle: "Encrypt assets";
10949
- readonly encryptAssetsDescription: "Encrypt assets, plugin code and the story bundle in packaged and previewed builds. Does not affect Dev Mode.";
10950
- readonly encryptAssetsWebHint: "Web builds always ship without asset protection.";
10835
+ readonly encryptAssetsDescription: "Encrypt assets, plugin code and the story bundle in packaged and previewed desktop builds. Does not affect Dev Mode.";
10836
+ readonly encryptAssetsWebHint: "Web, Android and iOS builds always ship without asset protection.";
10951
10837
  readonly signingDescription: "Which credential signs each platform. Certificates and passwords stay on this machine; the project stores only which one to use.";
10952
10838
  readonly imageModeTitle: "Image compression settings";
10953
10839
  readonly imageWebpQualityTitle: "WebP quality";
@@ -11022,7 +10908,7 @@ declare const en: {
11022
10908
  readonly scanning: "Scanning project\u2026";
11023
10909
  readonly empty: "No plugin dependencies.";
11024
10910
  readonly banner: {
11025
- readonly blocked: "Some plugins are disabled. Their installed version is incompatible. Update or reinstall them.";
10911
+ readonly blocked: "Some plugins are not loaded for this project. Their installed version is incompatible. Update or reinstall them.";
11026
10912
  readonly warnings: "A plugin is outdated, or an optional dependency is unavailable.";
11027
10913
  };
11028
10914
  readonly status: {
@@ -11031,6 +10917,7 @@ declare const en: {
11031
10917
  readonly missing: "Missing";
11032
10918
  readonly incompatible: "Incompatible";
11033
10919
  readonly disabled: "Disabled";
10920
+ readonly suppressed: "Off for this project";
11034
10921
  };
11035
10922
  readonly meta: {
11036
10923
  readonly requires: "Requires {version}";
@@ -11207,6 +11094,9 @@ declare const en: {
11207
11094
  readonly runAs: "Run as";
11208
11095
  readonly runWithDlc: "Run with DLC";
11209
11096
  readonly dlcCount: "{active} of {total}";
11097
+ readonly previewAsShipped: "Preview as shipped";
11098
+ readonly previewAsShippedDetail: "Preview runs the protected form players receive, and takes longer to start.";
11099
+ readonly asShipped: "As shipped";
11210
11100
  readonly resetData: "Reset player data";
11211
11101
  readonly resetWhileRunning: "Stop it to reset its data";
11212
11102
  readonly resetDevModeConfirm: "Reset Dev Mode player data?";
@@ -11463,6 +11353,11 @@ declare const en: {
11463
11353
  readonly atLine: "Line {line} \u00B7 {scene}";
11464
11354
  readonly inScene: "In {scene}";
11465
11355
  readonly onSurface: "On {surface}";
11356
+ readonly onPlugin: "Plugin {plugin}";
11357
+ readonly pluginNotDeclared: "{plugin} is installed but not among this project's plugin dependencies. It does not run in this session and is not included in a build. Rescan them in Project \u25B8 App.";
11358
+ readonly pluginUnusable: "{plugin} is among this project's plugin dependencies and cannot be loaded. It does not run in this session and is not included in a build. Check its status in Project \u25B8 App.";
11359
+ readonly pluginEntryFailed: "{plugin} failed to load: {error}. Its blueprint nodes and widgets are not registered in this session.";
11360
+ readonly pluginListFailed: "The runtime plugin list could not be read: {error}. No plugin runs in this session.";
11466
11361
  readonly noLocation: "Could not be traced to a line";
11467
11362
  readonly viaPlayHead: "where playback was";
11468
11363
  readonly stack: "Stack";
@@ -11586,6 +11481,11 @@ declare const en: {
11586
11481
  readonly openWorkspace: "Workspace";
11587
11482
  readonly cannotOpen: "This blueprint cannot be opened from preview.";
11588
11483
  readonly openFailed: "Unable to open blueprint.";
11484
+ readonly scriptLoaded: "Loaded";
11485
+ readonly scriptNotLoaded: "Not loaded";
11486
+ readonly scriptExports: "Exports: {names}";
11487
+ readonly scriptCalls: "Called here: {names}";
11488
+ readonly scriptExportsNone: "Exports nothing";
11589
11489
  };
11590
11490
  readonly output: {
11591
11491
  readonly logLevel: "Log Level";
@@ -11701,6 +11601,7 @@ declare const en: {
11701
11601
  readonly locale: "Read the game language and the project's localized text";
11702
11602
  readonly menu: "Provide the game's menu bar";
11703
11603
  readonly storyCompile: "Take part in compiling stories, and add actions to lines it did not write";
11604
+ readonly diagnostics: "Read how much memory the game\u2019s caches are using";
11704
11605
  };
11705
11606
  };
11706
11607
  readonly button: {
@@ -11730,6 +11631,18 @@ declare const en: {
11730
11631
  readonly trust: "This authority was not trusted.";
11731
11632
  };
11732
11633
  };
11634
+ readonly projectTrust: {
11635
+ readonly window: "Project Trust";
11636
+ readonly title: "Trust this project?";
11637
+ readonly untrusted: "Studio did not create this project. Until it is trusted, it can be edited but not run, previewed, built or tested.";
11638
+ readonly meaning: "Once trusted, the code this project ships runs on this machine.";
11639
+ readonly later: "This can be changed under Trusted projects in Settings.";
11640
+ readonly confirm: "Trust";
11641
+ readonly cancel: "Not now";
11642
+ readonly error: {
11643
+ readonly load: "The project details could not be read.";
11644
+ };
11645
+ };
11733
11646
  readonly plugins: {
11734
11647
  readonly installLocal: "Install from folder";
11735
11648
  readonly search: {
@@ -11800,6 +11713,25 @@ declare const en: {
11800
11713
  readonly registry: "Failed to reach the plugin registry";
11801
11714
  readonly download: "Failed to download plugin";
11802
11715
  };
11716
+ readonly dependencies: {
11717
+ readonly title: "Project dependencies";
11718
+ readonly unavailable: {
11719
+ readonly one: "{count} plugin this project needs is not available.";
11720
+ readonly other: "{count} plugins this project needs are not available.";
11721
+ };
11722
+ readonly allReady: "Every plugin this project needs is available.";
11723
+ readonly open: "Open dependencies";
11724
+ readonly installAll: "Install all";
11725
+ readonly updated: "Updated";
11726
+ readonly authorized: "Authorized";
11727
+ readonly notInRegistry: "Not in the registry";
11728
+ readonly noCompatibleVersion: "No compatible version";
11729
+ readonly task: {
11730
+ readonly running: "Installing dependencies\u2026";
11731
+ readonly done: "Dependencies installed.";
11732
+ readonly partial: "Some plugins were not installed.";
11733
+ };
11734
+ };
11803
11735
  readonly workspace: {
11804
11736
  readonly reload: "Reload in this workspace";
11805
11737
  readonly activity: {
@@ -11811,7 +11743,6 @@ declare const en: {
11811
11743
  readonly suppressedHint: "The installed version is incompatible with the one this project was authored against. Update it, or update the project's dependency table from Project \u25B8 App.";
11812
11744
  readonly failed: "Failed to load";
11813
11745
  };
11814
- readonly suppressedNotice: "Not loaded for this project: {names}. The installed version is incompatible with the one the project was authored against. See the Plugins panel.";
11815
11746
  readonly pendingReopen: "Takes effect the next time this project opens.";
11816
11747
  readonly restartHint: "Some plugin changes take effect only after the workspace is restarted.";
11817
11748
  readonly restart: "Restart";
@@ -12135,6 +12066,7 @@ declare const en: {
12135
12066
  readonly output: "Choose where to write the file.";
12136
12067
  readonly reading: "Reading the build folder.";
12137
12068
  readonly artifact: "That folder holds no build of this game.";
12069
+ readonly artifactAccess: "Choose that folder with Browse to read it.";
12138
12070
  readonly dlcBaseline: "Select the build this DLC adds to.";
12139
12071
  readonly dlcVariant: "That build is not the variant this DLC attaches to.";
12140
12072
  };
@@ -12249,6 +12181,7 @@ declare const en: {
12249
12181
  readonly "sidecar-crossbuild-exec-bit": string;
12250
12182
  readonly "encryption-key-unavailable": "Asset protection is on, but its key could not be read.";
12251
12183
  readonly "web-unprotected": "Asset protection does not apply to the web export; its files ship unprotected.";
12184
+ readonly "mobile-unprotected": "Asset protection does not apply to Android or iOS packages.";
12252
12185
  readonly "progress-carry-unsupported": string;
12253
12186
  readonly "lossy-images": "Images are re-encoded at quality {setting} and lose detail permanently.";
12254
12187
  readonly "lossy-audio": "Audio is re-encoded at {setting} kbit/s and loses detail permanently.";
@@ -12323,6 +12256,7 @@ declare const en: {
12323
12256
  readonly showAll: "Show all {count}";
12324
12257
  readonly failure: "Reason";
12325
12258
  };
12259
+ readonly cancelled: "Build stopped";
12326
12260
  readonly invalidCommand: "Invalid command in {story} / {scene}: {source}";
12327
12261
  readonly invalidCommandSummary: {
12328
12262
  readonly one: "Build stopped: {count} invalid command. See the console.";
@@ -12346,7 +12280,7 @@ declare const en: {
12346
12280
  readonly other: "Build stopped: {count} cut points are not at the top level of their scene. See the console.";
12347
12281
  };
12348
12282
  readonly contentBlockedStartStory: "A Start Game node in {location} picks its scene while the game runs. Pick the scene in the inspector, or list the scenes it can start in the {variant} variant.";
12349
- readonly contentBlockedScript: "The blueprint {location} is written in TypeScript and can start any scene. List the scenes it can start in the {variant} variant.";
12283
+ readonly contentBlockedScript: "The script {location} can start any scene. List the scenes it can start in the {variant} variant.";
12350
12284
  readonly contentBlockedPlugin: "The {location} plugin can start any scene. List the scenes it can start in the {variant} variant.";
12351
12285
  readonly contentBlockedSummary: {
12352
12286
  readonly one: "Build stopped: {count} place can start a scene the {variant} build cannot read. See the console.";
@@ -12377,6 +12311,7 @@ declare const en: {
12377
12311
  };
12378
12312
  readonly networkNodeDisallowed: "{blueprint} makes a network request, which this project does not allow.";
12379
12313
  readonly pointerNodeUnsupported: "{blueprint} moves the mouse cursor, which does not work on {platforms}.";
12314
+ readonly screenshotNodeUnsupported: "{blueprint} saves screenshots, which does not work on {platforms}.";
12380
12315
  readonly networkSummary: {
12381
12316
  readonly one: "Build stopped: {count} network node cannot run. Change the network policy in project settings, or remove the node.";
12382
12317
  readonly other: "Build stopped: {count} network nodes cannot run. Change the network policy in project settings, or remove the nodes.";
@@ -12569,6 +12504,10 @@ declare const en: {
12569
12504
  readonly description: "A network node in a project whose network policy is off";
12570
12505
  readonly message: "{blueprint} makes a network request, which this project does not allow";
12571
12506
  };
12507
+ readonly storyUnreadable: {
12508
+ readonly title: "Unreadable story";
12509
+ readonly description: "A story document this Studio cannot open";
12510
+ };
12572
12511
  readonly storyInvalidCommand: {
12573
12512
  readonly title: "Invalid command";
12574
12513
  readonly description: "A row the compiler refuses";
@@ -12677,6 +12616,11 @@ declare const en: {
12677
12616
  readonly description: "A row naming a transition this version cannot play";
12678
12617
  readonly message: "The transition {transition} is not available, so this change plays as a cut";
12679
12618
  };
12619
+ readonly storyBackgroundUnchanged: {
12620
+ readonly title: "Unchanged background";
12621
+ readonly description: "A row transitioning to the background already on screen";
12622
+ readonly message: "This background is already on screen, so the transition changes nothing";
12623
+ };
12680
12624
  readonly blueprintReferenceMissing: {
12681
12625
  readonly title: "Missing target";
12682
12626
  readonly description: "A node naming something the project no longer has";
@@ -12737,6 +12681,11 @@ declare const en: {
12737
12681
  readonly description: "A clickable widget nothing listens to";
12738
12682
  readonly message: "Nothing runs when this is clicked";
12739
12683
  };
12684
+ readonly uiUnknownWidget: {
12685
+ readonly title: "Unknown widget type";
12686
+ readonly description: "A widget whose type the project cannot load";
12687
+ readonly message: "{type} is not loaded, so this widget will not be drawn in the game";
12688
+ };
12740
12689
  readonly uiComponentMissing: {
12741
12690
  readonly title: "Missing component";
12742
12691
  readonly description: "An instance of a component the project does not have";
@@ -12762,6 +12711,11 @@ declare const en: {
12762
12711
  readonly description: "A Save Game node that will run with a declared save field left empty";
12763
12712
  readonly message: "{field} is empty, so this save is written with its default instead";
12764
12713
  };
12714
+ readonly blueprintRequiredInputUnwired: {
12715
+ readonly title: "Empty input";
12716
+ readonly description: "A node that will run with a required input left unconnected";
12717
+ readonly message: "{node} has nothing connected to {pin}";
12718
+ };
12765
12719
  readonly blueprintStartSceneForeign: {
12766
12720
  readonly title: "Scene from another story";
12767
12721
  readonly description: "A Start Game node whose scene is not in the story it names";
@@ -12870,6 +12824,8 @@ declare const en: {
12870
12824
  readonly message: {
12871
12825
  readonly ruleFailed: "{rule} could not run";
12872
12826
  readonly storyLoadFailed: "{story} could not be opened";
12827
+ readonly storyTooOld: "{story} is in story format v{version}, and this Studio opens v{minimum} and later";
12828
+ readonly storyTooNew: "{story} was written by a newer NarraLeaf Studio (story format v{version}); this Studio reads up to v{supported}";
12873
12829
  };
12874
12830
  readonly category: {
12875
12831
  readonly assets: "Assets";
@@ -12918,6 +12874,7 @@ declare const en: {
12918
12874
  readonly finding: "{location} {message} ({rule})";
12919
12875
  };
12920
12876
  readonly build: {
12877
+ readonly started: "Checking the project\u2026";
12921
12878
  readonly blocked: "Build stopped by {count} problems";
12922
12879
  readonly blockedHint: "Change this in Project \u25B8 Project \u25B8 Check before building";
12923
12880
  readonly skipped: "Project check skipped";
@@ -13115,7 +13072,10 @@ declare const en: {
13115
13072
  readonly blueprintRemoved: "Blueprint removed ({nodes} nodes)";
13116
13073
  readonly blueprintChanged: "Blueprint changed";
13117
13074
  readonly blueprintRenamed: "Renamed";
13118
- readonly blueprintSource: "Code changed";
13075
+ readonly blueprintSource: "Script file changed";
13076
+ readonly scriptAdded: "Script added";
13077
+ readonly scriptRemoved: "Script removed";
13078
+ readonly scriptChanged: "Script changed";
13119
13079
  readonly blueprintField: "{field} changed";
13120
13080
  readonly graphAdded: "Graph added ({nodes} nodes)";
13121
13081
  readonly graphRemoved: "Graph removed ({nodes} nodes)";
@@ -13379,7 +13339,6 @@ declare const en: {
13379
13339
  readonly animation: "Motion";
13380
13340
  readonly uiDocument: "Interface pages";
13381
13341
  readonly uiGraphs: "Interface blueprints";
13382
- readonly blueprint: "Blueprint";
13383
13342
  readonly variables: "Variables";
13384
13343
  readonly audioTracks: "Audio tracks";
13385
13344
  readonly brand: "Brand palette";
@@ -13601,6 +13560,7 @@ declare const en: {
13601
13560
  readonly durationMinutes: "{minutes}m {seconds}s";
13602
13561
  };
13603
13562
  readonly reason: {
13563
+ readonly distrusted: "Not available until this project is trusted in Settings";
13604
13564
  readonly frozen: "Not available while the workspace is frozen";
13605
13565
  readonly alreadyRunning: "Another run is in progress";
13606
13566
  readonly parameterEmpty: "{parameter} has no values in this project";
@@ -13813,6 +13773,10 @@ declare const en: {
13813
13773
  readonly title: "Assets";
13814
13774
  readonly body: string;
13815
13775
  };
13776
+ readonly assetSources: {
13777
+ readonly title: "Where an asset's file comes from";
13778
+ readonly body: string;
13779
+ };
13816
13780
  readonly assetSets: {
13817
13781
  readonly title: "Asset sets";
13818
13782
  readonly body: string;
@@ -13885,6 +13849,10 @@ declare const en: {
13885
13849
  readonly title: "Blueprints";
13886
13850
  readonly body: string;
13887
13851
  };
13852
+ readonly scripts: {
13853
+ readonly title: "Scripts";
13854
+ readonly body: string;
13855
+ };
13888
13856
  readonly uiBindings: {
13889
13857
  readonly title: "Values on a screen";
13890
13858
  readonly body: string;
@@ -14174,7 +14142,10 @@ declare const en: {
14174
14142
  readonly copyDetails: "Copy details";
14175
14143
  readonly copied: "Copied to the clipboard.";
14176
14144
  readonly copyFailed: "Could not copy: {error}";
14177
- readonly logAt: "The report is in {path}";
14145
+ readonly saveReport: "Save report";
14146
+ readonly reportSaved: "The report is in {path}";
14147
+ readonly reportFailed: "Could not save the report: {error}";
14148
+ readonly logAt: "The log is in {path}";
14178
14149
  readonly bridgeUnavailable: "The game's runtime bridge did not load";
14179
14150
  };
14180
14151
  readonly session: {
@@ -14224,6 +14195,30 @@ declare const en: {
14224
14195
  readonly quit: "Quit";
14225
14196
  };
14226
14197
  };
14198
+ readonly documents: {
14199
+ readonly tooNew: {
14200
+ readonly message: "{subject} was written by a newer NarraLeaf Studio ({kind} format v{version}); this build reads up to v{supported}";
14201
+ readonly kind: {
14202
+ readonly story: "story";
14203
+ readonly storyIndex: "story library";
14204
+ readonly storyAnimation: "animation";
14205
+ readonly uiDocument: "interface";
14206
+ readonly uiGraphs: "interface blueprint";
14207
+ readonly blueprints: "blueprint";
14208
+ readonly variables: "variable";
14209
+ readonly saveSchema: "save schema";
14210
+ readonly localization: "translation";
14211
+ readonly localizationKeys: "translation key";
14212
+ readonly voice: "voice";
14213
+ readonly brand: "design";
14214
+ readonly appTags: "variant";
14215
+ readonly dlc: "DLC";
14216
+ readonly assetSets: "asset set";
14217
+ readonly audioTracks: "audio track";
14218
+ readonly characters: "character";
14219
+ };
14220
+ };
14221
+ };
14227
14222
  };
14228
14223
  type Messages = typeof en;
14229
14224
  type Flatten<T, Prefix extends string = ""> = {
@@ -14317,7 +14312,6 @@ declare function createBoundPrivilegedFacade(token: PrivilegedFacadeToken): {
14317
14312
  ensureRegularFile: (path: string, data: string, encoding?: BufferEncoding) => Promise<RequestStatus<FsRequestResult<void>>>;
14318
14313
  writeFileNoFollow: (path: string, data: string, encoding?: BufferEncoding) => Promise<RequestStatus<FsRequestResult<void>>>;
14319
14314
  writeFileNoFollowOrCreate: (path: string, data: string, encoding?: BufferEncoding) => Promise<RequestStatus<FsRequestResult<void>>>;
14320
- recoverCorruptedJsonFile: (path: string, replacement: string, encoding?: BufferEncoding) => Promise<RequestStatus<FsRequestResult<void>>>;
14321
14315
  createDir: (path: string) => Promise<RequestStatus<FsRequestResult<void>>>;
14322
14316
  deleteFile: (path: string) => Promise<RequestStatus<FsRequestResult<void>>>;
14323
14317
  deleteDir: (path: string) => Promise<RequestStatus<FsRequestResult<void>>>;
@@ -14487,8 +14481,6 @@ export declare enum AssetType {
14487
14481
  Audio = "audio",
14488
14482
  Video = "video",
14489
14483
  JSON = "json",
14490
- /** Shared blueprint asset (M2); content is {@link import("@shared/types/blueprint/document").SharedBlueprintAsset} JSON */
14491
- Blueprint = "blueprint",
14492
14484
  Font = "font",
14493
14485
  /**
14494
14486
  * A **model bundle**: many files that form one authored thing (a Live2D or Spine character),
@@ -14537,12 +14529,6 @@ type JSONAssetMetadata = {
14537
14529
  isValid: boolean;
14538
14530
  schema?: string;
14539
14531
  };
14540
- type BlueprintAssetMetadata = {
14541
- size: number;
14542
- isValid: boolean;
14543
- /** Logical schema version of the on-disk JSON wrapper; not the instance BlueprintDocument schema */
14544
- schemaVersion?: number;
14545
- };
14546
14532
  type FontAssetMetadata = {
14547
14533
  family?: string;
14548
14534
  style?: string;
@@ -14592,9 +14578,6 @@ export type AssetData<Type extends AssetType> = Type extends AssetType.Image ? {
14592
14578
  } : Type extends AssetType.JSON ? {
14593
14579
  data: Record<string, any>;
14594
14580
  metadata: JSONAssetMetadata;
14595
- } : Type extends AssetType.Blueprint ? {
14596
- data: SharedBlueprintAsset;
14597
- metadata: BlueprintAssetMetadata;
14598
14581
  } : Type extends AssetType.Font ? {
14599
14582
  data: Uint8Array;
14600
14583
  metadata: FontAssetMetadata;
@@ -14625,7 +14608,6 @@ export declare const AssetExtensions: {
14625
14608
  audio: string[];
14626
14609
  video: string[];
14627
14610
  json: string[];
14628
- blueprint: string[];
14629
14611
  font: string[];
14630
14612
  /**
14631
14613
  * A model bundle is picked as a *directory*, not by extension, so this list is never handed to a
@@ -14636,26 +14618,6 @@ export declare const AssetExtensions: {
14636
14618
  model: string[];
14637
14619
  other: string[];
14638
14620
  };
14639
- type BlueprintVector2D = {
14640
- x: number;
14641
- y: number;
14642
- };
14643
- type BlueprintRect = {
14644
- x: number;
14645
- y: number;
14646
- width: number;
14647
- height: number;
14648
- };
14649
- type BlueprintRGBAColor = {
14650
- r: number;
14651
- g: number;
14652
- b: number;
14653
- a: number;
14654
- };
14655
- type BlueprintImageAsset = {
14656
- kind: "imageAsset";
14657
- assetId: string;
14658
- };
14659
14621
  type BlueprintAssetPinKind = "image" | "audio" | "font";
14660
14622
  type BlueprintAssetPinRef = {
14661
14623
  kind: BlueprintAssetPinKind;
@@ -14674,10 +14636,6 @@ type BlueprintAssetPinRef = {
14674
14636
  */
14675
14637
  origin?: "stored" | "published";
14676
14638
  };
14677
- type BlueprintSoundHandle = {
14678
- kind: "soundHandle";
14679
- id: string;
14680
- };
14681
14639
  interface ProjectProps {
14682
14640
  projectPath: string;
14683
14641
  }
@@ -14923,7 +14881,21 @@ export type TestAvailabilityContext = {
14923
14881
  * participant is the working tree, so a game launched from it runs what everybody is looking at
14924
14882
  * and there is nothing for the refusal to protect.
14925
14883
  */
14926
- readonly frozen: boolean;
14884
+ readonly frozen: boolean;
14885
+ /**
14886
+ * Whether this project is one Studio will not run anything for - it arrived from a package or a
14887
+ * remote source and nobody has vouched for it yet.
14888
+ *
14889
+ * Passed in for the reason above and one more of its own: the ledger that answers it lives in
14890
+ * the main process, so asking costs a round trip, and everything here is synchronous. The host
14891
+ * settles the answer when the workspace comes up and hands the settled copy down.
14892
+ *
14893
+ * `checkAvailability` will not normally see this true - the host refuses every test before it
14894
+ * asks a definition anything, because a run is an execution of the project. It is here because
14895
+ * `options` is *not* gated: a list that would cost real work to build can decline to build it
14896
+ * for a project that cannot run it.
14897
+ */
14898
+ readonly distrusted: boolean;
14927
14899
  };
14928
14900
  export type TestAvailability = {
14929
14901
  available: true;
@@ -15010,7 +14982,8 @@ export type TestDefinition = {
15010
14982
  /**
15011
14983
  * Evaluated when the picker opens, so keep it synchronous and cheap. Absent means always
15012
14984
  * available; the host still applies its own gates (a `windowed` test is unavailable while the
15013
- * workspace is frozen no matter what this returns).
14985
+ * workspace is frozen, and no test runs at all in a project that is not trusted, no matter what
14986
+ * this returns).
15014
14987
  */
15015
14988
  checkAvailability?(ctx: TestAvailabilityContext): TestAvailability;
15016
14989
  run(ctx: TestRunContext): Promise<TestVerdict> | TestVerdict;
@@ -15214,6 +15187,26 @@ interface CharacterEditorProfile extends CharacterBaseProfile {
15214
15187
  * survives a kind switch, which discards everything the kinds do not share.
15215
15188
  */
15216
15189
  voiceTrackId?: string | null;
15190
+ /**
15191
+ * The transform props this character's `enter` rows fall back to, channel by channel.
15192
+ *
15193
+ * How big a sprite is drawn, which way it faces and where its feet land are properties of the
15194
+ * artwork, not of the line that brings it on: the numbers come from the picture's pixel size
15195
+ * against the stage's, so an author who has to state them on every entrance is copying one
15196
+ * answer down the whole script. Absent means what it always meant - an entrance states
15197
+ * everything or takes the stage's own values.
15198
+ *
15199
+ * A row still wins on any channel it names, and only on that channel; see
15200
+ * `@shared/story/characterEntrance` for the merge, which channels a default may carry, and why
15201
+ * `move` and `exit` do not inherit.
15202
+ *
15203
+ * On the profile rather than the appearance because a kind switch discards everything the kinds
15204
+ * do not share, and a character is the same size on stage whichever way she is drawn.
15205
+ *
15206
+ * Additive: no character written before this carries one, so no schema bump - the same terms
15207
+ * `voiceTrackId` was added on.
15208
+ */
15209
+ entranceTransform?: StoryTransformProps;
15217
15210
  }
15218
15211
  interface CharacterNamed {
15219
15212
  readonly id: string;
@@ -15601,6 +15594,18 @@ declare class CharacterProfile {
15601
15594
  */
15602
15595
  getVoiceTrackId(): string | null;
15603
15596
  setVoiceTrackId(trackId: string | null): void;
15597
+ /**
15598
+ * The transform props this character's entrances fall back to. `undefined` is "no defaults",
15599
+ * which is what every character had before the field existed.
15600
+ */
15601
+ getEntranceTransform(): StoryTransformProps | undefined;
15602
+ /**
15603
+ * Stored sanitized, so what the compiler reads back is what this setter accepted - a bag holding
15604
+ * only channels an entrance can act on. An empty bag is stored as no bag at all: "states
15605
+ * nothing" and "has no defaults" are the same instruction here, and keeping the empty record
15606
+ * would leave a key in the document that no longer means anything.
15607
+ */
15608
+ setEntranceTransform(props: StoryTransformProps | undefined): void;
15604
15609
  getNicknames(): string[];
15605
15610
  addNickname(nickname: string): void;
15606
15611
  removeNickname(nickname: string): void;
@@ -15666,33 +15671,6 @@ type UIElementSelection = {
15666
15671
  elementIds: UIElementId[];
15667
15672
  primaryId?: UIElementId;
15668
15673
  };
15669
- type GradientKind = "linear" | "radial" | "conic";
15670
- interface GradientStop {
15671
- /** 0..1 along the gradient line. */
15672
- offset: number;
15673
- /**
15674
- * A stored colour string: a literal, or `nlbrand:<id>[/<alpha>]`. Deliberately unresolved - see
15675
- * the file comment.
15676
- */
15677
- color: string;
15678
- }
15679
- interface GradientFill {
15680
- kind: GradientKind;
15681
- /** Normalised to two or more, sorted by offset, offsets clamped to 0..1. */
15682
- stops: GradientStop[];
15683
- /** Linear and conic. Degrees, CSS convention: 0 points to the top, 90 to the right. */
15684
- angle?: number;
15685
- /** Radial and conic. 0..1 of the painted box. */
15686
- center?: {
15687
- x: number;
15688
- y: number;
15689
- };
15690
- /** Radial. 0..1 of the painted box, one radius per axis. */
15691
- radius?: {
15692
- x: number;
15693
- y: number;
15694
- };
15695
- }
15696
15674
  type ImageFillMode = "cover" | "contain" | "stretch" | "crop" | "tile";
15697
15675
  interface ImageFillCropPlacement {
15698
15676
  leftPct: number;
@@ -15727,980 +15705,11 @@ type UIListItemScope = {
15727
15705
  */
15728
15706
  struct?: UIStructDef | null;
15729
15707
  };
15730
- type UIListScrollMetrics = {
15731
- offset: number;
15732
- maxOffset: number;
15733
- progress: number;
15734
- };
15735
- declare const BLUEPRINT_HOST_API_CONTRACT_VERSION: 39;
15736
- type BlueprintHostApiContractVersion = typeof BLUEPRINT_HOST_API_CONTRACT_VERSION;
15737
- type BlueprintCharacterInfo = {
15738
- id: string;
15739
- /** Author-facing display name. Empty when the character is unnamed - never falls back to `id`, which is a UUID. */
15740
- name: string;
15741
- /**
15742
- * The author's accent colour, already in pin shape. Null when the character has no colour set,
15743
- * which is a different thing from "white" - see {@link blueprintCharacterColorOrDefault} for
15744
- * what a non-nullable colour pin does with it.
15745
- */
15746
- color: BlueprintRGBAColor | null;
15747
- /** The character's default dialog avatar, or null when it has none. */
15748
- avatar: BlueprintImageAsset | null;
15749
- };
15750
- type AppearanceSystemCondition = Partial<{
15751
- hovered: boolean;
15752
- active: boolean;
15753
- disabled: boolean;
15754
- focused: boolean;
15755
- /** Inside the row a list has selected. */
15756
- selected: boolean;
15757
- }>;
15758
- type AppearanceRowValue = string | number | boolean | null | ImageFill | GradientFill | Record<string, unknown>;
15759
- type AppearanceValueRow = {
15760
- conditions?: AppearanceSystemCondition | null;
15761
- value: AppearanceRowValue;
15762
- };
15763
- type AppearanceTransitionTweenEasing = "linear" | "easeIn" | "easeOut" | "easeInOut" | "circIn" | "circOut" | "circInOut";
15764
- type AppearanceFieldTransition = {
15765
- type: "tween";
15766
- durationMs: number;
15767
- delayMs?: number;
15768
- easing: AppearanceTransitionTweenEasing;
15769
- } | {
15770
- type: "spring";
15771
- delayMs?: number;
15772
- stiffness: number;
15773
- damping: number;
15774
- mass: number;
15775
- };
15776
- type ContainerAppearancePropertyKey = "backgroundColor" | "borderRadius" | "borderRadiusTL" | "borderRadiusTR" | "borderRadiusBL" | "borderRadiusBR" | "borderRadiusLinked" | "borderColor" | "borderWidth" | "borderStyle" | "backgroundImage" | "backgroundFit" | "imageFill" | "gradientFill" | "fillType" | "fillVisible" | "fillOpacity" | "strokeVisible" | "strokeOpacity" | "strokeAlign" | "strokeSide" | "borderJoin" | "cornerAdvanced" | "transformOffsetX" | "transformOffsetY" | "transformScale" | "transformRotation" | "transformOpacity" | "effectBlur" | "effectBackgroundBlur" | "effectShadow" | "effectInnerShadow" | "effectBlend" | "effectGlow" | "effectFilter";
15777
- declare const BUTTON_CURSOR_VALUES: readonly [
15778
- "auto",
15779
- "default",
15780
- "pointer",
15781
- "text",
15782
- "move",
15783
- "grab",
15784
- "grabbing",
15785
- "crosshair",
15786
- "help",
15787
- "wait",
15788
- "progress",
15789
- "not-allowed"
15790
- ];
15791
- type ButtonCursorValue = (typeof BUTTON_CURSOR_VALUES)[number];
15792
- type ButtonAppearancePropertyKey = "fontAssetId" | "fontSize" | "fontWeight" | "color" | "lineHeight" | "backgroundColor" | "fillType" | "fillOpacity" | "fillVisible" | "imageFill" | "gradientFill" | "backgroundImage" | "backgroundFit" | "borderRadius" | "borderWidth" | "borderColor" | "borderStyle" | "strokeOpacity" | "strokeSide" | "borderJoin" | "strokeAlign" | "paddingX" | "paddingY" | "clipContent" | "cursor" | "transformOffsetX" | "transformOffsetY" | "transformScale" | "transformRotation" | "transformOpacity" | "effectBlur" | "effectBackgroundBlur" | "effectShadow" | "effectTextShadow" | "effectInnerShadow" | "effectBlend" | "effectGlow" | "effectFilter";
15793
- type TextAppearancePropertyKey = "fontAssetId" | "fontSize" | "fontWeight" | "fontStyle" | "color" | "lineHeight" | "transformOffsetX" | "transformOffsetY" | "transformScale" | "transformRotation" | "transformOpacity" | "effectBlur" | "effectTextShadow" | "effectBlend" | "effectFilter";
15794
- type AppearancePropertyGroup = {
15795
- key: ContainerAppearancePropertyKey;
15796
- rows: AppearanceValueRow[];
15797
- transition?: AppearanceFieldTransition | null;
15798
- } | {
15799
- key: ButtonAppearancePropertyKey;
15800
- rows: AppearanceValueRow[];
15801
- transition?: AppearanceFieldTransition | null;
15802
- } | {
15803
- key: TextAppearancePropertyKey;
15804
- rows: AppearanceValueRow[];
15805
- transition?: AppearanceFieldTransition | null;
15806
- };
15807
- type AppearanceVariant = {
15808
- id: string;
15809
- name: string;
15810
- propertyGroups: AppearancePropertyGroup[];
15811
- };
15812
- type AppearanceModel = {
15813
- defaultVariantId: string;
15814
- variants: AppearanceVariant[];
15815
- };
15816
- type UISliderOrientation = "horizontal" | "vertical";
15817
- type UISliderWidgetProps = {
15818
- value: number;
15819
- min: number;
15820
- max: number;
15821
- step: number;
15822
- orientation: UISliderOrientation;
15823
- trackElementId?: string | null;
15824
- handleElementId?: string | null;
15825
- };
15826
- type UISliderRange = {
15827
- min: number;
15828
- max: number;
15829
- step: number;
15830
- };
15831
- type UISliderRuntimeValue = UISliderRange & {
15832
- value: number;
15833
- normalizedValue: number;
15834
- };
15835
- type UISwitchWidgetProps = {
15836
- /** The author's starting state. What the player toggles lives in WidgetRuntimeStateStore. */
15837
- checked: boolean;
15838
- /** Blocks pointer and keyboard toggling. Looks are the `disabled` appearance signal's job. */
15839
- interactionDisabled: boolean;
15840
- trackElementId?: string | null;
15841
- thumbElementId?: string | null;
15842
- };
15843
- type UISwitchRuntimeValue = {
15844
- checked: boolean;
15845
- };
15846
- type UITextInputMode = "text" | "password" | "number";
15847
- type UITextInputWidgetProps = {
15848
- value: string;
15849
- placeholder: string;
15850
- /** i18n attach-layer key for `placeholder`; player-facing text is never a Studio catalog key. */
15851
- placeholderLocalizationKey?: string | null;
15852
- inputMode: UITextInputMode;
15853
- /** 0 = unlimited. */
15854
- maxLength: number;
15855
- readOnly: boolean;
15856
- disabled: boolean;
15857
- textAlign: "left" | "center" | "right";
15858
- };
15859
- type UITextInputRuntimeValue = {
15860
- value: string;
15861
- /** Length in code points, so an emoji counts once - this is what `maxLength` is measured in. */
15862
- length: number;
15863
- };
15864
- type UIDisplayableMotionFromCurrentValue = {
15865
- from: "current";
15866
- to: number;
15867
- };
15868
- type UIDisplayableMotionValue = number | number[] | UIDisplayableMotionFromCurrentValue;
15869
- type UIDisplayableMotionTarget = {
15870
- x?: UIDisplayableMotionValue;
15871
- y?: UIDisplayableMotionValue;
15872
- scale?: UIDisplayableMotionValue;
15873
- rotate?: UIDisplayableMotionValue;
15874
- opacity?: UIDisplayableMotionValue;
15875
- };
15876
- type UIDisplayableMotionTransition = {
15877
- type: "tween";
15878
- durationMs: number;
15879
- delayMs?: number;
15880
- easing?: string;
15881
- } | {
15882
- type: "spring";
15883
- delayMs?: number;
15884
- stiffness: number;
15885
- damping: number;
15886
- mass: number;
15887
- };
15888
- type UIDisplayableMotionOverride = {
15889
- id: string;
15890
- target: UIDisplayableMotionTarget;
15891
- transition: UIDisplayableMotionTransition;
15892
- /** One-shot effects such as shake/pulse should hand control back to authored layout when finished. */
15893
- resetOnComplete?: boolean;
15894
- };
15895
- type TextWritingMode = NlrTextWritingMode;
15896
- type TextOrientation = TextGlyphOrientation;
15897
- type EffectShadowLayerData = {
15898
- offsetX: number;
15899
- offsetY: number;
15900
- blur: number;
15901
- spread: number;
15902
- color: string;
15903
- };
15904
- type FilterPresetId = "brightness" | "contrast" | "saturate" | "grayscale";
15905
- type EffectShadowLayer = EffectShadowLayerData;
15906
- type EffectShadowStored = {
15907
- storage: "layer";
15908
- layer: EffectShadowLayer;
15909
- } | {
15910
- storage: "css";
15911
- css: string;
15912
- };
15913
- type EffectFilterStored = {
15914
- storage: "preset";
15915
- preset: FilterPresetId;
15916
- amount: number;
15917
- } | {
15918
- storage: "css";
15919
- css: string;
15920
- };
15921
- type ElementEffectValues = {
15922
- effectBlur: number;
15923
- effectBackgroundBlur: number;
15924
- effectShadow: EffectShadowStored | null;
15925
- /** Text widgets: CSS text-shadow (separate from box-shadow `effectShadow`). */
15926
- effectTextShadow: EffectShadowStored | null;
15927
- effectInnerShadow: EffectShadowStored | null;
15928
- effectBlend: string;
15929
- effectGlow: EffectShadowStored | null;
15930
- effectFilter: EffectFilterStored | null;
15931
- };
15932
- type TextAlign = "left" | "center" | "right";
15933
- type TextVerticalAlign = "start" | "center" | "end";
15934
- type TextWrapMode = "word" | "character" | "nowrap";
15935
- type TextWidgetProps = {
15936
- text: string;
15937
- /** Game-localization opt-in: registers the implicit translation unit `ui:<elementId>.text`. */
15938
- localizable?: boolean;
15939
- /** Named localization key reference; takes precedence over the implicit unit. */
15940
- localizationKey?: string;
15941
- fontSize: number;
15942
- color: string;
15943
- fontWeight: "normal" | "bold" | "600";
15944
- fontStyle: "normal" | "italic";
15945
- textAlign: TextAlign;
15946
- textVerticalAlign: TextVerticalAlign;
15947
- lineHeight: number;
15948
- /** Project font asset id when using a custom typeface in the editor; null inherits canvas default */
15949
- fontAssetId: string | null;
15950
- textWrapMode: TextWrapMode;
15951
- /**
15952
- * Shrink the rendered text until it fits the element's box.
15953
- *
15954
- * The authored `fontSize` becomes a ceiling rather than a fixed value: the text is never set
15955
- * larger than it, and never smaller than {@link TextWidgetProps.textAutoFitMinFontSize}. A line
15956
- * that still does not fit at the floor is clipped, which is what every line does today.
15957
- */
15958
- textAutoFit: boolean;
15959
- /** Smallest size auto fit may set, in px. */
15960
- textAutoFitMinFontSize: number;
15961
- /** Block flow. `horizontal-tb` leaves every other vertical setting inert. */
15962
- writingMode: TextWritingMode;
15963
- textOrientation: TextOrientation;
15964
- /**
15965
- * 縦中横: sets a short Latin or digit run upright across the column instead of on its side,
15966
- * the way a Japanese novel sets a two-digit number. Only read while writing vertically.
15967
- */
15968
- tateChuYoko: boolean;
15969
- /** Longest run tate-chu-yoko combines, in characters. Two is the typographic convention. */
15970
- tateChuYokoMaxLength: number;
15971
- transformOffsetX: number;
15972
- transformOffsetY: number;
15973
- transformScale: number;
15974
- transformRotation: number;
15975
- transformOpacity: number;
15976
- /** Static baseline effects; appearance overlays may override per variant / state. */
15977
- effects: ElementEffectValues;
15978
- /** Optional variant + conditional row visuals; when absent, flat props are the sole source. */
15979
- appearance?: AppearanceModel | null;
15980
- };
15981
- type BlueprintPointerMoveOptions = {
15982
- durationSeconds?: number;
15983
- easing?: BlueprintPointerMoveEasing;
15984
- };
15985
- type BlueprintTextProperties = Pick<TextWidgetProps, "text" | "fontAssetId" | "fontSize" | "fontWeight" | "color" | "textAlign" | "textVerticalAlign" | "lineHeight" | "textWrapMode" | "effects">;
15986
- type BlueprintTextPropertiesPatch = Partial<BlueprintTextProperties>;
15987
- type BlueprintSliderProperties = UISliderRuntimeValue;
15988
- type BlueprintSliderPropertiesPatch = Partial<Pick<UISliderWidgetProps, "value" | "min" | "max" | "step">>;
15989
- type BlueprintSwitchProperties = UISwitchRuntimeValue;
15990
- type BlueprintSwitchPropertiesPatch = Partial<Pick<UISwitchWidgetProps, "checked">>;
15991
- type BlueprintTextInputProperties = UITextInputRuntimeValue;
15992
- type BlueprintTextInputPropertiesPatch = Partial<Pick<UITextInputWidgetProps, "value">>;
15993
- type BlueprintListProperties = {
15994
- items: unknown[];
15995
- selectedIndex: number;
15996
- /**
15997
- * The shape the list declares, or null when it declares none.
15998
- *
15999
- * Carried with the items rather than fetched separately, because every node that reads a field
16000
- * needs both and reading them apart is how the two drift: a graph that sorted by a field the
16001
- * list no longer declares would sort by nothing and report success.
16002
- */
16003
- struct: UIStructDef | null;
16004
- /**
16005
- * Where the list has got to along its axis, as it last measured itself.
16006
- *
16007
- * A list that has not been rendered - or has been rendered somewhere with no runtime store, like
16008
- * a Surface thumbnail - reports at-rest rather than nothing, so a graph asking gets the answer
16009
- * for a list that cannot scroll instead of an undefined it has no way to branch on.
16010
- */
16011
- scroll: UIListScrollMetrics;
16012
- };
16013
- type BlueprintDisplayableProperties = {
16014
- position: {
16015
- x: number;
16016
- y: number;
16017
- };
16018
- offset: {
16019
- x: number;
16020
- y: number;
16021
- };
16022
- /**
16023
- * The extent the widget covers, never negative. The authored layout may hold a negative width
16024
- * or height - that is how a widget dragged past its own origin is stored - and `position`
16025
- * already reports the true top-left, so reporting the raw sign here would have described a
16026
- * rectangle whose right edge sits left of its left edge.
16027
- */
16028
- size: {
16029
- width: number;
16030
- height: number;
16031
- };
16032
- bounds: BlueprintRect;
16033
- rotation: number;
16034
- opacity: number;
16035
- display: boolean;
16036
- visible: boolean;
16037
- };
16038
- type BlueprintDisplayablePropertiesPatch = Partial<{
16039
- x: number;
16040
- y: number;
16041
- offsetX: number;
16042
- offsetY: number;
16043
- width: number;
16044
- height: number;
16045
- rotation: number;
16046
- opacity: number;
16047
- display: boolean;
16048
- visible: boolean;
16049
- }>;
16050
- type BlueprintDisplayableMotionRequest = {
16051
- id?: string;
16052
- target: UIDisplayableMotionTarget;
16053
- transition: UIDisplayableMotionTransition;
16054
- resetOnComplete?: boolean;
16055
- commitLayoutOnComplete?: Partial<Pick<BlueprintDisplayablePropertiesPatch, "x" | "y">>;
16056
- };
16057
- type BlueprintWidgetCommonProperties = {
16058
- visible: boolean;
16059
- enabled: boolean;
16060
- variantId: string | null;
16061
- };
16062
- type BlueprintButtonProperties = {
16063
- label: string;
16064
- cursor: ButtonCursorValue;
16065
- };
16066
- type BlueprintContainerProperties = {
16067
- clipContent: boolean;
16068
- };
16069
- type BlueprintImageProperties = {
16070
- asset: BlueprintImageAsset | null;
16071
- /** Legacy patch/read alias kept so older saved graph nodes can still run. */
16072
- assetId: string | null;
16073
- fitMode: ImageFillMode;
16074
- cropRect: ImageFillCropPlacement;
16075
- flipX: boolean;
16076
- flipY: boolean;
16077
- };
16078
- type BlueprintFrameProperties = {
16079
- targetSurfaceId: string | null;
16080
- params: Record<string, unknown>;
16081
- };
16082
- type BlueprintGamePreferenceKey = "autoForward" | "skip"
16083
- /**
16084
- * Studio's own, not the engine's: skipping stops at a line the player has not read.
16085
- *
16086
- * It lives in the engine's preference store all the same (see `preferenceRuntime`), which is
16087
- * what lets it reach this API, the `gamePreferenceChanged` event and the project's preference
16088
- * defaults through exactly the same plumbing as the twelve the engine defines.
16089
- */
16090
- | "skipReadText"
16091
- /**
16092
- * Studio's own, and transient: the skip run is going. Writing it is the equivalent of holding
16093
- * the skip key, and the host clears it whenever the run ends - a guard stopping it, the game
16094
- * leaving the stage, the window losing focus. Never persisted (see `@shared/types/preference`).
16095
- */
16096
- | "skipping"
16097
- /**
16098
- * Studio's own: the engine keeps this in `game.config`, not in its preference store, so the
16099
- * host copies it across on every change (see `preferenceRuntime`).
16100
- */
16101
- | "autoForwardDelay" | "showDialog" | "gameSpeed" | "cps"
16102
- /** Milliseconds a newly typed character takes to fade in; `0` types it at full strength. */
16103
- | "textRevealDuration" | "voiceVolume" | "voiceFadeDuration" | "voiceEndMode" | "bgmVolume" | "soundVolume" | "globalVolume" | "skipDelay" | "skipInterval";
16104
- type BlueprintGamePreferenceVoiceEndMode = "fade" | "stop" | "none";
16105
- type BlueprintGamePreferenceValue = boolean | number | BlueprintGamePreferenceVoiceEndMode;
16106
- type BlueprintLayerShowOptions = {
16107
- /** Everything below goes inert and the keys belong to this layer. */
16108
- modal?: boolean;
16109
- /** Whether Go back closes it. Default true. */
16110
- dismissible?: boolean;
16111
- /** Mutual-exclusion group; a second layer of an occupied group queues behind the first. */
16112
- group?: string | null;
16113
- };
16114
- type BlueprintHostApiRuntime = {
16115
- navigation: {
16116
- openSurface: (surfaceId: string, props?: unknown) => Promise<void>;
16117
- getPageProps: () => Record<string, unknown>;
16118
- pageBack: () => Promise<void>;
16119
- clearPages: () => Promise<void>;
16120
- clearGameOverlay: () => Promise<void>;
16121
- quitApplication: () => Promise<void>;
16122
- getFullscreen: () => Promise<boolean>;
16123
- setFullscreen: (fullscreen: boolean) => Promise<void>;
16124
- /** The sizes worth offering, ascending. Empty where the shell has no window to size. */
16125
- getWindowScaleOptions: () => Promise<number[]>;
16126
- getWindowScale: () => Promise<number>;
16127
- setWindowScale: (scale: number) => Promise<void>;
16128
- getWindowSize: () => Promise<{
16129
- width: number;
16130
- height: number;
16131
- }>;
16132
- setWindowSize: (width: number, height: number) => Promise<void>;
16133
- /**
16134
- * Open one web address in the player's browser.
16135
- *
16136
- * The host does not decide: it hands the request to whatever the shell supplied, and the
16137
- * shell's own process checks it against the addresses the build declared. Nothing here
16138
- * consults the project's network setting, because no request is made - see
16139
- * `@shared/types/blueprint/externalLink`.
16140
- */
16141
- openExternal: (request: BlueprintOpenExternalRequest) => Promise<BlueprintOpenExternalResult>;
16142
- };
16143
- /** Surfaces stacked over the page lane. See the `layers` family in `@shared/types/blueprint/hostApi`. */
16144
- layers: {
16145
- /** Put a page up as a layer and return the handle that names it. */
16146
- show: (surfaceId: string, props?: unknown, options?: BlueprintLayerShowOptions) => Promise<string>;
16147
- /** Take that layer down, settling once it has finished animating out. */
16148
- hide: (handle: string) => Promise<void>;
16149
- /** Take a whole group down - what is on screen and what is queued behind it. */
16150
- hideGroup: (group: string) => Promise<void>;
16151
- /** Wait for that layer to close and read what it closed with. Null for a handle already gone. */
16152
- wait: (handle: string) => Promise<unknown>;
16153
- /** Close the layer the calling graph runs in. A no-op with a warning anywhere else. */
16154
- closeSelf: (result?: unknown) => Promise<void>;
16155
- isMounted: (handle: string) => boolean;
16156
- };
16157
- widget: {
16158
- setVisible: (elementId: string, visible: boolean) => Promise<void>;
16159
- setEnabled: (elementId: string, enabled: boolean) => Promise<void>;
16160
- /** `null` clears runtime override and restores authored default variant resolution. */
16161
- setVariant: (elementId: string, variantId: string | null, options?: {
16162
- waitForTransition?: boolean;
16163
- }) => Promise<void>;
16164
- getCommonProperties: (elementId: string) => BlueprintWidgetCommonProperties;
16165
- getTextProperties: (elementId: string) => BlueprintTextProperties;
16166
- setTextProperties: (elementId: string, patch: BlueprintTextPropertiesPatch) => Promise<void>;
16167
- getButtonProperties: (elementId: string) => BlueprintButtonProperties;
16168
- setButtonProperties: (elementId: string, patch: Partial<BlueprintButtonProperties>) => Promise<void>;
16169
- getContainerProperties: (elementId: string) => BlueprintContainerProperties;
16170
- setContainerProperties: (elementId: string, patch: Partial<BlueprintContainerProperties>) => Promise<void>;
16171
- getImageProperties: (elementId: string) => BlueprintImageProperties;
16172
- setImageProperties: (elementId: string, patch: Partial<BlueprintImageProperties>) => Promise<void>;
16173
- getSliderProperties: (elementId: string) => BlueprintSliderProperties;
16174
- setSliderProperties: (elementId: string, patch: BlueprintSliderPropertiesPatch) => Promise<void>;
16175
- getSwitchProperties: (elementId: string) => BlueprintSwitchProperties;
16176
- setSwitchProperties: (elementId: string, patch: BlueprintSwitchPropertiesPatch) => Promise<void>;
16177
- getTextInputProperties: (elementId: string) => BlueprintTextInputProperties;
16178
- setTextInputProperties: (elementId: string, patch: BlueprintTextInputPropertiesPatch) => Promise<void>;
16179
- getListProperties: (elementId: string) => BlueprintListProperties;
16180
- setListItems: (elementId: string, items: readonly unknown[]) => Promise<void>;
16181
- setListSelectedIndex: (elementId: string, index: number) => Promise<void>;
16182
- scrollListToIndex: (elementId: string, index: number) => Promise<void>;
16183
- scrollListToTop: (elementId: string) => Promise<void>;
16184
- scrollListToBottom: (elementId: string) => Promise<void>;
16185
- getDisplayableProperties: (elementId: string) => BlueprintDisplayableProperties;
16186
- /**
16187
- * What the widget currently covers on screen, in the coordinates of the surface it is on,
16188
- * or `null` when nothing is painted for it.
16189
- *
16190
- * Separate from {@link getDisplayableProperties} because the two answer different
16191
- * questions. That one reads the document - where the author put the widget - and is the
16192
- * right answer for layout arithmetic. This one measures the DOM, so it accounts for a
16193
- * motion in flight, an appearance variant that shifted the widget, a text box sized to its
16194
- * own words, and which row of a list an instance ended up on.
16195
- */
16196
- getMeasuredRect: (elementId: string) => BlueprintRect | null;
16197
- setDisplayableProperties: (elementId: string, patch: BlueprintDisplayablePropertiesPatch) => Promise<void>;
16198
- animateDisplayable: (elementId: string, request: BlueprintDisplayableMotionRequest) => Promise<UIDisplayableMotionOverride>;
16199
- stopDisplayableAnimation: (animationId: string) => Promise<void>;
16200
- getFrameProperties: (elementId: string) => BlueprintFrameProperties;
16201
- setFrameProperties: (elementId: string, patch: Partial<BlueprintFrameProperties>) => Promise<void>;
16202
- };
16203
- state: {
16204
- get: (scope: string, key: string) => unknown;
16205
- set: (scope: string, key: string, value: unknown) => void;
16206
- };
16207
- persistence: {
16208
- get: (key: string) => Promise<unknown>;
16209
- set: (key: string, value: unknown) => Promise<void>;
16210
- };
16211
- localization: {
16212
- /** Localization setup of the running game, or null when the project has none. */
16213
- getConfig: () => GameLocalizationConfigSnapshot | null;
16214
- /** Effective current locale (stored player choice, else the source locale). */
16215
- getLocale: () => Promise<string>;
16216
- /** Persist the player's language choice; callers validate against getConfig(). */
16217
- setLocale: (code: string) => Promise<void>;
16218
- };
16219
- /**
16220
- * Voice-over: which dub the player hears, and replaying a take on demand.
16221
- *
16222
- * Separate from `localization` because dub language and subtitle language are separate player
16223
- * choices - a game may be read in English and heard in Japanese.
16224
- */
16225
- voice: {
16226
- /** The dub languages this build ships, in project order. Empty when the game has no voice. */
16227
- listLocales: () => VoiceLocaleEntry[];
16228
- /** Effective dub language: the stored player choice when the build ships it, else the first. */
16229
- getLocale: () => Promise<string>;
16230
- /** Persist the player's dub choice. Takes effect from the next spoken line - no restart. */
16231
- setLocale: (code: string) => Promise<void>;
16232
- /**
16233
- * Play one line's take in the current dub language, on that speaker's bus.
16234
- *
16235
- * The id is a voice unit id - the same id a backlog entry reports as `voiceId` - which is why
16236
- * a replay button is built from this rather than from the entry's resolved URL. Resolves to
16237
- * false when the line has no take in the current language.
16238
- */
16239
- play: (unitId: string) => Promise<boolean>;
16240
- /**
16241
- * Play one choice option's take, at most one instance of that option at a time.
16242
- *
16243
- * Same clip and same bus as {@link play}; what differs is the bookkeeping a menu needs. A
16244
- * hover fires as often as the pointer crosses a row, so a line already speaking is left
16245
- * alone rather than restarted, and it answers false. `interruptOthers` stops the takes of
16246
- * the *other* options - the author's call, because a menu that reads each option over the
16247
- * last is as deliberate a design as one that speaks a single line at a time.
16248
- */
16249
- playChoice: (unitId: string, options?: {
16250
- interruptOthers?: boolean;
16251
- }) => Promise<boolean>;
16252
- };
16253
- frame: {
16254
- getParam: (key: string) => unknown;
16255
- emit: (eventName: string, data: unknown) => Promise<void>;
16256
- };
16257
- game: {
16258
- /**
16259
- * Begin a story. `options.inheritSavedGame` carries a save's saved-scope values and visited
16260
- * scenes into the new game - see the `Inherit From` pin - and carries nothing else.
16261
- */
16262
- startStory: (request: DevModeStartStoryRequest, options?: {
16263
- inheritSavedGame?: unknown;
16264
- }) => Promise<void>;
16265
- /** The running playthrough as a serialized game, or null when none is running. */
16266
- captureRun: () => unknown | null;
16267
- /** The serialized game stored in a slot, or null when there is no such slot. */
16268
- readSaveGame: (id: string) => Promise<unknown | null>;
16269
- isInGame: () => boolean;
16270
- isGameOverlay: () => boolean;
16271
- quit: (surfaceId: string) => Promise<void>;
16272
- writeSave: (id: string, metadata?: unknown, screenshot?: boolean) => Promise<void>;
16273
- /** False when the save was not applied - the player and the author have both been told. */
16274
- loadSave: (id: string) => Promise<boolean>;
16275
- deleteSave: (id: string) => Promise<void>;
16276
- listSaveIds: () => Promise<string[]>;
16277
- getSaveMetadata: (id: string) => Promise<unknown>;
16278
- /** When a slot was written, or null when there is no such slot. */
16279
- getSaveTimes: (id: string) => Promise<SaveRecordTimes | null>;
16280
- /** Where a slot stopped, or null when there is no such slot. */
16281
- getSaveLine: (id: string) => Promise<SaveRecordLine | null>;
16282
- /** How long a slot was played, or null when there is no such slot. */
16283
- getSavePlaytime: (id: string) => Promise<SaveRecordPlaytime | null>;
16284
- /** The running playthrough's playtime, in seconds. */
16285
- getPlaytime: () => number;
16286
- /** Seconds ever spent in this project, across every playthrough. */
16287
- getTotalPlaytime: () => number;
16288
- getSavePreview: (id: string) => Promise<BlueprintImageAsset | null>;
16289
- /** Write an autosave into the reserved ring now, regardless of the timer. */
16290
- writeAutoSave: () => Promise<void>;
16291
- /** The reserved autosave ring, newest first. Never overlaps `listSaveIds`. */
16292
- listAutoSaves: () => Promise<AutoSaveEntry[]>;
16293
- /**
16294
- * The backlog behind the play head, oldest first.
16295
- *
16296
- * From engine 0.26.0 this stops at the head: after the player steps back, the lines they
16297
- * stepped past are no longer in here, they are in {@link getFuture}. Before anyone steps
16298
- * back - which is every ordinary playthrough - the two are the whole backlog and nothing.
16299
- */
16300
- getHistory: () => Promise<BlueprintGameHistoryEntry[]>;
16301
- /** The lines ahead of the play head, nearest first. Empty until the player steps back. */
16302
- getFuture: () => Promise<BlueprintGameHistoryEntry[]>;
16303
- /** Jump back to a history entry by id; omit the id to undo the last entry. */
16304
- restoreHistory: (id?: string) => Promise<void>;
16305
- /** Step the play head forward one line, back over a line the player has already read. */
16306
- redoHistory: () => Promise<void>;
16307
- canUndoHistory: () => boolean;
16308
- canRedoHistory: () => boolean;
16309
- getNametag: () => string | null;
16310
- /**
16311
- * The speaking character's dialog avatar, or null. Already keyed on the differential the
16312
- * character is currently wearing - the engine resolves it off the live portrait element.
16313
- */
16314
- getSpeakerAvatar: () => BlueprintImageAsset | null;
16315
- /**
16316
- * The speaking character's authored accent colour, already in pin shape. Opaque white when
16317
- * nobody is speaking, the narrator is, or the character has no colour - the pin it feeds is
16318
- * a non-nullable RGBAColor, so "no colour" and "the default colour" are the same answer.
16319
- */
16320
- getSpeakerColor: () => BlueprintRGBAColor;
16321
- /**
16322
- * Has the line on screen finished revealing, with the dialog now waiting for the player.
16323
- *
16324
- * False while it is still typing, and false again the moment the next line mounts, so an
16325
- * indicator bound to it needs no timer of its own. False with no dialog on screen at all.
16326
- */
16327
- isDialogWaiting: () => boolean;
16328
- /**
16329
- * The current line's text - the whole line, not the part revealed so far. Empty string when
16330
- * no line is on screen.
16331
- */
16332
- getDialogText: () => string;
16333
- /**
16334
- * Does the current line have no speaker. Distinct from a null nametag, which a character
16335
- * with a blank name also reports. False when no line is on screen.
16336
- */
16337
- isNarrator: () => boolean;
16338
- /**
16339
- * Any character by id, from the table mirrored into global state - the addressable read the
16340
- * speaker-scoped getters above cannot do. Null when the id is empty, or names a character
16341
- * that is not (or is no longer) in the project.
16342
- */
16343
- getCharacter: (characterId: string) => BlueprintCharacterInfo | null;
16344
- getNotifications: () => BlueprintGameNotification[];
16345
- getChoiceCount: () => number;
16346
- isNvlMode: () => boolean;
16347
- /** True while a dialog line is on screen and its message is marked read. */
16348
- isCurrentTextRead: () => boolean;
16349
- isTextRead: (textId: string) => boolean;
16350
- /** Wipe the persisted text-read record (all stories). */
16351
- clearTextRead: () => Promise<void>;
16352
- /**
16353
- * Has the player ever ENTERED this scene, by Studio scene id.
16354
- *
16355
- * Not the same question as `isTextRead`: that record is written when a line is displayed,
16356
- * this one when a scene actually starts. Saved-domain, so loading an older save rewinds it.
16357
- */
16358
- isSceneVisited: (sceneId: string) => boolean;
16359
- /**
16360
- * One saved variable of the running playthrough, by the id a `savedVariableRef` names.
16361
- *
16362
- * `found` is false with no game running, and with an id this build's story does not
16363
- * declare. The two are worth telling apart from a value: `null` and the declared default
16364
- * are both real values a variable can hold, so neither can double as "there was nothing to
16365
- * read". See the capability's own note for why this is read-only.
16366
- */
16367
- getSavedVariable: (variableId: string) => {
16368
- value: unknown;
16369
- found: boolean;
16370
- };
16371
- /**
16372
- * Write one saved variable of the running playthrough.
16373
- *
16374
- * Throws when there is no game, when the id names nothing this build declares, and when the
16375
- * value cannot go into a save file. All three are authoring errors a button would otherwise
16376
- * swallow; see the capability's own note for what a write from a screen does and does not do.
16377
- */
16378
- setSavedVariable: (variableId: string, value: unknown) => void;
16379
- /**
16380
- * Has the player ever PICKED this choice option, by the option row's Studio block id. The
16381
- * one thing the text-read record structurally cannot answer - a menu that merely appeared
16382
- * marks every option of it read.
16383
- */
16384
- isOptionPicked: (optionId: string) => boolean;
16385
- /**
16386
- * Wipe the visited record of the running game.
16387
- *
16388
- * Synchronous, unlike `clearTextRead`: the record lives in the live `Storable`, not in host
16389
- * persistence, so there is nothing to await. It is also scoped to the running session - with
16390
- * no game up there is no record, and the call is a no-op instead of an error.
16391
- */
16392
- clearVisited: () => void;
16393
- /**
16394
- * Has the player ever reached this ending, by the `ending` row's Studio block id.
16395
- *
16396
- * Project persistence rather than the save file, unlike the visited record above: an endings
16397
- * screen reports what this player has ever seen, so loading an older save must not re-lock
16398
- * anything. Needs no running story - a title screen asks it before the first game exists.
16399
- */
16400
- isEndingReached: (endingId: string) => boolean;
16401
- /**
16402
- * Is this DLC installed beside the running build, by the id the author gave it.
16403
- *
16404
- * The whole of what a game may ask about its DLC, and deliberately not "does the player own
16405
- * it". Ownership is a storefront's fact and a plugin's to answer; what decides whether the
16406
- * content is here is whether its file is, which is the question this asks. A build with no
16407
- * DLC beside it answers false to everything, which is what a title screen wants before the
16408
- * player has bought anything.
16409
- */
16410
- isDlcInstalled: (dlcId: string) => boolean;
16411
- /**
16412
- * Every ending one story declares, in document order, each row already carrying whether it
16413
- * was reached. Empty for an unknown or unnamed story rather than an error.
16414
- *
16415
- * The list comes from the story document this build ships, so it can never offer an ending
16416
- * the compiler does not emit, and it is available with no game running for the same reason
16417
- * the reader above is.
16418
- */
16419
- listEndings: (storyId: string) => BlueprintStoryEnding[];
16420
- /**
16421
- * Forget one ending. Awaited, unlike `clearVisited`: this writes host persistence rather
16422
- * than a live `Storable`, and a caller that navigates away on the next beat has to know the
16423
- * write landed.
16424
- */
16425
- clearEndingState: (endingId: string) => Promise<void>;
16426
- /** Wipe the whole endings record. The `Clear Text Read` of this family. */
16427
- clearEndings: () => Promise<void>;
16428
- choose: (index: number) => Promise<void>;
16429
- next: () => Promise<void>;
16430
- skip: () => Promise<void>;
16431
- showDialog: () => Promise<void>;
16432
- hideDialog: () => Promise<void>;
16433
- toggleDialogDisplay: () => Promise<void>;
16434
- setSentenceSpeed: (cps: number) => Promise<void>;
16435
- getPreference: (key: BlueprintGamePreferenceKey) => BlueprintGamePreferenceValue;
16436
- setPreference: (key: BlueprintGamePreferenceKey, value: BlueprintGamePreferenceValue) => Promise<void>;
16437
- };
16438
- sound: {
16439
- play: (input: BlueprintSoundPlayInput) => Promise<BlueprintSoundHandle | null>;
16440
- stop: (handle: BlueprintSoundHandle | null, fadeMs?: number) => Promise<void>;
16441
- pause: (handle: BlueprintSoundHandle) => Promise<void>;
16442
- resume: (handle: BlueprintSoundHandle) => Promise<void>;
16443
- /** Ramp rather than jump when `fadeMs` is set - this is also the fade-out/duck node. */
16444
- setVolume: (handle: BlueprintSoundHandle, volume: number, fadeMs?: number) => Promise<void>;
16445
- /** Milliseconds from the start of the file, not from the clip's in point. */
16446
- seek: (handle: BlueprintSoundHandle, timeMs: number) => Promise<void>;
16447
- isPlaying: (handle: BlueprintSoundHandle) => boolean;
16448
- /**
16449
- * The volume a **host-owned** media element (the `nl.video` widget's `<video>`) must be set
16450
- * to so it obeys the same mixer everything else does.
16451
- *
16452
- * A DOM element the host created sits on none of the engine's gain nodes, so the whole
16453
- * product has to be computed and written to `element.volume`: the authored volume, times
16454
- * every bus in the track's chain, times the player's slider for whichever seeded bus that
16455
- * chain runs through, times master. Without this a muted game keeps playing video at full
16456
- * volume. Pair it with {@link subscribeMixerChanges} - a value read once goes stale the
16457
- * moment the player drags a slider, bus faders included.
16458
- */
16459
- resolveElementVolume: (input: {
16460
- audioTrackId?: string | null;
16461
- volume?: number | null;
16462
- }) => number;
16463
- /** Fires when any preference feeding `resolveElementVolume` changes. Returns a disposer. */
16464
- subscribeMixerChanges: (listener: () => void) => () => void;
16465
- /**
16466
- * An audio **track**'s own volume, 0..1 - one strip of the player's mixer.
16467
- *
16468
- * The player-facing counterpart of {@link setVolume}, which addresses one playing clip by
16469
- * handle. A track is a bus every clip beneath it is routed through, so setting one applies
16470
- * live to everything already playing and survives the clip that provoked it. This is what
16471
- * makes "turn Alice down" expressible at all: the four fixed volume preferences can only
16472
- * reach the three buses the engine seeds.
16473
- *
16474
- * An unknown or deleted track id reads as unity and writes nowhere, so a settings page
16475
- * built against a track the author later removed degrades to an inert slider.
16476
- */
16477
- getTrackVolume: (trackId: string) => number;
16478
- setTrackVolume: (trackId: string, volume: number) => Promise<void>;
16479
- };
16480
- /**
16481
- * HTTP, for the Fetch node.
16482
- *
16483
- * The host does not issue the request itself: it hands it to whatever the shell supplied, which
16484
- * on desktop and in Dev Mode is the main process (`onNetworkFetch`). Nothing here calls
16485
- * `fetch()` - see `@shared/utils/blueprintNetworkFetch` for why the renderer must not.
16486
- */
16487
- network: {
16488
- fetch: (request: BlueprintNetworkFetchRequest) => Promise<BlueprintNetworkFetchResult>;
16489
- };
16490
- /**
16491
- * The read side of input routing, for `Is Action Held` and `Get Input Device`.
16492
- *
16493
- * The only part of the input model a graph can ask about rather than be told about. Everything
16494
- * else in it is a dispatch - an action fires, a head runs - and none of that can answer "while
16495
- * the gesture is down" or "with which hand", because a fired event leaves nothing behind that
16496
- * says whether the hand is still there or what it was.
16497
- *
16498
- * Structural rather than a declared family in `@shared/types/blueprint/hostApi`, matching how
16499
- * both nodes reach for it (see `BlueprintInputActionHostApi`): the contract there names
16500
- * capabilities a host may or may not implement, and these are answered by the window every host
16501
- * already has.
16502
- */
16503
- input: {
16504
- isActionHeld: (actionId: string) => boolean;
16505
- /**
16506
- * Which device the player is using at this moment.
16507
- *
16508
- * One of the four values the `On Action` head's `source` pin carries, typed as a plain
16509
- * string so a graph compares both against the same literals.
16510
- */
16511
- getDevice: () => string;
16512
- };
16513
- /**
16514
- * Moving the player's real cursor, for the Move Mouse family.
16515
- *
16516
- * The author names a point in a surface's own coordinates, which is the only frame they have
16517
- * reason to think in. Turning that into a point in the window happens here, off the same
16518
- * surface shell every mouse event's payload is divided by, so "the centre of this button"
16519
- * measured by `widget.getMeasuredRect` and the point the cursor lands on are the same place.
16520
- *
16521
- * `surfaceId` is the surface the point belongs to; `null` means the active one. A point on a
16522
- * surface that is not currently laid out has nowhere to be, and reports `failed` rather than
16523
- * being guessed at against a different surface's scale.
16524
- */
16525
- pointer: {
16526
- moveTo: (surfaceId: string | null, point: BlueprintVector2D, options?: BlueprintPointerMoveOptions) => Promise<BlueprintPointerMoveResult>;
16527
- /**
16528
- * The same act aimed at a widget's centre, measured rather than computed from the document.
16529
- *
16530
- * A method of its own rather than something a caller assembles out of `getMeasuredRect` and
16531
- * `moveTo`, because the two halves have to agree about which surface the widget turned out
16532
- * to be painted on. A component instance renders its contents wherever it was placed, so
16533
- * the answer is not always the surface the element was authored under, and a caller
16534
- * stitching the halves together would have to know that to get it right.
16535
- */
16536
- moveToElementCenter: (elementId: string, options?: BlueprintPointerMoveOptions) => Promise<BlueprintPointerMoveResult>;
16537
- };
16538
- /**
16539
- * Carrying a playthrough between two editions of one title, for the Export/Import Progress
16540
- * nodes.
16541
- *
16542
- * The host does not decide where the document is: it hands the act to whatever the shell
16543
- * supplied, and the shell's own process resolves the file from the build's progress key. What
16544
- * this side states is what the playthrough holds, never where it goes.
16545
- *
16546
- * `import` answers with a scene id rather than going anywhere with it. The node deliberately
16547
- * does not jump - `Start Game` is what starts a story, and an author's graph usually has
16548
- * something to do first.
16549
- */
16550
- progress: {
16551
- export: () => Promise<{
16552
- outcome: "written" | "failed";
16553
- error: string;
16554
- }>;
16555
- import: () => Promise<GameProgressImportOutcome>;
16556
- };
16557
- /**
16558
- * What the shell can promise about the data it writes, for the `Check Storage Durability` node.
16559
- *
16560
- * A fact about where the game is running, not about the playthrough: a packaged desktop game
16561
- * keeps files nothing reclaims, a web export holds whatever grant the browser gave it. Stated,
16562
- * never acted on - what a player is told about it belongs to the title.
16563
- */
16564
- storage: {
16565
- durability: () => Promise<GameStorageDurability>;
16566
- };
16567
- devtools: {
16568
- log: (level: string, message: string) => void;
16569
- };
16570
- };
16571
- type BlueprintSoundPlayInput = {
16572
- assetId: string;
16573
- /**
16574
- * Project audio track (`ProjectAudioTrack.id`), which **is** the engine bus this clip is routed
16575
- * into, and whose own gain is applied live by the gain graph rather than folded in here. It also
16576
- * supplies the loop default below. Absent resolves to the seeded SFX bus, which is what an
16577
- * unqualified "play this clip" has always meant.
16578
- */
16579
- audioTrackId?: string | null;
16580
- /** Author override; absent means the track's own default. */
16581
- loop?: boolean | null;
16582
- /** Author override, 0..1 as authored; absent means unity. Never pre-multiplied by a bus gain. */
16583
- volume?: number | null;
16584
- /** Fade-in in milliseconds; absent means a hard start (a fade belongs to the moment). */
16585
- fadeInMs?: number | null;
16586
- };
16587
- type GameLocalizationConfigSnapshot = Pick<GameLocalizationBundle, "sourceLocale" | "locales"> & Partial<Pick<GameLocalizationBundle, "tables" | "keys" | "scenes">>;
16588
- type BlueprintGameNotification = {
16589
- id: string;
16590
- message: string;
16591
- };
16592
- type BlueprintStoryEnding = {
16593
- endingId: string;
16594
- name: string;
16595
- sceneId: string;
16596
- /** The scene the ending row sits in, so a row can be grouped or captioned without a lookup. */
16597
- sceneName: string;
16598
- isReached: boolean;
16599
- };
16600
- type BlueprintGameHistoryEntry = {
16601
- /** History token; pass to Restore From History to jump the game back to this point. */
16602
- id: string;
16603
- /** "say" for spoken lines, "menu" for a resolved choice. */
16604
- type: "say" | "menu";
16605
- /** Sentence text (say) or the menu prompt (menu); empty string when the source had none. */
16606
- text: string;
16607
- /** Speaker nametag for a say entry; null for menu entries or narration. */
16608
- character: string | null;
16609
- /** Resolved voice clip URL for a say entry; null when absent. Not addressable - see `voiceId`. */
16610
- voice: string | null;
16611
- /**
16612
- * The voice unit id this line's take is filed under; null when the line was not voiced through
16613
- * the voice module. This is the replayable handle: feed it to the Play Voice node. `voice` is a
16614
- * URL the player already heard and nothing in the runtime accepts a URL.
16615
- */
16616
- voiceId: string | null;
16617
- /** Chosen option text for a menu entry; null for say entries or an unresolved menu. */
16618
- selected: string | null;
16619
- /** True while the entry is the line currently being shown (not yet committed). */
16620
- isPending: boolean;
16621
- };
16622
15708
  type BehaviorNodeExecuteResult = {
16623
15709
  nextPort?: string;
16624
15710
  nextPorts?: string[];
16625
15711
  outputValues?: Record<string, unknown>;
16626
15712
  };
16627
- type BehaviorGraphExecutionTrace = {
16628
- executionId: string;
16629
- graphId: UIGraphId;
16630
- blueprintId?: string;
16631
- eventId?: string;
16632
- /**
16633
- * Surface the graph belongs to, carried so an `execution.error` raised in here says where it
16634
- * happened. The dispatcher reports the same failure a second time when it catches it, and the
16635
- * two reports have to be the SAME report - a host that collapses repeats by their text would
16636
- * otherwise list one failure twice, once with a place and once without.
16637
- */
16638
- surfaceId?: string;
16639
- emit: (event: BlueprintDebugEvent) => void;
16640
- };
16641
- type BlueprintValueDependency = {
16642
- surfaceId: string;
16643
- elementId: string;
16644
- propPath: string;
16645
- };
16646
- type BehaviorGraphValueExecution = {
16647
- returnValue(value: unknown): void;
16648
- trackDependency?(dependency: BlueprintValueDependency): void;
16649
- };
16650
- type BehaviorGraphEventControl = {
16651
- stopPropagation(): void;
16652
- isPropagationStopped(): boolean;
16653
- };
16654
- type BehaviorNodeExecutionContext = {
16655
- graph: UIGraph;
16656
- entry: UIGraphEntry;
16657
- node: UIGraphNode;
16658
- params: Record<string, unknown>;
16659
- /**
16660
- * Read one of this node's declared data input pins, following the wired
16661
- * edge. Lazy - nothing is resolved unless a node asks. Returns undefined for
16662
- * unwired or undeclared pins.
16663
- *
16664
- * Always supplied by both graph executors; optional only because tests build
16665
- * partial contexts. Call it as `ctx.resolveInput?.(pinId)`.
16666
- */
16667
- resolveInput?: (pinId: string) => unknown;
16668
- hostAdapter: UIHostAdapter;
16669
- trace?: BehaviorGraphExecutionTrace;
16670
- /** Per-event execution locals; initialized from blueprint member variables (M4 simplified editor). */
16671
- blueprintLocals?: Record<string, unknown>;
16672
- /** Runtime event slot currently being handled, for nodes that need to continue event propagation. */
16673
- eventName?: string;
16674
- eventPayload?: Record<string, unknown>;
16675
- eventControl?: BehaviorGraphEventControl;
16676
- signal?: AbortSignal;
16677
- listItemScope?: UIListItemScope | null;
16678
- instanceKey?: string;
16679
- executionOwner?: {
16680
- surfaceId?: string;
16681
- elementId?: string;
16682
- blueprintId?: string;
16683
- componentId?: string;
16684
- /**
16685
- * Resolved params of the component instance this execution belongs to, by param id.
16686
- *
16687
- * Sits beside `componentId` rather than at the top of the context because owner identity and
16688
- * the instance's own values are one answer to "which placement is running" - and because
16689
- * every data-pin resolver already forwards this object as a unit, which is what lets a pure
16690
- * node read it without thirty-odd call sites learning a new field.
16691
- */
16692
- componentParams?: Record<string, string>;
16693
- };
16694
- persistentVariables?: PersistentVariableRuntimeTable;
16695
- valueExecution?: BehaviorGraphValueExecution;
16696
- /** Nesting depth of blueprint fn invocations; guards runaway recursion in the dispatcher. */
16697
- fnCallDepth?: number;
16698
- };
16699
- type BehaviorNodeDefinition = {
16700
- type: string;
16701
- displayName: string;
16702
- execute: (ctx: BehaviorNodeExecutionContext) => BehaviorNodeExecuteResult | void | Promise<BehaviorNodeExecuteResult | void>;
16703
- };
16704
15713
  type StoryBlockSelection = {
16705
15714
  editor: "story";
16706
15715
  tabId: string;
@@ -16885,176 +15894,6 @@ type SelectionState = {
16885
15894
  type: "storyBlock";
16886
15895
  data: StoryBlockSelection;
16887
15896
  };
16888
- type ViewportTransform = {
16889
- scale: number;
16890
- offsetX: number;
16891
- offsetY: number;
16892
- };
16893
- type CanvasFitMode = "contain" | "cover" | "width" | "actual";
16894
- type SurfaceViewportFit = {
16895
- mode: CanvasFitMode;
16896
- /**
16897
- * True when the mode came from the zoom menu. It survives a resize the same way, and only this
16898
- * one escapes {@link SURFACE_FIT_MAX_SCALE}.
16899
- */
16900
- chosen: boolean;
16901
- };
16902
- type UITool = {
16903
- kind: "select";
16904
- } | {
16905
- kind: "pan";
16906
- } | {
16907
- kind: "insert";
16908
- nodeType: string;
16909
- componentId?: string;
16910
- };
16911
- type SnapGuideKind = "surface-edge" | "surface-center" | "element-edge" | "element-center";
16912
- type ActiveSnapGuideSegment = {
16913
- value: number;
16914
- kind: SnapGuideKind;
16915
- };
16916
- type ActiveSnapGuides = {
16917
- surfaceId: string;
16918
- vertical: ActiveSnapGuideSegment[];
16919
- horizontal: ActiveSnapGuideSegment[];
16920
- };
16921
- type SmartSnapDetailSettings = {
16922
- /** Snap selection edges/centers to other elements' center lines. */
16923
- snapElementLayout: boolean;
16924
- /** Snap element edges to other elements' edges. */
16925
- snapElementBorder: boolean;
16926
- /** Snap to canvas (surface) edges and center lines. */
16927
- snapCanvasLayout: boolean;
16928
- };
16929
- declare class UIEditorStateService extends Service<UIEditorStateService> implements IUIEditorStateService {
16930
- private uiStore;
16931
- private documentService;
16932
- private settingsService;
16933
- private readonly events;
16934
- private selection;
16935
- private tool;
16936
- private viewport;
16937
- /** Which interface {@link viewport} currently describes - it is one transform shared by every tab. */
16938
- private viewportSurfaceId;
16939
- /**
16940
- * Set while {@link viewport} is a computed zoom - a fit mode rather than somewhere the author
16941
- * zoomed or panned to by hand. `null` means the transform is theirs and nothing may revise it.
16942
- */
16943
- private viewportFit;
16944
- /** Hand-set transforms, so switching back to an interface returns to the view it was left at. */
16945
- private readonly viewportBySurfaceId;
16946
- /** Fit modes, so switching back to an interface resumes the mode it was left following. */
16947
- private readonly viewportFitBySurfaceId;
16948
- private interactionOverride;
16949
- private selectionUnsubscribe?;
16950
- private enteredState;
16951
- /** Only stores `true` keys; missing id => collapsed. */
16952
- private readonly appearanceBorderSidesExpandedByElementId;
16953
- private appearanceInspectorUiCachePersistTimer;
16954
- /** Presence means the outline branch is collapsed. */
16955
- private readonly outlineCollapsedBranchIds;
16956
- private outlinePanelCollapsed;
16957
- private outlineCollapsePersistTimer;
16958
- private smartSnapEnabled;
16959
- private smartSnapDetail;
16960
- private snapGuides;
16961
- /** Pure view state: screen-ratio preview frame preset id, `null` = off. Never touches the UIDocument. */
16962
- private previewAspectId;
16963
- /** Pure view state: safe-area preview frame device preset id, `null` = off. Never touches the UIDocument. */
16964
- private previewSafeAreaId;
16965
- protected init(ctx: WorkspaceContext, depend: (services: Service[]) => Promise<void>): Promise<void>;
16966
- dispose(_ctx: WorkspaceContext): void;
16967
- getTool(): UITool;
16968
- setTool(tool: UITool): void;
16969
- getViewportTransform(): ViewportTransform;
16970
- /**
16971
- * A hand gesture: a wheel zoom, a pan, or a zoom the author typed. It ends whatever fit mode
16972
- * was running, because from here on the author has said where they want to be looking and a
16973
- * pane resize must not overrule that.
16974
- */
16975
- updateViewport(transform: Partial<ViewportTransform>): ViewportTransform;
16976
- /** Which interface the current transform describes; `null` before any editor tab claimed it. */
16977
- getViewportSurfaceId(): string | null;
16978
- /**
16979
- * The fit mode the viewport is currently following, or `null` once the author has zoomed or
16980
- * panned by hand. Only while it is set may the editor recompute the transform on its own, when
16981
- * the pane resizes or the design size changes.
16982
- */
16983
- getViewportFit(): SurfaceViewportFit | null;
16984
- /**
16985
- * Installs a computed zoom as the viewport for `surfaceId`.
16986
- *
16987
- * Separate from {@link updateViewport} because the two carry opposite intent: this one is a
16988
- * mode being applied, and it stays live across resizes; that one is a place the author chose,
16989
- * and nothing may move it.
16990
- */
16991
- applyFittedViewport(surfaceId: string, transform: ViewportTransform, fit: SurfaceViewportFit): ViewportTransform;
16992
- /**
16993
- * Hands the shared viewport to `surfaceId` when opening or re-showing its tab.
16994
- *
16995
- * One transform serves every surface editor tab, so switching tabs would otherwise show the
16996
- * next interface through the last one's zoom.
16997
- *
16998
- * Returns `null` when this interface was left at a hand-set transform - it has been restored
16999
- * and the caller has nothing to do. Otherwise returns the mode the caller must recompute for
17000
- * the space it has now, which for an interface being opened for the first time is the plain
17001
- * fit nobody asked for.
17002
- */
17003
- adoptSurfaceViewport(surfaceId: string): SurfaceViewportFit | null;
17004
- getSelection(): SelectionState;
17005
- setSelection(selection: SelectionState): void;
17006
- setUIElementSelection(selection: UIElementSelection): void;
17007
- getInteractionOverride(): InteractionOverride | null;
17008
- setInteractionOverride(next: InteractionOverride | null): void;
17009
- getDocument(): UIDocument;
17010
- getSurface(surfaceId: string): UISurface | undefined;
17011
- getEnteredState(): UIEditorEnteredState | null;
17012
- setEnteredState(next: UIEditorEnteredState | null): void;
17013
- getAppearanceBorderSidesExpanded(elementId: string): boolean;
17014
- setAppearanceBorderSidesExpanded(elementId: string, expanded: boolean): void;
17015
- isOutlineBranchCollapsed(elementId: string): boolean;
17016
- setOutlineBranchCollapsed(elementId: string, collapsed: boolean): void;
17017
- getOutlinePanelCollapsed(): boolean;
17018
- setOutlinePanelCollapsed(collapsed: boolean): void;
17019
- getSmartSnapEnabled(): boolean;
17020
- setSmartSnapEnabled(enabled: boolean): void;
17021
- getSmartSnapDetailSettings(): SmartSnapDetailSettings;
17022
- patchSmartSnapDetailSettings(patch: Partial<SmartSnapDetailSettings>): void;
17023
- getPreviewAspectId(): string | null;
17024
- /**
17025
- * Pure view state — persisted in global settings only. Deliberately does NOT go through
17026
- * `UIDocumentService`, so toggling a preview frame never dirties the project, never emits
17027
- * `documentChanged` and never enters the undo stack.
17028
- */
17029
- setPreviewAspectId(aspectId: string | null): void;
17030
- getPreviewSafeAreaId(): string | null;
17031
- /** Pure view state — see `setPreviewAspectId`. */
17032
- setPreviewSafeAreaId(safeAreaId: string | null): void;
17033
- getSnapGuides(): ActiveSnapGuides | null;
17034
- setSnapGuides(guides: ActiveSnapGuides | null): void;
17035
- on<K extends keyof UIEditorStateEvents>(event: K, handler: (data: UIEditorStateEvents[K]) => void): () => void;
17036
- private ensureUIStore;
17037
- private normalizeViewport;
17038
- private persistViewport;
17039
- private scheduleAppearanceInspectorUiCachePersistence;
17040
- private persistAppearanceInspectorUiCachesNow;
17041
- private flushAppearanceInspectorUiCachePersistence;
17042
- private scheduleOutlineCollapsePersistence;
17043
- private persistOutlineCollapsedBranchesNow;
17044
- private flushOutlineCollapsePersistence;
17045
- private areSnapGuidesEqual;
17046
- /**
17047
- * Drops the entered state when the author moves to another interface.
17048
- *
17049
- * Selection is left alone on purpose. A canvas click on a widget's part promotes the selection to
17050
- * the parent it drills from, so exiting on "the selection left the subtree" exits on the very
17051
- * click an author makes to grab what they are editing - the state flickered away under them, and
17052
- * whatever they did next landed somewhere they were not looking.
17053
- */
17054
- private ensureEnteredStateValid;
17055
- private ensureInteractionOverrideValid;
17056
- private areOverridesEqual;
17057
- }
17058
15897
  type LiveUIComponentShell = Omit<UIComponentDefinition, "elements">;
17059
15898
  type LiveUIParts = {
17060
15899
  /** Records of the shared element map. */
@@ -18065,53 +16904,6 @@ interface PropertyEditorSchema<TData = any> {
18065
16904
  /** Whether to show saving indicator */
18066
16905
  showSavingIndicator?: boolean;
18067
16906
  }
18068
- type WidgetRendererProps = {
18069
- element: UIElement;
18070
- surface: UISurface;
18071
- document: UIDocument;
18072
- hostAdapter: UIHostAdapter;
18073
- children?: React$1.ReactNode;
18074
- /** Stable suffix for repeated structural renderers such as list item previews. */
18075
- instanceKey?: string;
18076
- /** Current list item scope when this element renders inside a list-like item template. */
18077
- listItemScope?: UIListItemScope | null;
18078
- /**
18079
- * Structural widgets may render children lazily with an instance scope.
18080
- * `nl.list` uses this to repeat one authored item template without cloning UIDocument elements.
18081
- */
18082
- renderChildren?: (options?: {
18083
- childrenIds?: string[];
18084
- listItemScope?: UIListItemScope | null;
18085
- instanceKey?: string;
18086
- elementOverrides?: Record<string, UIElement>;
18087
- }) => React$1.ReactNode[];
18088
- /**
18089
- * Render another Page surface inside the current element without using an iframe.
18090
- * Runtime hosts may isolate state/lifecycle by frame instance.
18091
- */
18092
- renderSurface?: (options: {
18093
- targetSurfaceId: string | null;
18094
- frameElement: UIElement;
18095
- params?: Record<string, unknown>;
18096
- instanceKey?: string;
18097
- }) => React$1.ReactNode;
18098
- /** Runtime state readers exposed to structural widgets that resolve their own data source. */
18099
- runtimeData?: {
18100
- surfaceState?: {
18101
- get(key: string): unknown;
18102
- };
18103
- globalState?: {
18104
- get(key: string): unknown;
18105
- };
18106
- /** Props the current page was opened with; fixed for the life of the page instance. */
18107
- pageProps?: Readonly<Record<string, unknown>>;
18108
- };
18109
- /**
18110
- * When true, canvas appearance resolves the variant from the inspector cache (editing-area preview).
18111
- * Dev Mode and other hosts omit this so runtime/blueprint variant overrides stay authoritative.
18112
- */
18113
- useAppearanceInspectorPreview?: boolean;
18114
- };
18115
16907
  type UIInspectorData = {
18116
16908
  element: UIElement;
18117
16909
  elements: UIElement[];
@@ -18120,10 +16912,6 @@ type UIInspectorData = {
18120
16912
  /** Set when inspecting a canvas widget; required for Blueprint M2 binding UI. */
18121
16913
  surfaceId?: string;
18122
16914
  };
18123
- type InspectorContext = {
18124
- element: UIElement;
18125
- documentService: UIDocumentService;
18126
- };
18127
16915
  type DockerBarItem = DockerBarButton | DockerBarSelect | DockerBarNumberInput | DockerBarSeparator;
18128
16916
  type DockerBarButton = {
18129
16917
  kind: "button";
@@ -18168,17 +16956,6 @@ type DockerBarSeparator = {
18168
16956
  kind: "separator";
18169
16957
  id: string;
18170
16958
  };
18171
- type DockerBarContext = {
18172
- element: UIElement;
18173
- documentService: UIDocumentService;
18174
- stateService?: UIEditorStateService;
18175
- surfaceId?: string;
18176
- };
18177
- type WidgetContextMenuContext = {
18178
- element: UIElement;
18179
- documentService: UIDocumentService;
18180
- surfaceId: string;
18181
- };
18182
16959
  type FloatingToolbarButton = {
18183
16960
  kind: "button";
18184
16961
  id: string;
@@ -18189,18 +16966,6 @@ type FloatingToolbarButton = {
18189
16966
  onClick: () => void;
18190
16967
  };
18191
16968
  type FloatingToolbarItem = FloatingToolbarButton;
18192
- type FloatingToolbarContext = {
18193
- element: UIElement;
18194
- documentService: UIDocumentService;
18195
- surfaceId: string;
18196
- openSurfaceEditor?: (surfaceId: string) => void;
18197
- };
18198
- type LayoutSizeFieldContext = {
18199
- element: UIElement;
18200
- documentService: UIDocumentService;
18201
- surfaceId?: string;
18202
- primaryId: string;
18203
- };
18204
16969
  type DefaultChildElementContext = {
18205
16970
  element: UIElement;
18206
16971
  generateId: () => string;
@@ -18209,203 +16974,6 @@ type DefaultChildElementResult = {
18209
16974
  elementPatch?: Partial<UIElement>;
18210
16975
  children: UIElement[];
18211
16976
  };
18212
- interface UIWidgetModule {
18213
- /** Unique type identifier (e.g. "nl.container") */
18214
- readonly type: string;
18215
- /**
18216
- * Widget type this module specialises, set by `extendWidgetModule`.
18217
- *
18218
- * Mirrors the entry in `WIDGET_TYPE_PARENTS`, which is the shared table the capability lookups
18219
- * (effect kinds, logic API, appearance backfill) read - `shared` cannot see a renderer module.
18220
- */
18221
- readonly extends?: string;
18222
- /** Shared logic capability schema for editor, runtime, and blueprint tooling. */
18223
- readonly logicApi?: WidgetLogicApi;
18224
- /** Human-readable display name */
18225
- readonly displayName: string;
18226
- /** Icon shown in the docker bar's element palette */
18227
- readonly icon: LucideIcon;
18228
- /**
18229
- * Creates the default partial element when the user inserts this widget.
18230
- * The returned object is merged with system defaults (id, parentId, etc.).
18231
- */
18232
- createDefaultElement(): Partial<UIElement>;
18233
- /**
18234
- * Creates structural child elements that must be present immediately after inserting the widget.
18235
- * The service applies the returned parent patch and child list in the same UIDocument mutation.
18236
- */
18237
- createDefaultChildElements?(context: DefaultChildElementContext): DefaultChildElementResult;
18238
- /**
18239
- * The states this widget can be shown in, when they belong to the widget rather than to an
18240
- * appearance model.
18241
- *
18242
- * A switch is on or off whatever its parts look like, and it carries no appearance of its own, so
18243
- * there are no variants for the state bar to list. Declaring them here puts the bar on the widget
18244
- * itself; entering one broadcasts that variant id to the subtree, which is where the parts that
18245
- * do carry variants pick it up. `id: null` is the state the widget rests in.
18246
- */
18247
- listEditorStates?(element: UIElement): {
18248
- id: string | null;
18249
- name: string;
18250
- }[];
18251
- /**
18252
- * Renders the element on the editor canvas.
18253
- */
18254
- render(props: WidgetRendererProps): React$1.ReactElement | null;
18255
- /**
18256
- * Returns property inspector fields for the properties panel.
18257
- * These fields are appended after the common layout fields.
18258
- * Return `undefined` to show only layout fields.
18259
- */
18260
- createInspector?(context: InspectorContext): PropertyEditorSchema<UIInspectorData> | undefined;
18261
- /**
18262
- * Returns docker bar items shown when this element is selected.
18263
- * Return `undefined` or empty array for no element-specific docker items.
18264
- */
18265
- createDockerBarItems?(context: DockerBarContext): DockerBarItem[];
18266
- /**
18267
- * Returns docker bar items used when multiple elements of this type are selected.
18268
- * The final multi-select docker bar shows only the items whose `id` exists for every selected module.
18269
- */
18270
- createMultiSelectDockerBarItems?(context: DockerBarContext): DockerBarItem[];
18271
- /**
18272
- * Extra context menu items when this element is the sole selection (canvas or outline).
18273
- */
18274
- createContextMenuItems?(context: WidgetContextMenuContext): ContextMenuItemDef[];
18275
- /**
18276
- * Returns icon actions rendered as one floating toolbar above the selected element's transform box.
18277
- * Keep actions concise; all modules share the same group renderer.
18278
- */
18279
- createFloatingToolbarItems?(context: FloatingToolbarContext): FloatingToolbarItem[];
18280
- /**
18281
- * Override the common Width / Height row in the layout inspector.
18282
- * Return `undefined` to use the default row, or `null` to hide the row.
18283
- */
18284
- createLayoutSizeField?(context: LayoutSizeFieldContext): FieldDefinition<UIInspectorData> | null | undefined;
18285
- /**
18286
- * Optional hook to register additional blueprint nodes (via `defineBlueprintNode`) when the module loads.
18287
- * Keep side effects idempotent - the host may call this once per session.
18288
- */
18289
- registerBlueprintNodes?(): void;
18290
- }
18291
- type UIEditorReadOnly = {
18292
- /** Whether every write gesture on this surface is inert right now. */
18293
- readonly active: boolean;
18294
- /** Hover text for the controls this state disables. The workspace passes the freeze reason. */
18295
- readonly reason?: string;
18296
- };
18297
- type UIHost$1 = "app" | "player";
18298
- type UIHostAdapterElementEventOptions = {
18299
- listItemScope?: UIListItemScope | null;
18300
- instanceKey?: string;
18301
- componentId?: UIComponentId;
18302
- /** Resolved values by param id: the instance's own, falling back to the declared default. */
18303
- componentParams?: Record<string, string>;
18304
- eventControl?: BehaviorGraphEventControl;
18305
- allowClosedScopeExecution?: boolean;
18306
- };
18307
- type UIHostAdapterBlueprintRuntime = {
18308
- surfaceId: string;
18309
- /** Instance-specific scope id. Defaults to `surfaceId` for top-level surfaces. */
18310
- runtimeScopeId?: string;
18311
- setSurfaceState: (key: string, value: unknown) => void;
18312
- getSurfaceState: (key: string) => unknown;
18313
- emitDebug: (event: BlueprintDebugEvent) => void;
18314
- getSurfaceTransitionState?: () => {
18315
- isEntering: boolean;
18316
- isExiting: boolean;
18317
- };
18318
- /** Dispatch a widget private event slot (for example `init` or `mouseClick`) on the owner-local blueprint. */
18319
- dispatchElementBlueprintEvent: (elementId: string, eventName: string, payload?: Record<string, unknown>, options?: UIHostAdapterElementEventOptions) => Promise<void>;
18320
- /** Continue the current widget event from this element to its structural parent. */
18321
- continueElementEventBubble?: (elementId: string, eventName: string, payload?: Record<string, unknown>, options?: UIHostAdapterElementEventOptions) => Promise<boolean>;
18322
- /** Dispatch a surface-level event on the current surfaceMain blueprint. */
18323
- dispatchSurfaceBlueprintEvent?: (eventName: string, payload?: Record<string, unknown>) => Promise<void>;
18324
- /**
18325
- * Raise one of this surface's declared input actions on its surfaceMain blueprint.
18326
- *
18327
- * The seam between routing and authoring: routing decides that this click, wheel or key means
18328
- * "advance" on this surface (see `runtime/input/surfaceInputActions`), and this hands that
18329
- * decision to the graph. Named rather than positional because the payload is what the action's
18330
- * head node reads its pins from.
18331
- *
18332
- * It resolves when the action's graphs have run, which is what lets a lane walk stay sequential.
18333
- */
18334
- dispatchSurfaceInputAction?: (payload: UIInputActionEventPayload) => Promise<void>;
18335
- dispatchBroadcastEvent?: (eventName: string, data: unknown, sender?: string) => Promise<void>;
18336
- getBroadcastListenerCount?: (eventName: string) => number;
18337
- /** Invoke a declared blueprint fn (Call Fn node); awaits the fn body and returns its Fn Return values. */
18338
- invokeBlueprintFn?: (input: {
18339
- fnRef: string;
18340
- args: Record<string, unknown>;
18341
- depth: number;
18342
- /** Surface of the calling execution; global callers omit it and only see global fns. */
18343
- callerSurfaceId?: string;
18344
- /** Component definition of the calling execution, when it is running inside one. */
18345
- callerComponentId?: string;
18346
- /** That instance's resolved params, which the fn body runs with. */
18347
- callerComponentParams?: Record<string, string>;
18348
- /** Which drawing the call came from, so the body's widget writes land on it. */
18349
- callerInstanceKey?: string;
18350
- signal?: AbortSignal;
18351
- callerExecutionId?: string;
18352
- }) => Promise<{
18353
- returns: Record<string, unknown>;
18354
- }>;
18355
- frame?: {
18356
- getParam: (key: string) => unknown;
18357
- emit: (eventName: string, data: unknown) => Promise<void> | void;
18358
- };
18359
- /** M3-full: Dev Mode host API (graphs + TS ctx); absent in editor preview. */
18360
- hostApi?: BlueprintHostApiRuntime;
18361
- };
18362
- type UIHostAdapter = {
18363
- host: UIHost$1;
18364
- navigate?: (target: unknown) => Promise<void> | void;
18365
- resolveSlot?: (slotId: string) => {
18366
- mount: (node: React$1.ReactNode) => void;
18367
- } | null;
18368
- gameUiRuntime?: {
18369
- slotId: UIStageSlotId;
18370
- };
18371
- /**
18372
- * M1 latch: which frozen BlueprintHostApiContract generation this adapter targets.
18373
- * Does not imply all capabilities are implemented yet.
18374
- */
18375
- blueprintHostApiVersion?: BlueprintHostApiContractVersion;
18376
- /** M3-min: optional Blueprint runtime surface (Dev Mode). */
18377
- blueprintRuntime?: UIHostAdapterBlueprintRuntime;
18378
- /**
18379
- * Story Action Blueprint runtime surface. Present only while a story-action blueprint graph
18380
- * runs inside a compiled NLR `Script`; resolves scene/saved variable ids to their NLR backing
18381
- * (`Scene.local` / `Storable`). Absent for UI blueprints.
18382
- */
18383
- storyRuntime?: UIHostAdapterStoryRuntime;
18384
- /** Editor preview: use the active workspace service instance for canvas-local interaction overrides. */
18385
- editorStateService?: UIEditorStateService;
18386
- /** Editor preview: use the active document service, including component-editor adapters. */
18387
- editorDocumentService?: UIDocumentService;
18388
- /**
18389
- * Whether the surface this adapter renders is read-only right now (a frozen workspace).
18390
- *
18391
- * The two services above are the only thing a widget renderer needs in order to write the
18392
- * document from inside its own markup, and the interaction layer's gesture table cannot reach
18393
- * those handlers - a widget's `onDoubleClick` is attached by the widget, not by the canvas. So
18394
- * the state travels on the adapter beside them, and {@link resolveInlineTextEditHost} is where
18395
- * the two are read together.
18396
- */
18397
- editorReadOnly?: UIEditorReadOnly;
18398
- };
18399
- type StoryVariableRuntimeAccess = {
18400
- /** Resolve `variableId` to its stored value, or the declared default when unset. */
18401
- get: (variableId: string) => unknown;
18402
- /** Resolve `variableId` and write `value` to the backing store. */
18403
- set: (variableId: string, value: unknown) => void;
18404
- };
18405
- type UIHostAdapterStoryRuntime = {
18406
- sceneVar: StoryVariableRuntimeAccess;
18407
- savedVar: StoryVariableRuntimeAccess;
18408
- };
18409
16977
  type BlueprintPinSemantic = "exec" | "data";
18410
16978
  export type BlueprintNodePinDef = {
18411
16979
  id: string;
@@ -18531,20 +17099,8 @@ type BlueprintInspectorParamDef = {
18531
17099
  optionMetaKey: string;
18532
17100
  };
18533
17101
  };
18534
- type BlueprintNodeScopeOwnerKind = BlueprintOwnerRef["kind"];
18535
- type BlueprintNodeScope = {
18536
- anyOf?: BlueprintNodeScope[];
18537
- ownerKinds?: BlueprintNodeScopeOwnerKind[];
18538
- /** When set, node only appears for widgetMain blueprints whose element.type matches. */
18539
- widgetElementTypes?: string[];
18540
- };
18541
17102
  type BlueprintNodeRole = "normal" | "eventHead" | "fnHead" | "functionEntry" | "reroute" | "dataLiteral" | "elementLiteral" | "elementEventHead" | "imageAssetLiteral" | "valueReturn" | "comment";
18542
- export type BlueprintNodeExecuteFn = BehaviorNodeDefinition["execute"];
18543
- /**
18544
- * Full node definition: editor pins + inspector + runtime execute.
18545
- * Registered via defineBlueprintNode().
18546
- */
18547
- export type BlueprintNodeDef = {
17103
+ type BlueprintNodeDeclaration = {
18548
17104
  type: string;
18549
17105
  displayName: string;
18550
17106
  category: string;
@@ -18575,7 +17131,12 @@ export type BlueprintNodeDef = {
18575
17131
  * built on one refreshes on the host's dependencies, never on the plugin's.
18576
17132
  */
18577
17133
  allowInBlueprintValueGraph?: boolean;
18578
- /** Palette-only guard for nodes that read the active List item template scope. */
17134
+ /**
17135
+ * The node reads the list row that is in scope while it runs, so it belongs only where a row can
17136
+ * be: on an element a list draws once per row, or on the list itself, whose item heads each run
17137
+ * for one row. Enforced by `isBlueprintNodeAllowedInGraphContext`, so the palette and the graph
17138
+ * validator answer it the same way.
17139
+ */
18579
17140
  requiresListItemContext?: boolean;
18580
17141
  /** Latent/async execution (delay, host awaits) - disallowed in function graphs */
18581
17142
  isLatent?: boolean;
@@ -18594,20 +17155,7 @@ export type BlueprintNodeDef = {
18594
17155
  kind: "input" | "output";
18595
17156
  };
18596
17157
  inspectorParams?: BlueprintInspectorParamDef[];
18597
- scope?: BlueprintNodeScope;
18598
- /**
18599
- * This node reaches the blueprint host API, so it may only appear where a host serves one.
18600
- *
18601
- * Set at registration for whole families rather than per node (see `HOST_API_OWNER_KINDS`),
18602
- * and deliberately NOT expressed as a {@link BlueprintNodeScope}: a scope answers "which
18603
- * owners and which widget types", and `resolveEffectiveBlueprintNodePins` reads the mere
18604
- * PRESENCE of one as "this is the widget-scoped variant, so hide the element pin". Writing
18605
- * this restriction as a scope therefore stripped the element pin off every magic-element
18606
- * node in the catalogue.
18607
- */
18608
- requiresHostApi?: boolean;
18609
17158
  role?: BlueprintNodeRole;
18610
- execute: BlueprintNodeExecuteFn;
18611
17159
  };
18612
17160
  interface WorkspaceContext {
18613
17161
  project: Porject;
@@ -18784,98 +17332,6 @@ interface IUIDocumentService extends IService {
18784
17332
  };
18785
17333
  renameElement(elementId: string, name: string): void;
18786
17334
  }
18787
- type InteractionOverride = {
18788
- kind: "imageCrop";
18789
- surfaceId: string;
18790
- elementId: string;
18791
- source: string;
18792
- } | {
18793
- kind: "textEdit";
18794
- surfaceId: string;
18795
- elementId: string;
18796
- };
18797
- type InteractionOverrideChange = {
18798
- previous: InteractionOverride | null;
18799
- next: InteractionOverride | null;
18800
- };
18801
- type UIEditorEnteredState = {
18802
- surfaceId: string;
18803
- elementId: string;
18804
- variantId: string | null;
18805
- };
18806
- interface UIEditorStateEvents {
18807
- toolChanged: UITool;
18808
- viewportChanged: ViewportTransform;
18809
- selectionChanged: SelectionState;
18810
- interactionOverrideChanged: InteractionOverrideChange;
18811
- /** Editor-only: which element is showing one of its states, and which; drives canvas preview. */
18812
- enteredStateChanged: UIEditorEnteredState | null;
18813
- /** Outline panel expand/collapse memory (persisted); payload unused. */
18814
- outlineExpansionChanged: null;
18815
- /** Outline panel chrome collapsed state (persisted). */
18816
- outlinePanelCollapsedChanged: boolean;
18817
- /** Smart snap / smart guides toggle (persisted in project settings). */
18818
- smartSnapEnabledChanged: boolean;
18819
- /** Per-category snap targets when smart snap is enabled (persisted). */
18820
- smartSnapDetailSettingsChanged: SmartSnapDetailSettings;
18821
- /** Ephemeral snap guide lines in surface space (viewport overlay). */
18822
- snapGuidesChanged: ActiveSnapGuides | null;
18823
- /** Screen-ratio preview frame preset id, `null` = off (pure view state, global settings). */
18824
- previewAspectChanged: string | null;
18825
- /** Safe-area preview frame device preset id, `null` = off (pure view state, global settings). */
18826
- previewSafeAreaChanged: string | null;
18827
- }
18828
- interface IUIEditorStateService extends IService {
18829
- getTool(): UITool;
18830
- setTool(tool: UITool): void;
18831
- getViewportTransform(): ViewportTransform;
18832
- /** A hand gesture (zoom, pan, or a typed zoom); ends the fit mode the interface was following. */
18833
- updateViewport(transform: Partial<ViewportTransform>): ViewportTransform;
18834
- /** Which interface the current transform describes; `null` before any editor tab claimed it. */
18835
- getViewportSurfaceId(): string | null;
18836
- /** The fit mode in force, or `null` once the author moved the view by hand. */
18837
- getViewportFit(): SurfaceViewportFit | null;
18838
- /** Installs a computed zoom for an interface (stays live across resizes, unlike a hand gesture). */
18839
- applyFittedViewport(surfaceId: string, transform: ViewportTransform, fit: SurfaceViewportFit): ViewportTransform;
18840
- /** Restores a hand-set view (`null`), or returns the mode the caller must recompute. */
18841
- adoptSurfaceViewport(surfaceId: string): SurfaceViewportFit | null;
18842
- getSelection(): SelectionState;
18843
- setSelection(selection: SelectionState): void;
18844
- setUIElementSelection(selection: UIElementSelection): void;
18845
- getDocument(): UIDocument;
18846
- getSurface(surfaceId: string): UISurface | undefined;
18847
- /** The state being shown on the canvas right now, or null while every element rests. */
18848
- getEnteredState(): UIEditorEnteredState | null;
18849
- setEnteredState(next: UIEditorEnteredState | null): void;
18850
- /** Whether compact Border panel "sides" row is expanded (per element, persisted with project settings). */
18851
- getAppearanceBorderSidesExpanded(elementId: string): boolean;
18852
- setAppearanceBorderSidesExpanded(elementId: string, expanded: boolean): void;
18853
- /** Outline: branch is collapsed when true (editor-only, project settings). */
18854
- isOutlineBranchCollapsed(elementId: string): boolean;
18855
- setOutlineBranchCollapsed(elementId: string, collapsed: boolean): void;
18856
- /** Outline panel chrome: collapsed when true (editor-only global settings). */
18857
- getOutlinePanelCollapsed(): boolean;
18858
- setOutlinePanelCollapsed(collapsed: boolean): void;
18859
- /** When true, dragging/resizing/inserting snaps to surface and sibling guides (project settings). */
18860
- getSmartSnapEnabled(): boolean;
18861
- setSmartSnapEnabled(enabled: boolean): void;
18862
- /** Which guide categories participate when smart snap is on (persisted). */
18863
- getSmartSnapDetailSettings(): SmartSnapDetailSettings;
18864
- patchSmartSnapDetailSettings(patch: Partial<SmartSnapDetailSettings>): void;
18865
- /**
18866
- * Screen-ratio preview frame preset id (`null` = off). Pure view state: persisted in global
18867
- * settings, never in the UIDocument, so toggling it cannot dirty the project.
18868
- */
18869
- getPreviewAspectId(): string | null;
18870
- setPreviewAspectId(aspectId: string | null): void;
18871
- /** Safe-area preview frame device preset id (`null` = off). Pure view state, see above. */
18872
- getPreviewSafeAreaId(): string | null;
18873
- setPreviewSafeAreaId(safeAreaId: string | null): void;
18874
- /** Active snap guides for the current interaction (null clears overlay). */
18875
- getSnapGuides(): ActiveSnapGuides | null;
18876
- setSnapGuides(guides: ActiveSnapGuides | null): void;
18877
- on<K extends keyof UIEditorStateEvents>(event: K, handler: (data: UIEditorStateEvents[K]) => void): () => void;
18878
- }
18879
17335
  export type StoryPluginActionCreateInput = {
18880
17336
  generateId: () => string;
18881
17337
  initialText?: string;
@@ -18907,6 +17363,7 @@ declare const HELP_TOPIC_IDS: readonly [
18907
17363
  "dictionary",
18908
17364
  "dictionaryMarks",
18909
17365
  "assets",
17366
+ "assetSources",
18910
17367
  "assetSets",
18911
17368
  "assetSetAxes",
18912
17369
  "mediaConversion",
@@ -18925,6 +17382,7 @@ declare const HELP_TOPIC_IDS: readonly [
18925
17382
  "inputActionsInBlueprints",
18926
17383
  "uiComponents",
18927
17384
  "blueprints",
17385
+ "scripts",
18928
17386
  "uiBindings",
18929
17387
  "networkNodes",
18930
17388
  "spellcheck",
@@ -19681,6 +18139,49 @@ export type RuntimePluginLocale = {
19681
18139
  export type RuntimePluginMenu = {
19682
18140
  set(spec: GameMenuSpec): Promise<void>;
19683
18141
  };
18142
+ /**
18143
+ * What the engine's image cache is holding, against what it is allowed to hold. All sizes in bytes.
18144
+ *
18145
+ * Restated here rather than re-exported from the engine because a plugin cannot import
18146
+ * `narraleaf-react` - the only module specifiers it can resolve are `narraleaf-studio/*` and React.
18147
+ * The shape is the engine's `ImageCacheStats`; if that grows a field, this is the second place.
18148
+ */
18149
+ export type RuntimePluginImageCacheStats = {
18150
+ /** Sources the cache holds a url for. */
18151
+ entries: number;
18152
+ /**
18153
+ * Bytes of fetched image data the cache is keeping alive.
18154
+ *
18155
+ * **Zero is a real answer, not a missing one.** A host that serves its own assets hands the
18156
+ * player urls instead of bytes, and then the player holds none: what the images cost lives in
18157
+ * the browser's cache, outside anything this can count. A reader that shows this as "memory
18158
+ * used" will report an improvement that did not happen - see {@link entries}, which still
18159
+ * counts, and the decoded figures below, which are the ones with a budget behind them.
18160
+ */
18161
+ blobBytes: number;
18162
+ /** Sources whose decoded bitmap the cache is holding. */
18163
+ decodedEntries: number;
18164
+ /** Estimated size of those bitmaps, at width x height x 4 bytes each. */
18165
+ decodedBytes: number;
18166
+ /** Entries nothing may evict right now: shown by a mounted element, or pinned by the scene. */
18167
+ pinned: number;
18168
+ /** The budgets in force. `Infinity` where the game removed one. */
18169
+ budget: {
18170
+ blobBytes: number;
18171
+ decodedBytes: number;
18172
+ };
18173
+ };
18174
+ /**
18175
+ * `diagnostics` — what the player's caches weigh.
18176
+ *
18177
+ * Every member answers null before a game session exists, which is the ordinary state during
18178
+ * `setup()`. A plugin polls this; there is no change event, because a cache that announced every
18179
+ * eviction would cost more to watch than to run.
18180
+ */
18181
+ export type RuntimePluginDiagnostics = {
18182
+ /** The engine's image cache, or null when no session is live. */
18183
+ imageCache(): RuntimePluginImageCacheStats | null;
18184
+ };
19684
18185
  /** `assets` — turn an asset id from the pack into a URL this shell can load. */
19685
18186
  export type RuntimePluginAssets = {
19686
18187
  url(assetId: string): string;
@@ -19811,6 +18312,8 @@ export type RuntimePluginGame = {
19811
18312
  menu?: RuntimePluginMenu;
19812
18313
  /** Present with `"story.compile"`. */
19813
18314
  story?: RuntimePluginStory;
18315
+ /** Present with `"diagnostics"`. */
18316
+ diagnostics?: RuntimePluginDiagnostics;
19814
18317
  /** Present when `contributes.sidecars` is non-empty. */
19815
18318
  sidecar?: RuntimePluginSidecars;
19816
18319
  /** Present when `contributes.externalLinks` is non-empty. */
@@ -19831,6 +18334,163 @@ export type RuntimePluginDefinition = {
19831
18334
  };
19832
18335
  export declare function defineRuntimePlugin(definition: RuntimePluginDefinition): RuntimePluginDefinition;
19833
18336
  export declare function isRuntimePluginDefinition(value: unknown): value is RuntimePluginDefinition;
18337
+ /**
18338
+ * The interface-editor extension surface a plugin actually gets.
18339
+ *
18340
+ * Studio's own widgets are described by `UIWidgetModule`, whose callbacks are handed the live
18341
+ * `UIDocumentService` and `UIEditorStateService`. Those are `Service` instances, and `getContext()`
18342
+ * on a service is public - so `documentService.getContext().services.get(...)` returns the workspace
18343
+ * service registry, and with it a `FileSystemService` that speaks to the main process under the
18344
+ * window's default privileged facade: recursive read and write over the author's whole project,
18345
+ * authorised as the window rather than as the plugin. That is the same escalation
18346
+ * `pluginWorkspaceGuard` closed on `ActionDefinition.onClick`, reached through the widget door.
18347
+ *
18348
+ * A class instance cannot be made safe by wrapping one method, either: `service.constructor` is the
18349
+ * real class, `Service` extends `Singleton`, and `Singleton.instances` is an ordinary static
18350
+ * property holding every service that has ever been constructed. Anything with that prototype chain
18351
+ * hands over the registry however many members are trapped on the way past.
18352
+ *
18353
+ * So the types below are what a widget is handed instead - plain objects with named methods,
18354
+ * built by `pluginWidgetGuard` and enforced there rather than here. **These declarations state the
18355
+ * contract; they do not impose it.** A plugin ships compiled JavaScript and can cast anything to
18356
+ * anything; the guard is what makes the cast find nothing.
18357
+ *
18358
+ * The surface is derived from what the built-in widgets do, which is the only honest measure of what
18359
+ * a widget needs: read the interface document, write the element's own props, layout, animation,
18360
+ * extra and list-item wiring, group a burst of those into one undo step, and move the selection.
18361
+ * Nothing here reaches outside `uidoc.json`.
18362
+ */
18363
+ /**
18364
+ * Interface-document access for a plugin widget.
18365
+ *
18366
+ * Whole-document reads are deliberate: a structural widget cannot resolve its own parts without
18367
+ * looking them up, which is why the game side hands plugin renderers the document too. The document
18368
+ * is authored content the editor is already drawing, not a host power - and it is one document, not
18369
+ * an index that leads to unrelated resources.
18370
+ *
18371
+ * Writes are element-scoped by signature. They are not restricted to the element being inspected: a
18372
+ * widget with parts edits its parts, exactly as the built-in switch and list do, and there is no
18373
+ * honest way to tell "my part" from "someone else's element" from here.
18374
+ */
18375
+ export type PluginWidgetDocumentApi = {
18376
+ /** The whole interface document, as the editor currently holds it. */
18377
+ getDocument(): UIDocument;
18378
+ /** A fresh element id, for a widget that builds child elements of its own. */
18379
+ generateId(): string;
18380
+ /** One component definition by id, for a widget that draws a linked component instance. */
18381
+ getComponent(componentId: string): UIComponentDefinition | undefined;
18382
+ createElement(parentId: string, type: string, layoutPatch?: Partial<UILayout>): UIElement;
18383
+ updateElementProps(elementId: string, propsPatch: Record<string, unknown>): void;
18384
+ updateElementExtra(elementId: string, extraPatch: Record<string, unknown>): void;
18385
+ updateElementLayout(elementId: string, layoutPatch: Partial<UILayout>, options?: {
18386
+ skipHistory?: boolean;
18387
+ }): void;
18388
+ updateElementAnimation(elementId: string, animation: UIPageAnimationSettings | null, options?: {
18389
+ mergeKey?: string;
18390
+ }): void;
18391
+ /** Collapse everything the callback writes into one undo entry on that surface. */
18392
+ runSurfaceHistoryTransaction(surfaceId: string, action: () => void): void;
18393
+ setListItemStructFields(elementId: string, fields: readonly UIStructField[]): void;
18394
+ setElementListItemFieldBinding(elementId: string, propPath: string, fieldId: string | null): void;
18395
+ ensureElementBlueprintValueBinding(elementId: string, propPath: string, input: {
18396
+ valueType: UIElementValueBindingValueType;
18397
+ displayName?: string;
18398
+ literalValue?: unknown;
18399
+ }): {
18400
+ blueprintId: string;
18401
+ };
18402
+ clearElementBlueprintValueBinding(elementId: string, propPath: string): void;
18403
+ };
18404
+ /**
18405
+ * Editor state a plugin widget's docker bar may read and move.
18406
+ *
18407
+ * Selection only. The interaction overrides (inline text edit, image crop) are not here because the
18408
+ * host honours them in built-in renderers alone - offering a plugin a switch that turns nothing on
18409
+ * would be worse than not having it.
18410
+ */
18411
+ export type PluginWidgetEditorStateApi = {
18412
+ getSelection(): SelectionState;
18413
+ setUIElementSelection(selection: UIElementSelection): void;
18414
+ getEnteredState(): {
18415
+ surfaceId: string;
18416
+ elementId: string;
18417
+ variantId: string | null;
18418
+ } | null;
18419
+ setEnteredState(next: {
18420
+ surfaceId: string;
18421
+ elementId: string;
18422
+ variantId: string | null;
18423
+ } | null): void;
18424
+ };
18425
+ /** What a plugin widget's property fields read and write through. */
18426
+ export type PluginWidgetInspectorData = {
18427
+ element: UIElement;
18428
+ elements: UIElement[];
18429
+ documentService: PluginWidgetDocumentApi;
18430
+ surfaceId?: string;
18431
+ };
18432
+ export type PluginWidgetInspectorContext = {
18433
+ element: UIElement;
18434
+ documentService: PluginWidgetDocumentApi;
18435
+ };
18436
+ export type PluginWidgetDockerBarContext = {
18437
+ element: UIElement;
18438
+ documentService: PluginWidgetDocumentApi;
18439
+ stateService?: PluginWidgetEditorStateApi;
18440
+ surfaceId?: string;
18441
+ };
18442
+ export type PluginWidgetContextMenuContext = {
18443
+ element: UIElement;
18444
+ documentService: PluginWidgetDocumentApi;
18445
+ surfaceId: string;
18446
+ };
18447
+ export type PluginWidgetFloatingToolbarContext = {
18448
+ element: UIElement;
18449
+ documentService: PluginWidgetDocumentApi;
18450
+ surfaceId: string;
18451
+ openSurfaceEditor?: (surfaceId: string) => void;
18452
+ };
18453
+ export type PluginWidgetLayoutSizeFieldContext = {
18454
+ element: UIElement;
18455
+ documentService: PluginWidgetDocumentApi;
18456
+ surfaceId?: string;
18457
+ primaryId: string;
18458
+ };
18459
+ /**
18460
+ * A widget type contributed by a plugin.
18461
+ *
18462
+ * `render` takes the same {@link RuntimeWidgetRendererProps} the game hands a plugin renderer,
18463
+ * rather than the editor's wider props: one render function, drawn the same way in both places, and
18464
+ * no `hostAdapter` on either side. See `create-plugin.md` for the shared-module pattern that relies
18465
+ * on it.
18466
+ *
18467
+ * `registerBlueprintNodes` is absent on purpose. It exists on the built-in module type and the host
18468
+ * only ever calls it for built-ins; a plugin registers nodes through `app.services.blueprintNodes`,
18469
+ * where the execute context is narrowed the same way this is.
18470
+ */
18471
+ export type PluginWidgetModule = {
18472
+ /** Unique type id; must start with the plugin id and be declared in `contributes.widgets`. */
18473
+ readonly type: string;
18474
+ /** Widget type this one specialises. */
18475
+ readonly extends?: string;
18476
+ /** Event and effect capabilities, shared with the blueprint tooling. */
18477
+ readonly logicApi?: WidgetLogicApi;
18478
+ readonly displayName: string;
18479
+ readonly icon: LucideIcon;
18480
+ createDefaultElement(): Partial<UIElement>;
18481
+ createDefaultChildElements?(context: DefaultChildElementContext): DefaultChildElementResult;
18482
+ listEditorStates?(element: UIElement): {
18483
+ id: string | null;
18484
+ name: string;
18485
+ }[];
18486
+ render(props: RuntimeWidgetRendererProps): React$1.ReactElement | null;
18487
+ createInspector?(context: PluginWidgetInspectorContext): PropertyEditorSchema<PluginWidgetInspectorData> | undefined;
18488
+ createDockerBarItems?(context: PluginWidgetDockerBarContext): DockerBarItem[];
18489
+ createMultiSelectDockerBarItems?(context: PluginWidgetDockerBarContext): DockerBarItem[];
18490
+ createContextMenuItems?(context: PluginWidgetContextMenuContext): ContextMenuItemDef[];
18491
+ createFloatingToolbarItems?(context: PluginWidgetFloatingToolbarContext): FloatingToolbarItem[];
18492
+ createLayoutSizeField?(context: PluginWidgetLayoutSizeFieldContext): FieldDefinition<PluginWidgetInspectorData> | null | undefined;
18493
+ };
19834
18494
  /**
19835
18495
  * Caller-defined section (e.g. built-in presets) shown as a collapsible group in the asset list.
19836
18496
  * Workspace filter chips do not apply; only the search box filters `assets` (same rules as project assets).
@@ -20387,8 +19047,30 @@ declare const pluginUi: Readonly<{
20387
19047
  }>;
20388
19048
  export type PluginUiKit = typeof pluginUi;
20389
19049
  /**
20390
- * A blueprint node as a *plugin* writes it: the editor's full palette metadata,
20391
- * but with the narrowed execute of `narraleaf-studio/runtime`.
19050
+ * What a plugin can learn about a widget type it did not register.
19051
+ *
19052
+ * The registry itself holds host objects, so what comes back is the answer to the question a plugin
19053
+ * can act on - does this type exist, and what is it called - rather than the module behind it.
19054
+ */
19055
+ export type PluginWidgetTypeInfo = {
19056
+ type: string;
19057
+ displayName: string;
19058
+ /** The widget type this one specialises, when it specialises one. */
19059
+ extends?: string;
19060
+ /** The plugin that contributed it, absent for Studio's own widgets. */
19061
+ ownerPluginId?: string;
19062
+ };
19063
+ /**
19064
+ * A blueprint node as a *plugin* writes it: everything a node declares about itself, with the
19065
+ * narrowed execute of `narraleaf-studio/runtime`.
19066
+ *
19067
+ * Built on `BlueprintNodeDeclaration` rather than on the host's `BlueprintNodeDef`, so the two
19068
+ * fields that say *where* a node may appear — `scope` and `requiresHostApi` — are not merely
19069
+ * omitted here but unreachable from the published package. `scope` in particular is a list of
19070
+ * owner kinds taken from `BlueprintOwnerRef`; publishing it would let a plugin pin an internal
19071
+ * union, and every later change to the blueprint model would break plugins that had. Both
19072
+ * restrictions are the host's answer, decided by review for the built-in catalogue, and the host
19073
+ * drops either one a plugin's compiled JavaScript still carries.
20392
19074
  *
20393
19075
  * The host's own `BlueprintNodeDef.execute` receives a `BehaviorNodeExecutionContext`,
20394
19076
  * which carries `hostAdapter` — and through it every host API: saves, localization,
@@ -20396,13 +19078,15 @@ export type PluginUiKit = typeof pluginUi;
20396
19078
  * declared and the user never approved. So a plugin's execute gets the very same
20397
19079
  * capability-gated context its runtime entry gets, in both targets: one node module
20398
19080
  * can be shared by the studio and runtime entries, and neither is the privileged one.
19081
+ * That is also why `BlueprintNodeExecuteFn`, which names the host context, is not published:
19082
+ * nothing a plugin can write would satisfy it.
20399
19083
  *
20400
19084
  * The editor is an environment that backs no game, so the gated domains on
20401
19085
  * `ctx.game` (`saves`, `store`, `state`, …) are absent while a node runs in Studio.
20402
19086
  * Nodes must degrade rather than assume them — the same discipline a plugin already
20403
19087
  * needs for the web export versus the desktop shell.
20404
19088
  */
20405
- export type PluginBlueprintNodeDef = Omit<BlueprintNodeDef, "execute"> & {
19089
+ export type PluginBlueprintNodeDef = BlueprintNodeDeclaration & {
20406
19090
  execute: RuntimeBlueprintNodeExecute;
20407
19091
  };
20408
19092
  /**
@@ -20627,7 +19311,7 @@ export type PluginAssetsService = {
20627
19311
  revokeObjectUrl(url: string): void;
20628
19312
  };
20629
19313
  /** An active editor locale code (built-in like "en"/"zh", or a plugin-provided locale). */
20630
- type LocaleCode$1 = string;
19314
+ export type LocaleCode = string;
20631
19315
  /**
20632
19316
  * A plugin's own message tables: `locale code -> (message key -> string)`. This
20633
19317
  * is the plugin's private catalog, unrelated to Studio's own translations.
@@ -20647,7 +19331,7 @@ export type PluginMessageBundle = {
20647
19331
  * {@link PluginI18n.onLocaleChange} to re-render on a language switch.
20648
19332
  */
20649
19333
  export type PluginTranslator = {
20650
- readonly locale: LocaleCode$1;
19334
+ readonly locale: LocaleCode;
20651
19335
  t(key: string, params?: Record<string, string | number>): string;
20652
19336
  };
20653
19337
  /**
@@ -20657,14 +19341,14 @@ export type PluginTranslator = {
20657
19341
  */
20658
19342
  export type PluginI18n = {
20659
19343
  /** The editor's active locale code. */
20660
- readonly locale: LocaleCode$1;
19344
+ readonly locale: LocaleCode;
20661
19345
  /**
20662
19346
  * Subscribe to editor-language changes. The listener fires with the new
20663
19347
  * locale code whenever the active editor language changes. Returns a
20664
19348
  * {@link PluginCleanup} (also tracked by the host, so it is reclaimed on
20665
19349
  * unload even if you forget to call it).
20666
19350
  */
20667
- onLocaleChange(listener: (locale: LocaleCode$1) => void): PluginCleanup;
19351
+ onLocaleChange(listener: (locale: LocaleCode) => void): PluginCleanup;
20668
19352
  /** Locale-aware number formatting bound to the editor's active locale. */
20669
19353
  formatNumber(value: number, options?: Intl.NumberFormatOptions): string;
20670
19354
  /** Locale-aware date formatting bound to the editor's active locale. */
@@ -20798,11 +19482,18 @@ export type PluginServices = {
20798
19482
  error(message: string): void;
20799
19483
  };
20800
19484
  };
19485
+ /**
19486
+ * Contribute a widget type to the interface editor; see {@link PluginWidgetModule}.
19487
+ *
19488
+ * `get` and `list` answer with a type's name rather than with its module. A widget module is
19489
+ * the host's own object - Studio's built-ins carry the editor services in their callbacks - and
19490
+ * "which types exist" is the whole of what a plugin can act on.
19491
+ */
20801
19492
  widgets: {
20802
- register(module: UIWidgetModule): PluginCleanup;
20803
- registerMany(modules: UIWidgetModule[]): PluginCleanup;
20804
- get(type: string): UIWidgetModule | undefined;
20805
- list(): UIWidgetModule[];
19493
+ register(module: PluginWidgetModule): PluginCleanup;
19494
+ registerMany(modules: PluginWidgetModule[]): PluginCleanup;
19495
+ get(type: string): PluginWidgetTypeInfo | undefined;
19496
+ list(): PluginWidgetTypeInfo[];
20806
19497
  has(type: string): boolean;
20807
19498
  };
20808
19499
  story: {
@@ -20851,7 +19542,6 @@ export declare function isPluginDefinition(value: unknown): value is PluginDefin
20851
19542
 
20852
19543
  export {
20853
19544
  BehaviorNodeExecuteResult as RuntimeBlueprintNodeResult,
20854
- LocaleCode$1 as LocaleCode,
20855
19545
  SelectOption$1 as SelectOption,
20856
19546
  };
20857
19547