narraleaf-studio 0.7.0 → 0.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/_api.d.ts CHANGED
@@ -11,7 +11,6 @@
11
11
  // Generated by dts-bundle-generator v9.5.1
12
12
 
13
13
  import { LucideIcon } from 'lucide-react';
14
- import { TextGlyphOrientation, TextWritingMode as NlrTextWritingMode } from 'narraleaf-react';
15
14
  import React$1 from 'react';
16
15
  import { ComponentType, InputHTMLAttributes, ReactElement, ReactNode, RefObject } from 'react';
17
16
 
@@ -1422,92 +1421,6 @@ type StoryAlignPositionValue = {
1422
1421
  xoffset?: number;
1423
1422
  yoffset?: number;
1424
1423
  };
1425
- type BlueprintDebugEvent = {
1426
- type: "execution.started";
1427
- executionId: string;
1428
- blueprintId: string;
1429
- } | {
1430
- type: "execution.finished";
1431
- executionId: string;
1432
- blueprintId: string;
1433
- } | {
1434
- type: "execution.cancelled";
1435
- executionId: string;
1436
- blueprintId?: string;
1437
- eventId?: string;
1438
- graphId?: string;
1439
- nodeId?: string;
1440
- reason?: string;
1441
- } | {
1442
- type: "node.enter";
1443
- executionId: string;
1444
- nodeId: string;
1445
- } | {
1446
- type: "node.exit";
1447
- executionId: string;
1448
- nodeId: string;
1449
- } | {
1450
- type: "state.read";
1451
- scope: string;
1452
- key: string;
1453
- } | {
1454
- type: "state.write";
1455
- scope: string;
1456
- key: string;
1457
- } | {
1458
- type: "binding.evaluated";
1459
- bindingId: string;
1460
- } | {
1461
- type: "function.call";
1462
- functionId: string;
1463
- } | {
1464
- type: "function.return";
1465
- functionId: string;
1466
- } | {
1467
- type: "devtools.log";
1468
- level: string;
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;
1493
- } | {
1494
- type: "execution.error";
1495
- executionId: string;
1496
- message: string;
1497
- blueprintId?: string;
1498
- eventId?: string;
1499
- graphId?: string;
1500
- nodeId?: string;
1501
- /**
1502
- * The UI surface whose graph failed, when the failure happened on one.
1503
- *
1504
- * The rest of this event names OUR ids - a blueprint, a graph, a node - none of which an
1505
- * author can find their way back from. A surface id resolves against the document they
1506
- * drew, which is what lets a host say "the Quick Menu" rather than "bp:8f2c1a…". Absent on
1507
- * the global blueprint, which belongs to no surface.
1508
- */
1509
- surfaceId?: string;
1510
- };
1511
1424
  type BlueprintOwnerRef = {
1512
1425
  kind: "globalMain";
1513
1426
  } | {
@@ -1747,70 +1660,6 @@ type BlueprintDiagnostic = {
1747
1660
  /** Source span or module location; M1 opaque */
1748
1661
  location?: Record<string, unknown>;
1749
1662
  };
1750
- type LocaleCode = string;
1751
- type LocalizationLocaleEntry = {
1752
- code: LocaleCode;
1753
- /** Author-facing autonym shown to players (e.g. "日本語", never "Japanese"). */
1754
- displayName: string;
1755
- /** Optional intermediate fallback locale tried before the source locale. */
1756
- fallback?: LocaleCode;
1757
- };
1758
- type GameLocalizationBundle = {
1759
- sourceLocale: LocaleCode;
1760
- locales: LocalizationLocaleEntry[];
1761
- tables: Record<LocaleCode, Record<string, string>>;
1762
- /** Named-key source texts (key name → source-language text). */
1763
- keys?: Record<string, string>;
1764
- /**
1765
- * Scene-name source texts (scene id → source-language name), for the scenes this build ships.
1766
- *
1767
- * The same job `keys` does for named keys: a translation table only holds the *target* side, so
1768
- * without this a `scene:` reference read while the game is in the source language has nothing to
1769
- * render but the id. Assembled from the story documents the bundle carries, so a scene a variant
1770
- * dropped is absent here too.
1771
- */
1772
- scenes?: Record<string, string>;
1773
- };
1774
- type SaveRecordTimes = {
1775
- /** When this slot was last written, epoch milliseconds; 0 when the record carries no stamp. */
1776
- savedAt: number;
1777
- /** When this slot was first written, epoch milliseconds; 0 when the record carries no stamp. */
1778
- createdAt: number;
1779
- };
1780
- type SaveRecordPlaytime = {
1781
- /** Seconds of play behind the slot; 0 when nothing was recorded. */
1782
- seconds: number;
1783
- /** False when the slot carries no reading at all. */
1784
- recorded: boolean;
1785
- };
1786
- type SaveRecordLine = {
1787
- /** The last sentence shown, or "" when the record carries none. */
1788
- line: string;
1789
- /** Who spoke it, or "" when the record carries no speaker (narration, or none yet). */
1790
- speaker: string;
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
- };
1798
- type AutoSaveEntry = {
1799
- id: string;
1800
- /** Slot index within the ring. */
1801
- slot: number;
1802
- /** When this slot was last written, epoch milliseconds. */
1803
- timestamp: number;
1804
- /** When this slot was first written, epoch milliseconds. */
1805
- createdAt: number;
1806
- /** Whatever the writer attached as user metadata (null when none). */
1807
- metadata: unknown;
1808
- };
1809
- type VoiceLocaleEntry = {
1810
- code: LocaleCode;
1811
- /** Author-facing autonym shown for this voice language (e.g. "日本語"). */
1812
- displayName: string;
1813
- };
1814
1663
  type AudioClipRegion = {
1815
1664
  /** Offset from the start of the clip, in milliseconds. Where playback starts. */
1816
1665
  inMs?: number;
@@ -1838,67 +1687,7 @@ type BlueprintOpenExternalResult = {
1838
1687
  /** Human-readable reason, null when the page was handed over. */
1839
1688
  error: string | null;
1840
1689
  };
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
1690
  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
1691
  type GameBuildPlatform = "windows" | "macos" | "linux" | "web" | "android" | "ios";
1903
1692
  type PluginPermissionPersistence = "temporary" | "permanent";
1904
1693
  type PluginFileSystemPermissionMode = "read" | "write" | "readwrite";
@@ -2044,6 +1833,24 @@ declare const PluginRuntimeCapability: {
2044
1833
  * declared.
2045
1834
  */
2046
1835
  readonly StoryCompile: "story.compile";
1836
+ /**
1837
+ * `app.game.diagnostics` — read what the player's caches are holding.
1838
+ *
1839
+ * The lightest of the list to grant and the easiest to misread as heavier than it is. Nothing
1840
+ * here is authored data: it reports how many images the engine is holding, how many bytes those
1841
+ * cost, and what budgets they are being held against. It reads no story, no save and no
1842
+ * variable, and every member is a read - there is nothing to set.
1843
+ *
1844
+ * It is its own capability rather than free like `data` and `config` because a plugin that
1845
+ * watches memory is a plugin that runs continuously and reports numbers about the player's
1846
+ * machine, and an author should see that named at install. The performance inspector is the
1847
+ * plugin this exists for.
1848
+ *
1849
+ * Absent until a game session is live, which is the same rule every other engine-backed member
1850
+ * follows: a plugin's `setup()` runs during boot, and asking then answers null rather than
1851
+ * throwing.
1852
+ */
1853
+ readonly Diagnostics: "diagnostics";
2047
1854
  };
2048
1855
  type PluginRuntimeCapability = typeof PluginRuntimeCapability[keyof typeof PluginRuntimeCapability];
2049
1856
  /**
@@ -2397,11 +2204,6 @@ export type RuntimePluginDescriptor = {
2397
2204
  */
2398
2205
  buildConfig?: Record<string, string>;
2399
2206
  };
2400
- type GameProgressImportOutcome = {
2401
- outcome: "found" | "missing" | "failed";
2402
- sceneId: string;
2403
- error: string;
2404
- };
2405
2207
  type GameMenuLabel = {
2406
2208
  readonly key?: string | null;
2407
2209
  readonly text: string;
@@ -2511,13 +2313,6 @@ type GameMenuSpecMenu = {
2511
2313
  type GameMenuSpec = {
2512
2314
  readonly menus: readonly GameMenuSpecMenu[];
2513
2315
  };
2514
- type UIInputActionSource = "pointer" | "key" | "gamepad" | "touch";
2515
- type UIInputActionEventPayload = {
2516
- actionId: string;
2517
- source: UIInputActionSource;
2518
- x?: number;
2519
- y?: number;
2520
- };
2521
2316
  declare const UI_INPUT_POINTER_GESTURES: readonly [
2522
2317
  "click",
2523
2318
  "doubleClick",
@@ -2823,30 +2618,6 @@ type UILayout = {
2823
2618
  lockAspectRatio?: boolean;
2824
2619
  };
2825
2620
  type UIStyle = Record<string, unknown>;
2826
- type GameStorageDurability = "durable" | "evictable" | "unknown";
2827
- type DevModeStartStoryRequest = {
2828
- storyId: StoryId;
2829
- sceneId: string;
2830
- /** Row-precise "play from here": enter the game pre-posed at this block and play forward. */
2831
- startBlockId?: string;
2832
- /** Scene Snapshot (变量快照) whose variable overrides seed the launch. */
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
- };
2849
- };
2850
2621
  type GameTestLogLevel = "verbose" | "info" | "success" | "warning" | "error";
2851
2622
  type GameTestExitReason =
2852
2623
  /** Closed from inside the game - the window's own close, or the engine quitting itself. */
@@ -9680,6 +9451,10 @@ declare const en: {
9680
9451
  };
9681
9452
  readonly refs: "{count} refs";
9682
9453
  };
9454
+ readonly canvas: {
9455
+ readonly unknownWidget: "Unknown widget";
9456
+ readonly widgetRenderFailed: "Widget failed to draw";
9457
+ };
9683
9458
  readonly editor: {
9684
9459
  readonly componentNotFound: "Component not found";
9685
9460
  readonly interfaceNotFound: "Interface not found";
@@ -10524,6 +10299,7 @@ declare const en: {
10524
10299
  readonly insert: "Insert {name}";
10525
10300
  readonly drawing: "Drawing {name}: drag on canvas to create";
10526
10301
  readonly moreInsertElements: "More insert elements";
10302
+ readonly fromPlugin: "From {plugin}";
10527
10303
  readonly components: "Components";
10528
10304
  readonly openComponentLibrary: "Open Component Library";
10529
10305
  readonly componentLibrary: "Component Library";
@@ -11825,6 +11601,7 @@ declare const en: {
11825
11601
  readonly locale: "Read the game language and the project's localized text";
11826
11602
  readonly menu: "Provide the game's menu bar";
11827
11603
  readonly storyCompile: "Take part in compiling stories, and add actions to lines it did not write";
11604
+ readonly diagnostics: "Read how much memory the game\u2019s caches are using";
11828
11605
  };
11829
11606
  };
11830
11607
  readonly button: {
@@ -11936,6 +11713,25 @@ declare const en: {
11936
11713
  readonly registry: "Failed to reach the plugin registry";
11937
11714
  readonly download: "Failed to download plugin";
11938
11715
  };
11716
+ readonly dependencies: {
11717
+ readonly title: "Project dependencies";
11718
+ readonly unavailable: {
11719
+ readonly one: "{count} plugin this project needs is not available.";
11720
+ readonly other: "{count} plugins this project needs are not available.";
11721
+ };
11722
+ readonly allReady: "Every plugin this project needs is available.";
11723
+ readonly open: "Open dependencies";
11724
+ readonly installAll: "Install all";
11725
+ readonly updated: "Updated";
11726
+ readonly authorized: "Authorized";
11727
+ readonly notInRegistry: "Not in the registry";
11728
+ readonly noCompatibleVersion: "No compatible version";
11729
+ readonly task: {
11730
+ readonly running: "Installing dependencies\u2026";
11731
+ readonly done: "Dependencies installed.";
11732
+ readonly partial: "Some plugins were not installed.";
11733
+ };
11734
+ };
11939
11735
  readonly workspace: {
11940
11736
  readonly reload: "Reload in this workspace";
11941
11737
  readonly activity: {
@@ -11947,7 +11743,6 @@ declare const en: {
11947
11743
  readonly suppressedHint: "The installed version is incompatible with the one this project was authored against. Update it, or update the project's dependency table from Project \u25B8 App.";
11948
11744
  readonly failed: "Failed to load";
11949
11745
  };
11950
- readonly suppressedNotice: "Not loaded for this project: {names}. The installed version is incompatible with the one the project was authored against. See the Plugins panel.";
11951
11746
  readonly pendingReopen: "Takes effect the next time this project opens.";
11952
11747
  readonly restartHint: "Some plugin changes take effect only after the workspace is restarted.";
11953
11748
  readonly restart: "Restart";
@@ -12886,6 +12681,11 @@ declare const en: {
12886
12681
  readonly description: "A clickable widget nothing listens to";
12887
12682
  readonly message: "Nothing runs when this is clicked";
12888
12683
  };
12684
+ readonly uiUnknownWidget: {
12685
+ readonly title: "Unknown widget type";
12686
+ readonly description: "A widget whose type the project cannot load";
12687
+ readonly message: "{type} is not loaded, so this widget will not be drawn in the game";
12688
+ };
12889
12689
  readonly uiComponentMissing: {
12890
12690
  readonly title: "Missing component";
12891
12691
  readonly description: "An instance of a component the project does not have";
@@ -14818,26 +14618,6 @@ export declare const AssetExtensions: {
14818
14618
  model: string[];
14819
14619
  other: string[];
14820
14620
  };
14821
- type BlueprintVector2D = {
14822
- x: number;
14823
- y: number;
14824
- };
14825
- type BlueprintRect = {
14826
- x: number;
14827
- y: number;
14828
- width: number;
14829
- height: number;
14830
- };
14831
- type BlueprintRGBAColor = {
14832
- r: number;
14833
- g: number;
14834
- b: number;
14835
- a: number;
14836
- };
14837
- type BlueprintImageAsset = {
14838
- kind: "imageAsset";
14839
- assetId: string;
14840
- };
14841
14621
  type BlueprintAssetPinKind = "image" | "audio" | "font";
14842
14622
  type BlueprintAssetPinRef = {
14843
14623
  kind: BlueprintAssetPinKind;
@@ -14856,10 +14636,6 @@ type BlueprintAssetPinRef = {
14856
14636
  */
14857
14637
  origin?: "stored" | "published";
14858
14638
  };
14859
- type BlueprintSoundHandle = {
14860
- kind: "soundHandle";
14861
- id: string;
14862
- };
14863
14639
  interface ProjectProps {
14864
14640
  projectPath: string;
14865
14641
  }
@@ -15895,33 +15671,6 @@ type UIElementSelection = {
15895
15671
  elementIds: UIElementId[];
15896
15672
  primaryId?: UIElementId;
15897
15673
  };
15898
- type GradientKind = "linear" | "radial" | "conic";
15899
- interface GradientStop {
15900
- /** 0..1 along the gradient line. */
15901
- offset: number;
15902
- /**
15903
- * A stored colour string: a literal, or `nlbrand:<id>[/<alpha>]`. Deliberately unresolved - see
15904
- * the file comment.
15905
- */
15906
- color: string;
15907
- }
15908
- interface GradientFill {
15909
- kind: GradientKind;
15910
- /** Normalised to two or more, sorted by offset, offsets clamped to 0..1. */
15911
- stops: GradientStop[];
15912
- /** Linear and conic. Degrees, CSS convention: 0 points to the top, 90 to the right. */
15913
- angle?: number;
15914
- /** Radial and conic. 0..1 of the painted box. */
15915
- center?: {
15916
- x: number;
15917
- y: number;
15918
- };
15919
- /** Radial. 0..1 of the painted box, one radius per axis. */
15920
- radius?: {
15921
- x: number;
15922
- y: number;
15923
- };
15924
- }
15925
15674
  type ImageFillMode = "cover" | "contain" | "stretch" | "crop" | "tile";
15926
15675
  interface ImageFillCropPlacement {
15927
15676
  leftPct: number;
@@ -15956,1030 +15705,97 @@ type UIListItemScope = {
15956
15705
  */
15957
15706
  struct?: UIStructDef | null;
15958
15707
  };
15959
- type UIListScrollMetrics = {
15960
- offset: number;
15961
- maxOffset: number;
15962
- progress: number;
15963
- };
15964
- declare const BLUEPRINT_HOST_API_CONTRACT_VERSION: 39;
15965
- type BlueprintHostApiContractVersion = typeof BLUEPRINT_HOST_API_CONTRACT_VERSION;
15966
- type BlueprintCharacterInfo = {
15967
- id: string;
15968
- /** Author-facing display name. Empty when the character is unnamed - never falls back to `id`, which is a UUID. */
15969
- name: string;
15970
- /**
15971
- * The author's accent colour, already in pin shape. Null when the character has no colour set,
15972
- * which is a different thing from "white" - see {@link blueprintCharacterColorOrDefault} for
15973
- * what a non-nullable colour pin does with it.
15974
- */
15975
- color: BlueprintRGBAColor | null;
15976
- /** The character's default dialog avatar, or null when it has none. */
15977
- avatar: BlueprintImageAsset | null;
15978
- };
15979
- type AppearanceSystemCondition = Partial<{
15980
- hovered: boolean;
15981
- active: boolean;
15982
- disabled: boolean;
15983
- focused: boolean;
15984
- /** Inside the row a list has selected. */
15985
- selected: boolean;
15986
- }>;
15987
- type AppearanceRowValue = string | number | boolean | null | ImageFill | GradientFill | Record<string, unknown>;
15988
- type AppearanceValueRow = {
15989
- conditions?: AppearanceSystemCondition | null;
15990
- value: AppearanceRowValue;
15991
- };
15992
- type AppearanceTransitionTweenEasing = "linear" | "easeIn" | "easeOut" | "easeInOut" | "circIn" | "circOut" | "circInOut";
15993
- type AppearanceFieldTransition = {
15994
- type: "tween";
15995
- durationMs: number;
15996
- delayMs?: number;
15997
- easing: AppearanceTransitionTweenEasing;
15998
- } | {
15999
- type: "spring";
16000
- delayMs?: number;
16001
- stiffness: number;
16002
- damping: number;
16003
- mass: number;
16004
- };
16005
- type ContainerAppearancePropertyKey = "backgroundColor" | "borderRadius" | "borderRadiusTL" | "borderRadiusTR" | "borderRadiusBL" | "borderRadiusBR" | "borderRadiusLinked" | "borderColor" | "borderWidth" | "borderStyle" | "backgroundImage" | "backgroundFit" | "imageFill" | "gradientFill" | "fillType" | "fillVisible" | "fillOpacity" | "strokeVisible" | "strokeOpacity" | "strokeAlign" | "strokeSide" | "borderJoin" | "cornerAdvanced" | "transformOffsetX" | "transformOffsetY" | "transformScale" | "transformRotation" | "transformOpacity" | "effectBlur" | "effectBackgroundBlur" | "effectShadow" | "effectInnerShadow" | "effectBlend" | "effectGlow" | "effectFilter";
16006
- declare const BUTTON_CURSOR_VALUES: readonly [
16007
- "auto",
16008
- "default",
16009
- "pointer",
16010
- "text",
16011
- "move",
16012
- "grab",
16013
- "grabbing",
16014
- "crosshair",
16015
- "help",
16016
- "wait",
16017
- "progress",
16018
- "not-allowed"
16019
- ];
16020
- type ButtonCursorValue = (typeof BUTTON_CURSOR_VALUES)[number];
16021
- type ButtonAppearancePropertyKey = "fontAssetId" | "fontSize" | "fontWeight" | "color" | "lineHeight" | "backgroundColor" | "fillType" | "fillOpacity" | "fillVisible" | "imageFill" | "gradientFill" | "backgroundImage" | "backgroundFit" | "borderRadius" | "borderWidth" | "borderColor" | "borderStyle" | "strokeOpacity" | "strokeSide" | "borderJoin" | "strokeAlign" | "paddingX" | "paddingY" | "clipContent" | "cursor" | "transformOffsetX" | "transformOffsetY" | "transformScale" | "transformRotation" | "transformOpacity" | "effectBlur" | "effectBackgroundBlur" | "effectShadow" | "effectTextShadow" | "effectInnerShadow" | "effectBlend" | "effectGlow" | "effectFilter";
16022
- type TextAppearancePropertyKey = "fontAssetId" | "fontSize" | "fontWeight" | "fontStyle" | "color" | "lineHeight" | "transformOffsetX" | "transformOffsetY" | "transformScale" | "transformRotation" | "transformOpacity" | "effectBlur" | "effectTextShadow" | "effectBlend" | "effectFilter";
16023
- type AppearancePropertyGroup = {
16024
- key: ContainerAppearancePropertyKey;
16025
- rows: AppearanceValueRow[];
16026
- transition?: AppearanceFieldTransition | null;
16027
- } | {
16028
- key: ButtonAppearancePropertyKey;
16029
- rows: AppearanceValueRow[];
16030
- transition?: AppearanceFieldTransition | null;
16031
- } | {
16032
- key: TextAppearancePropertyKey;
16033
- rows: AppearanceValueRow[];
16034
- transition?: AppearanceFieldTransition | null;
16035
- };
16036
- type AppearanceVariant = {
16037
- id: string;
16038
- name: string;
16039
- propertyGroups: AppearancePropertyGroup[];
16040
- };
16041
- type AppearanceModel = {
16042
- defaultVariantId: string;
16043
- variants: AppearanceVariant[];
16044
- };
16045
- type UISliderOrientation = "horizontal" | "vertical";
16046
- type UISliderWidgetProps = {
16047
- value: number;
16048
- min: number;
16049
- max: number;
16050
- step: number;
16051
- orientation: UISliderOrientation;
16052
- trackElementId?: string | null;
16053
- handleElementId?: string | null;
16054
- };
16055
- type UISliderRange = {
16056
- min: number;
16057
- max: number;
16058
- step: number;
16059
- };
16060
- type UISliderRuntimeValue = UISliderRange & {
16061
- value: number;
16062
- normalizedValue: number;
16063
- };
16064
- type UISwitchWidgetProps = {
16065
- /** The author's starting state. What the player toggles lives in WidgetRuntimeStateStore. */
16066
- checked: boolean;
16067
- /** Blocks pointer and keyboard toggling. Looks are the `disabled` appearance signal's job. */
16068
- interactionDisabled: boolean;
16069
- trackElementId?: string | null;
16070
- thumbElementId?: string | null;
16071
- };
16072
- type UISwitchRuntimeValue = {
16073
- checked: boolean;
16074
- };
16075
- type UITextInputMode = "text" | "password" | "number";
16076
- type UITextInputWidgetProps = {
16077
- value: string;
16078
- placeholder: string;
16079
- /** i18n attach-layer key for `placeholder`; player-facing text is never a Studio catalog key. */
16080
- placeholderLocalizationKey?: string | null;
16081
- inputMode: UITextInputMode;
16082
- /** 0 = unlimited. */
16083
- maxLength: number;
16084
- readOnly: boolean;
16085
- disabled: boolean;
16086
- textAlign: "left" | "center" | "right";
16087
- };
16088
- type UITextInputRuntimeValue = {
16089
- value: string;
16090
- /** Length in code points, so an emoji counts once - this is what `maxLength` is measured in. */
16091
- length: number;
16092
- };
16093
- type UIDisplayableMotionFromCurrentValue = {
16094
- from: "current";
16095
- to: number;
16096
- };
16097
- type UIDisplayableMotionValue = number | number[] | UIDisplayableMotionFromCurrentValue;
16098
- type UIDisplayableMotionTarget = {
16099
- x?: UIDisplayableMotionValue;
16100
- y?: UIDisplayableMotionValue;
16101
- scale?: UIDisplayableMotionValue;
16102
- rotate?: UIDisplayableMotionValue;
16103
- opacity?: UIDisplayableMotionValue;
16104
- };
16105
- type UIDisplayableMotionTransition = {
16106
- type: "tween";
16107
- durationMs: number;
16108
- delayMs?: number;
16109
- easing?: string;
16110
- } | {
16111
- type: "spring";
16112
- delayMs?: number;
16113
- stiffness: number;
16114
- damping: number;
16115
- mass: number;
16116
- };
16117
- type UIDisplayableMotionOverride = {
16118
- id: string;
16119
- target: UIDisplayableMotionTarget;
16120
- transition: UIDisplayableMotionTransition;
16121
- /** One-shot effects such as shake/pulse should hand control back to authored layout when finished. */
16122
- resetOnComplete?: boolean;
16123
- };
16124
- type TextWritingMode = NlrTextWritingMode;
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
- };
16131
- type EffectShadowLayerData = {
16132
- offsetX: number;
16133
- offsetY: number;
16134
- blur: number;
16135
- spread: number;
16136
- color: string;
16137
- };
16138
- type FilterPresetId = "brightness" | "contrast" | "saturate" | "grayscale";
16139
- type EffectShadowLayer = EffectShadowLayerData;
16140
- type EffectShadowStored = {
16141
- storage: "layer";
16142
- layer: EffectShadowLayer;
16143
- } | {
16144
- storage: "css";
16145
- css: string;
16146
- };
16147
- type EffectFilterStored = {
16148
- storage: "preset";
16149
- preset: FilterPresetId;
16150
- amount: number;
16151
- } | {
16152
- storage: "css";
16153
- css: string;
16154
- };
16155
- type ElementEffectValues = {
16156
- effectBlur: number;
16157
- effectBackgroundBlur: number;
16158
- effectShadow: EffectShadowStored | null;
16159
- /** Text widgets: CSS text-shadow (separate from box-shadow `effectShadow`). */
16160
- effectTextShadow: EffectShadowStored | null;
16161
- effectInnerShadow: EffectShadowStored | null;
16162
- effectBlend: string;
16163
- effectGlow: EffectShadowStored | null;
16164
- effectFilter: EffectFilterStored | null;
16165
- };
16166
- type TextAlign = "left" | "center" | "right";
16167
- type TextVerticalAlign = "start" | "center" | "end";
16168
- type TextWrapMode = "word" | "character" | "nowrap";
16169
- type TextWidgetProps = {
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[];
16180
- /** Game-localization opt-in: registers the implicit translation unit `ui:<elementId>.text`. */
16181
- localizable?: boolean;
16182
- /** Named localization key reference; takes precedence over the implicit unit. */
16183
- localizationKey?: string;
16184
- fontSize: number;
16185
- color: string;
16186
- fontWeight: "normal" | "bold" | "600";
16187
- fontStyle: "normal" | "italic";
16188
- textAlign: TextAlign;
16189
- textVerticalAlign: TextVerticalAlign;
16190
- lineHeight: number;
16191
- /** Project font asset id when using a custom typeface in the editor; null inherits canvas default */
16192
- fontAssetId: string | null;
16193
- textWrapMode: TextWrapMode;
16194
- /**
16195
- * Shrink the rendered text until it fits the element's box.
16196
- *
16197
- * The authored `fontSize` becomes a ceiling rather than a fixed value: the text is never set
16198
- * larger than it, and never smaller than {@link TextWidgetProps.textAutoFitMinFontSize}. A line
16199
- * that still does not fit at the floor is clipped, which is what every line does today.
16200
- */
16201
- textAutoFit: boolean;
16202
- /** Smallest size auto fit may set, in px. */
16203
- textAutoFitMinFontSize: number;
16204
- /** Block flow. `horizontal-tb` leaves every other vertical setting inert. */
16205
- writingMode: TextWritingMode;
16206
- textOrientation: TextOrientation;
16207
- /**
16208
- * 縦中横: sets a short Latin or digit run upright across the column instead of on its side,
16209
- * the way a Japanese novel sets a two-digit number. Only read while writing vertically.
16210
- */
16211
- tateChuYoko: boolean;
16212
- /** Longest run tate-chu-yoko combines, in characters. Two is the typographic convention. */
16213
- tateChuYokoMaxLength: number;
16214
- transformOffsetX: number;
16215
- transformOffsetY: number;
16216
- transformScale: number;
16217
- transformRotation: number;
16218
- transformOpacity: number;
16219
- /** Static baseline effects; appearance overlays may override per variant / state. */
16220
- effects: ElementEffectValues;
16221
- /** Optional variant + conditional row visuals; when absent, flat props are the sole source. */
16222
- appearance?: AppearanceModel | null;
16223
- };
16224
- type BlueprintPointerMoveOptions = {
16225
- durationSeconds?: number;
16226
- easing?: BlueprintPointerMoveEasing;
16227
- };
16228
- type BlueprintTextProperties = Pick<TextWidgetProps, "text" | "fontAssetId" | "fontSize" | "fontWeight" | "color" | "textAlign" | "textVerticalAlign" | "lineHeight" | "textWrapMode" | "effects">;
16229
- type BlueprintTextPropertiesPatch = Partial<BlueprintTextProperties>;
16230
- type BlueprintSliderProperties = UISliderRuntimeValue;
16231
- type BlueprintSliderPropertiesPatch = Partial<Pick<UISliderWidgetProps, "value" | "min" | "max" | "step">>;
16232
- type BlueprintSwitchProperties = UISwitchRuntimeValue;
16233
- type BlueprintSwitchPropertiesPatch = Partial<Pick<UISwitchWidgetProps, "checked">>;
16234
- type BlueprintTextInputProperties = UITextInputRuntimeValue;
16235
- type BlueprintTextInputPropertiesPatch = Partial<Pick<UITextInputWidgetProps, "value">>;
16236
- type BlueprintListProperties = {
16237
- items: unknown[];
16238
- selectedIndex: number;
16239
- /**
16240
- * The shape the list declares, or null when it declares none.
16241
- *
16242
- * Carried with the items rather than fetched separately, because every node that reads a field
16243
- * needs both and reading them apart is how the two drift: a graph that sorted by a field the
16244
- * list no longer declares would sort by nothing and report success.
16245
- */
16246
- struct: UIStructDef | null;
16247
- /**
16248
- * Where the list has got to along its axis, as it last measured itself.
16249
- *
16250
- * A list that has not been rendered - or has been rendered somewhere with no runtime store, like
16251
- * a Surface thumbnail - reports at-rest rather than nothing, so a graph asking gets the answer
16252
- * for a list that cannot scroll instead of an undefined it has no way to branch on.
16253
- */
16254
- scroll: UIListScrollMetrics;
16255
- };
16256
- type BlueprintDisplayableProperties = {
16257
- position: {
16258
- x: number;
16259
- y: number;
16260
- };
16261
- offset: {
16262
- x: number;
16263
- y: number;
16264
- };
16265
- /**
16266
- * The extent the widget covers, never negative. The authored layout may hold a negative width
16267
- * or height - that is how a widget dragged past its own origin is stored - and `position`
16268
- * already reports the true top-left, so reporting the raw sign here would have described a
16269
- * rectangle whose right edge sits left of its left edge.
16270
- */
16271
- size: {
16272
- width: number;
16273
- height: number;
16274
- };
16275
- bounds: BlueprintRect;
16276
- rotation: number;
16277
- opacity: number;
16278
- display: boolean;
16279
- visible: boolean;
16280
- };
16281
- type BlueprintDisplayablePropertiesPatch = Partial<{
16282
- x: number;
16283
- y: number;
16284
- offsetX: number;
16285
- offsetY: number;
16286
- width: number;
16287
- height: number;
16288
- rotation: number;
16289
- opacity: number;
16290
- display: boolean;
16291
- visible: boolean;
16292
- }>;
16293
- type BlueprintDisplayableMotionRequest = {
16294
- id?: string;
16295
- target: UIDisplayableMotionTarget;
16296
- transition: UIDisplayableMotionTransition;
16297
- resetOnComplete?: boolean;
16298
- commitLayoutOnComplete?: Partial<Pick<BlueprintDisplayablePropertiesPatch, "x" | "y">>;
16299
- };
16300
- type BlueprintWidgetCommonProperties = {
16301
- visible: boolean;
16302
- enabled: boolean;
16303
- variantId: string | null;
16304
- };
16305
- type BlueprintButtonProperties = {
16306
- label: string;
16307
- cursor: ButtonCursorValue;
16308
- };
16309
- type BlueprintContainerProperties = {
16310
- clipContent: boolean;
15708
+ type BehaviorNodeExecuteResult = {
15709
+ nextPort?: string;
15710
+ nextPorts?: string[];
15711
+ outputValues?: Record<string, unknown>;
16311
15712
  };
16312
- type BlueprintImageProperties = {
16313
- asset: BlueprintImageAsset | null;
16314
- /** Legacy patch/read alias kept so older saved graph nodes can still run. */
16315
- assetId: string | null;
16316
- fitMode: ImageFillMode;
16317
- cropRect: ImageFillCropPlacement;
16318
- flipX: boolean;
16319
- flipY: boolean;
15713
+ type StoryBlockSelection = {
15714
+ editor: "story";
15715
+ tabId: string;
15716
+ storyId: StoryId;
15717
+ sceneId: StorySceneId;
15718
+ /** The focused row, or null when the scene itself is the subject. */
15719
+ blockId: StoryBlockId | null;
16320
15720
  };
16321
- type BlueprintFrameProperties = {
16322
- targetSurfaceId: string | null;
16323
- params: Record<string, unknown>;
15721
+ type StoryMotionKeyframeSelection = {
15722
+ editor: "story-motion";
15723
+ tabId: string;
15724
+ animationId: string;
15725
+ trackId: string;
15726
+ keyframeId: string;
16324
15727
  };
16325
- type BlueprintGamePreferenceKey = "autoForward" | "skip"
15728
+ type ComparisonHalf = "base" | "head";
15729
+ interface ComparisonElementSelection {
15730
+ /** Repository-relative path of the document being compared. Identity, not a read address. */
15731
+ readonly documentPath: string;
15732
+ readonly half: ComparisonHalf;
15733
+ /** What that half calls its version, already resolved to text by the tab that knows. */
15734
+ readonly versionLabel: string;
15735
+ /** What the OTHER half calls its version. The strip names it when the element is not in it. */
15736
+ readonly counterpartLabel: string;
15737
+ readonly surfaceId: string;
15738
+ readonly elementId: string;
15739
+ /** The element, out of that half's parsed document. */
15740
+ readonly element: UIElement;
15741
+ /** That half's whole document, so a field can resolve a parent, a component or a binding. */
15742
+ readonly document: UIDocument;
15743
+ /** The same element in the other half, or null when that half does not hold it. */
15744
+ readonly counterpart: UIElement | null;
15745
+ /** The other half's document, for the fields that read one. Null when there is no other half. */
15746
+ readonly counterpartDocument: UIDocument | null;
15747
+ }
16326
15748
  /**
16327
- * Studio's own, not the engine's: skipping stops at a line the player has not read.
15749
+ * What a plugin may add to Studio's built-in text editor.
15750
+ *
15751
+ * Studio ships the editor and nothing on top of it: no Markdown preview, no lint, no formatter.
15752
+ * Those are plugin work, and this module is the whole of what a plugin needs to do them - a
15753
+ * grammar, a preview pane, a command. The host registry is
15754
+ * `TextEditorContributionService`; the plugin-facing names are re-exported from
15755
+ * `@/plugin` and published in the `narraleaf-studio` types package.
15756
+ *
15757
+ * Two rules the rest of the design follows from:
16328
15758
  *
16329
- * It lives in the engine's preference store all the same (see `preferenceRuntime`), which is
16330
- * what lets it reach this API, the `gamePreferenceChanged` event and the project's preference
16331
- * defaults through exactly the same plumbing as the twelve the engine defines.
15759
+ * - **Imperative, not declarative.** There is no `contributes.textEditor` manifest key, for the
15760
+ * same reason `ui.panels` has none: nothing outside the editor session needs to know these
15761
+ * exist, so a static declaration would be bookkeeping with no reader.
15762
+ * - **Nothing is rendered for an empty registry.** A preview toggle with no preview behind it is
15763
+ * a dead control, and the editor's status bar is values-only by design. The consumer shows the
15764
+ * toggles for the previews that match *this* document's extension and nothing otherwise.
16332
15765
  */
16333
- | "skipReadText"
15766
+ /** The character encoding a document is currently being read and written in. */
15767
+ export type PluginTextEditorEncodingId = TextEncodingId;
16334
15768
  /**
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.
15769
+ * A Monarch grammar - monaco's `languages.IMonarchLanguage`.
15770
+ *
15771
+ * Typed structurally rather than by importing monaco's declarations: the published
15772
+ * `narraleaf-studio` types package would otherwise have to carry monaco's entire `.d.ts` surface,
15773
+ * and a plugin would need monaco installed to write a twenty-line grammar. The host casts on the
15774
+ * way into `monaco.languages.setMonarchTokensProvider`.
16337
15775
  */
16338
- | "muteOnWindowBlur"
15776
+ export type PluginTextEditorMonarchGrammar = {
15777
+ tokenizer: Record<string, unknown>;
15778
+ [key: string]: unknown;
15779
+ };
15780
+ /** A monaco `languages.LanguageConfiguration` (comments, brackets, auto-closing pairs, folding). */
15781
+ export type PluginTextEditorLanguageConfiguration = Record<string, unknown>;
16339
15782
  /**
16340
- * Studio's own, and transient: the skip run is going. Writing it is the equivalent of holding
16341
- * the skip key, and the host clears it whenever the run ends - a guard stopping it, the game
16342
- * leaving the stage, the window losing focus. Never persisted (see `@shared/types/preference`).
15783
+ * A language the built-in editor should colour.
15784
+ *
15785
+ * Registered into monaco **lazily** - the first time a document with one of these extensions is
15786
+ * opened, not when the plugin's `setup` runs. Monaco is a large module that Studio loads on the
15787
+ * first text tab and never before; a language registration at setup time would drag it into
15788
+ * startup for every workspace, whether or not a text file is ever opened.
16343
15789
  */
16344
- | "skipping"
16345
- /**
16346
- * Studio's own: the engine keeps this in `game.config`, not in its preference store, so the
16347
- * host copies it across on every change (see `preferenceRuntime`).
16348
- */
16349
- | "autoForwardDelay" | "showDialog" | "gameSpeed" | "cps"
16350
- /** Milliseconds a newly typed character takes to fade in; `0` types it at full strength. */
16351
- | "textRevealDuration" | "voiceVolume" | "voiceFadeDuration" | "voiceEndMode" | "bgmVolume" | "soundVolume" | "globalVolume" | "skipDelay" | "skipInterval";
16352
- type BlueprintGamePreferenceVoiceEndMode = "fade" | "stop" | "none";
16353
- type BlueprintGamePreferenceValue = boolean | number | BlueprintGamePreferenceVoiceEndMode;
16354
- type BlueprintLayerShowOptions = {
16355
- /** Everything below goes inert and the keys belong to this layer. */
16356
- modal?: boolean;
16357
- /** Whether Go back closes it. Default true. */
16358
- dismissible?: boolean;
16359
- /** Mutual-exclusion group; a second layer of an occupied group queues behind the first. */
16360
- group?: string | null;
16361
- };
16362
- type BlueprintHostApiRuntime = {
16363
- navigation: {
16364
- openSurface: (surfaceId: string, props?: unknown) => Promise<void>;
16365
- getPageProps: () => Record<string, unknown>;
16366
- pageBack: () => Promise<void>;
16367
- clearPages: () => Promise<void>;
16368
- clearGameOverlay: () => Promise<void>;
16369
- quitApplication: () => Promise<void>;
16370
- getFullscreen: () => Promise<boolean>;
16371
- setFullscreen: (fullscreen: boolean) => Promise<void>;
16372
- /** The sizes worth offering, ascending. Empty where the shell has no window to size. */
16373
- getWindowScaleOptions: () => Promise<number[]>;
16374
- getWindowScale: () => Promise<number>;
16375
- setWindowScale: (scale: number) => Promise<void>;
16376
- getWindowSize: () => Promise<{
16377
- width: number;
16378
- height: number;
16379
- }>;
16380
- setWindowSize: (width: number, height: number) => Promise<void>;
16381
- /**
16382
- * Open one web address in the player's browser.
16383
- *
16384
- * The host does not decide: it hands the request to whatever the shell supplied, and the
16385
- * shell's own process checks it against the addresses the build declared. Nothing here
16386
- * consults the project's network setting, because no request is made - see
16387
- * `@shared/types/blueprint/externalLink`.
16388
- */
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>;
16406
- };
16407
- /** Surfaces stacked over the page lane. See the `layers` family in `@shared/types/blueprint/hostApi`. */
16408
- layers: {
16409
- /** Put a page up as a layer and return the handle that names it. */
16410
- show: (surfaceId: string, props?: unknown, options?: BlueprintLayerShowOptions) => Promise<string>;
16411
- /** Take that layer down, settling once it has finished animating out. */
16412
- hide: (handle: string) => Promise<void>;
16413
- /** Take a whole group down - what is on screen and what is queued behind it. */
16414
- hideGroup: (group: string) => Promise<void>;
16415
- /** Wait for that layer to close and read what it closed with. Null for a handle already gone. */
16416
- wait: (handle: string) => Promise<unknown>;
16417
- /** Close the layer the calling graph runs in. A no-op with a warning anywhere else. */
16418
- closeSelf: (result?: unknown) => Promise<void>;
16419
- isMounted: (handle: string) => boolean;
16420
- };
16421
- widget: {
16422
- setVisible: (elementId: string, visible: boolean) => Promise<void>;
16423
- setEnabled: (elementId: string, enabled: boolean) => Promise<void>;
16424
- /** `null` clears runtime override and restores authored default variant resolution. */
16425
- setVariant: (elementId: string, variantId: string | null, options?: {
16426
- waitForTransition?: boolean;
16427
- }) => Promise<void>;
16428
- getCommonProperties: (elementId: string) => BlueprintWidgetCommonProperties;
16429
- getTextProperties: (elementId: string) => BlueprintTextProperties;
16430
- setTextProperties: (elementId: string, patch: BlueprintTextPropertiesPatch) => Promise<void>;
16431
- getButtonProperties: (elementId: string) => BlueprintButtonProperties;
16432
- setButtonProperties: (elementId: string, patch: Partial<BlueprintButtonProperties>) => Promise<void>;
16433
- getContainerProperties: (elementId: string) => BlueprintContainerProperties;
16434
- setContainerProperties: (elementId: string, patch: Partial<BlueprintContainerProperties>) => Promise<void>;
16435
- getImageProperties: (elementId: string) => BlueprintImageProperties;
16436
- setImageProperties: (elementId: string, patch: Partial<BlueprintImageProperties>) => Promise<void>;
16437
- getSliderProperties: (elementId: string) => BlueprintSliderProperties;
16438
- setSliderProperties: (elementId: string, patch: BlueprintSliderPropertiesPatch) => Promise<void>;
16439
- getSwitchProperties: (elementId: string) => BlueprintSwitchProperties;
16440
- setSwitchProperties: (elementId: string, patch: BlueprintSwitchPropertiesPatch) => Promise<void>;
16441
- getTextInputProperties: (elementId: string) => BlueprintTextInputProperties;
16442
- setTextInputProperties: (elementId: string, patch: BlueprintTextInputPropertiesPatch) => Promise<void>;
16443
- getListProperties: (elementId: string) => BlueprintListProperties;
16444
- setListItems: (elementId: string, items: readonly unknown[]) => Promise<void>;
16445
- setListSelectedIndex: (elementId: string, index: number) => Promise<void>;
16446
- scrollListToIndex: (elementId: string, index: number) => Promise<void>;
16447
- scrollListToTop: (elementId: string) => Promise<void>;
16448
- scrollListToBottom: (elementId: string) => Promise<void>;
16449
- getDisplayableProperties: (elementId: string) => BlueprintDisplayableProperties;
16450
- /**
16451
- * What the widget currently covers on screen, in the coordinates of the surface it is on,
16452
- * or `null` when nothing is painted for it.
16453
- *
16454
- * Separate from {@link getDisplayableProperties} because the two answer different
16455
- * questions. That one reads the document - where the author put the widget - and is the
16456
- * right answer for layout arithmetic. This one measures the DOM, so it accounts for a
16457
- * motion in flight, an appearance variant that shifted the widget, a text box sized to its
16458
- * own words, and which row of a list an instance ended up on.
16459
- */
16460
- getMeasuredRect: (elementId: string) => BlueprintRect | null;
16461
- setDisplayableProperties: (elementId: string, patch: BlueprintDisplayablePropertiesPatch) => Promise<void>;
16462
- animateDisplayable: (elementId: string, request: BlueprintDisplayableMotionRequest) => Promise<UIDisplayableMotionOverride>;
16463
- stopDisplayableAnimation: (animationId: string) => Promise<void>;
16464
- getFrameProperties: (elementId: string) => BlueprintFrameProperties;
16465
- setFrameProperties: (elementId: string, patch: Partial<BlueprintFrameProperties>) => Promise<void>;
16466
- };
16467
- state: {
16468
- get: (scope: string, key: string) => unknown;
16469
- set: (scope: string, key: string, value: unknown) => void;
16470
- };
16471
- persistence: {
16472
- get: (key: string) => Promise<unknown>;
16473
- set: (key: string, value: unknown) => Promise<void>;
16474
- };
16475
- localization: {
16476
- /** Localization setup of the running game, or null when the project has none. */
16477
- getConfig: () => GameLocalizationConfigSnapshot | null;
16478
- /** Effective current locale (stored player choice, else the source locale). */
16479
- getLocale: () => Promise<string>;
16480
- /** Persist the player's language choice; callers validate against getConfig(). */
16481
- setLocale: (code: string) => Promise<void>;
16482
- };
16483
- /**
16484
- * Voice-over: which dub the player hears, and replaying a take on demand.
16485
- *
16486
- * Separate from `localization` because dub language and subtitle language are separate player
16487
- * choices - a game may be read in English and heard in Japanese.
16488
- */
16489
- voice: {
16490
- /** The dub languages this build ships, in project order. Empty when the game has no voice. */
16491
- listLocales: () => VoiceLocaleEntry[];
16492
- /** Effective dub language: the stored player choice when the build ships it, else the first. */
16493
- getLocale: () => Promise<string>;
16494
- /** Persist the player's dub choice. Takes effect from the next spoken line - no restart. */
16495
- setLocale: (code: string) => Promise<void>;
16496
- /**
16497
- * Play one line's take in the current dub language, on that speaker's bus.
16498
- *
16499
- * The id is a voice unit id - the same id a backlog entry reports as `voiceId` - which is why
16500
- * a replay button is built from this rather than from the entry's resolved URL. Resolves to
16501
- * false when the line has no take in the current language.
16502
- */
16503
- play: (unitId: string) => Promise<boolean>;
16504
- /**
16505
- * Play one choice option's take, at most one instance of that option at a time.
16506
- *
16507
- * Same clip and same bus as {@link play}; what differs is the bookkeeping a menu needs. A
16508
- * hover fires as often as the pointer crosses a row, so a line already speaking is left
16509
- * alone rather than restarted, and it answers false. `interruptOthers` stops the takes of
16510
- * the *other* options - the author's call, because a menu that reads each option over the
16511
- * last is as deliberate a design as one that speaks a single line at a time.
16512
- */
16513
- playChoice: (unitId: string, options?: {
16514
- interruptOthers?: boolean;
16515
- }) => Promise<boolean>;
16516
- };
16517
- frame: {
16518
- getParam: (key: string) => unknown;
16519
- emit: (eventName: string, data: unknown) => Promise<void>;
16520
- };
16521
- game: {
16522
- /**
16523
- * Begin a story. `options.inheritSavedGame` carries a save's saved-scope values and visited
16524
- * scenes into the new game - see the `Inherit From` pin - and carries nothing else.
16525
- */
16526
- startStory: (request: DevModeStartStoryRequest, options?: {
16527
- inheritSavedGame?: unknown;
16528
- }) => Promise<void>;
16529
- /** The running playthrough as a serialized game, or null when none is running. */
16530
- captureRun: () => unknown | null;
16531
- /** The serialized game stored in a slot, or null when there is no such slot. */
16532
- readSaveGame: (id: string) => Promise<unknown | null>;
16533
- isInGame: () => boolean;
16534
- isGameOverlay: () => boolean;
16535
- quit: (surfaceId: string) => Promise<void>;
16536
- writeSave: (id: string, metadata?: unknown, screenshot?: boolean) => Promise<void>;
16537
- /** False when the save was not applied - the player and the author have both been told. */
16538
- loadSave: (id: string) => Promise<boolean>;
16539
- deleteSave: (id: string) => Promise<void>;
16540
- listSaveIds: () => Promise<string[]>;
16541
- getSaveMetadata: (id: string) => Promise<unknown>;
16542
- /** When a slot was written, or null when there is no such slot. */
16543
- getSaveTimes: (id: string) => Promise<SaveRecordTimes | null>;
16544
- /** Where a slot stopped, or null when there is no such slot. */
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>;
16548
- /** How long a slot was played, or null when there is no such slot. */
16549
- getSavePlaytime: (id: string) => Promise<SaveRecordPlaytime | null>;
16550
- /** The running playthrough's playtime, in seconds. */
16551
- getPlaytime: () => number;
16552
- /** Seconds ever spent in this project, across every playthrough. */
16553
- getTotalPlaytime: () => number;
16554
- getSavePreview: (id: string) => Promise<BlueprintImageAsset | null>;
16555
- /** Write an autosave into the reserved ring now, regardless of the timer. */
16556
- writeAutoSave: () => Promise<void>;
16557
- /** The reserved autosave ring, newest first. Never overlaps `listSaveIds`. */
16558
- listAutoSaves: () => Promise<AutoSaveEntry[]>;
16559
- /**
16560
- * The backlog behind the play head, oldest first.
16561
- *
16562
- * From engine 0.26.0 this stops at the head: after the player steps back, the lines they
16563
- * stepped past are no longer in here, they are in {@link getFuture}. Before anyone steps
16564
- * back - which is every ordinary playthrough - the two are the whole backlog and nothing.
16565
- */
16566
- getHistory: () => Promise<BlueprintGameHistoryEntry[]>;
16567
- /** The lines ahead of the play head, nearest first. Empty until the player steps back. */
16568
- getFuture: () => Promise<BlueprintGameHistoryEntry[]>;
16569
- /** Jump back to a history entry by id; omit the id to undo the last entry. */
16570
- restoreHistory: (id?: string) => Promise<void>;
16571
- /** Step the play head forward one line, back over a line the player has already read. */
16572
- redoHistory: () => Promise<void>;
16573
- canUndoHistory: () => boolean;
16574
- canRedoHistory: () => boolean;
16575
- getNametag: () => string | null;
16576
- /**
16577
- * The speaking character's dialog avatar, or null. Already keyed on the differential the
16578
- * character is currently wearing - the engine resolves it off the live portrait element.
16579
- */
16580
- getSpeakerAvatar: () => BlueprintImageAsset | null;
16581
- /**
16582
- * The speaking character's authored accent colour, already in pin shape. Opaque white when
16583
- * nobody is speaking, the narrator is, or the character has no colour - the pin it feeds is
16584
- * a non-nullable RGBAColor, so "no colour" and "the default colour" are the same answer.
16585
- */
16586
- getSpeakerColor: () => BlueprintRGBAColor;
16587
- /**
16588
- * Has the line on screen finished revealing, with the dialog now waiting for the player.
16589
- *
16590
- * False while it is still typing, and false again the moment the next line mounts, so an
16591
- * indicator bound to it needs no timer of its own. False with no dialog on screen at all.
16592
- */
16593
- isDialogWaiting: () => boolean;
16594
- /**
16595
- * The current line's text - the whole line, not the part revealed so far. Empty string when
16596
- * no line is on screen.
16597
- */
16598
- getDialogText: () => string;
16599
- /**
16600
- * Does the current line have no speaker. Distinct from a null nametag, which a character
16601
- * with a blank name also reports. False when no line is on screen.
16602
- */
16603
- isNarrator: () => boolean;
16604
- /**
16605
- * Any character by id, from the table mirrored into global state - the addressable read the
16606
- * speaker-scoped getters above cannot do. Null when the id is empty, or names a character
16607
- * that is not (or is no longer) in the project.
16608
- */
16609
- getCharacter: (characterId: string) => BlueprintCharacterInfo | null;
16610
- getNotifications: () => BlueprintGameNotification[];
16611
- getChoiceCount: () => number;
16612
- isNvlMode: () => boolean;
16613
- /** True while a dialog line is on screen and its message is marked read. */
16614
- isCurrentTextRead: () => boolean;
16615
- isTextRead: (textId: string) => boolean;
16616
- /** Wipe the persisted text-read record (all stories). */
16617
- clearTextRead: () => Promise<void>;
16618
- /**
16619
- * Has the player ever ENTERED this scene, by Studio scene id.
16620
- *
16621
- * Not the same question as `isTextRead`: that record is written when a line is displayed,
16622
- * this one when a scene actually starts. Saved-domain, so loading an older save rewinds it.
16623
- */
16624
- isSceneVisited: (sceneId: string) => boolean;
16625
- /**
16626
- * One saved variable of the running playthrough, by the id a `savedVariableRef` names.
16627
- *
16628
- * `found` is false with no game running, and with an id this build's story does not
16629
- * declare. The two are worth telling apart from a value: `null` and the declared default
16630
- * are both real values a variable can hold, so neither can double as "there was nothing to
16631
- * read". See the capability's own note for why this is read-only.
16632
- */
16633
- getSavedVariable: (variableId: string) => {
16634
- value: unknown;
16635
- found: boolean;
16636
- };
16637
- /**
16638
- * Write one saved variable of the running playthrough.
16639
- *
16640
- * Throws when there is no game, when the id names nothing this build declares, and when the
16641
- * value cannot go into a save file. All three are authoring errors a button would otherwise
16642
- * swallow; see the capability's own note for what a write from a screen does and does not do.
16643
- */
16644
- setSavedVariable: (variableId: string, value: unknown) => void;
16645
- /**
16646
- * Has the player ever PICKED this choice option, by the option row's Studio block id. The
16647
- * one thing the text-read record structurally cannot answer - a menu that merely appeared
16648
- * marks every option of it read.
16649
- */
16650
- isOptionPicked: (optionId: string) => boolean;
16651
- /**
16652
- * Wipe the visited record of the running game.
16653
- *
16654
- * Synchronous, unlike `clearTextRead`: the record lives in the live `Storable`, not in host
16655
- * persistence, so there is nothing to await. It is also scoped to the running session - with
16656
- * no game up there is no record, and the call is a no-op instead of an error.
16657
- */
16658
- clearVisited: () => void;
16659
- /**
16660
- * Has the player ever reached this ending, by the `ending` row's Studio block id.
16661
- *
16662
- * Project persistence rather than the save file, unlike the visited record above: an endings
16663
- * screen reports what this player has ever seen, so loading an older save must not re-lock
16664
- * anything. Needs no running story - a title screen asks it before the first game exists.
16665
- */
16666
- isEndingReached: (endingId: string) => boolean;
16667
- /**
16668
- * Is this DLC installed beside the running build, by the id the author gave it.
16669
- *
16670
- * The whole of what a game may ask about its DLC, and deliberately not "does the player own
16671
- * it". Ownership is a storefront's fact and a plugin's to answer; what decides whether the
16672
- * content is here is whether its file is, which is the question this asks. A build with no
16673
- * DLC beside it answers false to everything, which is what a title screen wants before the
16674
- * player has bought anything.
16675
- */
16676
- isDlcInstalled: (dlcId: string) => boolean;
16677
- /**
16678
- * Every ending one story declares, in document order, each row already carrying whether it
16679
- * was reached. Empty for an unknown or unnamed story rather than an error.
16680
- *
16681
- * The list comes from the story document this build ships, so it can never offer an ending
16682
- * the compiler does not emit, and it is available with no game running for the same reason
16683
- * the reader above is.
16684
- */
16685
- listEndings: (storyId: string) => BlueprintStoryEnding[];
16686
- /**
16687
- * Forget one ending. Awaited, unlike `clearVisited`: this writes host persistence rather
16688
- * than a live `Storable`, and a caller that navigates away on the next beat has to know the
16689
- * write landed.
16690
- */
16691
- clearEndingState: (endingId: string) => Promise<void>;
16692
- /** Wipe the whole endings record. The `Clear Text Read` of this family. */
16693
- clearEndings: () => Promise<void>;
16694
- choose: (index: number) => Promise<void>;
16695
- next: () => Promise<void>;
16696
- skip: () => Promise<void>;
16697
- showDialog: () => Promise<void>;
16698
- hideDialog: () => Promise<void>;
16699
- toggleDialogDisplay: () => Promise<void>;
16700
- setSentenceSpeed: (cps: number) => Promise<void>;
16701
- getPreference: (key: BlueprintGamePreferenceKey) => BlueprintGamePreferenceValue;
16702
- setPreference: (key: BlueprintGamePreferenceKey, value: BlueprintGamePreferenceValue) => Promise<void>;
16703
- };
16704
- sound: {
16705
- play: (input: BlueprintSoundPlayInput) => Promise<BlueprintSoundHandle | null>;
16706
- stop: (handle: BlueprintSoundHandle | null, fadeMs?: number) => Promise<void>;
16707
- pause: (handle: BlueprintSoundHandle) => Promise<void>;
16708
- resume: (handle: BlueprintSoundHandle) => Promise<void>;
16709
- /** Ramp rather than jump when `fadeMs` is set - this is also the fade-out/duck node. */
16710
- setVolume: (handle: BlueprintSoundHandle, volume: number, fadeMs?: number) => Promise<void>;
16711
- /** Milliseconds from the start of the file, not from the clip's in point. */
16712
- seek: (handle: BlueprintSoundHandle, timeMs: number) => Promise<void>;
16713
- isPlaying: (handle: BlueprintSoundHandle) => boolean;
16714
- /**
16715
- * The volume a **host-owned** media element (the `nl.video` widget's `<video>`) must be set
16716
- * to so it obeys the same mixer everything else does.
16717
- *
16718
- * A DOM element the host created sits on none of the engine's gain nodes, so the whole
16719
- * product has to be computed and written to `element.volume`: the authored volume, times
16720
- * every bus in the track's chain, times the player's slider for whichever seeded bus that
16721
- * chain runs through, times master. Without this a muted game keeps playing video at full
16722
- * volume. Pair it with {@link subscribeMixerChanges} - a value read once goes stale the
16723
- * moment the player drags a slider, bus faders included.
16724
- */
16725
- resolveElementVolume: (input: {
16726
- audioTrackId?: string | null;
16727
- volume?: number | null;
16728
- }) => number;
16729
- /** Fires when any preference feeding `resolveElementVolume` changes. Returns a disposer. */
16730
- subscribeMixerChanges: (listener: () => void) => () => void;
16731
- /**
16732
- * An audio **track**'s own volume, 0..1 - one strip of the player's mixer.
16733
- *
16734
- * The player-facing counterpart of {@link setVolume}, which addresses one playing clip by
16735
- * handle. A track is a bus every clip beneath it is routed through, so setting one applies
16736
- * live to everything already playing and survives the clip that provoked it. This is what
16737
- * makes "turn Alice down" expressible at all: the four fixed volume preferences can only
16738
- * reach the three buses the engine seeds.
16739
- *
16740
- * An unknown or deleted track id reads as unity and writes nowhere, so a settings page
16741
- * built against a track the author later removed degrades to an inert slider.
16742
- */
16743
- getTrackVolume: (trackId: string) => number;
16744
- setTrackVolume: (trackId: string, volume: number) => Promise<void>;
16745
- };
16746
- /**
16747
- * HTTP, for the Fetch node.
16748
- *
16749
- * The host does not issue the request itself: it hands it to whatever the shell supplied, which
16750
- * on desktop and in Dev Mode is the main process (`onNetworkFetch`). Nothing here calls
16751
- * `fetch()` - see `@shared/utils/blueprintNetworkFetch` for why the renderer must not.
16752
- */
16753
- network: {
16754
- fetch: (request: BlueprintNetworkFetchRequest) => Promise<BlueprintNetworkFetchResult>;
16755
- };
16756
- /**
16757
- * The read side of input routing, for `Is Action Held` and `Get Input Device`.
16758
- *
16759
- * The only part of the input model a graph can ask about rather than be told about. Everything
16760
- * else in it is a dispatch - an action fires, a head runs - and none of that can answer "while
16761
- * the gesture is down" or "with which hand", because a fired event leaves nothing behind that
16762
- * says whether the hand is still there or what it was.
16763
- *
16764
- * Structural rather than a declared family in `@shared/types/blueprint/hostApi`, matching how
16765
- * both nodes reach for it (see `BlueprintInputActionHostApi`): the contract there names
16766
- * capabilities a host may or may not implement, and these are answered by the window every host
16767
- * already has.
16768
- */
16769
- input: {
16770
- isActionHeld: (actionId: string) => boolean;
16771
- /**
16772
- * Which device the player is using at this moment.
16773
- *
16774
- * One of the four values the `On Action` head's `source` pin carries, typed as a plain
16775
- * string so a graph compares both against the same literals.
16776
- */
16777
- getDevice: () => string;
16778
- };
16779
- /**
16780
- * Moving the player's real cursor, for the Move Mouse family.
16781
- *
16782
- * The author names a point in a surface's own coordinates, which is the only frame they have
16783
- * reason to think in. Turning that into a point in the window happens here, off the same
16784
- * surface shell every mouse event's payload is divided by, so "the centre of this button"
16785
- * measured by `widget.getMeasuredRect` and the point the cursor lands on are the same place.
16786
- *
16787
- * `surfaceId` is the surface the point belongs to; `null` means the active one. A point on a
16788
- * surface that is not currently laid out has nowhere to be, and reports `failed` rather than
16789
- * being guessed at against a different surface's scale.
16790
- */
16791
- pointer: {
16792
- moveTo: (surfaceId: string | null, point: BlueprintVector2D, options?: BlueprintPointerMoveOptions) => Promise<BlueprintPointerMoveResult>;
16793
- /**
16794
- * The same act aimed at a widget's centre, measured rather than computed from the document.
16795
- *
16796
- * A method of its own rather than something a caller assembles out of `getMeasuredRect` and
16797
- * `moveTo`, because the two halves have to agree about which surface the widget turned out
16798
- * to be painted on. A component instance renders its contents wherever it was placed, so
16799
- * the answer is not always the surface the element was authored under, and a caller
16800
- * stitching the halves together would have to know that to get it right.
16801
- */
16802
- moveToElementCenter: (elementId: string, options?: BlueprintPointerMoveOptions) => Promise<BlueprintPointerMoveResult>;
16803
- };
16804
- /**
16805
- * Carrying a playthrough between two editions of one title, for the Export/Import Progress
16806
- * nodes.
16807
- *
16808
- * The host does not decide where the document is: it hands the act to whatever the shell
16809
- * supplied, and the shell's own process resolves the file from the build's progress key. What
16810
- * this side states is what the playthrough holds, never where it goes.
16811
- *
16812
- * `import` answers with a scene id rather than going anywhere with it. The node deliberately
16813
- * does not jump - `Start Game` is what starts a story, and an author's graph usually has
16814
- * something to do first.
16815
- */
16816
- progress: {
16817
- export: () => Promise<{
16818
- outcome: "written" | "failed";
16819
- error: string;
16820
- }>;
16821
- import: () => Promise<GameProgressImportOutcome>;
16822
- };
16823
- /**
16824
- * What the shell can promise about the data it writes, for the `Check Storage Durability` node.
16825
- *
16826
- * A fact about where the game is running, not about the playthrough: a packaged desktop game
16827
- * keeps files nothing reclaims, a web export holds whatever grant the browser gave it. Stated,
16828
- * never acted on - what a player is told about it belongs to the title.
16829
- */
16830
- storage: {
16831
- durability: () => Promise<GameStorageDurability>;
16832
- };
16833
- devtools: {
16834
- log: (level: string, message: string) => void;
16835
- };
16836
- };
16837
- type BlueprintSoundPlayInput = {
16838
- assetId: string;
16839
- /**
16840
- * Project audio track (`ProjectAudioTrack.id`), which **is** the engine bus this clip is routed
16841
- * into, and whose own gain is applied live by the gain graph rather than folded in here. It also
16842
- * supplies the loop default below. Absent resolves to the seeded SFX bus, which is what an
16843
- * unqualified "play this clip" has always meant.
16844
- */
16845
- audioTrackId?: string | null;
16846
- /** Author override; absent means the track's own default. */
16847
- loop?: boolean | null;
16848
- /** Author override, 0..1 as authored; absent means unity. Never pre-multiplied by a bus gain. */
16849
- volume?: number | null;
16850
- /** Fade-in in milliseconds; absent means a hard start (a fade belongs to the moment). */
16851
- fadeInMs?: number | null;
16852
- };
16853
- type GameLocalizationConfigSnapshot = Pick<GameLocalizationBundle, "sourceLocale" | "locales"> & Partial<Pick<GameLocalizationBundle, "tables" | "keys" | "scenes">>;
16854
- type BlueprintGameNotification = {
16855
- id: string;
16856
- message: string;
16857
- };
16858
- type BlueprintStoryEnding = {
16859
- endingId: string;
16860
- name: string;
16861
- sceneId: string;
16862
- /** The scene the ending row sits in, so a row can be grouped or captioned without a lookup. */
16863
- sceneName: string;
16864
- isReached: boolean;
16865
- };
16866
- type BlueprintGameHistoryEntry = {
16867
- /** History token; pass to Restore From History to jump the game back to this point. */
16868
- id: string;
16869
- /** "say" for spoken lines, "menu" for a resolved choice. */
16870
- type: "say" | "menu";
16871
- /** Sentence text (say) or the menu prompt (menu); empty string when the source had none. */
16872
- text: string;
16873
- /** Speaker nametag for a say entry; null for menu entries or narration. */
16874
- character: string | null;
16875
- /** Resolved voice clip URL for a say entry; null when absent. Not addressable - see `voiceId`. */
16876
- voice: string | null;
16877
- /**
16878
- * The voice unit id this line's take is filed under; null when the line was not voiced through
16879
- * the voice module. This is the replayable handle: feed it to the Play Voice node. `voice` is a
16880
- * URL the player already heard and nothing in the runtime accepts a URL.
16881
- */
16882
- voiceId: string | null;
16883
- /** Chosen option text for a menu entry; null for say entries or an unresolved menu. */
16884
- selected: string | null;
16885
- /** True while the entry is the line currently being shown (not yet committed). */
16886
- isPending: boolean;
16887
- };
16888
- type BehaviorNodeExecuteResult = {
16889
- nextPort?: string;
16890
- nextPorts?: string[];
16891
- outputValues?: Record<string, unknown>;
16892
- };
16893
- type BehaviorGraphEventControl = {
16894
- stopPropagation(): void;
16895
- isPropagationStopped(): boolean;
16896
- };
16897
- type StoryBlockSelection = {
16898
- editor: "story";
16899
- tabId: string;
16900
- storyId: StoryId;
16901
- sceneId: StorySceneId;
16902
- /** The focused row, or null when the scene itself is the subject. */
16903
- blockId: StoryBlockId | null;
16904
- };
16905
- type StoryMotionKeyframeSelection = {
16906
- editor: "story-motion";
16907
- tabId: string;
16908
- animationId: string;
16909
- trackId: string;
16910
- keyframeId: string;
16911
- };
16912
- type ComparisonHalf = "base" | "head";
16913
- interface ComparisonElementSelection {
16914
- /** Repository-relative path of the document being compared. Identity, not a read address. */
16915
- readonly documentPath: string;
16916
- readonly half: ComparisonHalf;
16917
- /** What that half calls its version, already resolved to text by the tab that knows. */
16918
- readonly versionLabel: string;
16919
- /** What the OTHER half calls its version. The strip names it when the element is not in it. */
16920
- readonly counterpartLabel: string;
16921
- readonly surfaceId: string;
16922
- readonly elementId: string;
16923
- /** The element, out of that half's parsed document. */
16924
- readonly element: UIElement;
16925
- /** That half's whole document, so a field can resolve a parent, a component or a binding. */
16926
- readonly document: UIDocument;
16927
- /** The same element in the other half, or null when that half does not hold it. */
16928
- readonly counterpart: UIElement | null;
16929
- /** The other half's document, for the fields that read one. Null when there is no other half. */
16930
- readonly counterpartDocument: UIDocument | null;
16931
- }
16932
- /**
16933
- * What a plugin may add to Studio's built-in text editor.
16934
- *
16935
- * Studio ships the editor and nothing on top of it: no Markdown preview, no lint, no formatter.
16936
- * Those are plugin work, and this module is the whole of what a plugin needs to do them - a
16937
- * grammar, a preview pane, a command. The host registry is
16938
- * `TextEditorContributionService`; the plugin-facing names are re-exported from
16939
- * `@/plugin` and published in the `narraleaf-studio` types package.
16940
- *
16941
- * Two rules the rest of the design follows from:
16942
- *
16943
- * - **Imperative, not declarative.** There is no `contributes.textEditor` manifest key, for the
16944
- * same reason `ui.panels` has none: nothing outside the editor session needs to know these
16945
- * exist, so a static declaration would be bookkeeping with no reader.
16946
- * - **Nothing is rendered for an empty registry.** A preview toggle with no preview behind it is
16947
- * a dead control, and the editor's status bar is values-only by design. The consumer shows the
16948
- * toggles for the previews that match *this* document's extension and nothing otherwise.
16949
- */
16950
- /** The character encoding a document is currently being read and written in. */
16951
- export type PluginTextEditorEncodingId = TextEncodingId;
16952
- /**
16953
- * A Monarch grammar - monaco's `languages.IMonarchLanguage`.
16954
- *
16955
- * Typed structurally rather than by importing monaco's declarations: the published
16956
- * `narraleaf-studio` types package would otherwise have to carry monaco's entire `.d.ts` surface,
16957
- * and a plugin would need monaco installed to write a twenty-line grammar. The host casts on the
16958
- * way into `monaco.languages.setMonarchTokensProvider`.
16959
- */
16960
- export type PluginTextEditorMonarchGrammar = {
16961
- tokenizer: Record<string, unknown>;
16962
- [key: string]: unknown;
16963
- };
16964
- /** A monaco `languages.LanguageConfiguration` (comments, brackets, auto-closing pairs, folding). */
16965
- export type PluginTextEditorLanguageConfiguration = Record<string, unknown>;
16966
- /**
16967
- * A language the built-in editor should colour.
16968
- *
16969
- * Registered into monaco **lazily** - the first time a document with one of these extensions is
16970
- * opened, not when the plugin's `setup` runs. Monaco is a large module that Studio loads on the
16971
- * first text tab and never before; a language registration at setup time would drag it into
16972
- * startup for every workspace, whether or not a text file is ever opened.
16973
- */
16974
- export type PluginTextEditorLanguageDef = {
16975
- /** Monaco language id. Must be prefixed with the plugin id. */
16976
- id: string;
16977
- /** File extensions, with or without the leading dot; matched case-insensitively. */
16978
- extensions: string[];
16979
- aliases?: string[];
16980
- monarch?: PluginTextEditorMonarchGrammar;
16981
- configuration?: PluginTextEditorLanguageConfiguration;
16982
- };
15790
+ export type PluginTextEditorLanguageDef = {
15791
+ /** Monaco language id. Must be prefixed with the plugin id. */
15792
+ id: string;
15793
+ /** File extensions, with or without the leading dot; matched case-insensitively. */
15794
+ extensions: string[];
15795
+ aliases?: string[];
15796
+ monarch?: PluginTextEditorMonarchGrammar;
15797
+ configuration?: PluginTextEditorLanguageConfiguration;
15798
+ };
16983
15799
  /**
16984
15800
  * What a preview component is handed on every render.
16985
15801
  *
@@ -17078,176 +15894,6 @@ type SelectionState = {
17078
15894
  type: "storyBlock";
17079
15895
  data: StoryBlockSelection;
17080
15896
  };
17081
- type ViewportTransform = {
17082
- scale: number;
17083
- offsetX: number;
17084
- offsetY: number;
17085
- };
17086
- type CanvasFitMode = "contain" | "cover" | "width" | "actual";
17087
- type SurfaceViewportFit = {
17088
- mode: CanvasFitMode;
17089
- /**
17090
- * True when the mode came from the zoom menu. It survives a resize the same way, and only this
17091
- * one escapes {@link SURFACE_FIT_MAX_SCALE}.
17092
- */
17093
- chosen: boolean;
17094
- };
17095
- type UITool = {
17096
- kind: "select";
17097
- } | {
17098
- kind: "pan";
17099
- } | {
17100
- kind: "insert";
17101
- nodeType: string;
17102
- componentId?: string;
17103
- };
17104
- type SnapGuideKind = "surface-edge" | "surface-center" | "element-edge" | "element-center";
17105
- type ActiveSnapGuideSegment = {
17106
- value: number;
17107
- kind: SnapGuideKind;
17108
- };
17109
- type ActiveSnapGuides = {
17110
- surfaceId: string;
17111
- vertical: ActiveSnapGuideSegment[];
17112
- horizontal: ActiveSnapGuideSegment[];
17113
- };
17114
- type SmartSnapDetailSettings = {
17115
- /** Snap selection edges/centers to other elements' center lines. */
17116
- snapElementLayout: boolean;
17117
- /** Snap element edges to other elements' edges. */
17118
- snapElementBorder: boolean;
17119
- /** Snap to canvas (surface) edges and center lines. */
17120
- snapCanvasLayout: boolean;
17121
- };
17122
- declare class UIEditorStateService extends Service<UIEditorStateService> implements IUIEditorStateService {
17123
- private uiStore;
17124
- private documentService;
17125
- private settingsService;
17126
- private readonly events;
17127
- private selection;
17128
- private tool;
17129
- private viewport;
17130
- /** Which interface {@link viewport} currently describes - it is one transform shared by every tab. */
17131
- private viewportSurfaceId;
17132
- /**
17133
- * Set while {@link viewport} is a computed zoom - a fit mode rather than somewhere the author
17134
- * zoomed or panned to by hand. `null` means the transform is theirs and nothing may revise it.
17135
- */
17136
- private viewportFit;
17137
- /** Hand-set transforms, so switching back to an interface returns to the view it was left at. */
17138
- private readonly viewportBySurfaceId;
17139
- /** Fit modes, so switching back to an interface resumes the mode it was left following. */
17140
- private readonly viewportFitBySurfaceId;
17141
- private interactionOverride;
17142
- private selectionUnsubscribe?;
17143
- private enteredState;
17144
- /** Only stores `true` keys; missing id => collapsed. */
17145
- private readonly appearanceBorderSidesExpandedByElementId;
17146
- private appearanceInspectorUiCachePersistTimer;
17147
- /** Presence means the outline branch is collapsed. */
17148
- private readonly outlineCollapsedBranchIds;
17149
- private outlinePanelCollapsed;
17150
- private outlineCollapsePersistTimer;
17151
- private smartSnapEnabled;
17152
- private smartSnapDetail;
17153
- private snapGuides;
17154
- /** Pure view state: screen-ratio preview frame preset id, `null` = off. Never touches the UIDocument. */
17155
- private previewAspectId;
17156
- /** Pure view state: safe-area preview frame device preset id, `null` = off. Never touches the UIDocument. */
17157
- private previewSafeAreaId;
17158
- protected init(ctx: WorkspaceContext, depend: (services: Service[]) => Promise<void>): Promise<void>;
17159
- dispose(_ctx: WorkspaceContext): void;
17160
- getTool(): UITool;
17161
- setTool(tool: UITool): void;
17162
- getViewportTransform(): ViewportTransform;
17163
- /**
17164
- * A hand gesture: a wheel zoom, a pan, or a zoom the author typed. It ends whatever fit mode
17165
- * was running, because from here on the author has said where they want to be looking and a
17166
- * pane resize must not overrule that.
17167
- */
17168
- updateViewport(transform: Partial<ViewportTransform>): ViewportTransform;
17169
- /** Which interface the current transform describes; `null` before any editor tab claimed it. */
17170
- getViewportSurfaceId(): string | null;
17171
- /**
17172
- * The fit mode the viewport is currently following, or `null` once the author has zoomed or
17173
- * panned by hand. Only while it is set may the editor recompute the transform on its own, when
17174
- * the pane resizes or the design size changes.
17175
- */
17176
- getViewportFit(): SurfaceViewportFit | null;
17177
- /**
17178
- * Installs a computed zoom as the viewport for `surfaceId`.
17179
- *
17180
- * Separate from {@link updateViewport} because the two carry opposite intent: this one is a
17181
- * mode being applied, and it stays live across resizes; that one is a place the author chose,
17182
- * and nothing may move it.
17183
- */
17184
- applyFittedViewport(surfaceId: string, transform: ViewportTransform, fit: SurfaceViewportFit): ViewportTransform;
17185
- /**
17186
- * Hands the shared viewport to `surfaceId` when opening or re-showing its tab.
17187
- *
17188
- * One transform serves every surface editor tab, so switching tabs would otherwise show the
17189
- * next interface through the last one's zoom.
17190
- *
17191
- * Returns `null` when this interface was left at a hand-set transform - it has been restored
17192
- * and the caller has nothing to do. Otherwise returns the mode the caller must recompute for
17193
- * the space it has now, which for an interface being opened for the first time is the plain
17194
- * fit nobody asked for.
17195
- */
17196
- adoptSurfaceViewport(surfaceId: string): SurfaceViewportFit | null;
17197
- getSelection(): SelectionState;
17198
- setSelection(selection: SelectionState): void;
17199
- setUIElementSelection(selection: UIElementSelection): void;
17200
- getInteractionOverride(): InteractionOverride | null;
17201
- setInteractionOverride(next: InteractionOverride | null): void;
17202
- getDocument(): UIDocument;
17203
- getSurface(surfaceId: string): UISurface | undefined;
17204
- getEnteredState(): UIEditorEnteredState | null;
17205
- setEnteredState(next: UIEditorEnteredState | null): void;
17206
- getAppearanceBorderSidesExpanded(elementId: string): boolean;
17207
- setAppearanceBorderSidesExpanded(elementId: string, expanded: boolean): void;
17208
- isOutlineBranchCollapsed(elementId: string): boolean;
17209
- setOutlineBranchCollapsed(elementId: string, collapsed: boolean): void;
17210
- getOutlinePanelCollapsed(): boolean;
17211
- setOutlinePanelCollapsed(collapsed: boolean): void;
17212
- getSmartSnapEnabled(): boolean;
17213
- setSmartSnapEnabled(enabled: boolean): void;
17214
- getSmartSnapDetailSettings(): SmartSnapDetailSettings;
17215
- patchSmartSnapDetailSettings(patch: Partial<SmartSnapDetailSettings>): void;
17216
- getPreviewAspectId(): string | null;
17217
- /**
17218
- * Pure view state — persisted in global settings only. Deliberately does NOT go through
17219
- * `UIDocumentService`, so toggling a preview frame never dirties the project, never emits
17220
- * `documentChanged` and never enters the undo stack.
17221
- */
17222
- setPreviewAspectId(aspectId: string | null): void;
17223
- getPreviewSafeAreaId(): string | null;
17224
- /** Pure view state — see `setPreviewAspectId`. */
17225
- setPreviewSafeAreaId(safeAreaId: string | null): void;
17226
- getSnapGuides(): ActiveSnapGuides | null;
17227
- setSnapGuides(guides: ActiveSnapGuides | null): void;
17228
- on<K extends keyof UIEditorStateEvents>(event: K, handler: (data: UIEditorStateEvents[K]) => void): () => void;
17229
- private ensureUIStore;
17230
- private normalizeViewport;
17231
- private persistViewport;
17232
- private scheduleAppearanceInspectorUiCachePersistence;
17233
- private persistAppearanceInspectorUiCachesNow;
17234
- private flushAppearanceInspectorUiCachePersistence;
17235
- private scheduleOutlineCollapsePersistence;
17236
- private persistOutlineCollapsedBranchesNow;
17237
- private flushOutlineCollapsePersistence;
17238
- private areSnapGuidesEqual;
17239
- /**
17240
- * Drops the entered state when the author moves to another interface.
17241
- *
17242
- * Selection is left alone on purpose. A canvas click on a widget's part promotes the selection to
17243
- * the parent it drills from, so exiting on "the selection left the subtree" exits on the very
17244
- * click an author makes to grab what they are editing - the state flickered away under them, and
17245
- * whatever they did next landed somewhere they were not looking.
17246
- */
17247
- private ensureEnteredStateValid;
17248
- private ensureInteractionOverrideValid;
17249
- private areOverridesEqual;
17250
- }
17251
15897
  type LiveUIComponentShell = Omit<UIComponentDefinition, "elements">;
17252
15898
  type LiveUIParts = {
17253
15899
  /** Records of the shared element map. */
@@ -18258,53 +16904,6 @@ interface PropertyEditorSchema<TData = any> {
18258
16904
  /** Whether to show saving indicator */
18259
16905
  showSavingIndicator?: boolean;
18260
16906
  }
18261
- type WidgetRendererProps = {
18262
- element: UIElement;
18263
- surface: UISurface;
18264
- document: UIDocument;
18265
- hostAdapter: UIHostAdapter;
18266
- children?: React$1.ReactNode;
18267
- /** Stable suffix for repeated structural renderers such as list item previews. */
18268
- instanceKey?: string;
18269
- /** Current list item scope when this element renders inside a list-like item template. */
18270
- listItemScope?: UIListItemScope | null;
18271
- /**
18272
- * Structural widgets may render children lazily with an instance scope.
18273
- * `nl.list` uses this to repeat one authored item template without cloning UIDocument elements.
18274
- */
18275
- renderChildren?: (options?: {
18276
- childrenIds?: string[];
18277
- listItemScope?: UIListItemScope | null;
18278
- instanceKey?: string;
18279
- elementOverrides?: Record<string, UIElement>;
18280
- }) => React$1.ReactNode[];
18281
- /**
18282
- * Render another Page surface inside the current element without using an iframe.
18283
- * Runtime hosts may isolate state/lifecycle by frame instance.
18284
- */
18285
- renderSurface?: (options: {
18286
- targetSurfaceId: string | null;
18287
- frameElement: UIElement;
18288
- params?: Record<string, unknown>;
18289
- instanceKey?: string;
18290
- }) => React$1.ReactNode;
18291
- /** Runtime state readers exposed to structural widgets that resolve their own data source. */
18292
- runtimeData?: {
18293
- surfaceState?: {
18294
- get(key: string): unknown;
18295
- };
18296
- globalState?: {
18297
- get(key: string): unknown;
18298
- };
18299
- /** Props the current page was opened with; fixed for the life of the page instance. */
18300
- pageProps?: Readonly<Record<string, unknown>>;
18301
- };
18302
- /**
18303
- * When true, canvas appearance resolves the variant from the inspector cache (editing-area preview).
18304
- * Dev Mode and other hosts omit this so runtime/blueprint variant overrides stay authoritative.
18305
- */
18306
- useAppearanceInspectorPreview?: boolean;
18307
- };
18308
16907
  type UIInspectorData = {
18309
16908
  element: UIElement;
18310
16909
  elements: UIElement[];
@@ -18313,10 +16912,6 @@ type UIInspectorData = {
18313
16912
  /** Set when inspecting a canvas widget; required for Blueprint M2 binding UI. */
18314
16913
  surfaceId?: string;
18315
16914
  };
18316
- type InspectorContext = {
18317
- element: UIElement;
18318
- documentService: UIDocumentService;
18319
- };
18320
16915
  type DockerBarItem = DockerBarButton | DockerBarSelect | DockerBarNumberInput | DockerBarSeparator;
18321
16916
  type DockerBarButton = {
18322
16917
  kind: "button";
@@ -18361,17 +16956,6 @@ type DockerBarSeparator = {
18361
16956
  kind: "separator";
18362
16957
  id: string;
18363
16958
  };
18364
- type DockerBarContext = {
18365
- element: UIElement;
18366
- documentService: UIDocumentService;
18367
- stateService?: UIEditorStateService;
18368
- surfaceId?: string;
18369
- };
18370
- type WidgetContextMenuContext = {
18371
- element: UIElement;
18372
- documentService: UIDocumentService;
18373
- surfaceId: string;
18374
- };
18375
16959
  type FloatingToolbarButton = {
18376
16960
  kind: "button";
18377
16961
  id: string;
@@ -18382,18 +16966,6 @@ type FloatingToolbarButton = {
18382
16966
  onClick: () => void;
18383
16967
  };
18384
16968
  type FloatingToolbarItem = FloatingToolbarButton;
18385
- type FloatingToolbarContext = {
18386
- element: UIElement;
18387
- documentService: UIDocumentService;
18388
- surfaceId: string;
18389
- openSurfaceEditor?: (surfaceId: string) => void;
18390
- };
18391
- type LayoutSizeFieldContext = {
18392
- element: UIElement;
18393
- documentService: UIDocumentService;
18394
- surfaceId?: string;
18395
- primaryId: string;
18396
- };
18397
16969
  type DefaultChildElementContext = {
18398
16970
  element: UIElement;
18399
16971
  generateId: () => string;
@@ -18402,203 +16974,6 @@ type DefaultChildElementResult = {
18402
16974
  elementPatch?: Partial<UIElement>;
18403
16975
  children: UIElement[];
18404
16976
  };
18405
- interface UIWidgetModule {
18406
- /** Unique type identifier (e.g. "nl.container") */
18407
- readonly type: string;
18408
- /**
18409
- * Widget type this module specialises, set by `extendWidgetModule`.
18410
- *
18411
- * Mirrors the entry in `WIDGET_TYPE_PARENTS`, which is the shared table the capability lookups
18412
- * (effect kinds, logic API, appearance backfill) read - `shared` cannot see a renderer module.
18413
- */
18414
- readonly extends?: string;
18415
- /** Shared logic capability schema for editor, runtime, and blueprint tooling. */
18416
- readonly logicApi?: WidgetLogicApi;
18417
- /** Human-readable display name */
18418
- readonly displayName: string;
18419
- /** Icon shown in the docker bar's element palette */
18420
- readonly icon: LucideIcon;
18421
- /**
18422
- * Creates the default partial element when the user inserts this widget.
18423
- * The returned object is merged with system defaults (id, parentId, etc.).
18424
- */
18425
- createDefaultElement(): Partial<UIElement>;
18426
- /**
18427
- * Creates structural child elements that must be present immediately after inserting the widget.
18428
- * The service applies the returned parent patch and child list in the same UIDocument mutation.
18429
- */
18430
- createDefaultChildElements?(context: DefaultChildElementContext): DefaultChildElementResult;
18431
- /**
18432
- * The states this widget can be shown in, when they belong to the widget rather than to an
18433
- * appearance model.
18434
- *
18435
- * A switch is on or off whatever its parts look like, and it carries no appearance of its own, so
18436
- * there are no variants for the state bar to list. Declaring them here puts the bar on the widget
18437
- * itself; entering one broadcasts that variant id to the subtree, which is where the parts that
18438
- * do carry variants pick it up. `id: null` is the state the widget rests in.
18439
- */
18440
- listEditorStates?(element: UIElement): {
18441
- id: string | null;
18442
- name: string;
18443
- }[];
18444
- /**
18445
- * Renders the element on the editor canvas.
18446
- */
18447
- render(props: WidgetRendererProps): React$1.ReactElement | null;
18448
- /**
18449
- * Returns property inspector fields for the properties panel.
18450
- * These fields are appended after the common layout fields.
18451
- * Return `undefined` to show only layout fields.
18452
- */
18453
- createInspector?(context: InspectorContext): PropertyEditorSchema<UIInspectorData> | undefined;
18454
- /**
18455
- * Returns docker bar items shown when this element is selected.
18456
- * Return `undefined` or empty array for no element-specific docker items.
18457
- */
18458
- createDockerBarItems?(context: DockerBarContext): DockerBarItem[];
18459
- /**
18460
- * Returns docker bar items used when multiple elements of this type are selected.
18461
- * The final multi-select docker bar shows only the items whose `id` exists for every selected module.
18462
- */
18463
- createMultiSelectDockerBarItems?(context: DockerBarContext): DockerBarItem[];
18464
- /**
18465
- * Extra context menu items when this element is the sole selection (canvas or outline).
18466
- */
18467
- createContextMenuItems?(context: WidgetContextMenuContext): ContextMenuItemDef[];
18468
- /**
18469
- * Returns icon actions rendered as one floating toolbar above the selected element's transform box.
18470
- * Keep actions concise; all modules share the same group renderer.
18471
- */
18472
- createFloatingToolbarItems?(context: FloatingToolbarContext): FloatingToolbarItem[];
18473
- /**
18474
- * Override the common Width / Height row in the layout inspector.
18475
- * Return `undefined` to use the default row, or `null` to hide the row.
18476
- */
18477
- createLayoutSizeField?(context: LayoutSizeFieldContext): FieldDefinition<UIInspectorData> | null | undefined;
18478
- /**
18479
- * Optional hook to register additional blueprint nodes (via `defineBlueprintNode`) when the module loads.
18480
- * Keep side effects idempotent - the host may call this once per session.
18481
- */
18482
- registerBlueprintNodes?(): void;
18483
- }
18484
- type UIEditorReadOnly = {
18485
- /** Whether every write gesture on this surface is inert right now. */
18486
- readonly active: boolean;
18487
- /** Hover text for the controls this state disables. The workspace passes the freeze reason. */
18488
- readonly reason?: string;
18489
- };
18490
- type UIHost$1 = "app" | "player";
18491
- type UIHostAdapterElementEventOptions = {
18492
- listItemScope?: UIListItemScope | null;
18493
- instanceKey?: string;
18494
- componentId?: UIComponentId;
18495
- /** Resolved values by param id: the instance's own, falling back to the declared default. */
18496
- componentParams?: Record<string, string>;
18497
- eventControl?: BehaviorGraphEventControl;
18498
- allowClosedScopeExecution?: boolean;
18499
- };
18500
- type UIHostAdapterBlueprintRuntime = {
18501
- surfaceId: string;
18502
- /** Instance-specific scope id. Defaults to `surfaceId` for top-level surfaces. */
18503
- runtimeScopeId?: string;
18504
- setSurfaceState: (key: string, value: unknown) => void;
18505
- getSurfaceState: (key: string) => unknown;
18506
- emitDebug: (event: BlueprintDebugEvent) => void;
18507
- getSurfaceTransitionState?: () => {
18508
- isEntering: boolean;
18509
- isExiting: boolean;
18510
- };
18511
- /** Dispatch a widget private event slot (for example `init` or `mouseClick`) on the owner-local blueprint. */
18512
- dispatchElementBlueprintEvent: (elementId: string, eventName: string, payload?: Record<string, unknown>, options?: UIHostAdapterElementEventOptions) => Promise<void>;
18513
- /** Continue the current widget event from this element to its structural parent. */
18514
- continueElementEventBubble?: (elementId: string, eventName: string, payload?: Record<string, unknown>, options?: UIHostAdapterElementEventOptions) => Promise<boolean>;
18515
- /** Dispatch a surface-level event on the current surfaceMain blueprint. */
18516
- dispatchSurfaceBlueprintEvent?: (eventName: string, payload?: Record<string, unknown>) => Promise<void>;
18517
- /**
18518
- * Raise one of this surface's declared input actions on its surfaceMain blueprint.
18519
- *
18520
- * The seam between routing and authoring: routing decides that this click, wheel or key means
18521
- * "advance" on this surface (see `runtime/input/surfaceInputActions`), and this hands that
18522
- * decision to the graph. Named rather than positional because the payload is what the action's
18523
- * head node reads its pins from.
18524
- *
18525
- * It resolves when the action's graphs have run, which is what lets a lane walk stay sequential.
18526
- */
18527
- dispatchSurfaceInputAction?: (payload: UIInputActionEventPayload) => Promise<void>;
18528
- dispatchBroadcastEvent?: (eventName: string, data: unknown, sender?: string) => Promise<void>;
18529
- getBroadcastListenerCount?: (eventName: string) => number;
18530
- /** Invoke a declared blueprint fn (Call Fn node); awaits the fn body and returns its Fn Return values. */
18531
- invokeBlueprintFn?: (input: {
18532
- fnRef: string;
18533
- args: Record<string, unknown>;
18534
- depth: number;
18535
- /** Surface of the calling execution; global callers omit it and only see global fns. */
18536
- callerSurfaceId?: string;
18537
- /** Component definition of the calling execution, when it is running inside one. */
18538
- callerComponentId?: string;
18539
- /** That instance's resolved params, which the fn body runs with. */
18540
- callerComponentParams?: Record<string, string>;
18541
- /** Which drawing the call came from, so the body's widget writes land on it. */
18542
- callerInstanceKey?: string;
18543
- signal?: AbortSignal;
18544
- callerExecutionId?: string;
18545
- }) => Promise<{
18546
- returns: Record<string, unknown>;
18547
- }>;
18548
- frame?: {
18549
- getParam: (key: string) => unknown;
18550
- emit: (eventName: string, data: unknown) => Promise<void> | void;
18551
- };
18552
- /** M3-full: Dev Mode host API (graphs + TS ctx); absent in editor preview. */
18553
- hostApi?: BlueprintHostApiRuntime;
18554
- };
18555
- type UIHostAdapter = {
18556
- host: UIHost$1;
18557
- navigate?: (target: unknown) => Promise<void> | void;
18558
- resolveSlot?: (slotId: string) => {
18559
- mount: (node: React$1.ReactNode) => void;
18560
- } | null;
18561
- gameUiRuntime?: {
18562
- slotId: UIStageSlotId;
18563
- };
18564
- /**
18565
- * M1 latch: which frozen BlueprintHostApiContract generation this adapter targets.
18566
- * Does not imply all capabilities are implemented yet.
18567
- */
18568
- blueprintHostApiVersion?: BlueprintHostApiContractVersion;
18569
- /** M3-min: optional Blueprint runtime surface (Dev Mode). */
18570
- blueprintRuntime?: UIHostAdapterBlueprintRuntime;
18571
- /**
18572
- * Story Action Blueprint runtime surface. Present only while a story-action blueprint graph
18573
- * runs inside a compiled NLR `Script`; resolves scene/saved variable ids to their NLR backing
18574
- * (`Scene.local` / `Storable`). Absent for UI blueprints.
18575
- */
18576
- storyRuntime?: UIHostAdapterStoryRuntime;
18577
- /** Editor preview: use the active workspace service instance for canvas-local interaction overrides. */
18578
- editorStateService?: UIEditorStateService;
18579
- /** Editor preview: use the active document service, including component-editor adapters. */
18580
- editorDocumentService?: UIDocumentService;
18581
- /**
18582
- * Whether the surface this adapter renders is read-only right now (a frozen workspace).
18583
- *
18584
- * The two services above are the only thing a widget renderer needs in order to write the
18585
- * document from inside its own markup, and the interaction layer's gesture table cannot reach
18586
- * those handlers - a widget's `onDoubleClick` is attached by the widget, not by the canvas. So
18587
- * the state travels on the adapter beside them, and {@link resolveInlineTextEditHost} is where
18588
- * the two are read together.
18589
- */
18590
- editorReadOnly?: UIEditorReadOnly;
18591
- };
18592
- type StoryVariableRuntimeAccess = {
18593
- /** Resolve `variableId` to its stored value, or the declared default when unset. */
18594
- get: (variableId: string) => unknown;
18595
- /** Resolve `variableId` and write `value` to the backing store. */
18596
- set: (variableId: string, value: unknown) => void;
18597
- };
18598
- type UIHostAdapterStoryRuntime = {
18599
- sceneVar: StoryVariableRuntimeAccess;
18600
- savedVar: StoryVariableRuntimeAccess;
18601
- };
18602
16977
  type BlueprintPinSemantic = "exec" | "data";
18603
16978
  export type BlueprintNodePinDef = {
18604
16979
  id: string;
@@ -18957,98 +17332,6 @@ interface IUIDocumentService extends IService {
18957
17332
  };
18958
17333
  renameElement(elementId: string, name: string): void;
18959
17334
  }
18960
- type InteractionOverride = {
18961
- kind: "imageCrop";
18962
- surfaceId: string;
18963
- elementId: string;
18964
- source: string;
18965
- } | {
18966
- kind: "textEdit";
18967
- surfaceId: string;
18968
- elementId: string;
18969
- };
18970
- type InteractionOverrideChange = {
18971
- previous: InteractionOverride | null;
18972
- next: InteractionOverride | null;
18973
- };
18974
- type UIEditorEnteredState = {
18975
- surfaceId: string;
18976
- elementId: string;
18977
- variantId: string | null;
18978
- };
18979
- interface UIEditorStateEvents {
18980
- toolChanged: UITool;
18981
- viewportChanged: ViewportTransform;
18982
- selectionChanged: SelectionState;
18983
- interactionOverrideChanged: InteractionOverrideChange;
18984
- /** Editor-only: which element is showing one of its states, and which; drives canvas preview. */
18985
- enteredStateChanged: UIEditorEnteredState | null;
18986
- /** Outline panel expand/collapse memory (persisted); payload unused. */
18987
- outlineExpansionChanged: null;
18988
- /** Outline panel chrome collapsed state (persisted). */
18989
- outlinePanelCollapsedChanged: boolean;
18990
- /** Smart snap / smart guides toggle (persisted in project settings). */
18991
- smartSnapEnabledChanged: boolean;
18992
- /** Per-category snap targets when smart snap is enabled (persisted). */
18993
- smartSnapDetailSettingsChanged: SmartSnapDetailSettings;
18994
- /** Ephemeral snap guide lines in surface space (viewport overlay). */
18995
- snapGuidesChanged: ActiveSnapGuides | null;
18996
- /** Screen-ratio preview frame preset id, `null` = off (pure view state, global settings). */
18997
- previewAspectChanged: string | null;
18998
- /** Safe-area preview frame device preset id, `null` = off (pure view state, global settings). */
18999
- previewSafeAreaChanged: string | null;
19000
- }
19001
- interface IUIEditorStateService extends IService {
19002
- getTool(): UITool;
19003
- setTool(tool: UITool): void;
19004
- getViewportTransform(): ViewportTransform;
19005
- /** A hand gesture (zoom, pan, or a typed zoom); ends the fit mode the interface was following. */
19006
- updateViewport(transform: Partial<ViewportTransform>): ViewportTransform;
19007
- /** Which interface the current transform describes; `null` before any editor tab claimed it. */
19008
- getViewportSurfaceId(): string | null;
19009
- /** The fit mode in force, or `null` once the author moved the view by hand. */
19010
- getViewportFit(): SurfaceViewportFit | null;
19011
- /** Installs a computed zoom for an interface (stays live across resizes, unlike a hand gesture). */
19012
- applyFittedViewport(surfaceId: string, transform: ViewportTransform, fit: SurfaceViewportFit): ViewportTransform;
19013
- /** Restores a hand-set view (`null`), or returns the mode the caller must recompute. */
19014
- adoptSurfaceViewport(surfaceId: string): SurfaceViewportFit | null;
19015
- getSelection(): SelectionState;
19016
- setSelection(selection: SelectionState): void;
19017
- setUIElementSelection(selection: UIElementSelection): void;
19018
- getDocument(): UIDocument;
19019
- getSurface(surfaceId: string): UISurface | undefined;
19020
- /** The state being shown on the canvas right now, or null while every element rests. */
19021
- getEnteredState(): UIEditorEnteredState | null;
19022
- setEnteredState(next: UIEditorEnteredState | null): void;
19023
- /** Whether compact Border panel "sides" row is expanded (per element, persisted with project settings). */
19024
- getAppearanceBorderSidesExpanded(elementId: string): boolean;
19025
- setAppearanceBorderSidesExpanded(elementId: string, expanded: boolean): void;
19026
- /** Outline: branch is collapsed when true (editor-only, project settings). */
19027
- isOutlineBranchCollapsed(elementId: string): boolean;
19028
- setOutlineBranchCollapsed(elementId: string, collapsed: boolean): void;
19029
- /** Outline panel chrome: collapsed when true (editor-only global settings). */
19030
- getOutlinePanelCollapsed(): boolean;
19031
- setOutlinePanelCollapsed(collapsed: boolean): void;
19032
- /** When true, dragging/resizing/inserting snaps to surface and sibling guides (project settings). */
19033
- getSmartSnapEnabled(): boolean;
19034
- setSmartSnapEnabled(enabled: boolean): void;
19035
- /** Which guide categories participate when smart snap is on (persisted). */
19036
- getSmartSnapDetailSettings(): SmartSnapDetailSettings;
19037
- patchSmartSnapDetailSettings(patch: Partial<SmartSnapDetailSettings>): void;
19038
- /**
19039
- * Screen-ratio preview frame preset id (`null` = off). Pure view state: persisted in global
19040
- * settings, never in the UIDocument, so toggling it cannot dirty the project.
19041
- */
19042
- getPreviewAspectId(): string | null;
19043
- setPreviewAspectId(aspectId: string | null): void;
19044
- /** Safe-area preview frame device preset id (`null` = off). Pure view state, see above. */
19045
- getPreviewSafeAreaId(): string | null;
19046
- setPreviewSafeAreaId(safeAreaId: string | null): void;
19047
- /** Active snap guides for the current interaction (null clears overlay). */
19048
- getSnapGuides(): ActiveSnapGuides | null;
19049
- setSnapGuides(guides: ActiveSnapGuides | null): void;
19050
- on<K extends keyof UIEditorStateEvents>(event: K, handler: (data: UIEditorStateEvents[K]) => void): () => void;
19051
- }
19052
17335
  export type StoryPluginActionCreateInput = {
19053
17336
  generateId: () => string;
19054
17337
  initialText?: string;
@@ -19856,6 +18139,49 @@ export type RuntimePluginLocale = {
19856
18139
  export type RuntimePluginMenu = {
19857
18140
  set(spec: GameMenuSpec): Promise<void>;
19858
18141
  };
18142
+ /**
18143
+ * What the engine's image cache is holding, against what it is allowed to hold. All sizes in bytes.
18144
+ *
18145
+ * Restated here rather than re-exported from the engine because a plugin cannot import
18146
+ * `narraleaf-react` - the only module specifiers it can resolve are `narraleaf-studio/*` and React.
18147
+ * The shape is the engine's `ImageCacheStats`; if that grows a field, this is the second place.
18148
+ */
18149
+ export type RuntimePluginImageCacheStats = {
18150
+ /** Sources the cache holds a url for. */
18151
+ entries: number;
18152
+ /**
18153
+ * Bytes of fetched image data the cache is keeping alive.
18154
+ *
18155
+ * **Zero is a real answer, not a missing one.** A host that serves its own assets hands the
18156
+ * player urls instead of bytes, and then the player holds none: what the images cost lives in
18157
+ * the browser's cache, outside anything this can count. A reader that shows this as "memory
18158
+ * used" will report an improvement that did not happen - see {@link entries}, which still
18159
+ * counts, and the decoded figures below, which are the ones with a budget behind them.
18160
+ */
18161
+ blobBytes: number;
18162
+ /** Sources whose decoded bitmap the cache is holding. */
18163
+ decodedEntries: number;
18164
+ /** Estimated size of those bitmaps, at width x height x 4 bytes each. */
18165
+ decodedBytes: number;
18166
+ /** Entries nothing may evict right now: shown by a mounted element, or pinned by the scene. */
18167
+ pinned: number;
18168
+ /** The budgets in force. `Infinity` where the game removed one. */
18169
+ budget: {
18170
+ blobBytes: number;
18171
+ decodedBytes: number;
18172
+ };
18173
+ };
18174
+ /**
18175
+ * `diagnostics` — what the player's caches weigh.
18176
+ *
18177
+ * Every member answers null before a game session exists, which is the ordinary state during
18178
+ * `setup()`. A plugin polls this; there is no change event, because a cache that announced every
18179
+ * eviction would cost more to watch than to run.
18180
+ */
18181
+ export type RuntimePluginDiagnostics = {
18182
+ /** The engine's image cache, or null when no session is live. */
18183
+ imageCache(): RuntimePluginImageCacheStats | null;
18184
+ };
19859
18185
  /** `assets` — turn an asset id from the pack into a URL this shell can load. */
19860
18186
  export type RuntimePluginAssets = {
19861
18187
  url(assetId: string): string;
@@ -19986,6 +18312,8 @@ export type RuntimePluginGame = {
19986
18312
  menu?: RuntimePluginMenu;
19987
18313
  /** Present with `"story.compile"`. */
19988
18314
  story?: RuntimePluginStory;
18315
+ /** Present with `"diagnostics"`. */
18316
+ diagnostics?: RuntimePluginDiagnostics;
19989
18317
  /** Present when `contributes.sidecars` is non-empty. */
19990
18318
  sidecar?: RuntimePluginSidecars;
19991
18319
  /** Present when `contributes.externalLinks` is non-empty. */
@@ -20006,6 +18334,163 @@ export type RuntimePluginDefinition = {
20006
18334
  };
20007
18335
  export declare function defineRuntimePlugin(definition: RuntimePluginDefinition): RuntimePluginDefinition;
20008
18336
  export declare function isRuntimePluginDefinition(value: unknown): value is RuntimePluginDefinition;
18337
+ /**
18338
+ * The interface-editor extension surface a plugin actually gets.
18339
+ *
18340
+ * Studio's own widgets are described by `UIWidgetModule`, whose callbacks are handed the live
18341
+ * `UIDocumentService` and `UIEditorStateService`. Those are `Service` instances, and `getContext()`
18342
+ * on a service is public - so `documentService.getContext().services.get(...)` returns the workspace
18343
+ * service registry, and with it a `FileSystemService` that speaks to the main process under the
18344
+ * window's default privileged facade: recursive read and write over the author's whole project,
18345
+ * authorised as the window rather than as the plugin. That is the same escalation
18346
+ * `pluginWorkspaceGuard` closed on `ActionDefinition.onClick`, reached through the widget door.
18347
+ *
18348
+ * A class instance cannot be made safe by wrapping one method, either: `service.constructor` is the
18349
+ * real class, `Service` extends `Singleton`, and `Singleton.instances` is an ordinary static
18350
+ * property holding every service that has ever been constructed. Anything with that prototype chain
18351
+ * hands over the registry however many members are trapped on the way past.
18352
+ *
18353
+ * So the types below are what a widget is handed instead - plain objects with named methods,
18354
+ * built by `pluginWidgetGuard` and enforced there rather than here. **These declarations state the
18355
+ * contract; they do not impose it.** A plugin ships compiled JavaScript and can cast anything to
18356
+ * anything; the guard is what makes the cast find nothing.
18357
+ *
18358
+ * The surface is derived from what the built-in widgets do, which is the only honest measure of what
18359
+ * a widget needs: read the interface document, write the element's own props, layout, animation,
18360
+ * extra and list-item wiring, group a burst of those into one undo step, and move the selection.
18361
+ * Nothing here reaches outside `uidoc.json`.
18362
+ */
18363
+ /**
18364
+ * Interface-document access for a plugin widget.
18365
+ *
18366
+ * Whole-document reads are deliberate: a structural widget cannot resolve its own parts without
18367
+ * looking them up, which is why the game side hands plugin renderers the document too. The document
18368
+ * is authored content the editor is already drawing, not a host power - and it is one document, not
18369
+ * an index that leads to unrelated resources.
18370
+ *
18371
+ * Writes are element-scoped by signature. They are not restricted to the element being inspected: a
18372
+ * widget with parts edits its parts, exactly as the built-in switch and list do, and there is no
18373
+ * honest way to tell "my part" from "someone else's element" from here.
18374
+ */
18375
+ export type PluginWidgetDocumentApi = {
18376
+ /** The whole interface document, as the editor currently holds it. */
18377
+ getDocument(): UIDocument;
18378
+ /** A fresh element id, for a widget that builds child elements of its own. */
18379
+ generateId(): string;
18380
+ /** One component definition by id, for a widget that draws a linked component instance. */
18381
+ getComponent(componentId: string): UIComponentDefinition | undefined;
18382
+ createElement(parentId: string, type: string, layoutPatch?: Partial<UILayout>): UIElement;
18383
+ updateElementProps(elementId: string, propsPatch: Record<string, unknown>): void;
18384
+ updateElementExtra(elementId: string, extraPatch: Record<string, unknown>): void;
18385
+ updateElementLayout(elementId: string, layoutPatch: Partial<UILayout>, options?: {
18386
+ skipHistory?: boolean;
18387
+ }): void;
18388
+ updateElementAnimation(elementId: string, animation: UIPageAnimationSettings | null, options?: {
18389
+ mergeKey?: string;
18390
+ }): void;
18391
+ /** Collapse everything the callback writes into one undo entry on that surface. */
18392
+ runSurfaceHistoryTransaction(surfaceId: string, action: () => void): void;
18393
+ setListItemStructFields(elementId: string, fields: readonly UIStructField[]): void;
18394
+ setElementListItemFieldBinding(elementId: string, propPath: string, fieldId: string | null): void;
18395
+ ensureElementBlueprintValueBinding(elementId: string, propPath: string, input: {
18396
+ valueType: UIElementValueBindingValueType;
18397
+ displayName?: string;
18398
+ literalValue?: unknown;
18399
+ }): {
18400
+ blueprintId: string;
18401
+ };
18402
+ clearElementBlueprintValueBinding(elementId: string, propPath: string): void;
18403
+ };
18404
+ /**
18405
+ * Editor state a plugin widget's docker bar may read and move.
18406
+ *
18407
+ * Selection only. The interaction overrides (inline text edit, image crop) are not here because the
18408
+ * host honours them in built-in renderers alone - offering a plugin a switch that turns nothing on
18409
+ * would be worse than not having it.
18410
+ */
18411
+ export type PluginWidgetEditorStateApi = {
18412
+ getSelection(): SelectionState;
18413
+ setUIElementSelection(selection: UIElementSelection): void;
18414
+ getEnteredState(): {
18415
+ surfaceId: string;
18416
+ elementId: string;
18417
+ variantId: string | null;
18418
+ } | null;
18419
+ setEnteredState(next: {
18420
+ surfaceId: string;
18421
+ elementId: string;
18422
+ variantId: string | null;
18423
+ } | null): void;
18424
+ };
18425
+ /** What a plugin widget's property fields read and write through. */
18426
+ export type PluginWidgetInspectorData = {
18427
+ element: UIElement;
18428
+ elements: UIElement[];
18429
+ documentService: PluginWidgetDocumentApi;
18430
+ surfaceId?: string;
18431
+ };
18432
+ export type PluginWidgetInspectorContext = {
18433
+ element: UIElement;
18434
+ documentService: PluginWidgetDocumentApi;
18435
+ };
18436
+ export type PluginWidgetDockerBarContext = {
18437
+ element: UIElement;
18438
+ documentService: PluginWidgetDocumentApi;
18439
+ stateService?: PluginWidgetEditorStateApi;
18440
+ surfaceId?: string;
18441
+ };
18442
+ export type PluginWidgetContextMenuContext = {
18443
+ element: UIElement;
18444
+ documentService: PluginWidgetDocumentApi;
18445
+ surfaceId: string;
18446
+ };
18447
+ export type PluginWidgetFloatingToolbarContext = {
18448
+ element: UIElement;
18449
+ documentService: PluginWidgetDocumentApi;
18450
+ surfaceId: string;
18451
+ openSurfaceEditor?: (surfaceId: string) => void;
18452
+ };
18453
+ export type PluginWidgetLayoutSizeFieldContext = {
18454
+ element: UIElement;
18455
+ documentService: PluginWidgetDocumentApi;
18456
+ surfaceId?: string;
18457
+ primaryId: string;
18458
+ };
18459
+ /**
18460
+ * A widget type contributed by a plugin.
18461
+ *
18462
+ * `render` takes the same {@link RuntimeWidgetRendererProps} the game hands a plugin renderer,
18463
+ * rather than the editor's wider props: one render function, drawn the same way in both places, and
18464
+ * no `hostAdapter` on either side. See `create-plugin.md` for the shared-module pattern that relies
18465
+ * on it.
18466
+ *
18467
+ * `registerBlueprintNodes` is absent on purpose. It exists on the built-in module type and the host
18468
+ * only ever calls it for built-ins; a plugin registers nodes through `app.services.blueprintNodes`,
18469
+ * where the execute context is narrowed the same way this is.
18470
+ */
18471
+ export type PluginWidgetModule = {
18472
+ /** Unique type id; must start with the plugin id and be declared in `contributes.widgets`. */
18473
+ readonly type: string;
18474
+ /** Widget type this one specialises. */
18475
+ readonly extends?: string;
18476
+ /** Event and effect capabilities, shared with the blueprint tooling. */
18477
+ readonly logicApi?: WidgetLogicApi;
18478
+ readonly displayName: string;
18479
+ readonly icon: LucideIcon;
18480
+ createDefaultElement(): Partial<UIElement>;
18481
+ createDefaultChildElements?(context: DefaultChildElementContext): DefaultChildElementResult;
18482
+ listEditorStates?(element: UIElement): {
18483
+ id: string | null;
18484
+ name: string;
18485
+ }[];
18486
+ render(props: RuntimeWidgetRendererProps): React$1.ReactElement | null;
18487
+ createInspector?(context: PluginWidgetInspectorContext): PropertyEditorSchema<PluginWidgetInspectorData> | undefined;
18488
+ createDockerBarItems?(context: PluginWidgetDockerBarContext): DockerBarItem[];
18489
+ createMultiSelectDockerBarItems?(context: PluginWidgetDockerBarContext): DockerBarItem[];
18490
+ createContextMenuItems?(context: PluginWidgetContextMenuContext): ContextMenuItemDef[];
18491
+ createFloatingToolbarItems?(context: PluginWidgetFloatingToolbarContext): FloatingToolbarItem[];
18492
+ createLayoutSizeField?(context: PluginWidgetLayoutSizeFieldContext): FieldDefinition<PluginWidgetInspectorData> | null | undefined;
18493
+ };
20009
18494
  /**
20010
18495
  * Caller-defined section (e.g. built-in presets) shown as a collapsible group in the asset list.
20011
18496
  * Workspace filter chips do not apply; only the search box filters `assets` (same rules as project assets).
@@ -20561,6 +19046,20 @@ declare const pluginUi: Readonly<{
20561
19046
  }>;
20562
19047
  }>;
20563
19048
  export type PluginUiKit = typeof pluginUi;
19049
+ /**
19050
+ * What a plugin can learn about a widget type it did not register.
19051
+ *
19052
+ * The registry itself holds host objects, so what comes back is the answer to the question a plugin
19053
+ * can act on - does this type exist, and what is it called - rather than the module behind it.
19054
+ */
19055
+ export type PluginWidgetTypeInfo = {
19056
+ type: string;
19057
+ displayName: string;
19058
+ /** The widget type this one specialises, when it specialises one. */
19059
+ extends?: string;
19060
+ /** The plugin that contributed it, absent for Studio's own widgets. */
19061
+ ownerPluginId?: string;
19062
+ };
20564
19063
  /**
20565
19064
  * A blueprint node as a *plugin* writes it: everything a node declares about itself, with the
20566
19065
  * narrowed execute of `narraleaf-studio/runtime`.
@@ -20812,7 +19311,7 @@ export type PluginAssetsService = {
20812
19311
  revokeObjectUrl(url: string): void;
20813
19312
  };
20814
19313
  /** An active editor locale code (built-in like "en"/"zh", or a plugin-provided locale). */
20815
- type LocaleCode$1 = string;
19314
+ export type LocaleCode = string;
20816
19315
  /**
20817
19316
  * A plugin's own message tables: `locale code -> (message key -> string)`. This
20818
19317
  * is the plugin's private catalog, unrelated to Studio's own translations.
@@ -20832,7 +19331,7 @@ export type PluginMessageBundle = {
20832
19331
  * {@link PluginI18n.onLocaleChange} to re-render on a language switch.
20833
19332
  */
20834
19333
  export type PluginTranslator = {
20835
- readonly locale: LocaleCode$1;
19334
+ readonly locale: LocaleCode;
20836
19335
  t(key: string, params?: Record<string, string | number>): string;
20837
19336
  };
20838
19337
  /**
@@ -20842,14 +19341,14 @@ export type PluginTranslator = {
20842
19341
  */
20843
19342
  export type PluginI18n = {
20844
19343
  /** The editor's active locale code. */
20845
- readonly locale: LocaleCode$1;
19344
+ readonly locale: LocaleCode;
20846
19345
  /**
20847
19346
  * Subscribe to editor-language changes. The listener fires with the new
20848
19347
  * locale code whenever the active editor language changes. Returns a
20849
19348
  * {@link PluginCleanup} (also tracked by the host, so it is reclaimed on
20850
19349
  * unload even if you forget to call it).
20851
19350
  */
20852
- onLocaleChange(listener: (locale: LocaleCode$1) => void): PluginCleanup;
19351
+ onLocaleChange(listener: (locale: LocaleCode) => void): PluginCleanup;
20853
19352
  /** Locale-aware number formatting bound to the editor's active locale. */
20854
19353
  formatNumber(value: number, options?: Intl.NumberFormatOptions): string;
20855
19354
  /** Locale-aware date formatting bound to the editor's active locale. */
@@ -20983,11 +19482,18 @@ export type PluginServices = {
20983
19482
  error(message: string): void;
20984
19483
  };
20985
19484
  };
19485
+ /**
19486
+ * Contribute a widget type to the interface editor; see {@link PluginWidgetModule}.
19487
+ *
19488
+ * `get` and `list` answer with a type's name rather than with its module. A widget module is
19489
+ * the host's own object - Studio's built-ins carry the editor services in their callbacks - and
19490
+ * "which types exist" is the whole of what a plugin can act on.
19491
+ */
20986
19492
  widgets: {
20987
- register(module: UIWidgetModule): PluginCleanup;
20988
- registerMany(modules: UIWidgetModule[]): PluginCleanup;
20989
- get(type: string): UIWidgetModule | undefined;
20990
- list(): UIWidgetModule[];
19493
+ register(module: PluginWidgetModule): PluginCleanup;
19494
+ registerMany(modules: PluginWidgetModule[]): PluginCleanup;
19495
+ get(type: string): PluginWidgetTypeInfo | undefined;
19496
+ list(): PluginWidgetTypeInfo[];
20991
19497
  has(type: string): boolean;
20992
19498
  };
20993
19499
  story: {
@@ -21036,7 +19542,6 @@ export declare function isPluginDefinition(value: unknown): value is PluginDefin
21036
19542
 
21037
19543
  export {
21038
19544
  BehaviorNodeExecuteResult as RuntimeBlueprintNodeResult,
21039
- LocaleCode$1 as LocaleCode,
21040
19545
  SelectOption$1 as SelectOption,
21041
19546
  };
21042
19547