narraleaf-studio 0.6.0 → 0.7.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
@@ -1422,197 +1422,6 @@ type StoryAlignPositionValue = {
1422
1422
  xoffset?: number;
1423
1423
  yoffset?: number;
1424
1424
  };
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
1425
  type BlueprintDebugEvent = {
1617
1426
  type: "execution.started";
1618
1427
  executionId: string;
@@ -1658,6 +1467,29 @@ type BlueprintDebugEvent = {
1658
1467
  type: "devtools.log";
1659
1468
  level: string;
1660
1469
  message: string;
1470
+ } | {
1471
+ /**
1472
+ * A node ran with one of its required data inputs left unconnected and no value on the
1473
+ * card, so the pin resolved to nothing.
1474
+ *
1475
+ * Its own event rather than a `devtools.log`, because it has a place: an issue list can
1476
+ * put it on a surface, and a repeat of it on the same pin is the same problem rather than
1477
+ * a second line of output. Carries the node's and the pin's English names off the
1478
+ * catalogue, which is what a host that has no node-title map (the shipped game) can still
1479
+ * write into a player's log.
1480
+ */
1481
+ type: "node.input_missing";
1482
+ executionId: string;
1483
+ nodeId: string;
1484
+ /** The node's display name as its definition declares it. */
1485
+ nodeName: string;
1486
+ /** The unwired pin's label as its definition declares it. */
1487
+ pinLabel: string;
1488
+ blueprintId?: string;
1489
+ eventId?: string;
1490
+ graphId?: string;
1491
+ /** See the note on `execution.error`: what lets a host say "the Quick Menu". */
1492
+ surfaceId?: string;
1661
1493
  } | {
1662
1494
  type: "execution.error";
1663
1495
  executionId: string;
@@ -1694,9 +1526,6 @@ type BlueprintOwnerRef = {
1694
1526
  kind: "componentWidgetMain";
1695
1527
  componentId: string;
1696
1528
  elementId: string;
1697
- } | {
1698
- kind: "sharedAsset";
1699
- assetId: string;
1700
1529
  }
1701
1530
  /**
1702
1531
  * Story Action Blueprint: an implicit project resource bound 1:1 to a single story action.
@@ -1717,17 +1546,22 @@ type BlueprintOwnerRef = {
1717
1546
  blueprintId: string;
1718
1547
  mode?: "action" | "value" | "condition";
1719
1548
  };
1720
- type BlueprintFrontendKind = "visual" | "typescript";
1721
- type BlueprintProgramKind = "graph" | "scriptModule";
1722
1549
  type Blueprint = {
1723
1550
  id: string;
1724
1551
  name: string;
1725
1552
  owner: BlueprintOwnerRef;
1726
- frontend: BlueprintFrontendKind;
1727
- programKind: BlueprintProgramKind;
1728
1553
  members?: BlueprintMemberIndex;
1729
1554
  bindings?: Record<string, BindingDefinition>;
1730
- program: BlueprintProgram;
1555
+ /**
1556
+ * The layers this slot runs, in the order the author arranged them.
1557
+ *
1558
+ * Reached directly rather than through a `program: { kind }` wrapper. The wrapper existed to
1559
+ * separate a graph blueprint from a script one, and there is no such division any more: a
1560
+ * blueprint is a container of layers, and each layer says for itself whether it is a graph or a
1561
+ * file. Three fields used to answer the same question - `frontend`, `programKind` and
1562
+ * `program.kind` - and none of them could answer it for a blueprint holding one of each.
1563
+ */
1564
+ graphs: BlueprintGraphIndex;
1731
1565
  meta?: Record<string, unknown>;
1732
1566
  };
1733
1567
  type BlueprintMemberIndex = {
@@ -1779,12 +1613,10 @@ type BlueprintFunctionSignature = {
1779
1613
  returnType?: string;
1780
1614
  meta?: Record<string, unknown>;
1781
1615
  };
1782
- type BlueprintProgram = {
1783
- kind: "graph";
1784
- graphs: BlueprintGraphIndex;
1785
- } | {
1786
- kind: "scriptModule";
1787
- source: TypeScriptBlueprintSource;
1616
+ type BlueprintLayerScript = {
1617
+ scriptRef: string;
1618
+ /** What the last compile of {@link scriptRef} said. Absent until one has run. */
1619
+ diagnostics?: BlueprintDiagnostic[];
1788
1620
  };
1789
1621
  type BlueprintGraphIndex = {
1790
1622
  /**
@@ -1803,7 +1635,7 @@ type BlueprintGraphIndex = {
1803
1635
  * listed. Write it through the service, never by hand.
1804
1636
  */
1805
1637
  eventIds?: string[];
1806
- events: Record<string, BlueprintEventGraph>;
1638
+ events: Record<string, BlueprintLayer>;
1807
1639
  /**
1808
1640
  * Authored order of {@link functions}, on the same terms as {@link eventIds}.
1809
1641
  *
@@ -1861,11 +1693,13 @@ type BlueprintGraphEdge = {
1861
1693
  port: string;
1862
1694
  };
1863
1695
  };
1864
- type BlueprintEventGraph = {
1696
+ type BlueprintLayer = {
1865
1697
  id: string;
1866
1698
  name?: string;
1867
1699
  /** Event execution graph - may contain effectful nodes */
1868
1700
  graph?: BlueprintGraphIr;
1701
+ /** The author's file this layer runs, when it is a script layer rather than a graph one. */
1702
+ script?: BlueprintLayerScript;
1869
1703
  meta?: Record<string, unknown>;
1870
1704
  };
1871
1705
  type BlueprintFunctionGraph = {
@@ -1880,13 +1714,6 @@ type BlueprintMacroGraph = {
1880
1714
  graph?: BlueprintGraphIr;
1881
1715
  meta?: Record<string, unknown>;
1882
1716
  };
1883
- type TypeScriptBlueprintSource = {
1884
- language: "typescript";
1885
- code: string;
1886
- compiledModuleId?: string;
1887
- outputPath?: string;
1888
- diagnostics?: BlueprintDiagnostic[];
1889
- };
1890
1717
  type LiteralValue = string | number | boolean | null | LiteralValue[] | {
1891
1718
  [key: string]: LiteralValue;
1892
1719
  };
@@ -1920,16 +1747,6 @@ type BlueprintDiagnostic = {
1920
1747
  /** Source span or module location; M1 opaque */
1921
1748
  location?: Record<string, unknown>;
1922
1749
  };
1923
- type SharedBlueprintAsset = {
1924
- assetId: string;
1925
- name: string;
1926
- frontend: BlueprintFrontendKind;
1927
- blueprint: Blueprint;
1928
- meta?: {
1929
- tags?: string[];
1930
- category?: string;
1931
- };
1932
- };
1933
1750
  type LocaleCode = string;
1934
1751
  type LocalizationLocaleEntry = {
1935
1752
  code: LocaleCode;
@@ -1954,24 +1771,6 @@ type GameLocalizationBundle = {
1954
1771
  */
1955
1772
  scenes?: Record<string, string>;
1956
1773
  };
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;
1962
- /**
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.
1966
- */
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
1774
  type SaveRecordTimes = {
1976
1775
  /** When this slot was last written, epoch milliseconds; 0 when the record carries no stamp. */
1977
1776
  savedAt: number;
@@ -1990,6 +1789,12 @@ type SaveRecordLine = {
1990
1789
  /** Who spoke it, or "" when the record carries no speaker (narration, or none yet). */
1991
1790
  speaker: string;
1992
1791
  };
1792
+ type SaveRecordStory = {
1793
+ /** The story the save was written in, as an opaque reference; "" when the record carries none. */
1794
+ id: string;
1795
+ /** That story's author-facing name; "" when this build ships no story under that reference. */
1796
+ name: string;
1797
+ };
1993
1798
  type AutoSaveEntry = {
1994
1799
  id: string;
1995
1800
  /** Slot index within the ring. */
@@ -2022,64 +1827,269 @@ type AudioClipRegion = {
2022
1827
  * than clamped: clamping would invent a loop point the author never marked, while dropping
2023
1828
  * degrades to the plain loop the two other markers already describe.
2024
1829
  */
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;
1830
+ loopStartMs?: number;
1831
+ };
1832
+ type BlueprintOpenExternalRequest = {
1833
+ url: string;
1834
+ };
1835
+ type BlueprintOpenExternalOutcome = "opened" | "refused" | "failed";
1836
+ type BlueprintOpenExternalResult = {
1837
+ outcome: BlueprintOpenExternalOutcome;
1838
+ /** Human-readable reason, null when the page was handed over. */
1839
+ error: string | null;
1840
+ };
1841
+ type BlueprintPointerMoveOutcome =
1842
+ /** The cursor is now at the requested point. */
1843
+ "moved"
1844
+ /** This shell cannot move the cursor: a web export, or a host with no platform support. */
1845
+ | "unsupported"
1846
+ /** The move was attempted and failed. */
1847
+ | "failed";
1848
+ type BlueprintPointerMoveResult = {
1849
+ outcome: BlueprintPointerMoveOutcome;
1850
+ error?: string;
1851
+ };
1852
+ declare const BLUEPRINT_POINTER_MOVE_EASINGS: readonly [
1853
+ "linear",
1854
+ "easeIn",
1855
+ "easeOut",
1856
+ "easeInOut"
1857
+ ];
1858
+ type BlueprintPointerMoveEasing = (typeof BLUEPRINT_POINTER_MOVE_EASINGS)[number];
1859
+ type BlueprintScreenshotOutcome = "saved" | "failed";
1860
+ type BlueprintScreenshotResult = {
1861
+ outcome: BlueprintScreenshotOutcome;
1862
+ /** The file that was written, absolute, or null when nothing was. */
1863
+ path: string | null;
1864
+ /** Why nothing was written. Null on success. */
1865
+ error: string | null;
1866
+ };
1867
+ type BlueprintOpenScreenshotsResult = {
1868
+ outcome: "opened" | "failed";
1869
+ /** The folder that was opened, absolute, or null when none was. */
1870
+ path: string | null;
1871
+ error: string | null;
1872
+ };
1873
+ type BlueprintGraphKind = "event" | "function" | "macro";
1874
+ declare const BLUEPRINT_NETWORK_METHODS: readonly [
1875
+ "GET",
1876
+ "POST",
1877
+ "PUT",
1878
+ "PATCH",
1879
+ "DELETE",
1880
+ "HEAD"
1881
+ ];
1882
+ type BlueprintNetworkMethod = typeof BLUEPRINT_NETWORK_METHODS[number];
1883
+ type BlueprintNetworkFetchRequest = {
1884
+ url: string;
1885
+ method: BlueprintNetworkMethod;
1886
+ /** Header name -> value. Null and `{}` both mean "send none". */
1887
+ headers: Record<string, string> | null;
1888
+ /** Request body, for the methods that carry one. */
1889
+ body: string | null;
1890
+ timeoutMs: number;
1891
+ };
1892
+ type BlueprintNetworkFetchOutcome = "success" | "httpError" | "networkError" | "timeout";
1893
+ type BlueprintNetworkFetchResult = {
1894
+ outcome: BlueprintNetworkFetchOutcome;
1895
+ /** HTTP status, or 0 when no response was received. */
1896
+ status: number;
1897
+ /** Response body text, present whenever a response arrived. */
1898
+ body: string | null;
1899
+ /** Human-readable failure reason, null on success. */
1900
+ error: string | null;
1901
+ };
1902
+ type GameBuildPlatform = "windows" | "macos" | "linux" | "web" | "android" | "ios";
1903
+ type PluginPermissionPersistence = "temporary" | "permanent";
1904
+ type PluginFileSystemPermissionMode = "read" | "write" | "readwrite";
1905
+ /**
1906
+ * Install-time permissions split into two families, and the split is the whole
1907
+ * point:
1908
+ *
1909
+ * - **Author-declared** (`filesystem`, `api`) — privileged Studio controls the
1910
+ * plugin asks for explicitly in `permissions[]`.
1911
+ * - **Derived** (`runtime`, `sidecar`, `buildDependency`, `externalLink`,
1912
+ * `network`) — computed from `contributes` by {@link validatePluginManifest}
1913
+ * and *rejected* if written by
1914
+ * hand. A capability is declared in exactly one place, so what the prompt shows
1915
+ * and what the plugin can actually reach cannot drift apart. Adding a
1916
+ * capability widens the permission set, which makes the update re-prompt for
1917
+ * free (see `isPermissionSubset`).
1918
+ */
1919
+ export type PluginInstallPermission = {
1920
+ kind: "filesystem";
1921
+ path: string;
1922
+ mode: PluginFileSystemPermissionMode;
1923
+ recursive: boolean;
1924
+ } | {
1925
+ kind: "api";
1926
+ capability: string;
1927
+ } | {
1928
+ /** Derived from `contributes.runtimeCapabilities`. */
1929
+ kind: "runtime";
1930
+ capability: PluginRuntimeCapability;
1931
+ } | {
1932
+ /** Derived from `contributes.sidecars`: a native child process shipped inside the author's game. */
1933
+ kind: "sidecar";
1934
+ id: string;
1935
+ /**
1936
+ * Which of the two sidecar shapes this is, carried through from the manifest because the
1937
+ * two are different promises: `executable` starts a separate binary, `node` runs the
1938
+ * plugin's own JavaScript under the game's Electron as Node. An author told only "this
1939
+ * ships a helper program" has not been told which one they are approving.
1940
+ *
1941
+ * Named apart from `kind` above on purpose - that one says which permission this is, this
1942
+ * one says what the sidecar runs.
1943
+ */
1944
+ sidecarKind: PluginSidecarKind;
1945
+ /** `<platform>-<arch>` keys the sidecar ships binaries for. */
1946
+ platforms: string[];
1947
+ } | {
1948
+ /** Derived from `contributes.buildDependencies`: binaries downloaded at build time. */
1949
+ kind: "buildDependency";
1950
+ id: string;
1951
+ /** Distinct hostnames the binaries are fetched from. */
1952
+ hosts: string[];
1953
+ } | {
1954
+ /**
1955
+ * Derived from `contributes.externalLinks`: addresses outside the game this plugin may open
1956
+ * in the player's browser or platform handler.
1957
+ *
1958
+ * One permission carrying every pattern rather than one permission each, because what the
1959
+ * author is deciding is a single question - "may this plugin send the player out to these
1960
+ * places" - and a prompt that asked it four times would be four chances to stop reading.
1961
+ * `isPermissionSubset` still compares the patterns one by one, so adding one to a later
1962
+ * version widens the set and re-prompts.
1963
+ *
1964
+ * The patterns are the author's own strings, unrewritten: this list is what the prompt
1965
+ * shows, and normalizing a permission before showing it to the person approving it would
1966
+ * make the prompt and the manifest two slightly different documents.
1967
+ */
1968
+ kind: "externalLink";
1969
+ patterns: string[];
1970
+ } | {
1971
+ /**
1972
+ * Derived from `contributes.network`: hosts this plugin's runtime code requests bytes from.
1973
+ *
1974
+ * A separate question from `externalLink` and never folded into it. Opening a page hands an
1975
+ * address to the browser the player already uses and nothing comes back; this fetches, and
1976
+ * what comes back runs inside the game. An author deciding about one has not decided about
1977
+ * the other.
1978
+ *
1979
+ * The patterns are also what a project's network allowlist shows attributed to this plugin,
1980
+ * which is the point of declaring them: a build narrowed to a list still reaches what the
1981
+ * author approved here, and the list can say so rather than silently making room.
1982
+ */
1983
+ kind: "network";
1984
+ patterns: string[];
1985
+ };
1986
+ type PluginSidecarKind = "executable" | "node";
1987
+ declare const PluginRuntimeCapability: {
1988
+ /** `app.game.store` — plugin-scoped persistent key/value storage. */
1989
+ readonly Store: "store";
1990
+ /** `app.game.events` — game lifecycle and engine event subscription. */
1991
+ readonly Events: "events";
1992
+ /** `app.game.state.get` — read story variables. */
1993
+ readonly StateRead: "state.read";
1994
+ /** `app.game.state.set` — write story variables. */
1995
+ readonly StateWrite: "state.write";
1996
+ /** `app.game.saves` — list and read save metadata. */
1997
+ readonly SavesRead: "saves.read";
1998
+ /**
1999
+ * `app.game.saves.write` / `.load` — overwrite a save slot and load one.
2000
+ *
2001
+ * Separate from (and heavier than) `saves.read`: this can destroy a
2002
+ * playthrough. It exists because quick-save/quick-load is an ordinary thing
2003
+ * for a visual novel to ship — the built-in Quick Save plugin is exactly
2004
+ * this — and a capability model that cannot express a feature the product
2005
+ * already has would just push authors back around it.
2006
+ */
2007
+ readonly SavesWrite: "saves.write";
2008
+ /** `app.game.ui.overlay` — draw on top of the game. */
2009
+ readonly UiOverlay: "ui.overlay";
2010
+ /** `app.game.assets` — resolve packaged asset URLs. */
2011
+ readonly Assets: "assets";
2012
+ /**
2013
+ * `app.game.locale` — read and observe the game language, and read the project's own
2014
+ * localized text through the same table and fallback chain the `Get Text` node uses.
2015
+ */
2016
+ readonly Locale: "locale";
2017
+ /**
2018
+ * `app.game.menu` — own the menu bar above the game.
2019
+ *
2020
+ * Its own capability rather than part of anything else, because what it grants is *the chrome
2021
+ * the player reads the game through*: every row on that bar, and what each one does, is this
2022
+ * plugin's to decide. The rows still act through the game's own vocabulary (see
2023
+ * `@shared/types/gameMenu`) - nothing here reaches past what a blueprint could already do - but
2024
+ * an author approving this is handing over a surface their players will read as the game's own,
2025
+ * which is worth a name at install rather than arriving with something else.
2026
+ *
2027
+ * Absent on shells with no bar to give (the web export, Dev Mode), which is reported the way
2028
+ * every environment difference is: the member is not there.
2029
+ */
2030
+ readonly Menu: "menu";
2031
+ /**
2032
+ * `app.game.story` — register a compile pass that observes each scene and injects engine
2033
+ * actions around its rows.
2034
+ *
2035
+ * The heaviest of the ten to read, and the one whose weight is easiest to miss: nothing here
2036
+ * touches the player's files, and the author still sees only their own document — but a pass
2037
+ * runs over *every* scene of the project, sees who speaks in each, and can put actions around
2038
+ * lines it did not write. That is a plugin editing the story, at the last moment before it
2039
+ * plays, and it is worth a name the author approves at install.
2040
+ *
2041
+ * It is not `state.write` in disguise and does not imply it: a pass builds actions, it does not
2042
+ * run them, and the one piece of runtime state it can touch is a scene-local flag the compiler
2043
+ * creates and owns (`SceneCompileContext.runtimeFlag`), never a story variable the author
2044
+ * declared.
2045
+ */
2046
+ readonly StoryCompile: "story.compile";
2082
2047
  };
2048
+ type PluginRuntimeCapability = typeof PluginRuntimeCapability[keyof typeof PluginRuntimeCapability];
2049
+ /**
2050
+ * `app.game.sidecar` has no entry here on purpose: it exists exactly when
2051
+ * `contributes.sidecars` is non-empty. Declaring the sidecar *is* the request.
2052
+ */
2053
+ export interface PluginIdentity {
2054
+ id: string;
2055
+ name?: string;
2056
+ version?: string;
2057
+ publisher?: string;
2058
+ }
2059
+ interface PluginPermissionRequestBase {
2060
+ requestId: string;
2061
+ plugin: PluginIdentity;
2062
+ reason?: string;
2063
+ requestedAt?: number;
2064
+ }
2065
+ export type PluginPermissionRequest = (PluginPermissionRequestBase & {
2066
+ kind: "trust";
2067
+ persistence?: PluginPermissionPersistence;
2068
+ }) | (PluginPermissionRequestBase & {
2069
+ kind: "filesystem";
2070
+ path: string;
2071
+ mode: PluginFileSystemPermissionMode;
2072
+ recursive: boolean;
2073
+ persistence: PluginPermissionPersistence;
2074
+ }) | (PluginPermissionRequestBase & {
2075
+ kind: "install";
2076
+ source: string;
2077
+ permissions?: PluginInstallPermission[];
2078
+ persistence?: PluginPermissionPersistence;
2079
+ }) | (PluginPermissionRequestBase & {
2080
+ kind: "api";
2081
+ capability: string;
2082
+ persistence?: PluginPermissionPersistence;
2083
+ });
2084
+ interface PluginPermissionGrantResult {
2085
+ requestId: string;
2086
+ pluginId: string;
2087
+ kind: PluginPermissionRequest["kind"];
2088
+ approved: boolean;
2089
+ persistence: PluginPermissionPersistence;
2090
+ grantedAt?: number;
2091
+ }
2092
+ export type PluginPermissionPromptResult = PluginPermissionGrantResult | null;
2083
2093
  declare const PluginManifestVersion = 2;
2084
2094
  /**
2085
2095
  * Per-target plugin entry files. Each entry is a prebundled ESM file relative
@@ -2814,63 +2824,6 @@ type UILayout = {
2814
2824
  };
2815
2825
  type UIStyle = Record<string, unknown>;
2816
2826
  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
2827
  type DevModeStartStoryRequest = {
2875
2828
  storyId: StoryId;
2876
2829
  sceneId: string;
@@ -2878,6 +2831,21 @@ type DevModeStartStoryRequest = {
2878
2831
  startBlockId?: string;
2879
2832
  /** Scene Snapshot (变量快照) whose variable overrides seed the launch. */
2880
2833
  snapshotId?: string;
2834
+ /**
2835
+ * Variable values lifted off a running game, laid over the launch's own stage walk.
2836
+ *
2837
+ * Set only by a hot reload resuming where the player was: the walk reconstructs what the values
2838
+ * would be had the story been played from the top down one path, and these are what they
2839
+ * actually were. Applied after the walk and after any Scene Snapshot, because they are the later
2840
+ * state - re-seeding either over them would rewind the player.
2841
+ *
2842
+ * Storage keys, the way the compiler names namespace entries, not variable ids. Persistent
2843
+ * values are absent by design: they outlive the run, so a reload has nothing to restore.
2844
+ */
2845
+ resume?: {
2846
+ sceneVariables: Record<string, StoryLiteralValue>;
2847
+ savedVariables: Record<string, StoryLiteralValue>;
2848
+ };
2881
2849
  };
2882
2850
  type GameTestLogLevel = "verbose" | "info" | "success" | "warning" | "error";
2883
2851
  type GameTestExitReason =
@@ -3465,6 +3433,10 @@ declare const en: {
3465
3433
  readonly keybindings: {
3466
3434
  readonly label: "Keyboard shortcuts";
3467
3435
  };
3436
+ readonly projectTrust: {
3437
+ readonly label: "Trusted projects";
3438
+ readonly description: "Projects that Studio did not create, and whether they may run.";
3439
+ };
3468
3440
  readonly cacheInventory: {
3469
3441
  readonly label: "Cached files";
3470
3442
  };
@@ -3567,6 +3539,23 @@ declare const en: {
3567
3539
  };
3568
3540
  };
3569
3541
  readonly data: {
3542
+ readonly projectTrust: {
3543
+ readonly loading: "Reading\u2026";
3544
+ readonly empty: "Every project opened so far was created by Studio.";
3545
+ readonly waiting: "Waiting for a decision";
3546
+ readonly granted: "Trusted";
3547
+ readonly trust: "Trust";
3548
+ readonly remove: "Remove";
3549
+ readonly reloadNote: "A project that is open reloads when its trust changes.";
3550
+ readonly origin: {
3551
+ readonly package: "From a package";
3552
+ readonly remote: "From a remote source";
3553
+ readonly opened: "Opened from a folder";
3554
+ readonly created: "Created by Studio";
3555
+ readonly recent: "Opened before";
3556
+ readonly commandLine: "From the command line";
3557
+ };
3558
+ };
3570
3559
  readonly cache: {
3571
3560
  readonly measuring: "Measuring\u2026";
3572
3561
  readonly unavailable: "Not available";
@@ -4091,6 +4080,10 @@ declare const en: {
4091
4080
  readonly entry: {
4092
4081
  readonly edit: "edit";
4093
4082
  readonly storyEdit: "story edit";
4083
+ readonly storyMoveRowsToScene: "move to another scene";
4084
+ readonly storySplitScene: "scene split";
4085
+ readonly storyMergeScenes: "scene merge";
4086
+ readonly storySpeakerChange: "speaker change";
4094
4087
  readonly storyMotionEdit: "motion edit";
4095
4088
  readonly audioMarkers: "marker change";
4096
4089
  readonly surfaceEdit: "interface edit";
@@ -4212,6 +4205,9 @@ declare const en: {
4212
4205
  readonly errorOpenFailed: "Could not open that folder: {error}";
4213
4206
  readonly notAProjectTitle: "This folder is not a NarraLeaf project";
4214
4207
  readonly notAProjectDetail: "No .nlproj file was found.";
4208
+ readonly projectLockedTitle: "This project is open in another NarraLeaf Studio";
4209
+ readonly projectLockedHere: "Open on this computer since {time}. Retry once it has been closed there.";
4210
+ readonly projectLockedElsewhere: "Open on {host} since {time}. Retry once it has been closed there.";
4215
4211
  readonly openLauncher: "Open launcher";
4216
4212
  readonly panelRenderError: "This panel hit a rendering error";
4217
4213
  readonly mainEditorRegion: "Main editor";
@@ -4245,8 +4241,10 @@ declare const en: {
4245
4241
  };
4246
4242
  };
4247
4243
  readonly panelMenu: {
4248
- readonly removeItem: "Remove this item";
4244
+ readonly hideItem: "Hide this item";
4249
4245
  readonly collapseItem: "Collapse into group";
4246
+ readonly resetLayout: "Reset to default layout";
4247
+ readonly resetLayoutDisabled: "Already in the default layout.";
4250
4248
  };
4251
4249
  readonly panelGroup: {
4252
4250
  readonly title: "Collapsed panels";
@@ -4323,11 +4321,16 @@ declare const en: {
4323
4321
  };
4324
4322
  };
4325
4323
  readonly statusBar: {
4324
+ readonly distrusted: {
4325
+ readonly label: "Not trusted";
4326
+ readonly tooltip: "This project cannot run until it is trusted. Click to trust it.";
4327
+ };
4326
4328
  readonly devMode: "Dev Mode";
4327
4329
  readonly preview: "Preview";
4328
4330
  readonly production: "Production";
4329
4331
  readonly phase: {
4330
4332
  readonly starting: "Starting\u2026";
4333
+ readonly checking: "Checking\u2026";
4331
4334
  readonly preparing: "Preparing\u2026";
4332
4335
  readonly compiling: "Compiling\u2026";
4333
4336
  readonly launching: "Launching\u2026";
@@ -4357,6 +4360,7 @@ declare const en: {
4357
4360
  readonly entries: {
4358
4361
  readonly team: "NarraLeaf Team";
4359
4362
  readonly runStatus: "Run status";
4363
+ readonly projectTrust: "Project trust";
4360
4364
  readonly studioTasks: "Background work";
4361
4365
  readonly unsavedChanges: "Unsaved changes";
4362
4366
  readonly wordCount: "Story stats";
@@ -4409,6 +4413,7 @@ declare const en: {
4409
4413
  readonly characters: "characters";
4410
4414
  readonly project: "project settings";
4411
4415
  readonly assets: "asset library";
4416
+ readonly openEditors: "the open editor";
4412
4417
  };
4413
4418
  };
4414
4419
  readonly reload: {
@@ -4427,6 +4432,10 @@ declare const en: {
4427
4432
  readonly unavailable: "Unavailable while the project is frozen. Unfreeze the project to use it.";
4428
4433
  readonly unavailableLive: "Unavailable during a live session. Leave the session to use it.";
4429
4434
  };
4435
+ readonly distrust: {
4436
+ readonly unavailable: "Unavailable until this project is trusted. Click Not trusted in the status bar to trust it.";
4437
+ readonly refusedTitle: "This project is not trusted";
4438
+ };
4430
4439
  readonly revisionView: {
4431
4440
  readonly showPrevious: "Show the Previous Version (Read-Only)";
4432
4441
  readonly leave: "Stop Viewing History";
@@ -4475,6 +4484,7 @@ declare const en: {
4475
4484
  readonly committing: "Submitting this version\u2026";
4476
4485
  readonly nothingToCommit: "Nothing has changed since the last version.";
4477
4486
  readonly closingWithApp: "Studio is closing. Try again after it restarts.";
4487
+ readonly repositoryLocked: "Another program has this project's version history open. Close it to use versions here.";
4478
4488
  readonly commitBeforeSync: "Submit a version before getting the server's.";
4479
4489
  readonly branchDiverged: "This project and the server have both changed. Get the server's versions first, then send yours.";
4480
4490
  readonly changesUnknown: "Not checked";
@@ -6119,6 +6129,12 @@ declare const en: {
6119
6129
  readonly other: "Link speaker on {count} lines";
6120
6130
  };
6121
6131
  readonly playFromHere: "Play from here";
6132
+ readonly moveToScene: "Move to scene";
6133
+ readonly splitScene: "Split scene here\u2026";
6134
+ readonly mergeWithNext: "Merge with next scene";
6135
+ readonly mergeIntoPrevious: "Merge into previous scene";
6136
+ readonly changeSpeaker: "Change speaker";
6137
+ readonly speakerNameOnly: "{name} (name only)";
6122
6138
  readonly openInspector: "Open inspector";
6123
6139
  readonly delete: "Delete";
6124
6140
  };
@@ -6130,6 +6146,50 @@ declare const en: {
6130
6146
  readonly moveScene: "move scene {name}";
6131
6147
  readonly moveChapter: "move chapter {name}";
6132
6148
  };
6149
+ readonly structuralOps: {
6150
+ readonly moveRows: {
6151
+ readonly done: {
6152
+ readonly one: "{count} row moved to {scene}";
6153
+ readonly other: "{count} rows moved to {scene}";
6154
+ };
6155
+ readonly refused: "Not available during a live session";
6156
+ };
6157
+ readonly splitScene: {
6158
+ readonly title: "Split Scene";
6159
+ readonly description: "The rows from here to the end become this scene.";
6160
+ readonly placeholder: "Enter scene name";
6161
+ readonly namePattern: "{name} {index}";
6162
+ readonly done: {
6163
+ readonly one: "{count} row moved to {scene}";
6164
+ readonly other: "{count} rows moved to {scene}";
6165
+ };
6166
+ readonly jumpAdded: "jump added";
6167
+ readonly refused: "The rows after this one still need what comes before it";
6168
+ readonly refusedDetail: "Still in use after this row: {names}";
6169
+ };
6170
+ readonly mergeScenes: {
6171
+ readonly confirm: "Merge \"{merged}\" into \"{surviving}\"?";
6172
+ readonly detail: {
6173
+ readonly one: "Its {count} row moves to the end of {surviving}.";
6174
+ readonly other: "Its {count} rows move to the end of {surviving}.";
6175
+ };
6176
+ readonly done: {
6177
+ readonly one: "{count} row merged into {scene}";
6178
+ readonly other: "{count} rows merged into {scene}";
6179
+ };
6180
+ readonly refused: "\"{name}\" is still named elsewhere";
6181
+ readonly refusedDetail: "Named by: {referrers}";
6182
+ readonly referrerJump: "{scene} \u00B7 row {row}";
6183
+ readonly referrerEntryScene: "the story's entry scene";
6184
+ readonly noNeighbour: "There is no scene to merge with";
6185
+ };
6186
+ readonly speaker: {
6187
+ readonly done: {
6188
+ readonly one: "Speaker changed on {count} line";
6189
+ readonly other: "Speaker changed on {count} lines";
6190
+ };
6191
+ };
6192
+ };
6133
6193
  readonly keybindings: {
6134
6194
  readonly find: "Find and replace";
6135
6195
  readonly deleteRows: "Delete selected story rows";
@@ -6182,6 +6242,7 @@ declare const en: {
6182
6242
  };
6183
6243
  reason: {
6184
6244
  unknownCommand: string;
6245
+ unknownCommandNear: string;
6185
6246
  unknownParam: string;
6186
6247
  duplicateParam: string;
6187
6248
  extraPositional: string;
@@ -6700,6 +6761,7 @@ declare const en: {
6700
6761
  readonly xOffset: "X offset";
6701
6762
  readonly yOffset: "Y offset";
6702
6763
  readonly params: "Params";
6764
+ readonly fromCharacter: "From the character";
6703
6765
  };
6704
6766
  readonly background: {
6705
6767
  readonly image: "Image";
@@ -6813,7 +6875,6 @@ declare const en: {
6813
6875
  readonly audio: "Audio";
6814
6876
  readonly video: "Videos";
6815
6877
  readonly json: "JSON Files";
6816
- readonly blueprint: "Blueprints";
6817
6878
  readonly font: "Fonts";
6818
6879
  readonly model: "Models";
6819
6880
  readonly other: "Other";
@@ -6830,6 +6891,11 @@ declare const en: {
6830
6891
  readonly one: "{count} item";
6831
6892
  readonly other: "{count} items";
6832
6893
  };
6894
+ readonly unreadable: {
6895
+ readonly category: "This category could not be read. Its file is unchanged.";
6896
+ readonly notSaved: "Changes are not being saved";
6897
+ readonly notSavedDetail: "{file} could not be read. Nothing is written over it.";
6898
+ };
6833
6899
  readonly overview: {
6834
6900
  readonly loading: "Reading the asset library\u2026";
6835
6901
  readonly failed: "Could not read the asset library.";
@@ -7210,11 +7276,6 @@ declare const en: {
7210
7276
  readonly paste: "Paste assets";
7211
7277
  readonly rename: "Rename selected asset or group";
7212
7278
  };
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
7279
  readonly previewEditor: {
7219
7280
  readonly loadFailed: "Failed to load this asset.";
7220
7281
  };
@@ -7405,7 +7466,9 @@ declare const en: {
7405
7466
  readonly node: {
7406
7467
  readonly contextInvalid: "Node \"{name}\" is not allowed in this {ownerKind} {graphKind} graph.{hint}";
7407
7468
  readonly contextValueReturnHint: " Return Value only belongs in Blueprint Value graphs.";
7469
+ readonly contextListItemHint: " It reads the list row it runs for, and nothing here draws one.";
7408
7470
  readonly noRuntime: "Node \"{node}\": no runtime for type \"{type}\".";
7471
+ readonly inputMissing: "\"{node}\" has nothing connected to \"{pin}\".";
7409
7472
  readonly unknownType: "Node \"{node}\": unknown type \"{type}\". Its plugin may be uninstalled or disabled.";
7410
7473
  readonly variableIdInvalid: "Node \"{node}\": pick a variable.";
7411
7474
  readonly persistentVariableIdInvalid: "Node \"{node}\": pick a persistent variable.";
@@ -7445,12 +7508,22 @@ declare const en: {
7445
7508
  readonly selectDataType: "Select data type";
7446
7509
  };
7447
7510
  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";
7511
+ readonly createTitle: "Add layer";
7512
+ readonly createInvalid: "Name the layer before creating it.";
7451
7513
  readonly layerName: "Layer name";
7452
7514
  readonly defaultName: "Layer {index}";
7453
7515
  };
7516
+ readonly layerDialog: {
7517
+ readonly graphDescription: "Wire nodes together on the canvas.";
7518
+ readonly scriptDescription: "Run one of your own files.";
7519
+ readonly scriptPickerLabel: "Which file this layer runs";
7520
+ readonly newScript: "New script\u2026";
7521
+ readonly newScriptDetail: "Writes a starter file under scripts/";
7522
+ readonly alreadyRun: {
7523
+ readonly one: "Already run by {count} layer";
7524
+ readonly other: "Already run by {count} layers";
7525
+ };
7526
+ };
7454
7527
  readonly owner: {
7455
7528
  readonly global: "Global";
7456
7529
  readonly storyAction: "Story Action";
@@ -7467,6 +7540,7 @@ declare const en: {
7467
7540
  readonly renameLayerTitle: "Rename layer";
7468
7541
  readonly layerNamePlaceholder: "Layer name";
7469
7542
  readonly deleteLayer: "Delete layer\u2026";
7543
+ readonly deleteScriptLayer: "Remove layer (the file stays)";
7470
7544
  readonly deleteLayerConfirm: "Delete this layer?";
7471
7545
  readonly deleteLayerDetail: "Linked UI events will be cleared.";
7472
7546
  readonly deleteVariableLabel: "Delete variable \"{name}\"";
@@ -7490,16 +7564,9 @@ declare const en: {
7490
7564
  readonly defaultVariableName: "Variable";
7491
7565
  readonly defaultPersistentName: "Persistent";
7492
7566
  };
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
7567
  readonly frontend: {
7502
- readonly visual: "Visual";
7568
+ readonly visual: "Blueprint";
7569
+ readonly script: "Script";
7503
7570
  };
7504
7571
  readonly literal: {
7505
7572
  readonly string: "String";
@@ -7661,9 +7728,22 @@ declare const en: {
7661
7728
  readonly unnamedInputAction: "Unnamed action";
7662
7729
  readonly missingInputAction: "Missing action";
7663
7730
  };
7664
- readonly tsPane: {
7665
- readonly importHint: "Allowed import: \"narraleaf-studio\"";
7666
- readonly sourceLabel: "TypeScript blueprint source";
7731
+ readonly script: {
7732
+ readonly fileLabel: "Script file";
7733
+ readonly open: "Open in editor";
7734
+ readonly openIn: "Open in {editor}";
7735
+ readonly reveal: "Show in file manager";
7736
+ readonly openFolder: "Open scripts folder";
7737
+ readonly missing: "This file is missing.";
7738
+ readonly changeFile: "Use another file";
7739
+ readonly changeFileEmpty: "No other file under scripts/";
7740
+ readonly readOnly: "Scripts are edited in your own editor.";
7741
+ readonly sectionTitle: "Scripts";
7742
+ readonly tabTitle: "Script";
7743
+ readonly sectionEmpty: "No scripts yet. Open the logic of a page or a component, add a layer, and choose Script.";
7744
+ readonly unbound: "Nothing runs this file";
7745
+ readonly boundTo: "Runs as {name}";
7746
+ readonly boundToMany: "Runs as {name} and {count} more";
7667
7747
  };
7668
7748
  readonly tool: {
7669
7749
  readonly select: "Select tool";
@@ -7890,6 +7970,7 @@ declare const en: {
7890
7970
  readonly isEntering: "Is Entering";
7891
7971
  readonly isExiting: "Is Exiting";
7892
7972
  readonly isFullscreen: "Is Fullscreen";
7973
+ readonly isFocused: "Is Focused";
7893
7974
  readonly isPicked: "Is Picked";
7894
7975
  readonly isRead: "Is Read";
7895
7976
  readonly isInstalled: "Is Installed";
@@ -7979,6 +8060,7 @@ declare const en: {
7979
8060
  readonly skipDelay: "Skip Delay";
7980
8061
  readonly skipInterval: "Skip Interval";
7981
8062
  readonly skipReadText: "Skip Read Text";
8063
+ readonly muteWhenUnfocused: "Mute When Unfocused";
7982
8064
  readonly skipping: "Skipping";
7983
8065
  readonly slider: "Slider";
7984
8066
  readonly sound: "Sound";
@@ -7988,6 +8070,7 @@ declare const en: {
7988
8070
  readonly status: "Status";
7989
8071
  readonly step: "Step";
7990
8072
  readonly story: "Story";
8073
+ readonly storyName: "Story Name";
7991
8074
  readonly success: "Success";
7992
8075
  readonly string: "String";
7993
8076
  readonly switch: "Switch";
@@ -8146,6 +8229,7 @@ declare const en: {
8146
8229
  readonly getSkipDelay: "Get Skip Delay";
8147
8230
  readonly getSkipInterval: "Get Skip Interval";
8148
8231
  readonly getSkipReadText: "Get Skip Read Text";
8232
+ readonly getMuteWhenUnfocused: "Get Mute When Unfocused";
8149
8233
  readonly getSkipping: "Get Skipping";
8150
8234
  readonly getSliderEnabled: "Get Slider Enabled";
8151
8235
  readonly getSliderVisible: "Get Slider Visible";
@@ -8193,6 +8277,7 @@ declare const en: {
8193
8277
  readonly setSkipDelay: "Set Skip Delay";
8194
8278
  readonly setSkipInterval: "Set Skip Interval";
8195
8279
  readonly setSkipReadText: "Set Skip Read Text";
8280
+ readonly setMuteWhenUnfocused: "Set Mute When Unfocused";
8196
8281
  readonly setSkipping: "Set Skipping";
8197
8282
  readonly setSliderEnabled: "Set Slider Enabled";
8198
8283
  readonly setSliderVisible: "Set Slider Visible";
@@ -8457,11 +8542,15 @@ declare const en: {
8457
8542
  readonly onGameReady: "On Game Ready";
8458
8543
  readonly onFullscreenChanged: "On Fullscreen Changed";
8459
8544
  readonly onWindowCloseRequested: "On Window Close Requested";
8545
+ readonly onWindowFocusChanged: "On Window Focus Changed";
8460
8546
  readonly onAction: "On Action";
8461
8547
  readonly onKeyDown: "On Key Down";
8462
8548
  readonly onKeyUp: "On Key Up";
8463
8549
  readonly onPreferenceChanged: "On Preference Changed";
8464
8550
  readonly openLink: "Open Link";
8551
+ readonly openScreenshotsFolder: "Open Screenshots Folder";
8552
+ readonly saveScreenshot: "Save Screenshot";
8553
+ readonly isWindowFocused: "Is Window Focused";
8465
8554
  readonly openPage: "Open page";
8466
8555
  readonly or: "Or";
8467
8556
  readonly padEnd: "Pad End";
@@ -8599,6 +8688,7 @@ declare const en: {
8599
8688
  readonly getTimeZone: "Get Time Zone";
8600
8689
  readonly getSaveTime: "Get Save Time";
8601
8690
  readonly getSaveLine: "Get Save Line";
8691
+ readonly getSaveStory: "Get Save Story";
8602
8692
  readonly getSavePlaytime: "Get Save Playtime";
8603
8693
  readonly getPlaytime: "Get Playtime";
8604
8694
  readonly getTotalPlaytime: "Get Total Playtime";
@@ -8631,12 +8721,18 @@ declare const en: {
8631
8721
  readonly namePlaceholder: "Enter character name";
8632
8722
  readonly groupNamePlaceholder: "Enter group name";
8633
8723
  readonly deleteCharacterConfirm: "Delete character \"{name}\"?";
8724
+ readonly renameSpokenRowsConfirm: {
8725
+ readonly one: "Also rename {count} line that speaks as \"{name}\"?";
8726
+ readonly other: "Also rename {count} lines that speak as \"{name}\"?";
8727
+ };
8728
+ readonly renameSpokenRowsDetail: "Those lines carry the name, not the character. They become \"{name}\".";
8634
8729
  readonly deleteCharacterDetail: "Its dialogue keeps the name. Rows that place it on stage stop resolving.";
8635
8730
  readonly deleteGroupConfirm: "Delete group \"{name}\"?";
8636
8731
  readonly deleteGroupDetail: "Characters in this group will be unassigned.";
8637
8732
  };
8638
8733
  readonly history: {
8639
8734
  readonly deleteCharacter: "delete character {name}";
8735
+ readonly renameCharacter: "rename character {name}";
8640
8736
  readonly deleteGroup: "delete group {name}";
8641
8737
  };
8642
8738
  readonly create: {
@@ -8682,6 +8778,7 @@ declare const en: {
8682
8778
  readonly describeNoModel: "No model to read";
8683
8779
  readonly describeNoBackend: "No runtime chosen";
8684
8780
  readonly describeBackendMissing: "Runtime not installed here";
8781
+ readonly describeDistrusted: "Project not trusted";
8685
8782
  readonly describeNotSupported: "This runtime lists nothing";
8686
8783
  readonly describeFailed: "The model could not be read";
8687
8784
  readonly redescribe: "Read the model again";
@@ -8834,6 +8931,10 @@ declare const en: {
8834
8931
  readonly voiceTrack: "Voice bus";
8835
8932
  readonly voiceTrackMissing: "Missing bus";
8836
8933
  readonly voiceTrackEmpty: "Add a bus under Voice in Project \u25B8 Game to give this character its own volume control.";
8934
+ readonly entrance: "Entrance defaults";
8935
+ readonly entranceEmpty: "Entrance rows use the stage's own values until this is set.";
8936
+ readonly entranceDrag: "Drag to place";
8937
+ readonly entranceZoom: "Drag to scale";
8837
8938
  readonly select: "Select";
8838
8939
  readonly thumbnailAlt: "thumbnail";
8839
8940
  readonly color: "Color";
@@ -9096,6 +9197,9 @@ declare const en: {
9096
9197
  readonly refresh: "Check for Updates";
9097
9198
  readonly refreshFailedTitle: "Could not check the source";
9098
9199
  };
9200
+ readonly local: {
9201
+ readonly origin: "The project holds a copy of a file on this machine. Studio does not track that file; Replace File imports it again.";
9202
+ };
9099
9203
  readonly image: {
9100
9204
  readonly title: "Image Properties";
9101
9205
  readonly info: "Image Information";
@@ -9412,7 +9516,8 @@ declare const en: {
9412
9516
  };
9413
9517
  readonly storySnapshot: {
9414
9518
  readonly empty: "Open a story scene to manage its snapshots.";
9415
- readonly getStarted: "Add a snapshot to set launch values.";
9519
+ readonly defaults: "Defaults";
9520
+ readonly defaultsDetail: "Every variable starts at the value declared for it.";
9416
9521
  readonly noVariables: "No variables in scope for this scene.";
9417
9522
  readonly add: "Add snapshot";
9418
9523
  readonly delete: "Delete snapshot";
@@ -9422,11 +9527,6 @@ declare const en: {
9422
9527
  readonly true: "True";
9423
9528
  readonly false: "False";
9424
9529
  };
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
9530
  };
9431
9531
  readonly uiEditor: {
9432
9532
  readonly surfaceKind: {
@@ -9441,7 +9541,6 @@ declare const en: {
9441
9541
  readonly surfaceMain: "Page logic";
9442
9542
  readonly widgetMain: "Component logic";
9443
9543
  readonly widgetValue: "Component value";
9444
- readonly sharedAsset: "Shared blueprint";
9445
9544
  readonly storyAction: "Story action";
9446
9545
  };
9447
9546
  readonly stageSlot: {
@@ -9745,7 +9844,7 @@ declare const en: {
9745
9844
  readonly interaction: "Interaction";
9746
9845
  };
9747
9846
  readonly blueprint: {
9748
- readonly controlLabel: "Control blueprint";
9847
+ readonly controlLabel: "Component logic";
9749
9848
  };
9750
9849
  readonly appearance: {
9751
9850
  readonly title: "Appearance";
@@ -9757,6 +9856,7 @@ declare const en: {
9757
9856
  readonly horizontal: "Horizontal";
9758
9857
  readonly vertical: "Vertical";
9759
9858
  readonly gap: "Gap";
9859
+ readonly wrap: "Wrap";
9760
9860
  readonly perSidePx: "Per side (px)";
9761
9861
  readonly sides: {
9762
9862
  readonly top: "Top";
@@ -9924,6 +10024,10 @@ declare const en: {
9924
10024
  readonly title: "Text";
9925
10025
  readonly localizeText: "Localize text";
9926
10026
  };
10027
+ readonly textMarks: {
10028
+ readonly title: "Marks";
10029
+ readonly selectHint: "Select the text to mark";
10030
+ };
9927
10031
  readonly frame: {
9928
10032
  readonly title: "Page";
9929
10033
  readonly page: "Page";
@@ -10037,6 +10141,7 @@ declare const en: {
10037
10141
  readonly describeNoModel: "Pick a model bundle to list its names.";
10038
10142
  readonly describeNoBackend: "Pick a runtime to list the model's names.";
10039
10143
  readonly describeBackendMissing: "That runtime is not installed in this project, so names must be typed.";
10144
+ readonly describeDistrusted: "This project is not trusted, so its runtimes do not run. Trust it from the status bar.";
10040
10145
  readonly describeNotSupported: "This runtime does not describe its models. Type the names.";
10041
10146
  readonly describeFailed: "Could not read the model; type names by hand.";
10042
10147
  readonly redescribe: "Re-read";
@@ -10047,6 +10152,7 @@ declare const en: {
10047
10152
  readonly placeholderUnconfigured: "Select a model bundle and a runtime.";
10048
10153
  readonly placeholderNoModel: "The model bundle is not available here.";
10049
10154
  readonly placeholderBackendMissing: "No runtime named \u201C{backend}\u201D is installed in this project.";
10155
+ readonly placeholderDistrusted: "Not drawn: this project is not trusted, so its runtime is not run.";
10050
10156
  readonly placeholderLoading: "Loading the model\u2026";
10051
10157
  readonly placeholderError: "The runtime failed: {error}";
10052
10158
  readonly placeholderBudget: "Not drawn: {drawn} models are already drawn in this window.";
@@ -10864,6 +10970,10 @@ declare const en: {
10864
10970
  readonly title: "Voice fade";
10865
10971
  readonly description: "How long the fade lasts. Only used when the clip fades out.";
10866
10972
  };
10973
+ readonly muteOnWindowBlur: {
10974
+ readonly title: "Mute when unfocused";
10975
+ readonly description: "Silences the game while another window is in front.";
10976
+ };
10867
10977
  };
10868
10978
  readonly audio: {
10869
10979
  readonly add: "Add track";
@@ -10946,8 +11056,8 @@ declare const en: {
10946
11056
  readonly sidecarNote: "A program a plugin ships runs outside the game process and is not covered by the allowlist.";
10947
11057
  };
10948
11058
  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.";
11059
+ readonly encryptAssetsDescription: "Encrypt assets, plugin code and the story bundle in packaged and previewed desktop builds. Does not affect Dev Mode.";
11060
+ readonly encryptAssetsWebHint: "Web, Android and iOS builds always ship without asset protection.";
10951
11061
  readonly signingDescription: "Which credential signs each platform. Certificates and passwords stay on this machine; the project stores only which one to use.";
10952
11062
  readonly imageModeTitle: "Image compression settings";
10953
11063
  readonly imageWebpQualityTitle: "WebP quality";
@@ -11022,7 +11132,7 @@ declare const en: {
11022
11132
  readonly scanning: "Scanning project\u2026";
11023
11133
  readonly empty: "No plugin dependencies.";
11024
11134
  readonly banner: {
11025
- readonly blocked: "Some plugins are disabled. Their installed version is incompatible. Update or reinstall them.";
11135
+ readonly blocked: "Some plugins are not loaded for this project. Their installed version is incompatible. Update or reinstall them.";
11026
11136
  readonly warnings: "A plugin is outdated, or an optional dependency is unavailable.";
11027
11137
  };
11028
11138
  readonly status: {
@@ -11031,6 +11141,7 @@ declare const en: {
11031
11141
  readonly missing: "Missing";
11032
11142
  readonly incompatible: "Incompatible";
11033
11143
  readonly disabled: "Disabled";
11144
+ readonly suppressed: "Off for this project";
11034
11145
  };
11035
11146
  readonly meta: {
11036
11147
  readonly requires: "Requires {version}";
@@ -11207,6 +11318,9 @@ declare const en: {
11207
11318
  readonly runAs: "Run as";
11208
11319
  readonly runWithDlc: "Run with DLC";
11209
11320
  readonly dlcCount: "{active} of {total}";
11321
+ readonly previewAsShipped: "Preview as shipped";
11322
+ readonly previewAsShippedDetail: "Preview runs the protected form players receive, and takes longer to start.";
11323
+ readonly asShipped: "As shipped";
11210
11324
  readonly resetData: "Reset player data";
11211
11325
  readonly resetWhileRunning: "Stop it to reset its data";
11212
11326
  readonly resetDevModeConfirm: "Reset Dev Mode player data?";
@@ -11463,6 +11577,11 @@ declare const en: {
11463
11577
  readonly atLine: "Line {line} \u00B7 {scene}";
11464
11578
  readonly inScene: "In {scene}";
11465
11579
  readonly onSurface: "On {surface}";
11580
+ readonly onPlugin: "Plugin {plugin}";
11581
+ 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.";
11582
+ 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.";
11583
+ readonly pluginEntryFailed: "{plugin} failed to load: {error}. Its blueprint nodes and widgets are not registered in this session.";
11584
+ readonly pluginListFailed: "The runtime plugin list could not be read: {error}. No plugin runs in this session.";
11466
11585
  readonly noLocation: "Could not be traced to a line";
11467
11586
  readonly viaPlayHead: "where playback was";
11468
11587
  readonly stack: "Stack";
@@ -11586,6 +11705,11 @@ declare const en: {
11586
11705
  readonly openWorkspace: "Workspace";
11587
11706
  readonly cannotOpen: "This blueprint cannot be opened from preview.";
11588
11707
  readonly openFailed: "Unable to open blueprint.";
11708
+ readonly scriptLoaded: "Loaded";
11709
+ readonly scriptNotLoaded: "Not loaded";
11710
+ readonly scriptExports: "Exports: {names}";
11711
+ readonly scriptCalls: "Called here: {names}";
11712
+ readonly scriptExportsNone: "Exports nothing";
11589
11713
  };
11590
11714
  readonly output: {
11591
11715
  readonly logLevel: "Log Level";
@@ -11730,6 +11854,18 @@ declare const en: {
11730
11854
  readonly trust: "This authority was not trusted.";
11731
11855
  };
11732
11856
  };
11857
+ readonly projectTrust: {
11858
+ readonly window: "Project Trust";
11859
+ readonly title: "Trust this project?";
11860
+ readonly untrusted: "Studio did not create this project. Until it is trusted, it can be edited but not run, previewed, built or tested.";
11861
+ readonly meaning: "Once trusted, the code this project ships runs on this machine.";
11862
+ readonly later: "This can be changed under Trusted projects in Settings.";
11863
+ readonly confirm: "Trust";
11864
+ readonly cancel: "Not now";
11865
+ readonly error: {
11866
+ readonly load: "The project details could not be read.";
11867
+ };
11868
+ };
11733
11869
  readonly plugins: {
11734
11870
  readonly installLocal: "Install from folder";
11735
11871
  readonly search: {
@@ -12135,6 +12271,7 @@ declare const en: {
12135
12271
  readonly output: "Choose where to write the file.";
12136
12272
  readonly reading: "Reading the build folder.";
12137
12273
  readonly artifact: "That folder holds no build of this game.";
12274
+ readonly artifactAccess: "Choose that folder with Browse to read it.";
12138
12275
  readonly dlcBaseline: "Select the build this DLC adds to.";
12139
12276
  readonly dlcVariant: "That build is not the variant this DLC attaches to.";
12140
12277
  };
@@ -12249,6 +12386,7 @@ declare const en: {
12249
12386
  readonly "sidecar-crossbuild-exec-bit": string;
12250
12387
  readonly "encryption-key-unavailable": "Asset protection is on, but its key could not be read.";
12251
12388
  readonly "web-unprotected": "Asset protection does not apply to the web export; its files ship unprotected.";
12389
+ readonly "mobile-unprotected": "Asset protection does not apply to Android or iOS packages.";
12252
12390
  readonly "progress-carry-unsupported": string;
12253
12391
  readonly "lossy-images": "Images are re-encoded at quality {setting} and lose detail permanently.";
12254
12392
  readonly "lossy-audio": "Audio is re-encoded at {setting} kbit/s and loses detail permanently.";
@@ -12323,6 +12461,7 @@ declare const en: {
12323
12461
  readonly showAll: "Show all {count}";
12324
12462
  readonly failure: "Reason";
12325
12463
  };
12464
+ readonly cancelled: "Build stopped";
12326
12465
  readonly invalidCommand: "Invalid command in {story} / {scene}: {source}";
12327
12466
  readonly invalidCommandSummary: {
12328
12467
  readonly one: "Build stopped: {count} invalid command. See the console.";
@@ -12346,7 +12485,7 @@ declare const en: {
12346
12485
  readonly other: "Build stopped: {count} cut points are not at the top level of their scene. See the console.";
12347
12486
  };
12348
12487
  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.";
12488
+ readonly contentBlockedScript: "The script {location} can start any scene. List the scenes it can start in the {variant} variant.";
12350
12489
  readonly contentBlockedPlugin: "The {location} plugin can start any scene. List the scenes it can start in the {variant} variant.";
12351
12490
  readonly contentBlockedSummary: {
12352
12491
  readonly one: "Build stopped: {count} place can start a scene the {variant} build cannot read. See the console.";
@@ -12377,6 +12516,7 @@ declare const en: {
12377
12516
  };
12378
12517
  readonly networkNodeDisallowed: "{blueprint} makes a network request, which this project does not allow.";
12379
12518
  readonly pointerNodeUnsupported: "{blueprint} moves the mouse cursor, which does not work on {platforms}.";
12519
+ readonly screenshotNodeUnsupported: "{blueprint} saves screenshots, which does not work on {platforms}.";
12380
12520
  readonly networkSummary: {
12381
12521
  readonly one: "Build stopped: {count} network node cannot run. Change the network policy in project settings, or remove the node.";
12382
12522
  readonly other: "Build stopped: {count} network nodes cannot run. Change the network policy in project settings, or remove the nodes.";
@@ -12569,6 +12709,10 @@ declare const en: {
12569
12709
  readonly description: "A network node in a project whose network policy is off";
12570
12710
  readonly message: "{blueprint} makes a network request, which this project does not allow";
12571
12711
  };
12712
+ readonly storyUnreadable: {
12713
+ readonly title: "Unreadable story";
12714
+ readonly description: "A story document this Studio cannot open";
12715
+ };
12572
12716
  readonly storyInvalidCommand: {
12573
12717
  readonly title: "Invalid command";
12574
12718
  readonly description: "A row the compiler refuses";
@@ -12677,6 +12821,11 @@ declare const en: {
12677
12821
  readonly description: "A row naming a transition this version cannot play";
12678
12822
  readonly message: "The transition {transition} is not available, so this change plays as a cut";
12679
12823
  };
12824
+ readonly storyBackgroundUnchanged: {
12825
+ readonly title: "Unchanged background";
12826
+ readonly description: "A row transitioning to the background already on screen";
12827
+ readonly message: "This background is already on screen, so the transition changes nothing";
12828
+ };
12680
12829
  readonly blueprintReferenceMissing: {
12681
12830
  readonly title: "Missing target";
12682
12831
  readonly description: "A node naming something the project no longer has";
@@ -12762,6 +12911,11 @@ declare const en: {
12762
12911
  readonly description: "A Save Game node that will run with a declared save field left empty";
12763
12912
  readonly message: "{field} is empty, so this save is written with its default instead";
12764
12913
  };
12914
+ readonly blueprintRequiredInputUnwired: {
12915
+ readonly title: "Empty input";
12916
+ readonly description: "A node that will run with a required input left unconnected";
12917
+ readonly message: "{node} has nothing connected to {pin}";
12918
+ };
12765
12919
  readonly blueprintStartSceneForeign: {
12766
12920
  readonly title: "Scene from another story";
12767
12921
  readonly description: "A Start Game node whose scene is not in the story it names";
@@ -12870,6 +13024,8 @@ declare const en: {
12870
13024
  readonly message: {
12871
13025
  readonly ruleFailed: "{rule} could not run";
12872
13026
  readonly storyLoadFailed: "{story} could not be opened";
13027
+ readonly storyTooOld: "{story} is in story format v{version}, and this Studio opens v{minimum} and later";
13028
+ readonly storyTooNew: "{story} was written by a newer NarraLeaf Studio (story format v{version}); this Studio reads up to v{supported}";
12873
13029
  };
12874
13030
  readonly category: {
12875
13031
  readonly assets: "Assets";
@@ -12918,6 +13074,7 @@ declare const en: {
12918
13074
  readonly finding: "{location} {message} ({rule})";
12919
13075
  };
12920
13076
  readonly build: {
13077
+ readonly started: "Checking the project\u2026";
12921
13078
  readonly blocked: "Build stopped by {count} problems";
12922
13079
  readonly blockedHint: "Change this in Project \u25B8 Project \u25B8 Check before building";
12923
13080
  readonly skipped: "Project check skipped";
@@ -13115,7 +13272,10 @@ declare const en: {
13115
13272
  readonly blueprintRemoved: "Blueprint removed ({nodes} nodes)";
13116
13273
  readonly blueprintChanged: "Blueprint changed";
13117
13274
  readonly blueprintRenamed: "Renamed";
13118
- readonly blueprintSource: "Code changed";
13275
+ readonly blueprintSource: "Script file changed";
13276
+ readonly scriptAdded: "Script added";
13277
+ readonly scriptRemoved: "Script removed";
13278
+ readonly scriptChanged: "Script changed";
13119
13279
  readonly blueprintField: "{field} changed";
13120
13280
  readonly graphAdded: "Graph added ({nodes} nodes)";
13121
13281
  readonly graphRemoved: "Graph removed ({nodes} nodes)";
@@ -13379,7 +13539,6 @@ declare const en: {
13379
13539
  readonly animation: "Motion";
13380
13540
  readonly uiDocument: "Interface pages";
13381
13541
  readonly uiGraphs: "Interface blueprints";
13382
- readonly blueprint: "Blueprint";
13383
13542
  readonly variables: "Variables";
13384
13543
  readonly audioTracks: "Audio tracks";
13385
13544
  readonly brand: "Brand palette";
@@ -13601,6 +13760,7 @@ declare const en: {
13601
13760
  readonly durationMinutes: "{minutes}m {seconds}s";
13602
13761
  };
13603
13762
  readonly reason: {
13763
+ readonly distrusted: "Not available until this project is trusted in Settings";
13604
13764
  readonly frozen: "Not available while the workspace is frozen";
13605
13765
  readonly alreadyRunning: "Another run is in progress";
13606
13766
  readonly parameterEmpty: "{parameter} has no values in this project";
@@ -13813,6 +13973,10 @@ declare const en: {
13813
13973
  readonly title: "Assets";
13814
13974
  readonly body: string;
13815
13975
  };
13976
+ readonly assetSources: {
13977
+ readonly title: "Where an asset's file comes from";
13978
+ readonly body: string;
13979
+ };
13816
13980
  readonly assetSets: {
13817
13981
  readonly title: "Asset sets";
13818
13982
  readonly body: string;
@@ -13885,6 +14049,10 @@ declare const en: {
13885
14049
  readonly title: "Blueprints";
13886
14050
  readonly body: string;
13887
14051
  };
14052
+ readonly scripts: {
14053
+ readonly title: "Scripts";
14054
+ readonly body: string;
14055
+ };
13888
14056
  readonly uiBindings: {
13889
14057
  readonly title: "Values on a screen";
13890
14058
  readonly body: string;
@@ -14174,7 +14342,10 @@ declare const en: {
14174
14342
  readonly copyDetails: "Copy details";
14175
14343
  readonly copied: "Copied to the clipboard.";
14176
14344
  readonly copyFailed: "Could not copy: {error}";
14177
- readonly logAt: "The report is in {path}";
14345
+ readonly saveReport: "Save report";
14346
+ readonly reportSaved: "The report is in {path}";
14347
+ readonly reportFailed: "Could not save the report: {error}";
14348
+ readonly logAt: "The log is in {path}";
14178
14349
  readonly bridgeUnavailable: "The game's runtime bridge did not load";
14179
14350
  };
14180
14351
  readonly session: {
@@ -14224,6 +14395,30 @@ declare const en: {
14224
14395
  readonly quit: "Quit";
14225
14396
  };
14226
14397
  };
14398
+ readonly documents: {
14399
+ readonly tooNew: {
14400
+ readonly message: "{subject} was written by a newer NarraLeaf Studio ({kind} format v{version}); this build reads up to v{supported}";
14401
+ readonly kind: {
14402
+ readonly story: "story";
14403
+ readonly storyIndex: "story library";
14404
+ readonly storyAnimation: "animation";
14405
+ readonly uiDocument: "interface";
14406
+ readonly uiGraphs: "interface blueprint";
14407
+ readonly blueprints: "blueprint";
14408
+ readonly variables: "variable";
14409
+ readonly saveSchema: "save schema";
14410
+ readonly localization: "translation";
14411
+ readonly localizationKeys: "translation key";
14412
+ readonly voice: "voice";
14413
+ readonly brand: "design";
14414
+ readonly appTags: "variant";
14415
+ readonly dlc: "DLC";
14416
+ readonly assetSets: "asset set";
14417
+ readonly audioTracks: "audio track";
14418
+ readonly characters: "character";
14419
+ };
14420
+ };
14421
+ };
14227
14422
  };
14228
14423
  type Messages = typeof en;
14229
14424
  type Flatten<T, Prefix extends string = ""> = {
@@ -14317,7 +14512,6 @@ declare function createBoundPrivilegedFacade(token: PrivilegedFacadeToken): {
14317
14512
  ensureRegularFile: (path: string, data: string, encoding?: BufferEncoding) => Promise<RequestStatus<FsRequestResult<void>>>;
14318
14513
  writeFileNoFollow: (path: string, data: string, encoding?: BufferEncoding) => Promise<RequestStatus<FsRequestResult<void>>>;
14319
14514
  writeFileNoFollowOrCreate: (path: string, data: string, encoding?: BufferEncoding) => Promise<RequestStatus<FsRequestResult<void>>>;
14320
- recoverCorruptedJsonFile: (path: string, replacement: string, encoding?: BufferEncoding) => Promise<RequestStatus<FsRequestResult<void>>>;
14321
14515
  createDir: (path: string) => Promise<RequestStatus<FsRequestResult<void>>>;
14322
14516
  deleteFile: (path: string) => Promise<RequestStatus<FsRequestResult<void>>>;
14323
14517
  deleteDir: (path: string) => Promise<RequestStatus<FsRequestResult<void>>>;
@@ -14487,8 +14681,6 @@ export declare enum AssetType {
14487
14681
  Audio = "audio",
14488
14682
  Video = "video",
14489
14683
  JSON = "json",
14490
- /** Shared blueprint asset (M2); content is {@link import("@shared/types/blueprint/document").SharedBlueprintAsset} JSON */
14491
- Blueprint = "blueprint",
14492
14684
  Font = "font",
14493
14685
  /**
14494
14686
  * A **model bundle**: many files that form one authored thing (a Live2D or Spine character),
@@ -14537,12 +14729,6 @@ type JSONAssetMetadata = {
14537
14729
  isValid: boolean;
14538
14730
  schema?: string;
14539
14731
  };
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
14732
  type FontAssetMetadata = {
14547
14733
  family?: string;
14548
14734
  style?: string;
@@ -14592,9 +14778,6 @@ export type AssetData<Type extends AssetType> = Type extends AssetType.Image ? {
14592
14778
  } : Type extends AssetType.JSON ? {
14593
14779
  data: Record<string, any>;
14594
14780
  metadata: JSONAssetMetadata;
14595
- } : Type extends AssetType.Blueprint ? {
14596
- data: SharedBlueprintAsset;
14597
- metadata: BlueprintAssetMetadata;
14598
14781
  } : Type extends AssetType.Font ? {
14599
14782
  data: Uint8Array;
14600
14783
  metadata: FontAssetMetadata;
@@ -14625,7 +14808,6 @@ export declare const AssetExtensions: {
14625
14808
  audio: string[];
14626
14809
  video: string[];
14627
14810
  json: string[];
14628
- blueprint: string[];
14629
14811
  font: string[];
14630
14812
  /**
14631
14813
  * A model bundle is picked as a *directory*, not by extension, so this list is never handed to a
@@ -14924,6 +15106,20 @@ export type TestAvailabilityContext = {
14924
15106
  * and there is nothing for the refusal to protect.
14925
15107
  */
14926
15108
  readonly frozen: boolean;
15109
+ /**
15110
+ * Whether this project is one Studio will not run anything for - it arrived from a package or a
15111
+ * remote source and nobody has vouched for it yet.
15112
+ *
15113
+ * Passed in for the reason above and one more of its own: the ledger that answers it lives in
15114
+ * the main process, so asking costs a round trip, and everything here is synchronous. The host
15115
+ * settles the answer when the workspace comes up and hands the settled copy down.
15116
+ *
15117
+ * `checkAvailability` will not normally see this true - the host refuses every test before it
15118
+ * asks a definition anything, because a run is an execution of the project. It is here because
15119
+ * `options` is *not* gated: a list that would cost real work to build can decline to build it
15120
+ * for a project that cannot run it.
15121
+ */
15122
+ readonly distrusted: boolean;
14927
15123
  };
14928
15124
  export type TestAvailability = {
14929
15125
  available: true;
@@ -15010,7 +15206,8 @@ export type TestDefinition = {
15010
15206
  /**
15011
15207
  * Evaluated when the picker opens, so keep it synchronous and cheap. Absent means always
15012
15208
  * available; the host still applies its own gates (a `windowed` test is unavailable while the
15013
- * workspace is frozen no matter what this returns).
15209
+ * workspace is frozen, and no test runs at all in a project that is not trusted, no matter what
15210
+ * this returns).
15014
15211
  */
15015
15212
  checkAvailability?(ctx: TestAvailabilityContext): TestAvailability;
15016
15213
  run(ctx: TestRunContext): Promise<TestVerdict> | TestVerdict;
@@ -15214,6 +15411,26 @@ interface CharacterEditorProfile extends CharacterBaseProfile {
15214
15411
  * survives a kind switch, which discards everything the kinds do not share.
15215
15412
  */
15216
15413
  voiceTrackId?: string | null;
15414
+ /**
15415
+ * The transform props this character's `enter` rows fall back to, channel by channel.
15416
+ *
15417
+ * How big a sprite is drawn, which way it faces and where its feet land are properties of the
15418
+ * artwork, not of the line that brings it on: the numbers come from the picture's pixel size
15419
+ * against the stage's, so an author who has to state them on every entrance is copying one
15420
+ * answer down the whole script. Absent means what it always meant - an entrance states
15421
+ * everything or takes the stage's own values.
15422
+ *
15423
+ * A row still wins on any channel it names, and only on that channel; see
15424
+ * `@shared/story/characterEntrance` for the merge, which channels a default may carry, and why
15425
+ * `move` and `exit` do not inherit.
15426
+ *
15427
+ * On the profile rather than the appearance because a kind switch discards everything the kinds
15428
+ * do not share, and a character is the same size on stage whichever way she is drawn.
15429
+ *
15430
+ * Additive: no character written before this carries one, so no schema bump - the same terms
15431
+ * `voiceTrackId` was added on.
15432
+ */
15433
+ entranceTransform?: StoryTransformProps;
15217
15434
  }
15218
15435
  interface CharacterNamed {
15219
15436
  readonly id: string;
@@ -15601,6 +15818,18 @@ declare class CharacterProfile {
15601
15818
  */
15602
15819
  getVoiceTrackId(): string | null;
15603
15820
  setVoiceTrackId(trackId: string | null): void;
15821
+ /**
15822
+ * The transform props this character's entrances fall back to. `undefined` is "no defaults",
15823
+ * which is what every character had before the field existed.
15824
+ */
15825
+ getEntranceTransform(): StoryTransformProps | undefined;
15826
+ /**
15827
+ * Stored sanitized, so what the compiler reads back is what this setter accepted - a bag holding
15828
+ * only channels an entrance can act on. An empty bag is stored as no bag at all: "states
15829
+ * nothing" and "has no defaults" are the same instruction here, and keeping the empty record
15830
+ * would leave a key in the document that no longer means anything.
15831
+ */
15832
+ setEntranceTransform(props: StoryTransformProps | undefined): void;
15604
15833
  getNicknames(): string[];
15605
15834
  addNickname(nickname: string): void;
15606
15835
  removeNickname(nickname: string): void;
@@ -15894,6 +16123,11 @@ type UIDisplayableMotionOverride = {
15894
16123
  };
15895
16124
  type TextWritingMode = NlrTextWritingMode;
15896
16125
  type TextOrientation = TextGlyphOrientation;
16126
+ type UITextRunMarks = Pick<StoryTextMarks, "bold" | "italic" | "color" | "ruby" | "fontSizeStep" | "emphasis">;
16127
+ type UITextRun = {
16128
+ text: string;
16129
+ marks?: UITextRunMarks;
16130
+ };
15897
16131
  type EffectShadowLayerData = {
15898
16132
  offsetX: number;
15899
16133
  offsetY: number;
@@ -15934,6 +16168,15 @@ type TextVerticalAlign = "start" | "center" | "end";
15934
16168
  type TextWrapMode = "word" | "character" | "nowrap";
15935
16169
  type TextWidgetProps = {
15936
16170
  text: string;
16171
+ /**
16172
+ * The label's text as marked runs, when it carries any.
16173
+ *
16174
+ * `text` stays the plain string and stays what everything else reads - a value binding writes
16175
+ * it, a translation replaces it, a plain field edits it - and these runs are only drawn while
16176
+ * they still spell it (`resolveUITextRuns`). Absent on every label that has never been marked,
16177
+ * which is what keeps the drawing of a plain label exactly what it was.
16178
+ */
16179
+ rich?: UITextRun[];
15937
16180
  /** Game-localization opt-in: registers the implicit translation unit `ui:<elementId>.text`. */
15938
16181
  localizable?: boolean;
15939
16182
  /** Named localization key reference; takes precedence over the implicit unit. */
@@ -16088,6 +16331,11 @@ type BlueprintGamePreferenceKey = "autoForward" | "skip"
16088
16331
  * defaults through exactly the same plumbing as the twelve the engine defines.
16089
16332
  */
16090
16333
  | "skipReadText"
16334
+ /**
16335
+ * Studio's own: the game's whole output goes quiet while its window is not the one the player is
16336
+ * working in. What acts on it is the host's output gate (`focusMute`), not the engine.
16337
+ */
16338
+ | "muteOnWindowBlur"
16091
16339
  /**
16092
16340
  * Studio's own, and transient: the skip run is going. Writing it is the equivalent of holding
16093
16341
  * the skip key, and the host clears it whenever the run ends - a guard stopping it, the game
@@ -16139,6 +16387,22 @@ type BlueprintHostApiRuntime = {
16139
16387
  * `@shared/types/blueprint/externalLink`.
16140
16388
  */
16141
16389
  openExternal: (request: BlueprintOpenExternalRequest) => Promise<BlueprintOpenExternalResult>;
16390
+ /**
16391
+ * Write a picture of the frame the player is looking at, and say where it went.
16392
+ *
16393
+ * The shell decides where: a path chosen in a graph would be a path a graph could write
16394
+ * anywhere the player's account can. See `@shared/types/blueprint/screenshot`.
16395
+ */
16396
+ saveScreenshot: () => Promise<BlueprintScreenshotResult>;
16397
+ /** Show the player the folder those pictures are in. */
16398
+ openScreenshotsFolder: () => Promise<BlueprintOpenScreenshotsResult>;
16399
+ /**
16400
+ * Whether this game's window is the one the player is working in right now.
16401
+ *
16402
+ * True wherever the shell cannot tell, which is the honest reading of "there is no window
16403
+ * to be behind": a story preview inside Studio is always the thing being looked at.
16404
+ */
16405
+ isWindowFocused: () => Promise<boolean>;
16142
16406
  };
16143
16407
  /** Surfaces stacked over the page lane. See the `layers` family in `@shared/types/blueprint/hostApi`. */
16144
16408
  layers: {
@@ -16279,6 +16543,8 @@ type BlueprintHostApiRuntime = {
16279
16543
  getSaveTimes: (id: string) => Promise<SaveRecordTimes | null>;
16280
16544
  /** Where a slot stopped, or null when there is no such slot. */
16281
16545
  getSaveLine: (id: string) => Promise<SaveRecordLine | null>;
16546
+ /** Which story a slot was written in, or null when there is no such slot. */
16547
+ getSaveStory: (id: string) => Promise<SaveRecordStory | null>;
16282
16548
  /** How long a slot was played, or null when there is no such slot. */
16283
16549
  getSavePlaytime: (id: string) => Promise<SaveRecordPlaytime | null>;
16284
16550
  /** The running playthrough's playtime, in seconds. */
@@ -16624,83 +16890,10 @@ type BehaviorNodeExecuteResult = {
16624
16890
  nextPorts?: string[];
16625
16891
  outputValues?: Record<string, unknown>;
16626
16892
  };
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
16893
  type BehaviorGraphEventControl = {
16651
16894
  stopPropagation(): void;
16652
16895
  isPropagationStopped(): boolean;
16653
16896
  };
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
16897
  type StoryBlockSelection = {
16705
16898
  editor: "story";
16706
16899
  tabId: string;
@@ -18531,20 +18724,8 @@ type BlueprintInspectorParamDef = {
18531
18724
  optionMetaKey: string;
18532
18725
  };
18533
18726
  };
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
18727
  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 = {
18728
+ type BlueprintNodeDeclaration = {
18548
18729
  type: string;
18549
18730
  displayName: string;
18550
18731
  category: string;
@@ -18575,7 +18756,12 @@ export type BlueprintNodeDef = {
18575
18756
  * built on one refreshes on the host's dependencies, never on the plugin's.
18576
18757
  */
18577
18758
  allowInBlueprintValueGraph?: boolean;
18578
- /** Palette-only guard for nodes that read the active List item template scope. */
18759
+ /**
18760
+ * The node reads the list row that is in scope while it runs, so it belongs only where a row can
18761
+ * be: on an element a list draws once per row, or on the list itself, whose item heads each run
18762
+ * for one row. Enforced by `isBlueprintNodeAllowedInGraphContext`, so the palette and the graph
18763
+ * validator answer it the same way.
18764
+ */
18579
18765
  requiresListItemContext?: boolean;
18580
18766
  /** Latent/async execution (delay, host awaits) - disallowed in function graphs */
18581
18767
  isLatent?: boolean;
@@ -18594,20 +18780,7 @@ export type BlueprintNodeDef = {
18594
18780
  kind: "input" | "output";
18595
18781
  };
18596
18782
  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
18783
  role?: BlueprintNodeRole;
18610
- execute: BlueprintNodeExecuteFn;
18611
18784
  };
18612
18785
  interface WorkspaceContext {
18613
18786
  project: Porject;
@@ -18907,6 +19080,7 @@ declare const HELP_TOPIC_IDS: readonly [
18907
19080
  "dictionary",
18908
19081
  "dictionaryMarks",
18909
19082
  "assets",
19083
+ "assetSources",
18910
19084
  "assetSets",
18911
19085
  "assetSetAxes",
18912
19086
  "mediaConversion",
@@ -18925,6 +19099,7 @@ declare const HELP_TOPIC_IDS: readonly [
18925
19099
  "inputActionsInBlueprints",
18926
19100
  "uiComponents",
18927
19101
  "blueprints",
19102
+ "scripts",
18928
19103
  "uiBindings",
18929
19104
  "networkNodes",
18930
19105
  "spellcheck",
@@ -20387,8 +20562,16 @@ declare const pluginUi: Readonly<{
20387
20562
  }>;
20388
20563
  export type PluginUiKit = typeof pluginUi;
20389
20564
  /**
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`.
20565
+ * A blueprint node as a *plugin* writes it: everything a node declares about itself, with the
20566
+ * narrowed execute of `narraleaf-studio/runtime`.
20567
+ *
20568
+ * Built on `BlueprintNodeDeclaration` rather than on the host's `BlueprintNodeDef`, so the two
20569
+ * fields that say *where* a node may appear — `scope` and `requiresHostApi` — are not merely
20570
+ * omitted here but unreachable from the published package. `scope` in particular is a list of
20571
+ * owner kinds taken from `BlueprintOwnerRef`; publishing it would let a plugin pin an internal
20572
+ * union, and every later change to the blueprint model would break plugins that had. Both
20573
+ * restrictions are the host's answer, decided by review for the built-in catalogue, and the host
20574
+ * drops either one a plugin's compiled JavaScript still carries.
20392
20575
  *
20393
20576
  * The host's own `BlueprintNodeDef.execute` receives a `BehaviorNodeExecutionContext`,
20394
20577
  * which carries `hostAdapter` — and through it every host API: saves, localization,
@@ -20396,13 +20579,15 @@ export type PluginUiKit = typeof pluginUi;
20396
20579
  * declared and the user never approved. So a plugin's execute gets the very same
20397
20580
  * capability-gated context its runtime entry gets, in both targets: one node module
20398
20581
  * can be shared by the studio and runtime entries, and neither is the privileged one.
20582
+ * That is also why `BlueprintNodeExecuteFn`, which names the host context, is not published:
20583
+ * nothing a plugin can write would satisfy it.
20399
20584
  *
20400
20585
  * The editor is an environment that backs no game, so the gated domains on
20401
20586
  * `ctx.game` (`saves`, `store`, `state`, …) are absent while a node runs in Studio.
20402
20587
  * Nodes must degrade rather than assume them — the same discipline a plugin already
20403
20588
  * needs for the web export versus the desktop shell.
20404
20589
  */
20405
- export type PluginBlueprintNodeDef = Omit<BlueprintNodeDef, "execute"> & {
20590
+ export type PluginBlueprintNodeDef = BlueprintNodeDeclaration & {
20406
20591
  execute: RuntimeBlueprintNodeExecute;
20407
20592
  };
20408
20593
  /**