narraleaf-studio 0.8.0 → 0.9.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 +1891 -807
- package/dist/plugin.d.ts +1 -0
- package/dist/runtime.d.ts +16 -0
- package/package.json +50 -50
package/dist/_api.d.ts
CHANGED
|
@@ -22,6 +22,8 @@ declare enum FsRejectErrorCode {
|
|
|
22
22
|
NOT_A_FILE = "NOT_A_FILE",
|
|
23
23
|
NOT_A_DIR = "NOT_A_DIR",
|
|
24
24
|
IO_ERROR = "IO_ERROR",
|
|
25
|
+
/** The volume is full (`ENOSPC`). Its own code because it is the one an author can clear by hand. */
|
|
26
|
+
NO_SPACE = "NO_SPACE",
|
|
25
27
|
IPC_ERROR = "IPC_ERROR",
|
|
26
28
|
INVALID_JSON = "INVALID_JSON",
|
|
27
29
|
UNKNOWN = "UNKNOWN",
|
|
@@ -568,6 +570,14 @@ type StoryActionPayload = {
|
|
|
568
570
|
* reveal, and they are NOT migrated: such a row now declares and the object stays
|
|
569
571
|
* invisible until a `show` row is added. `story/declared-never-shown` reports the ones
|
|
570
572
|
* that never are.
|
|
573
|
+
*
|
|
574
|
+
* **A `show` that carries {@link assetId} is the one-row form**, and it is the exception the
|
|
575
|
+
* two-row rule needed: showing a picture that is not on stage yet otherwise meant going back
|
|
576
|
+
* for a `create` row, while `/show Alice` worked straight away - the same verb with a
|
|
577
|
+
* boundary nothing on screen drew. Such a row creates the image, names it via
|
|
578
|
+
* {@link objectName}, sources it and reveals it. It is not a second operation on purpose:
|
|
579
|
+
* one verb, one row shape, and the object it leaves behind is addressable by every later
|
|
580
|
+
* row exactly as a `create` row's is.
|
|
571
581
|
*/
|
|
572
582
|
action: "image";
|
|
573
583
|
operation: "create" | "setSource" | "show" | "hide";
|
|
@@ -660,6 +670,10 @@ type StoryActionPayload = {
|
|
|
660
670
|
* `create` declares, like the `image` arm's: it compiles to `Video.preload()`, which puts a
|
|
661
671
|
* hidden element on stage so the clip starts buffering, and `show` is what reveals it.
|
|
662
672
|
*
|
|
673
|
+
* A `show` carrying {@link assetId} is the one-row form, on the same terms as the `image`
|
|
674
|
+
* arm's - it builds the clip, names it and reveals it. Revealing is still not playing: the
|
|
675
|
+
* element is on screen holding its first frame, and `/play` is what runs it.
|
|
676
|
+
*
|
|
663
677
|
* Additive: the four transport operations and `timeMs` are new in A3, and no document
|
|
664
678
|
* written before them carries either, so no schema bump.
|
|
665
679
|
*/
|
|
@@ -1660,6 +1674,24 @@ type BlueprintDiagnostic = {
|
|
|
1660
1674
|
/** Source span or module location; M1 opaque */
|
|
1661
1675
|
location?: Record<string, unknown>;
|
|
1662
1676
|
};
|
|
1677
|
+
type BlueprintAssetPinKind = "image" | "audio" | "font";
|
|
1678
|
+
type BlueprintAssetPinRef = {
|
|
1679
|
+
kind: BlueprintAssetPinKind;
|
|
1680
|
+
paramKey?: string;
|
|
1681
|
+
/**
|
|
1682
|
+
* Where the pin's value comes from.
|
|
1683
|
+
*
|
|
1684
|
+
* `"stored"` (the default) means the document holds it: the id sits under `paramKey`, and it is
|
|
1685
|
+
* a reference the reverse-lookup index reads and reports.
|
|
1686
|
+
*
|
|
1687
|
+
* `"published"` means the host resolves it while the game runs, and **the pin provably cannot
|
|
1688
|
+
* carry a library asset id**. Nothing is stored to read, and an edge out of such a pin is not a
|
|
1689
|
+
* reference the index is failing to see - so it must not be reported as one. Marking a pin this
|
|
1690
|
+
* way is a claim about what can flow through it: it needs an argument at the declaration, not a
|
|
1691
|
+
* guess, because a wrong one hides a real reference.
|
|
1692
|
+
*/
|
|
1693
|
+
origin?: "stored" | "published";
|
|
1694
|
+
};
|
|
1663
1695
|
type AudioClipRegion = {
|
|
1664
1696
|
/** Offset from the start of the clip, in milliseconds. Where playback starts. */
|
|
1665
1697
|
inMs?: number;
|
|
@@ -1677,6 +1709,16 @@ type AudioClipRegion = {
|
|
|
1677
1709
|
* degrades to the plain loop the two other markers already describe.
|
|
1678
1710
|
*/
|
|
1679
1711
|
loopStartMs?: number;
|
|
1712
|
+
/**
|
|
1713
|
+
* Playback gain in decibels, never above 0: the engine cannot raise a clip past its own level, so
|
|
1714
|
+
* balancing loudness means bringing the loud clips down. Absent is unity. Folded into a volume
|
|
1715
|
+
* only by {@link clipVolume}.
|
|
1716
|
+
*/
|
|
1717
|
+
gainDb?: number;
|
|
1718
|
+
};
|
|
1719
|
+
type StoredAudioClipRegion = Pick<AudioClipRegion, "inMs" | "outMs" | "loopStartMs">;
|
|
1720
|
+
type StoredAudioGain = {
|
|
1721
|
+
db: number;
|
|
1680
1722
|
};
|
|
1681
1723
|
type BlueprintOpenExternalRequest = {
|
|
1682
1724
|
url: string;
|
|
@@ -1851,6 +1893,25 @@ declare const PluginRuntimeCapability: {
|
|
|
1851
1893
|
* throwing.
|
|
1852
1894
|
*/
|
|
1853
1895
|
readonly Diagnostics: "diagnostics";
|
|
1896
|
+
/**
|
|
1897
|
+
* `app.game.process.memory()` — read how much memory the game's processes hold, as the
|
|
1898
|
+
* operating system counts it.
|
|
1899
|
+
*
|
|
1900
|
+
* Its own capability rather than a member of `diagnostics`, because what it reports is not the
|
|
1901
|
+
* game's: `diagnostics` describes the engine's caches, which are the game's own bookkeeping,
|
|
1902
|
+
* while this is the player's machine - how much of its memory every process of the game is
|
|
1903
|
+
* holding, the main process and the GPU process included. An author who approved the first did
|
|
1904
|
+
* not approve the second, and a plugin that already holds `diagnostics` must not gain this by
|
|
1905
|
+
* an update without being asked again - which is what a capability of its own guarantees.
|
|
1906
|
+
*
|
|
1907
|
+
* Read-only, and numbers only: sizes and what each process is for, never a path, an id or a
|
|
1908
|
+
* command line. Nothing is sent anywhere by the host; what a plugin does with a reading is
|
|
1909
|
+
* visible in the code the author installed.
|
|
1910
|
+
*
|
|
1911
|
+
* Absent where there are no processes to count - the web export - and narrowed in Dev Mode to
|
|
1912
|
+
* the window's own renderer, since everything around it is Studio's.
|
|
1913
|
+
*/
|
|
1914
|
+
readonly ProcessMemory: "process.memory";
|
|
1854
1915
|
};
|
|
1855
1916
|
type PluginRuntimeCapability = typeof PluginRuntimeCapability[keyof typeof PluginRuntimeCapability];
|
|
1856
1917
|
/**
|
|
@@ -2313,6 +2374,58 @@ type GameMenuSpecMenu = {
|
|
|
2313
2374
|
type GameMenuSpec = {
|
|
2314
2375
|
readonly menus: readonly GameMenuSpecMenu[];
|
|
2315
2376
|
};
|
|
2377
|
+
/**
|
|
2378
|
+
* How much memory a running game costs the machine it runs on, process by process.
|
|
2379
|
+
*
|
|
2380
|
+
* Read in the main process from Electron's process metrics (`app.getAppMetrics()`), which is the
|
|
2381
|
+
* operating system's own account: the same working set a task manager shows. Nothing a page can
|
|
2382
|
+
* read gives this. `performance.memory` describes one JavaScript heap, and in Electron it is also
|
|
2383
|
+
* rounded to coarse buckets - the two arms of a measured comparison both read exactly 92.9 MB -
|
|
2384
|
+
* while the memory a visual novel actually spends is mostly outside any heap:
|
|
2385
|
+
* decoded pictures, textures in the GPU process, audio buffers, the main process serving and
|
|
2386
|
+
* decrypting assets. The whole game is several processes, and only the process that owns them can
|
|
2387
|
+
* see all of them.
|
|
2388
|
+
*
|
|
2389
|
+
* `process.memoryUsage()` in the main process was the other candidate and answers a narrower
|
|
2390
|
+
* question - the main process's own heap and buffers - which is the one process a game's pictures
|
|
2391
|
+
* are not in.
|
|
2392
|
+
*
|
|
2393
|
+
* Comments in English per project convention.
|
|
2394
|
+
*/
|
|
2395
|
+
/** What a process is for, in the words a reader of a memory report needs. */
|
|
2396
|
+
type GameProcessKind = "main" | "renderer" | "gpu" | "utility" | "other";
|
|
2397
|
+
type GameProcessMemoryEntry = {
|
|
2398
|
+
kind: GameProcessKind;
|
|
2399
|
+
/**
|
|
2400
|
+
* What the platform calls it, when it says: a utility process names its service ("Network
|
|
2401
|
+
* Service", "Audio Service", a sidecar's own name). Absent for the rest.
|
|
2402
|
+
*/
|
|
2403
|
+
name?: string;
|
|
2404
|
+
/** Whether this is the process the asking page runs in. */
|
|
2405
|
+
current: boolean;
|
|
2406
|
+
/** Memory currently resident in physical RAM, in bytes. */
|
|
2407
|
+
workingSetBytes: number;
|
|
2408
|
+
/** The most this process has ever had resident, in bytes. */
|
|
2409
|
+
peakWorkingSetBytes: number;
|
|
2410
|
+
/** Memory no other process shares, in bytes. Windows reports it; other platforms do not. */
|
|
2411
|
+
privateBytes?: number;
|
|
2412
|
+
};
|
|
2413
|
+
type GameProcessMemoryReading = {
|
|
2414
|
+
/**
|
|
2415
|
+
* What the processes below add up to.
|
|
2416
|
+
*
|
|
2417
|
+
* - `game` - every process the game is made of. A packaged game and a preview.
|
|
2418
|
+
* - `window` - only the process that draws this window. Dev Mode: the window is Studio's, and
|
|
2419
|
+
* the processes around it (Studio's main process, its GPU process, its other windows) are
|
|
2420
|
+
* shared with everything else Studio has open, so counting them would report Studio.
|
|
2421
|
+
*/
|
|
2422
|
+
scope: "game" | "window";
|
|
2423
|
+
processes: GameProcessMemoryEntry[];
|
|
2424
|
+
/** The sum of every process's working set, in bytes. */
|
|
2425
|
+
workingSetBytes: number;
|
|
2426
|
+
/** The sum of every process's private bytes, or null where the platform does not report them. */
|
|
2427
|
+
privateBytes: number | null;
|
|
2428
|
+
};
|
|
2316
2429
|
declare const UI_INPUT_POINTER_GESTURES: readonly [
|
|
2317
2430
|
"click",
|
|
2318
2431
|
"doubleClick",
|
|
@@ -2813,6 +2926,20 @@ declare const en: {
|
|
|
2813
2926
|
readonly error: "Error";
|
|
2814
2927
|
readonly warning: "Warning";
|
|
2815
2928
|
readonly untitled: "Untitled";
|
|
2929
|
+
readonly count: {
|
|
2930
|
+
readonly errors: {
|
|
2931
|
+
readonly one: "{count} error";
|
|
2932
|
+
readonly other: "{count} errors";
|
|
2933
|
+
};
|
|
2934
|
+
readonly warnings: {
|
|
2935
|
+
readonly one: "{count} warning";
|
|
2936
|
+
readonly other: "{count} warnings";
|
|
2937
|
+
};
|
|
2938
|
+
readonly infos: {
|
|
2939
|
+
readonly one: "{count} info";
|
|
2940
|
+
readonly other: "{count} info";
|
|
2941
|
+
};
|
|
2942
|
+
};
|
|
2816
2943
|
};
|
|
2817
2944
|
readonly menu: {
|
|
2818
2945
|
readonly app: {
|
|
@@ -2991,11 +3118,13 @@ declare const en: {
|
|
|
2991
3118
|
};
|
|
2992
3119
|
};
|
|
2993
3120
|
readonly windowIcon: {
|
|
2994
|
-
readonly label: "
|
|
2995
|
-
readonly description: "The icon on
|
|
3121
|
+
readonly label: "App icon";
|
|
3122
|
+
readonly description: "The icon Studio shows on the taskbar and in the notification area. Desktop and Start menu shortcuts keep the installed icon.";
|
|
3123
|
+
readonly descriptionMac: "The icon in the Dock while Studio is running. Finder and Launchpad keep the installed icon.";
|
|
2996
3124
|
readonly options: {
|
|
2997
|
-
readonly default: "NarraLeaf";
|
|
2998
3125
|
readonly narra: "Narra";
|
|
3126
|
+
readonly leafWhite: "Leaf on white";
|
|
3127
|
+
readonly leaf: "Leaf";
|
|
2999
3128
|
};
|
|
3000
3129
|
readonly unsupportedPlatform: "Not available on this operating system.";
|
|
3001
3130
|
};
|
|
@@ -3040,10 +3169,6 @@ declare const en: {
|
|
|
3040
3169
|
readonly monospace: "Monospace";
|
|
3041
3170
|
};
|
|
3042
3171
|
};
|
|
3043
|
-
readonly editorSurfaceOpacity: {
|
|
3044
|
-
readonly label: "Editor surface opacity";
|
|
3045
|
-
readonly description: "Opacity of the surfaces behind story text and inspector fields.";
|
|
3046
|
-
};
|
|
3047
3172
|
readonly maxActiveEditors: {
|
|
3048
3173
|
readonly label: "Maximum active editors";
|
|
3049
3174
|
readonly description: "How many editor tabs stay loaded at once, keeping their scroll position and focus ({min}-{max}). The rest reload when reopened.";
|
|
@@ -3270,6 +3395,8 @@ declare const en: {
|
|
|
3270
3395
|
readonly checking: "Checking\u2026";
|
|
3271
3396
|
readonly done: "Done";
|
|
3272
3397
|
readonly signOut: "Sign out";
|
|
3398
|
+
readonly usedBy: "Used by {projects}";
|
|
3399
|
+
readonly unused: "No project uses this sign-in.";
|
|
3273
3400
|
readonly signIn: "Sign in";
|
|
3274
3401
|
readonly signingIn: "Signing in\u2026";
|
|
3275
3402
|
readonly addressLabel: "Server address";
|
|
@@ -3392,7 +3519,10 @@ declare const en: {
|
|
|
3392
3519
|
readonly apply: "Apply";
|
|
3393
3520
|
readonly exportHint: "Writes the settings to a plain JSON file. The workspace background, the name recorded on commits, recent projects, statistics and window layout stay on this machine.";
|
|
3394
3521
|
readonly exported: "Saved to {path}";
|
|
3395
|
-
readonly imported:
|
|
3522
|
+
readonly imported: {
|
|
3523
|
+
readonly one: "Applied {count} setting.";
|
|
3524
|
+
readonly other: "Applied {count} settings.";
|
|
3525
|
+
};
|
|
3396
3526
|
readonly exportFailed: "The settings could not be saved.";
|
|
3397
3527
|
readonly importFailed: "The file could not be read.";
|
|
3398
3528
|
readonly planSummary: "{change} to change, {same} already the same, {skipped} skipped.";
|
|
@@ -3580,7 +3710,15 @@ declare const en: {
|
|
|
3580
3710
|
readonly openTable: "Open translation table";
|
|
3581
3711
|
readonly progress: "{completed}/{total} translated";
|
|
3582
3712
|
readonly staleCount: "{count} to review";
|
|
3583
|
-
readonly
|
|
3713
|
+
readonly importCounts: "Imported {applied} ({unchanged} unchanged, {unknown} unknown, {skippedEmpty} empty skipped)";
|
|
3714
|
+
readonly translationCount: {
|
|
3715
|
+
readonly one: "{count} translation";
|
|
3716
|
+
readonly other: "{count} translations";
|
|
3717
|
+
};
|
|
3718
|
+
readonly readFailed: "The translations for {name} could not be read.";
|
|
3719
|
+
readonly alreadyAdded: "{name} is already in the language list.";
|
|
3720
|
+
readonly sourceLocked: "{name} is the source language. Remove the other languages first, or set another language as the source language.";
|
|
3721
|
+
readonly languageGone: "This language is no longer in the language list.";
|
|
3584
3722
|
};
|
|
3585
3723
|
readonly settings: {
|
|
3586
3724
|
readonly menu: "Language settings\u2026";
|
|
@@ -3589,6 +3727,9 @@ declare const en: {
|
|
|
3589
3727
|
readonly fallbackLabel: "Fallback language";
|
|
3590
3728
|
readonly fallbackHint: "An entry with no translation here uses this language, then the source language.";
|
|
3591
3729
|
readonly fallbackLoops: "leads back here";
|
|
3730
|
+
readonly fallbackSelf: "A language cannot be its own fallback language.";
|
|
3731
|
+
readonly fallbackGone: "The fallback language is no longer in the language list.";
|
|
3732
|
+
readonly fallbackLoop: "{fallback} leads back to {name}.";
|
|
3592
3733
|
};
|
|
3593
3734
|
readonly exchange: {
|
|
3594
3735
|
readonly exportMenu: "Export translations\u2026";
|
|
@@ -3608,12 +3749,16 @@ declare const en: {
|
|
|
3608
3749
|
readonly scopeAll: "Everything";
|
|
3609
3750
|
readonly scopePending: "Untranslated and to review";
|
|
3610
3751
|
readonly exportAction: "Export";
|
|
3611
|
-
readonly exportDone:
|
|
3752
|
+
readonly exportDone: {
|
|
3753
|
+
readonly one: "Exported {count} line to {path}";
|
|
3754
|
+
readonly other: "Exported {count} lines to {path}";
|
|
3755
|
+
};
|
|
3612
3756
|
readonly exportEmpty: "Nothing to export.";
|
|
3613
|
-
readonly importFailed: "Could not read the file";
|
|
3614
3757
|
readonly importUnsupported: "Studio reads CSV, XLIFF, PO and JSON.";
|
|
3615
|
-
readonly
|
|
3616
|
-
|
|
3758
|
+
readonly importWarnings: {
|
|
3759
|
+
readonly one: "{count} entry was skipped. First: {first}";
|
|
3760
|
+
readonly other: "{count} entries were skipped. First: {first}";
|
|
3761
|
+
};
|
|
3617
3762
|
readonly localeMismatch: "This file is for {declared}. Import it into {name}?";
|
|
3618
3763
|
readonly localeMismatchDetail: "The translations are imported into the selected language regardless of what the file declares.";
|
|
3619
3764
|
};
|
|
@@ -3637,6 +3782,7 @@ declare const en: {
|
|
|
3637
3782
|
readonly keyNamePlaceholder: "Key (menu.start\u2026)";
|
|
3638
3783
|
readonly keySourcePlaceholder: "Source text";
|
|
3639
3784
|
readonly invalidKeyName: "Key names may contain letters, digits, and dots/underscores/hyphens between them.";
|
|
3785
|
+
readonly keyExists: "A key named \u201C{name}\u201D already exists.";
|
|
3640
3786
|
readonly removeKey: "Remove key";
|
|
3641
3787
|
readonly removeKeyConfirm: "Remove {name}?";
|
|
3642
3788
|
readonly removeKeyConfirmDetail: "Existing translations of this key stay in the language files.";
|
|
@@ -3695,11 +3841,25 @@ declare const en: {
|
|
|
3695
3841
|
readonly importAudio: "Import audio\u2026";
|
|
3696
3842
|
readonly exportDone: "Exported to {path}";
|
|
3697
3843
|
readonly pickupEmpty: "No outdated lines to re-record.";
|
|
3698
|
-
readonly
|
|
3844
|
+
readonly importCounts: "Linked {linked} ({unmatched} unmatched, {failed} failed)";
|
|
3845
|
+
readonly takeCount: {
|
|
3846
|
+
readonly one: "{count} take";
|
|
3847
|
+
readonly other: "{count} takes";
|
|
3848
|
+
};
|
|
3699
3849
|
readonly importFailed: "Could not import the audio files";
|
|
3700
3850
|
readonly importScript: "Import recording script\u2026";
|
|
3701
|
-
readonly
|
|
3702
|
-
readonly
|
|
3851
|
+
readonly importScriptCounts: "Applied {applied} ({unchanged} unchanged, {unknown} not voiced)";
|
|
3852
|
+
readonly scriptRowCount: {
|
|
3853
|
+
readonly one: "{count} row";
|
|
3854
|
+
readonly other: "{count} rows";
|
|
3855
|
+
};
|
|
3856
|
+
readonly importScriptSkipped: {
|
|
3857
|
+
readonly one: "{count} row was skipped";
|
|
3858
|
+
readonly other: "{count} rows were skipped";
|
|
3859
|
+
};
|
|
3860
|
+
readonly readFailed: "The voice assignments for {name} could not be read.";
|
|
3861
|
+
readonly alreadyAdded: "{name} is already in the voice language list.";
|
|
3862
|
+
readonly languageGone: "This voice language is no longer in the list.";
|
|
3703
3863
|
readonly namingTitle: "Recording filename pattern";
|
|
3704
3864
|
readonly namingHint: "Tokens: {tokens}. Imported audio is matched to lines by this name.";
|
|
3705
3865
|
readonly namingReset: "Reset to default";
|
|
@@ -3782,7 +3942,7 @@ declare const en: {
|
|
|
3782
3942
|
};
|
|
3783
3943
|
readonly details: {
|
|
3784
3944
|
readonly noStories: "No stories in this project.";
|
|
3785
|
-
readonly storiesRead: "
|
|
3945
|
+
readonly storiesRead: "Story documents read: {count}.";
|
|
3786
3946
|
};
|
|
3787
3947
|
readonly tools: {
|
|
3788
3948
|
readonly title: "Tools";
|
|
@@ -3839,7 +3999,7 @@ declare const en: {
|
|
|
3839
3999
|
readonly scope: {
|
|
3840
4000
|
readonly storyScene: "scene";
|
|
3841
4001
|
readonly storyMotion: "motion";
|
|
3842
|
-
readonly audioLoop: "audio markers";
|
|
4002
|
+
readonly audioLoop: "audio markers and gain";
|
|
3843
4003
|
readonly uiSurface: "interface";
|
|
3844
4004
|
readonly blueprint: "blueprint";
|
|
3845
4005
|
readonly project: "project";
|
|
@@ -3857,6 +4017,7 @@ declare const en: {
|
|
|
3857
4017
|
readonly storySpeakerChange: "speaker change";
|
|
3858
4018
|
readonly storyMotionEdit: "motion edit";
|
|
3859
4019
|
readonly audioMarkers: "marker change";
|
|
4020
|
+
readonly audioGain: "gain change";
|
|
3860
4021
|
readonly surfaceEdit: "interface edit";
|
|
3861
4022
|
readonly blueprintEdit: "blueprint edit";
|
|
3862
4023
|
readonly replaceText: "text replacement";
|
|
@@ -3871,6 +4032,9 @@ declare const en: {
|
|
|
3871
4032
|
readonly destination: "Server";
|
|
3872
4033
|
readonly projectOnServer: "Project name: {name}";
|
|
3873
4034
|
readonly noAccountHere: "This machine has no account on that server.";
|
|
4035
|
+
readonly signInUnused: "This project does not use the sign-in for that server.";
|
|
4036
|
+
readonly useSignIn: "Use the sign-in as {name}\u2026";
|
|
4037
|
+
readonly signOutHint: "Only this project is signed out. Other projects that use this sign-in are not affected.";
|
|
3874
4038
|
readonly manage: "Manage servers\u2026";
|
|
3875
4039
|
readonly notThere: "That server does not hold this project.";
|
|
3876
4040
|
readonly connected: "Connected";
|
|
@@ -3888,6 +4052,7 @@ declare const en: {
|
|
|
3888
4052
|
readonly liveBlockedMerge: "Finish the merge to start or join a live session.";
|
|
3889
4053
|
readonly liveBlockedRecovery: "Live sessions are unavailable in recovery mode.";
|
|
3890
4054
|
readonly liveBlockedSession: "This workspace is already in a live session.";
|
|
4055
|
+
readonly liveBlockedTakenOver: "This project is now open in another NarraLeaf Studio.";
|
|
3891
4056
|
readonly liveHost: "Host";
|
|
3892
4057
|
readonly liveGuest: "Guest";
|
|
3893
4058
|
readonly liveEntering: "Entering";
|
|
@@ -3979,6 +4144,12 @@ declare const en: {
|
|
|
3979
4144
|
readonly projectLockedTitle: "This project is open in another NarraLeaf Studio";
|
|
3980
4145
|
readonly projectLockedHere: "Open on this computer since {time}. Retry once it has been closed there.";
|
|
3981
4146
|
readonly projectLockedElsewhere: "Open on {host} since {time}. Retry once it has been closed there.";
|
|
4147
|
+
readonly projectTakenOverTitle: "This project is now open in another NarraLeaf Studio";
|
|
4148
|
+
readonly projectTakenOverHere: "Open on this computer since {time}. Changes in this window are no longer saved. Retry once it has been closed there.";
|
|
4149
|
+
readonly projectTakenOverElsewhere: "Open on {host} since {time}. Changes in this window are no longer saved. Retry once it has been closed there.";
|
|
4150
|
+
readonly projectDisplacedTitle: "This project was opened in another NarraLeaf Studio";
|
|
4151
|
+
readonly projectDisplacedHere: "Opened on this computer at {time}. Changes in this window are no longer saved. Retry to reopen the project.";
|
|
4152
|
+
readonly projectDisplacedElsewhere: "Opened on {host} at {time}. Changes in this window are no longer saved. Retry to reopen the project.";
|
|
3982
4153
|
readonly openLauncher: "Open launcher";
|
|
3983
4154
|
readonly panelRenderError: "This panel hit a rendering error";
|
|
3984
4155
|
readonly mainEditorRegion: "Main editor";
|
|
@@ -4069,6 +4240,10 @@ declare const en: {
|
|
|
4069
4240
|
readonly blurOff: "Off";
|
|
4070
4241
|
readonly fillMode: "Fill";
|
|
4071
4242
|
readonly anchor: "Position";
|
|
4243
|
+
readonly editorPlate: "Editor background";
|
|
4244
|
+
readonly editorPlateOpacity: "Editor background opacity";
|
|
4245
|
+
readonly sidebarPlate: "Sidebar background";
|
|
4246
|
+
readonly sidebarPlateOpacity: "Sidebar background opacity";
|
|
4072
4247
|
readonly fill: {
|
|
4073
4248
|
readonly cover: "Scale to fill";
|
|
4074
4249
|
readonly contain: "Fit";
|
|
@@ -4123,8 +4298,14 @@ declare const en: {
|
|
|
4123
4298
|
readonly retrySave: "Retry saving now";
|
|
4124
4299
|
readonly resetZoom: "Reset zoom to 100%";
|
|
4125
4300
|
readonly shortcuts: "Keyboard shortcuts";
|
|
4126
|
-
readonly words:
|
|
4127
|
-
|
|
4301
|
+
readonly words: {
|
|
4302
|
+
readonly one: "{count} word";
|
|
4303
|
+
readonly other: "{count} words";
|
|
4304
|
+
};
|
|
4305
|
+
readonly lines: {
|
|
4306
|
+
readonly one: "{count} line";
|
|
4307
|
+
readonly other: "{count} lines";
|
|
4308
|
+
};
|
|
4128
4309
|
readonly noStoryOpen: "No story open";
|
|
4129
4310
|
readonly openDashboard: "Open the project dashboard";
|
|
4130
4311
|
readonly openCurrentScene: "Open the current scene";
|
|
@@ -4147,16 +4328,39 @@ declare const en: {
|
|
|
4147
4328
|
};
|
|
4148
4329
|
};
|
|
4149
4330
|
readonly save: {
|
|
4150
|
-
readonly failedTitle: "Could not save {
|
|
4151
|
-
readonly
|
|
4152
|
-
readonly
|
|
4331
|
+
readonly failedTitle: "Could not save the {name}";
|
|
4332
|
+
readonly failedTitleNamed: "Could not save \u201C{name}\u201D";
|
|
4333
|
+
readonly failedTitleUnnamed: "Could not save a file";
|
|
4334
|
+
readonly failedDetailTransient: "Still retrying in the background.";
|
|
4335
|
+
readonly failedDetailPermanent: "Retrying fails until this is fixed.";
|
|
4336
|
+
readonly failedDetailNotSaved: "The change was not saved.";
|
|
4337
|
+
readonly failedDetailWithReason: "{reason} {retry}";
|
|
4338
|
+
readonly refusedUnreadable: "The {name} could not be read. Changes are not saved.";
|
|
4339
|
+
readonly fileFailed: {
|
|
4340
|
+
readonly plain: "Could not save \u201C{name}\u201D.";
|
|
4341
|
+
readonly withReason: "Could not save \u201C{name}\u201D. {reason}";
|
|
4342
|
+
};
|
|
4343
|
+
readonly storeFailed: {
|
|
4344
|
+
readonly plain: "Could not save the {name}.";
|
|
4345
|
+
readonly withReason: "Could not save the {name}. {reason}";
|
|
4346
|
+
};
|
|
4347
|
+
readonly reason: {
|
|
4348
|
+
readonly permissionDenied: "The file is read-only, or Studio is not allowed to write to it.";
|
|
4349
|
+
readonly folderMissing: "The folder it belongs in no longer exists.";
|
|
4350
|
+
readonly diskFull: "The disk is full.";
|
|
4351
|
+
};
|
|
4153
4352
|
readonly retry: "Retry now";
|
|
4154
4353
|
readonly consoleFailed: "write failed ({code}, attempt {attempt}): {path} \u00B7 {error}";
|
|
4354
|
+
readonly consoleFailedNotRetried: "write failed ({code}), not retried: {path} \u00B7 {error}";
|
|
4155
4355
|
readonly consoleRecovered: "write succeeded: {path}";
|
|
4156
4356
|
readonly flushFailed: "could not flush {label}: {error}";
|
|
4157
|
-
readonly unreadableTitle: "Could not read {
|
|
4357
|
+
readonly unreadableTitle: "Could not read the {name}";
|
|
4158
4358
|
readonly unreadableDetail: "{reason} The file is unchanged. Nothing was written over it.";
|
|
4159
|
-
readonly unreadableDetailQuarantined: "{reason} The file is unchanged
|
|
4359
|
+
readonly unreadableDetailQuarantined: "{reason} The file is unchanged, and a copy of it has been kept.";
|
|
4360
|
+
readonly unreadableReason: {
|
|
4361
|
+
readonly damaged: "The file is damaged or is not in a format Studio can read.";
|
|
4362
|
+
readonly newerVersion: "It was saved by a newer version of NarraLeaf Studio.";
|
|
4363
|
+
};
|
|
4160
4364
|
readonly consoleUnreadable: "read failed ({kind}): {path} \u00B7 {reason}";
|
|
4161
4365
|
readonly consoleQuarantined: "kept a copy of the unreadable file at {path}";
|
|
4162
4366
|
readonly frozenTitle: "Changes are not being saved";
|
|
@@ -4184,9 +4388,68 @@ declare const en: {
|
|
|
4184
4388
|
readonly characters: "characters";
|
|
4185
4389
|
readonly project: "project settings";
|
|
4186
4390
|
readonly assets: "asset library";
|
|
4391
|
+
readonly projectIcon: "project icon";
|
|
4392
|
+
readonly panelLayout: "panel layout";
|
|
4393
|
+
readonly recentColors: "recent colors";
|
|
4394
|
+
readonly pluginData: "plugin data";
|
|
4187
4395
|
readonly openEditors: "the open editor";
|
|
4188
4396
|
};
|
|
4189
4397
|
};
|
|
4398
|
+
readonly import: {
|
|
4399
|
+
readonly failed: "Could not import \u201C{name}\u201D.";
|
|
4400
|
+
readonly withReason: "{headline} {reason}";
|
|
4401
|
+
readonly reason: {
|
|
4402
|
+
readonly missing: "The file no longer exists.";
|
|
4403
|
+
readonly accessDenied: "Studio is not allowed to read the file.";
|
|
4404
|
+
readonly empty: "The file is empty.";
|
|
4405
|
+
readonly noIdColumn: "The file has no unit_id column.";
|
|
4406
|
+
readonly notFormat: "The file is not a readable {format} file.";
|
|
4407
|
+
readonly noRows: "The file has no entries to import.";
|
|
4408
|
+
readonly wrongType: "Files ending in .{ext} cannot be imported here.";
|
|
4409
|
+
readonly cannotDisplay: "NarraLeaf cannot display .{ext} files. Convert the file to {first} or {second} before importing.";
|
|
4410
|
+
readonly cannotPlay: "NarraLeaf cannot play .{ext} files. Convert the file to {first} or {second} before importing.";
|
|
4411
|
+
readonly cannotUse: "NarraLeaf cannot use .{ext} files. Convert the file to {first} or {second} before importing.";
|
|
4412
|
+
readonly mismatch: "The file is named .{ext}, but its contents are {actual}.";
|
|
4413
|
+
readonly copyFailed: "It could not be copied into the project folder.";
|
|
4414
|
+
readonly projectReadOnly: "Studio is not allowed to write to the project folder.";
|
|
4415
|
+
readonly notAFolder: "Models are imported as a folder.";
|
|
4416
|
+
readonly emptyFolder: "The folder is empty.";
|
|
4417
|
+
readonly copyIncomplete: "Not every file in the folder could be copied into the project.";
|
|
4418
|
+
readonly projectNotAccepting: "The project is not accepting changes right now.";
|
|
4419
|
+
};
|
|
4420
|
+
readonly remote: {
|
|
4421
|
+
readonly invalidUrl: "The address is not a valid URL.";
|
|
4422
|
+
readonly unsupportedScheme: "Only http and https addresses can be downloaded.";
|
|
4423
|
+
readonly unreachable: "Studio could not connect to the server.";
|
|
4424
|
+
readonly timeout: "The server did not respond within {seconds} seconds.";
|
|
4425
|
+
readonly notFound: "The server has no file at this address.";
|
|
4426
|
+
readonly accessDenied: "The server does not allow this file to be downloaded.";
|
|
4427
|
+
readonly serverError: "The server reported an error. Try again later.";
|
|
4428
|
+
readonly refused: "The server did not accept the request.";
|
|
4429
|
+
readonly tooLarge: "The file is larger than {limit} MB, the limit for a remote asset.";
|
|
4430
|
+
readonly noContent: "The server returned no content.";
|
|
4431
|
+
readonly bundle: "Models cannot be imported from a URL.";
|
|
4432
|
+
readonly unplayableCodecs: "NarraLeaf cannot play {codecs}. Convert the file and import the converted copy from disk.";
|
|
4433
|
+
readonly unplayableContainer: "NarraLeaf cannot open {container} files. Convert the file and import the converted copy from disk.";
|
|
4434
|
+
readonly unplayableFormat: "NarraLeaf cannot open this file's format. Convert the file and import the converted copy from disk.";
|
|
4435
|
+
readonly unplayableNoStreams: "The file holds no sound or picture that NarraLeaf can play.";
|
|
4436
|
+
readonly webPage: "The address returned a web page instead of a file.";
|
|
4437
|
+
readonly unrecognizedImage: "The address did not return an image in a format NarraLeaf recognizes.";
|
|
4438
|
+
readonly unrecognizedMedia: "The address did not return sound or video in a format NarraLeaf recognizes.";
|
|
4439
|
+
readonly unrecognizedFont: "The address did not return a font in a format NarraLeaf recognizes.";
|
|
4440
|
+
};
|
|
4441
|
+
readonly skipped: {
|
|
4442
|
+
readonly missingId: "An entry has no ID.";
|
|
4443
|
+
readonly missingIdAtRow: "Row {n} has no ID.";
|
|
4444
|
+
readonly missingIdAtEntry: "Entry {n} has no ID.";
|
|
4445
|
+
readonly notEntry: "An entry is not a translation.";
|
|
4446
|
+
readonly notEntryAtEntry: "Entry {n} is not a translation.";
|
|
4447
|
+
readonly unreadableLine: "Line {n} could not be read.";
|
|
4448
|
+
readonly noTake: "A row is for a line that is not voiced. Its note and status were not applied.";
|
|
4449
|
+
readonly noTakeAtRow: "Row {n} is for a line that is not voiced. Its note and status were not applied.";
|
|
4450
|
+
};
|
|
4451
|
+
};
|
|
4452
|
+
readonly fileDialogFailed: "The file dialog could not be opened.";
|
|
4190
4453
|
readonly reload: {
|
|
4191
4454
|
readonly failedTitle: "The project was not fully reloaded";
|
|
4192
4455
|
readonly failedDetail: "These still show their previous contents: {stores}. Reopen the project to read them again.";
|
|
@@ -4268,7 +4531,7 @@ declare const en: {
|
|
|
4268
4531
|
readonly moved: "Moved";
|
|
4269
4532
|
readonly copied: "Copied";
|
|
4270
4533
|
};
|
|
4271
|
-
readonly
|
|
4534
|
+
readonly changeFrom: "from {name}";
|
|
4272
4535
|
readonly changeConflict: "Unresolved conflict";
|
|
4273
4536
|
readonly changesMore: "{count} more not shown";
|
|
4274
4537
|
readonly command: {
|
|
@@ -4278,7 +4541,10 @@ declare const en: {
|
|
|
4278
4541
|
readonly compareChanges: "Compare Changes with the Last Version";
|
|
4279
4542
|
};
|
|
4280
4543
|
readonly filterPlaceholder: "Find a version by name or number";
|
|
4281
|
-
readonly filterNoMatch:
|
|
4544
|
+
readonly filterNoMatch: {
|
|
4545
|
+
readonly one: "No match in the {count} version read so far.";
|
|
4546
|
+
readonly other: "No match in the {count} versions read so far.";
|
|
4547
|
+
};
|
|
4282
4548
|
readonly today: "Today";
|
|
4283
4549
|
readonly yesterday: "Yesterday";
|
|
4284
4550
|
readonly compareBase: {
|
|
@@ -4287,7 +4553,10 @@ declare const en: {
|
|
|
4287
4553
|
readonly current: "Comparing with {version}";
|
|
4288
4554
|
readonly compare: "Compare with {version}";
|
|
4289
4555
|
};
|
|
4290
|
-
readonly showCheckpoints:
|
|
4556
|
+
readonly showCheckpoints: {
|
|
4557
|
+
readonly one: "Show {count} checkpoint";
|
|
4558
|
+
readonly other: "Show {count} checkpoints";
|
|
4559
|
+
};
|
|
4291
4560
|
readonly hideCheckpoints: "Hide checkpoints";
|
|
4292
4561
|
readonly systemMessage: {
|
|
4293
4562
|
readonly unnamed: "Unnamed version";
|
|
@@ -4361,6 +4630,7 @@ declare const en: {
|
|
|
4361
4630
|
readonly nameTaken: "Another project on that server is already called that. Choose a different name.";
|
|
4362
4631
|
readonly alreadyPublished: "This project is already on that server as {name}, and that server gives a project one name.";
|
|
4363
4632
|
readonly unknown: "That server did not record the project.";
|
|
4633
|
+
readonly declined: "This project does not use the sign-in for that server, so the project was not recorded.";
|
|
4364
4634
|
readonly connectedAs: "This project is already on that server as {name}, so it is connected under that name. Use Send to put this machine's versions on top of what is there.";
|
|
4365
4635
|
};
|
|
4366
4636
|
readonly signIn: {
|
|
@@ -4579,6 +4849,10 @@ declare const en: {
|
|
|
4579
4849
|
readonly deleteSceneConfirm: "Delete scene \"{name}\"?";
|
|
4580
4850
|
readonly deleteSceneDetail: "This removes the scene and its blocks. Jumps to it will stop resolving.";
|
|
4581
4851
|
};
|
|
4852
|
+
readonly readFailed: {
|
|
4853
|
+
readonly missing: "This story is no longer in this project.";
|
|
4854
|
+
readonly named: "The story \u201C{name}\u201D could not be read.";
|
|
4855
|
+
};
|
|
4582
4856
|
readonly script: {
|
|
4583
4857
|
readonly exportScene: "Export as Script\u2026";
|
|
4584
4858
|
readonly exportStory: "Export Story as Script\u2026";
|
|
@@ -4755,7 +5029,11 @@ declare const en: {
|
|
|
4755
5029
|
readonly paste: {
|
|
4756
5030
|
readonly title: "Paste as Rows";
|
|
4757
5031
|
readonly action: "Paste";
|
|
4758
|
-
readonly
|
|
5032
|
+
readonly totalCounts: "{dialogue} dialogue \u00B7 {narration} narration \u00B7 {created}";
|
|
5033
|
+
readonly newCharacterCount: {
|
|
5034
|
+
readonly one: "{count} new character";
|
|
5035
|
+
readonly other: "{count} new characters";
|
|
5036
|
+
};
|
|
4759
5037
|
readonly lineCount: {
|
|
4760
5038
|
readonly one: "{count} line";
|
|
4761
5039
|
readonly other: "{count} lines";
|
|
@@ -5423,7 +5701,6 @@ declare const en: {
|
|
|
5423
5701
|
readonly sceneMusicIntroLoop: "Plays {from}s, loops {loop}s to {to}s";
|
|
5424
5702
|
readonly sceneMusicFromIn: "Starts at {from}s";
|
|
5425
5703
|
readonly sceneMusicWholeClip: "Whole clip";
|
|
5426
|
-
readonly backgroundResolveError: "Image asset could not be resolved: {error}";
|
|
5427
5704
|
readonly selectDefaultBackground: "Select Default Background";
|
|
5428
5705
|
readonly tabInvalid: "Story scene editor tab is invalid.";
|
|
5429
5706
|
readonly loadingScene: "Loading story scene\u2026";
|
|
@@ -5467,7 +5744,7 @@ declare const en: {
|
|
|
5467
5744
|
readonly videoSkipped: "Videos are not previewed.";
|
|
5468
5745
|
readonly ambienceSkipped: "Ambience effects are not previewed.";
|
|
5469
5746
|
readonly storyActionSkipped: "Story Action Blueprint effects are not simulated in the preview.";
|
|
5470
|
-
readonly displayableNotFound: "
|
|
5747
|
+
readonly displayableNotFound: "\u201C{target}\u201D is not on stage.";
|
|
5471
5748
|
readonly displayableUnnamed: "(empty)";
|
|
5472
5749
|
readonly persistentAssignmentSkipped: "Persistent-variable assignments are not applied in the preview.";
|
|
5473
5750
|
readonly assignmentUnresolved: "Expression `{expression}` did not resolve; the assignment was skipped in the preview.";
|
|
@@ -5475,10 +5752,142 @@ declare const en: {
|
|
|
5475
5752
|
readonly persistentReadEmpty: "Persistent variables read as empty in the preview.";
|
|
5476
5753
|
readonly sceneVisitUntracked: "Scene visits are not tracked in the preview; `visited({name})` reads as false.";
|
|
5477
5754
|
readonly choicePickUntracked: "Choice picks are not tracked in the preview; `picked({name})` reads as false.";
|
|
5478
|
-
readonly presetNotFoldable: "
|
|
5479
|
-
readonly animationNotFound: "
|
|
5480
|
-
readonly animationIdMissing: "
|
|
5755
|
+
readonly presetNotFoldable: "An entrance cannot apply {preset}; use a separate transform row.";
|
|
5756
|
+
readonly animationNotFound: "The animation this row plays is no longer in this project.";
|
|
5757
|
+
readonly animationIdMissing: "This animation transform names no animation.";
|
|
5758
|
+
};
|
|
5759
|
+
};
|
|
5760
|
+
readonly compile: {
|
|
5761
|
+
readonly asset: {
|
|
5762
|
+
readonly missing: "{owner} refers to an asset that is no longer in this project.";
|
|
5763
|
+
readonly unreadable: "{owner} refers to an asset that could not be read.";
|
|
5764
|
+
readonly unreadableNamed: "{owner} refers to \u201C{asset}\u201D, which could not be read.";
|
|
5765
|
+
readonly notAsset: "{owner} is set to a value that is not an asset.";
|
|
5766
|
+
};
|
|
5767
|
+
readonly owner: {
|
|
5768
|
+
readonly row: "This row";
|
|
5769
|
+
readonly pose: "The pose \u201C{pose}\u201D of \u201C{character}\u201D";
|
|
5770
|
+
readonly layer: "The layer \u201C{layer}\u201D of \u201C{character}\u201D";
|
|
5771
|
+
readonly layerTag: "The \u201C{tag}\u201D image of the layer \u201C{layer}\u201D of \u201C{character}\u201D";
|
|
5772
|
+
readonly avatar: "The dialog avatar of \u201C{character}\u201D";
|
|
5773
|
+
readonly model: "The model of \u201C{character}\u201D";
|
|
5774
|
+
readonly sceneBackground: "The background of the scene \u201C{scene}\u201D";
|
|
5775
|
+
readonly sceneMusic: "The music of the scene \u201C{scene}\u201D";
|
|
5776
|
+
readonly voice: "The {language} voice recording of this line";
|
|
5777
|
+
readonly inlineSound: "The sound effect inside this line";
|
|
5778
|
+
};
|
|
5779
|
+
readonly unnamed: "(unnamed)";
|
|
5780
|
+
readonly unnamedCharacter: "Unnamed character";
|
|
5781
|
+
readonly variable: {
|
|
5782
|
+
readonly persistentCollision: "The persistent variable \u201C{name}\u201D is declared both in the project's variables and by a story row; references to it are ambiguous.";
|
|
5783
|
+
readonly savedCollision: "The saved variable \u201C{name}\u201D is declared both in the project's variables and by a story row; references to it are ambiguous.";
|
|
5784
|
+
readonly sceneMissingInText: "A scene variable shown in this line is no longer declared; it was left out.";
|
|
5785
|
+
readonly savedMissingInText: "A saved variable shown in this line is no longer declared; it was left out.";
|
|
5786
|
+
readonly persistentMissingInText: "A persistent variable shown in this line is no longer declared; it was left out.";
|
|
5787
|
+
readonly sceneMissingAssignment: "The scene variable this row assigns is no longer declared; the assignment was skipped.";
|
|
5788
|
+
readonly savedMissingAssignment: "The saved variable this row assigns is no longer declared; the assignment was skipped.";
|
|
5789
|
+
readonly persistentMissingAssignment: "The persistent variable this row assigns is no longer declared; the assignment was skipped.";
|
|
5790
|
+
readonly sceneMissingCondition: "The scene variable this condition tests is no longer declared; it evaluates false.";
|
|
5791
|
+
readonly savedMissingCondition: "The saved variable this condition tests is no longer declared; it evaluates false.";
|
|
5792
|
+
readonly persistentMissingCondition: "The persistent variable this condition tests is no longer declared; it evaluates false.";
|
|
5793
|
+
readonly persistenceUnavailableInText: "Persistent variables cannot be read here; the value was left out.";
|
|
5794
|
+
readonly persistenceUnavailableAssignment: "Persistent variables cannot be written here; the assignment was skipped.";
|
|
5795
|
+
};
|
|
5796
|
+
readonly expression: {
|
|
5797
|
+
readonly inTextUnresolved: "The value `{expression}` in this line did not resolve; it was left out.";
|
|
5798
|
+
readonly assignmentUnresolved: "Expression `{expression}` did not resolve; the assignment was skipped.";
|
|
5799
|
+
readonly conditionUnresolved: "Condition `{expression}` did not resolve; it evaluates false.";
|
|
5800
|
+
readonly callNeedsBlueprints: "Expression calls `{name}()`, which needs the project's blueprints; the expression was skipped.";
|
|
5801
|
+
};
|
|
5802
|
+
readonly blueprint: {
|
|
5803
|
+
readonly textNeedsBlueprints: "A blueprint value in this line needs the project's blueprints; it was left out.";
|
|
5804
|
+
readonly actionNeedsBlueprints: "This story action blueprint needs the project's blueprints; the row was skipped.";
|
|
5805
|
+
readonly conditionNeedsBlueprints: "This blueprint condition needs the project's blueprints; it evaluates false.";
|
|
5806
|
+
readonly missing: "The story action blueprint of this row is no longer in this project; the row was skipped.";
|
|
5807
|
+
readonly asyncValue: "\u201C{name}\u201D is evaluated where the story cannot wait, so {file} has to return a value rather than a promise.";
|
|
5808
|
+
readonly noDefaultExportSkipped: "{file} has no default export for \u201C{name}\u201D to run; the row was skipped.";
|
|
5809
|
+
readonly noDefaultExportEmpty: "{file} has no default export for \u201C{name}\u201D to run; nothing was evaluated.";
|
|
5810
|
+
};
|
|
5811
|
+
readonly flow: {
|
|
5812
|
+
readonly missingRow: "A row this scene refers to is missing from the story.";
|
|
5813
|
+
readonly pluginInjectionOutsideScene: "A plugin's compile step addressed a row that is not in this scene.";
|
|
5814
|
+
readonly optionOutsideMenu: "This option is not inside a menu.";
|
|
5815
|
+
readonly branchOutsideCondition: "This branch is not inside a condition.";
|
|
5816
|
+
readonly jumpTargetMissing: "The scene this jump goes to is no longer in this story.";
|
|
5817
|
+
readonly jumpTargetEmpty: "This jump names no scene.";
|
|
5818
|
+
readonly previewHoldsAtJump: "The preview stops before this jump instead of leaving the scene.";
|
|
5819
|
+
readonly previewHoldsAtBreak: "The preview stops at this break; a break only acts inside its loop.";
|
|
5820
|
+
readonly menuEmpty: "This menu has no options.";
|
|
5821
|
+
readonly conditionEmpty: "This condition has no branch.";
|
|
5822
|
+
readonly labelUnnamed: "This label has no name.";
|
|
5823
|
+
readonly labelDuplicate: "Label \u201C{name}\u201D is declared more than once in this scene.";
|
|
5824
|
+
readonly gotoEmpty: "This go-to names no label.";
|
|
5825
|
+
readonly gotoMissing: "Label \u201C{name}\u201D is not in this scene.";
|
|
5826
|
+
readonly breakOutsideLoop: "This break is not inside a repeat; there is no loop for it to leave.";
|
|
5827
|
+
readonly repeatUntilUnusable: "This repeat-until has no usable condition; the group was skipped.";
|
|
5828
|
+
readonly sharedSceneVariables: "The scenes \u201C{first}\u201D and \u201C{second}\u201D keep their scene variables under one name, so each overwrites the other's.";
|
|
5829
|
+
readonly sharedSceneVariablesSameName: "The two scenes named \u201C{name}\u201D keep their scene variables under one name, so each overwrites the other's.";
|
|
5830
|
+
};
|
|
5831
|
+
readonly notOnStage: {
|
|
5832
|
+
readonly image: "Image \u201C{name}\u201D is not on stage; an earlier row has to create it.";
|
|
5833
|
+
readonly text: "Text \u201C{name}\u201D is not on stage; an earlier row has to create it.";
|
|
5834
|
+
readonly layer: "Layer \u201C{name}\u201D is not on stage; an earlier row has to create it.";
|
|
5835
|
+
readonly video: "Video \u201C{name}\u201D is not on stage; an earlier row has to create it.";
|
|
5836
|
+
readonly ambience: "Ambience effect \u201C{name}\u201D is not on stage; an earlier row has to create it.";
|
|
5837
|
+
readonly character: "Character \u201C{name}\u201D is not on stage; an earlier row has to bring it on stage.";
|
|
5838
|
+
readonly characterGone: "The character this row acts on is no longer in this project, so it is not on stage.";
|
|
5839
|
+
readonly target: "\u201C{name}\u201D is not on stage.";
|
|
5840
|
+
};
|
|
5841
|
+
readonly character: {
|
|
5842
|
+
readonly missing: "The character of this row is no longer in this project.";
|
|
5843
|
+
readonly noPoses: "\u201C{character}\u201D has no poses, so nothing is drawn.";
|
|
5844
|
+
readonly poseMissing: "The pose this row selects is no longer among the poses of \u201C{character}\u201D.";
|
|
5845
|
+
readonly poseNoImage: "The pose \u201C{pose}\u201D of \u201C{character}\u201D has no image.";
|
|
5846
|
+
readonly noImage: "No image resolves for \u201C{character}\u201D.";
|
|
5847
|
+
readonly singleImage: "\u201C{character}\u201D is on stage as a single image, so its appearance tags cannot change here.";
|
|
5848
|
+
readonly noTagSelected: "This appearance change for \u201C{character}\u201D selects no tag; nothing changes.";
|
|
5849
|
+
readonly noRuntimeMotion: "\u201C{character}\u201D is not drawn by a runtime, so it has no motion to set.";
|
|
5850
|
+
readonly noRuntimeSkin: "\u201C{character}\u201D is not drawn by a runtime, so it has no skin to set.";
|
|
5851
|
+
readonly noRuntimeParams: "\u201C{character}\u201D is not drawn by a runtime, so it has no parameters to set.";
|
|
5852
|
+
readonly puppetNoModel: "\u201C{character}\u201D has no model.";
|
|
5853
|
+
readonly puppetNoRuntime: "\u201C{character}\u201D names no runtime; nothing draws it.";
|
|
5854
|
+
readonly inlineNoCharacter: "An appearance change inside this line names no character; it was skipped.";
|
|
5855
|
+
readonly inlineSingleImage: "An appearance change for \u201C{character}\u201D inside this line was skipped: the character is on stage as a single image, so its appearance tags cannot change.";
|
|
5856
|
+
readonly inlineNotOnStage: "An appearance change for \u201C{character}\u201D inside this line was skipped: the character is not on stage. Show it before this line; a character shown under a custom stage name cannot be changed from inside a line.";
|
|
5857
|
+
};
|
|
5858
|
+
readonly media: {
|
|
5859
|
+
readonly backgroundEmpty: "This background has no image or color.";
|
|
5860
|
+
readonly imageNoSource: "Image \u201C{name}\u201D has no asset or color.";
|
|
5861
|
+
readonly videoNoAsset: "Video \u201C{name}\u201D has no asset.";
|
|
5862
|
+
readonly soundNoAsset: "Sound \u201C{name}\u201D has no asset.";
|
|
5863
|
+
readonly soundNotPlaying: "Sound \u201C{name}\u201D is not playing; an earlier sound row has to start it.";
|
|
5864
|
+
readonly musicNotPlaying: "No background music is set before this row; a BGM row has to run first.";
|
|
5865
|
+
readonly trackConflict: "\u201C{name}\u201D is already playing on the track \u201C{existing}\u201D, so this row's track \u201C{requested}\u201D is ignored. Use a different sound name, or set the track on the row that starts it.";
|
|
5866
|
+
readonly removedTrack: "(removed track)";
|
|
5867
|
+
readonly ambienceClipConflict: "Ambience effect \u201C{name}\u201D already plays a different clip; this row uses the first one.";
|
|
5868
|
+
readonly ambienceNoClip: "Ambience effect \u201C{name}\u201D has no clip.";
|
|
5869
|
+
readonly weatherUnavailable: "Ambience effect \u201C{name}\u201D needs its weather produced, which is not possible here.";
|
|
5870
|
+
readonly weatherFailed: "The weather for ambience effect \u201C{name}\u201D could not be produced.";
|
|
5871
|
+
readonly assetSetWithoutLanguage: "An asset set was resolved without a language; the stage may show the member for another language.";
|
|
5872
|
+
};
|
|
5873
|
+
readonly camera: {
|
|
5874
|
+
readonly noTransform: "This camera row has no transform.";
|
|
5875
|
+
readonly unknownLens: "Camera lens \u201C{preset}\u201D is not a known effect.";
|
|
5876
|
+
readonly unknownLook: "Camera look \u201C{preset}\u201D is not a known grade.";
|
|
5481
5877
|
};
|
|
5878
|
+
readonly transform: {
|
|
5879
|
+
readonly loopNoReveal: "A looping transform cannot carry a clip reveal; the reveal is ignored.";
|
|
5880
|
+
readonly loopNotInterpolable: "A looping transform can only animate channels that interpolate; the rest of this row does not change.";
|
|
5881
|
+
readonly loopEmpty: "This looping transform states nothing to animate.";
|
|
5882
|
+
readonly loopUnsupported: "This engine version cannot play looping transforms. Update narraleaf-react to 0.32.0 or newer.";
|
|
5883
|
+
readonly filterConflict: "This transform sets the CSS filter channel more than once; only one reaches the stage.";
|
|
5884
|
+
readonly maskNoImage: "This mask effect has no image.";
|
|
5885
|
+
readonly maskOnEntrance: "An entrance cannot apply a mask; use a separate transform row.";
|
|
5886
|
+
readonly revealTargetOnly: "{effect} only applies to stage objects.";
|
|
5887
|
+
readonly ruleNoImage: "This rule transition names no rule image; the change was played as a cut.";
|
|
5888
|
+
readonly transitionUnavailable: "Transition \u201C{kind}\u201D is not available; the change was played as a cut. Choose a transition on this row.";
|
|
5889
|
+
};
|
|
5890
|
+
readonly positionalElementNames: "This engine version names stage elements by position, so saves do not survive edits to the story.";
|
|
5482
5891
|
};
|
|
5483
5892
|
readonly blueprintCard: {
|
|
5484
5893
|
readonly openAria: "Open story action blueprint";
|
|
@@ -5563,7 +5972,7 @@ declare const en: {
|
|
|
5563
5972
|
};
|
|
5564
5973
|
readonly show: {
|
|
5565
5974
|
readonly label: "Show";
|
|
5566
|
-
readonly detail: "Show a character
|
|
5975
|
+
readonly detail: "Show a character, a stage object, or an image or video from the asset library";
|
|
5567
5976
|
};
|
|
5568
5977
|
readonly hide: {
|
|
5569
5978
|
readonly label: "Hide";
|
|
@@ -6542,7 +6951,6 @@ declare const en: {
|
|
|
6542
6951
|
readonly change: "Change";
|
|
6543
6952
|
readonly select: "Select";
|
|
6544
6953
|
readonly clearImage: "Clear image";
|
|
6545
|
-
readonly assetError: "Image asset could not be resolved: {error}";
|
|
6546
6954
|
readonly selectImageTitle: "Select Background Image";
|
|
6547
6955
|
};
|
|
6548
6956
|
readonly control: {
|
|
@@ -6616,6 +7024,8 @@ declare const en: {
|
|
|
6616
7024
|
readonly moreReferences: "\u2026and {count} more";
|
|
6617
7025
|
readonly unverifiedTitle: "Cannot check what uses these assets";
|
|
6618
7026
|
readonly unverifiedMessage: "Their usage could not be determined. Delete them anyway?";
|
|
7027
|
+
readonly unverifiedComputed: "These places pick their asset by a name assembled at run time:";
|
|
7028
|
+
readonly unverifiedUnreadable: "These could not be read:";
|
|
6619
7029
|
readonly confirmTitle: {
|
|
6620
7030
|
readonly one: "Delete {count} item?";
|
|
6621
7031
|
readonly other: "Delete {count} items?";
|
|
@@ -6623,7 +7033,6 @@ declare const en: {
|
|
|
6623
7033
|
readonly confirmMessage: "Everything inside a selected group is deleted too.";
|
|
6624
7034
|
readonly action: "Delete";
|
|
6625
7035
|
readonly failedTitle: "Failed to delete";
|
|
6626
|
-
readonly failed: "Could not delete: {error}";
|
|
6627
7036
|
};
|
|
6628
7037
|
readonly rename: {
|
|
6629
7038
|
readonly failed: "Could not rename {name}";
|
|
@@ -6665,7 +7074,20 @@ declare const en: {
|
|
|
6665
7074
|
readonly unreadable: {
|
|
6666
7075
|
readonly category: "This category could not be read. Its file is unchanged.";
|
|
6667
7076
|
readonly notSaved: "Changes are not being saved";
|
|
6668
|
-
readonly notSavedDetail: "{
|
|
7077
|
+
readonly notSavedDetail: "The {category} category could not be read. Nothing is written over it.";
|
|
7078
|
+
};
|
|
7079
|
+
readonly reference: {
|
|
7080
|
+
readonly missing: "This asset is no longer in this project.";
|
|
7081
|
+
readonly unreadable: "This asset could not be read.";
|
|
7082
|
+
readonly unreadableNamed: "\u201C{asset}\u201D could not be read.";
|
|
7083
|
+
readonly notAsset: "This value is not an asset.";
|
|
7084
|
+
readonly withReason: "{headline} {reason}";
|
|
7085
|
+
readonly reason: {
|
|
7086
|
+
readonly fileMissing: "Its file is missing from the project folder.";
|
|
7087
|
+
readonly accessDenied: "Studio is not allowed to read its file.";
|
|
7088
|
+
readonly undecodable: "Its file is damaged or is not in a format Studio can open.";
|
|
7089
|
+
readonly newerVersion: "Its file was saved by a newer version of NarraLeaf Studio.";
|
|
7090
|
+
};
|
|
6669
7091
|
};
|
|
6670
7092
|
readonly overview: {
|
|
6671
7093
|
readonly loading: "Reading the asset library\u2026";
|
|
@@ -6818,7 +7240,10 @@ declare const en: {
|
|
|
6818
7240
|
readonly noneFound: "No {family} models in this folder.";
|
|
6819
7241
|
readonly noneFoundHint: "Check the kind selected above, then the folder. It must be the folder the exporter wrote.";
|
|
6820
7242
|
readonly entry: "Entry";
|
|
6821
|
-
readonly fileSummary:
|
|
7243
|
+
readonly fileSummary: {
|
|
7244
|
+
readonly one: "{count} file \u00B7 {size}";
|
|
7245
|
+
readonly other: "{count} files \u00B7 {size}";
|
|
7246
|
+
};
|
|
6822
7247
|
readonly selectAll: "Select all";
|
|
6823
7248
|
readonly selectNone: "Select none";
|
|
6824
7249
|
readonly importAction: "Import";
|
|
@@ -6867,6 +7292,7 @@ declare const en: {
|
|
|
6867
7292
|
readonly locale: "Language";
|
|
6868
7293
|
readonly release: "Variant";
|
|
6869
7294
|
};
|
|
7295
|
+
readonly deletedVariant: "Deleted variant";
|
|
6870
7296
|
readonly variantCount: {
|
|
6871
7297
|
readonly one: "{count} variant";
|
|
6872
7298
|
readonly other: "{count} variants";
|
|
@@ -6947,9 +7373,19 @@ declare const en: {
|
|
|
6947
7373
|
readonly one: "Exported {count} file.";
|
|
6948
7374
|
readonly other: "Exported {count} files.";
|
|
6949
7375
|
};
|
|
6950
|
-
readonly
|
|
7376
|
+
readonly partialCounts: "Exported {exported}, {failed} could not be exported.";
|
|
7377
|
+
readonly fileCount: {
|
|
7378
|
+
readonly one: "{count} file";
|
|
7379
|
+
readonly other: "{count} files";
|
|
7380
|
+
};
|
|
6951
7381
|
readonly partialTitle: "Some files were not exported";
|
|
6952
7382
|
readonly failed: "Export failed: {error}";
|
|
7383
|
+
readonly reason: {
|
|
7384
|
+
readonly permissionDenied: "Access was denied.";
|
|
7385
|
+
readonly sourceMissing: "The file is missing from the project folder.";
|
|
7386
|
+
readonly diskFull: "The disk is full.";
|
|
7387
|
+
readonly copyFailed: "The file could not be copied.";
|
|
7388
|
+
};
|
|
6953
7389
|
};
|
|
6954
7390
|
readonly selector: {
|
|
6955
7391
|
readonly selectType: "Select {type}";
|
|
@@ -6973,8 +7409,19 @@ declare const en: {
|
|
|
6973
7409
|
readonly categoryMapping: "Tag Category Mapping";
|
|
6974
7410
|
readonly exampleFilename: "Example Filename: {filename}";
|
|
6975
7411
|
readonly categoryPlaceholder: "Tag Category (e.g.: char, emo)";
|
|
6976
|
-
readonly moreFiles:
|
|
6977
|
-
|
|
7412
|
+
readonly moreFiles: {
|
|
7413
|
+
readonly one: "\u2026 and {count} more file";
|
|
7414
|
+
readonly other: "\u2026 and {count} more files";
|
|
7415
|
+
};
|
|
7416
|
+
readonly tagCounts: "Will add a total of {tags} to {files}";
|
|
7417
|
+
readonly tagCount: {
|
|
7418
|
+
readonly one: "{count} tag";
|
|
7419
|
+
readonly other: "{count} tags";
|
|
7420
|
+
};
|
|
7421
|
+
readonly fileCount: {
|
|
7422
|
+
readonly one: "{count} file";
|
|
7423
|
+
readonly other: "{count} files";
|
|
7424
|
+
};
|
|
6978
7425
|
readonly applying: "Applying\u2026";
|
|
6979
7426
|
readonly applyTags: "Apply Tags";
|
|
6980
7427
|
readonly parseFailedTitle: "Magic Tags parsing failed";
|
|
@@ -7006,6 +7453,35 @@ declare const en: {
|
|
|
7006
7453
|
readonly markLoop: "Set loop point at playhead";
|
|
7007
7454
|
readonly markOut: "Set out point at playhead";
|
|
7008
7455
|
readonly channels: "{count} ch";
|
|
7456
|
+
readonly seam: "Loop seam";
|
|
7457
|
+
readonly auditionSeam: "Audition seam";
|
|
7458
|
+
readonly auditionSeamTip: "Plays {seconds} seconds either side of the seam.";
|
|
7459
|
+
readonly clearMarkers: "Clear all markers";
|
|
7460
|
+
readonly gain: "Gain";
|
|
7461
|
+
readonly gainTip: "Lowers this clip's volume in the game. It cannot raise it.";
|
|
7462
|
+
readonly align: "Align loudness";
|
|
7463
|
+
readonly alignTip: "Sets the gain from the measured loudness, so every aligned clip plays at the same level. A clip that is already quieter keeps its level.";
|
|
7464
|
+
readonly seamEnd: {
|
|
7465
|
+
readonly out: "Out point";
|
|
7466
|
+
readonly clipEnd: "End of clip";
|
|
7467
|
+
};
|
|
7468
|
+
readonly seamStart: {
|
|
7469
|
+
readonly loop: "Loop point";
|
|
7470
|
+
readonly in: "In point";
|
|
7471
|
+
readonly clipStart: "Start of clip";
|
|
7472
|
+
};
|
|
7473
|
+
readonly levels: "Levels";
|
|
7474
|
+
readonly peak: "Peak";
|
|
7475
|
+
readonly loudness: "Loudness";
|
|
7476
|
+
readonly leadingSilence: "Leading silence";
|
|
7477
|
+
readonly trailingSilence: "Trailing silence";
|
|
7478
|
+
readonly clipping: "Clipping";
|
|
7479
|
+
readonly clippingNone: "None";
|
|
7480
|
+
readonly clippingCount: {
|
|
7481
|
+
readonly one: "{count} place";
|
|
7482
|
+
readonly other: "{count} places";
|
|
7483
|
+
};
|
|
7484
|
+
readonly seconds: "{value} s";
|
|
7009
7485
|
};
|
|
7010
7486
|
readonly keybindings: {
|
|
7011
7487
|
readonly playPause: "Play or pause";
|
|
@@ -7025,6 +7501,7 @@ declare const en: {
|
|
|
7025
7501
|
readonly clearIn: "Clear in point";
|
|
7026
7502
|
readonly clearLoop: "Clear loop point";
|
|
7027
7503
|
readonly clearOut: "Clear out point";
|
|
7504
|
+
readonly clearMarkers: "Clear all markers";
|
|
7028
7505
|
readonly undo: "Undo marker change";
|
|
7029
7506
|
readonly redo: "Redo marker change";
|
|
7030
7507
|
readonly selectAll: "Select whole clip";
|
|
@@ -7032,6 +7509,40 @@ declare const en: {
|
|
|
7032
7509
|
readonly zoomIn: "Zoom in";
|
|
7033
7510
|
readonly zoomOut: "Zoom out";
|
|
7034
7511
|
readonly zoomFit: "Fit whole clip";
|
|
7512
|
+
readonly auditionSeam: "Audition loop seam";
|
|
7513
|
+
};
|
|
7514
|
+
};
|
|
7515
|
+
readonly video: {
|
|
7516
|
+
readonly loading: "Loading video\u2026";
|
|
7517
|
+
readonly loadError: "Failed to load video";
|
|
7518
|
+
readonly editor: {
|
|
7519
|
+
readonly previousFrame: "Previous frame";
|
|
7520
|
+
readonly nextFrame: "Next frame";
|
|
7521
|
+
readonly speed: "Playback speed";
|
|
7522
|
+
readonly zoom: "Zoom";
|
|
7523
|
+
readonly zoomFit: "Fit";
|
|
7524
|
+
readonly saveFrame: "Save frame as image";
|
|
7525
|
+
readonly frameSaved: "Frame saved as {name}";
|
|
7526
|
+
readonly frameSaveFailed: "The frame could not be saved";
|
|
7527
|
+
readonly open: "Open";
|
|
7528
|
+
readonly frame: "Frame {frame} of {total}";
|
|
7529
|
+
readonly transparent: "Transparent";
|
|
7530
|
+
};
|
|
7531
|
+
readonly keybindings: {
|
|
7532
|
+
readonly playPause: "Play or pause";
|
|
7533
|
+
readonly auditionSeam: "Preview loop seam";
|
|
7534
|
+
readonly toStart: "Go to start";
|
|
7535
|
+
readonly toEnd: "Go to end";
|
|
7536
|
+
readonly previousFrame: "Previous frame";
|
|
7537
|
+
readonly nextFrame: "Next frame";
|
|
7538
|
+
readonly backSecond: "Back one second";
|
|
7539
|
+
readonly forwardSecond: "Forward one second";
|
|
7540
|
+
readonly loop: "Toggle loop";
|
|
7541
|
+
readonly selectAll: "Select whole clip";
|
|
7542
|
+
readonly clearSelection: "Clear selection";
|
|
7543
|
+
readonly zoomIn: "Zoom timeline in";
|
|
7544
|
+
readonly zoomOut: "Zoom timeline out";
|
|
7545
|
+
readonly zoomFit: "Fit whole clip in timeline";
|
|
7035
7546
|
};
|
|
7036
7547
|
};
|
|
7037
7548
|
readonly image: {
|
|
@@ -7240,6 +7751,8 @@ declare const en: {
|
|
|
7240
7751
|
readonly contextListItemHint: " It reads the list row it runs for, and nothing here draws one.";
|
|
7241
7752
|
readonly noRuntime: "Node \"{node}\": no runtime for type \"{type}\".";
|
|
7242
7753
|
readonly inputMissing: "\"{node}\" has nothing connected to \"{pin}\".";
|
|
7754
|
+
readonly stepLimit: "\"{head}\" stopped at \"{node}\" after {steps} steps without a wait.";
|
|
7755
|
+
readonly stepLimitGlobal: "\"{head}\" in the global blueprint stopped at \"{node}\" after {steps} steps without a wait.";
|
|
7243
7756
|
readonly unknownType: "Node \"{node}\": unknown type \"{type}\". Its plugin may be uninstalled or disabled.";
|
|
7244
7757
|
readonly variableIdInvalid: "Node \"{node}\": pick a variable.";
|
|
7245
7758
|
readonly persistentVariableIdInvalid: "Node \"{node}\": pick a persistent variable.";
|
|
@@ -7265,6 +7778,75 @@ declare const en: {
|
|
|
7265
7778
|
readonly missingField: "Missing field \"{id}\".";
|
|
7266
7779
|
};
|
|
7267
7780
|
};
|
|
7781
|
+
readonly runtimeError: {
|
|
7782
|
+
readonly needsHost: "This node runs only in a running game. Open Dev Mode to run it.";
|
|
7783
|
+
readonly needsHostScript: "Scripts run only in a running game. Open Dev Mode to run them.";
|
|
7784
|
+
readonly needsGame: "\u201C{node}\u201D needs a running game.";
|
|
7785
|
+
readonly needsGameAny: "This node needs a running game.";
|
|
7786
|
+
readonly needsSaves: "Saves are not available here.";
|
|
7787
|
+
readonly needsWindow: "The game window is not available here.";
|
|
7788
|
+
readonly needsLayers: "Layers are not available here.";
|
|
7789
|
+
readonly needsStory: "This node runs only inside a story.";
|
|
7790
|
+
readonly needsChoiceRow: "\u201C{node}\u201D runs only inside a choice list row.";
|
|
7791
|
+
readonly needsCloseRequest: "\u201C{node}\u201D runs only below \u201C{head}\u201D.";
|
|
7792
|
+
readonly cannotRunHere: "This node cannot run here.";
|
|
7793
|
+
readonly pickStory: "\u201C{node}\u201D: pick a story.";
|
|
7794
|
+
readonly pickScene: "\u201C{node}\u201D: pick a scene.";
|
|
7795
|
+
readonly pickPage: "\u201C{node}\u201D: pick a page.";
|
|
7796
|
+
readonly pickFunction: "\u201C{node}\u201D: pick a function.";
|
|
7797
|
+
readonly pickTrack: "\u201C{node}\u201D: pick a track.";
|
|
7798
|
+
readonly pickClip: "\u201C{node}\u201D: pick a clip.";
|
|
7799
|
+
readonly pickField: "\u201C{node}\u201D: pick a field.";
|
|
7800
|
+
readonly pickSceneVariable: "This node has no scene variable selected.";
|
|
7801
|
+
readonly pickSavedVariable: "This node has no saved variable selected.";
|
|
7802
|
+
readonly pickPersistentVariable: "This node has no persistent variable selected.";
|
|
7803
|
+
readonly noPage: "No page is selected.";
|
|
7804
|
+
readonly noSave: "This node has no save to act on.";
|
|
7805
|
+
readonly inputEmpty: "\u201C{node}\u201D: \u201C{pin}\u201D is empty.";
|
|
7806
|
+
readonly valueNotNumber: "\u201C{name}\u201D must be a number.";
|
|
7807
|
+
readonly valueNotBoolean: "\u201C{name}\u201D must be a boolean.";
|
|
7808
|
+
readonly valueAbove: "\u201C{name}\u201D must be greater than {min}.";
|
|
7809
|
+
readonly valueAtLeast: "\u201C{name}\u201D must be {min} or greater.";
|
|
7810
|
+
readonly valueNotIndex: "\u201C{name}\u201D must be a whole number, 0 or greater.";
|
|
7811
|
+
readonly voiceEndModeInvalid: "\u201C{name}\u201D must be \u201Cfade\u201D, \u201Cstop\u201D or \u201Cnone\u201D.";
|
|
7812
|
+
readonly preferenceUnknown: "\u201C{key}\u201D is not a game preference.";
|
|
7813
|
+
readonly noLanguages: "This project has no languages configured.";
|
|
7814
|
+
readonly unknownLanguage: "\u201C{language}\u201D is not one of this project's languages.";
|
|
7815
|
+
readonly noVoiceLanguages: "This project has no voice languages configured.";
|
|
7816
|
+
readonly unknownVoiceLanguage: "\u201C{language}\u201D is not one of this project's voice languages.";
|
|
7817
|
+
readonly noElement: "This node has no element to act on.";
|
|
7818
|
+
readonly elementWrongKind: "This node acts only on widgets of type {kind}.";
|
|
7819
|
+
readonly elementUnsupported: "This node cannot act on this kind of widget.";
|
|
7820
|
+
readonly elementOutOfScope: "This node can only act on elements of its own page or component.";
|
|
7821
|
+
readonly elementNotFound: "The element was not found on this page.";
|
|
7822
|
+
readonly widgetWrongKind: "\u201C{element}\u201D is not a widget of type {kind}.";
|
|
7823
|
+
readonly unnamedWidget: "Unnamed widget";
|
|
7824
|
+
readonly noVariants: "\u201C{element}\u201D has no variants.";
|
|
7825
|
+
readonly unknownVariant: "\u201C{element}\u201D has no such variant.";
|
|
7826
|
+
readonly pageNotFound: "The page was not found in this project.";
|
|
7827
|
+
readonly notALayer: "\u201C{node}\u201D: this page is not a layer, so nothing was closed.";
|
|
7828
|
+
readonly persistentVariableMissing: "The persistent variable this node uses no longer exists.";
|
|
7829
|
+
readonly persistentVariableNoKey: "The persistent variable \u201C{name}\u201D has no storage key.";
|
|
7830
|
+
readonly slotIsRunningGame: "This node needs a save in storage. The slot it received is the running game, which only \u201C{node}\u201D can inherit from.";
|
|
7831
|
+
readonly saveNotStored: "The save named by \u201C{pin}\u201D is not in storage.";
|
|
7832
|
+
readonly captureNotHeld: "\u201C{pin}\u201D names a captured game this run does not hold. Run \u201C{capture}\u201D in the same chain as \u201C{start}\u201D.";
|
|
7833
|
+
readonly captureRepeated: "\u201C{node}\u201D has already captured this run several times. Capture it once, not once per loop.";
|
|
7834
|
+
readonly noGameToCapture: "\u201C{node}\u201D: there is no running game to capture.";
|
|
7835
|
+
readonly responseGone: "\u201C{node}\u201D: the response is no longer available. A response can only be read by the run that fetched it.";
|
|
7836
|
+
readonly pureOnExecPath: "This node only produces values and cannot run in sequence.";
|
|
7837
|
+
readonly nodeMissing: "The blueprint refers to a node that no longer exists.";
|
|
7838
|
+
readonly nodeTypeMissing: "This node is not available. Its plugin may be uninstalled or disabled.";
|
|
7839
|
+
readonly stepLimitSync: "This blueprint stopped after {steps} steps without finishing.";
|
|
7840
|
+
readonly asyncInSyncGraph: "A node that waits cannot run here.";
|
|
7841
|
+
readonly valueNodeUnavailable: "A node in this Blueprint Value is not available. Its plugin may be uninstalled or disabled.";
|
|
7842
|
+
readonly valueNodeNotAllowed: "This Blueprint Value contains a node that is not allowed in a Blueprint Value.";
|
|
7843
|
+
readonly fnDepth: "Function calls went deeper than {depth} levels and were stopped.";
|
|
7844
|
+
readonly fnMissing: "The function this node calls no longer exists.";
|
|
7845
|
+
readonly fnOutOfScope: "The function \u201C{name}\u201D is not available in this scope.";
|
|
7846
|
+
readonly scriptLoadFailed: "\u201C{file}\u201D could not be loaded: {detail}";
|
|
7847
|
+
readonly scriptExportsUncalled: "\u201C{file}\u201D exports {exported}, none of which this layer calls. Handlers it calls: {names}.";
|
|
7848
|
+
readonly scriptExportsNoHandler: "\u201C{file}\u201D exports no handler this layer calls. Handlers it calls: {names}.";
|
|
7849
|
+
};
|
|
7268
7850
|
readonly variableScope: {
|
|
7269
7851
|
readonly page: "Page";
|
|
7270
7852
|
readonly blueprint: "Blueprint";
|
|
@@ -8641,9 +9223,16 @@ declare const en: {
|
|
|
8641
9223
|
readonly title: "Import PSD";
|
|
8642
9224
|
readonly choose: "Choose a PSD\u2026";
|
|
8643
9225
|
readonly canvas: "Document size";
|
|
8644
|
-
readonly
|
|
9226
|
+
readonly costCounts: "{layers} \u00B7 ~{megabytes} MB";
|
|
9227
|
+
readonly layerCount: {
|
|
9228
|
+
readonly one: "{count} layer";
|
|
9229
|
+
readonly other: "{count} layers";
|
|
9230
|
+
};
|
|
8645
9231
|
readonly mapping: "Layers";
|
|
8646
|
-
readonly axis:
|
|
9232
|
+
readonly axis: {
|
|
9233
|
+
readonly one: "axis, {count} tag";
|
|
9234
|
+
readonly other: "axis, {count} tags";
|
|
9235
|
+
};
|
|
8647
9236
|
readonly blends: "Blend modes the engine cannot reproduce";
|
|
8648
9237
|
readonly merge: "Merge down";
|
|
8649
9238
|
readonly skip: "Skip";
|
|
@@ -8657,6 +9246,7 @@ declare const en: {
|
|
|
8657
9246
|
readonly import: "Import";
|
|
8658
9247
|
readonly importing: "Importing\u2026";
|
|
8659
9248
|
readonly failed: "Import failed";
|
|
9249
|
+
readonly readFailed: "This PSD could not be read.";
|
|
8660
9250
|
readonly reason: {
|
|
8661
9251
|
readonly hidden: "hidden in Photoshop";
|
|
8662
9252
|
readonly blendSkipped: "skipped";
|
|
@@ -8867,7 +9457,6 @@ declare const en: {
|
|
|
8867
9457
|
readonly projectDefault: "Project default font";
|
|
8868
9458
|
readonly projectSection: "Project";
|
|
8869
9459
|
readonly choose: "Choose font";
|
|
8870
|
-
readonly loadError: "The font could not be loaded ({error}). The preview uses a fallback until the asset is valid.";
|
|
8871
9460
|
readonly select: "Select Font";
|
|
8872
9461
|
};
|
|
8873
9462
|
readonly imageFill: {
|
|
@@ -8882,7 +9471,6 @@ declare const en: {
|
|
|
8882
9471
|
readonly selectHint: "Asset browser opens on click";
|
|
8883
9472
|
readonly changeImage: "Change image";
|
|
8884
9473
|
readonly openEditor: "Click to open editor";
|
|
8885
|
-
readonly resolveError: "The image asset could not be resolved ({error}). The preview is inaccurate until it exists.";
|
|
8886
9474
|
readonly selectFillImage: "Select Fill Image";
|
|
8887
9475
|
readonly mode: {
|
|
8888
9476
|
readonly cover: "Cover";
|
|
@@ -8907,6 +9495,7 @@ declare const en: {
|
|
|
8907
9495
|
readonly none: "Not referenced anywhere";
|
|
8908
9496
|
readonly unknown: "Usage could not be determined";
|
|
8909
9497
|
readonly unknownDetail: "{location} could not be read";
|
|
9498
|
+
readonly unknownComputed: "{location} picks its asset by a name assembled at run time";
|
|
8910
9499
|
readonly count: {
|
|
8911
9500
|
readonly one: "{count} reference";
|
|
8912
9501
|
readonly other: "{count} references";
|
|
@@ -8920,6 +9509,7 @@ declare const en: {
|
|
|
8920
9509
|
readonly character: "Character";
|
|
8921
9510
|
readonly voice: "Voice";
|
|
8922
9511
|
readonly design: "Design";
|
|
9512
|
+
readonly plugin: "Plugin";
|
|
8923
9513
|
};
|
|
8924
9514
|
};
|
|
8925
9515
|
readonly tags: {
|
|
@@ -8939,6 +9529,7 @@ declare const en: {
|
|
|
8939
9529
|
readonly loadAsset: "Failed to load asset";
|
|
8940
9530
|
readonly deleteFailed: "Failed to delete thumbnail";
|
|
8941
9531
|
readonly saveFailed: "Failed to save thumbnail";
|
|
9532
|
+
readonly saveFailedWithReason: "Failed to save thumbnail. {reason}";
|
|
8942
9533
|
readonly unknown: "Unknown error";
|
|
8943
9534
|
};
|
|
8944
9535
|
};
|
|
@@ -9449,7 +10040,10 @@ declare const en: {
|
|
|
9449
10040
|
readonly one: "{count} linked instance will show as missing until unlinked or replaced.";
|
|
9450
10041
|
readonly other: "{count} linked instances will show as missing until unlinked or replaced.";
|
|
9451
10042
|
};
|
|
9452
|
-
readonly refs:
|
|
10043
|
+
readonly refs: {
|
|
10044
|
+
readonly one: "{count} ref";
|
|
10045
|
+
readonly other: "{count} refs";
|
|
10046
|
+
};
|
|
9453
10047
|
};
|
|
9454
10048
|
readonly canvas: {
|
|
9455
10049
|
readonly unknownWidget: "Unknown widget";
|
|
@@ -9815,6 +10409,7 @@ declare const en: {
|
|
|
9815
10409
|
readonly missingPage: "Missing Page";
|
|
9816
10410
|
readonly targetNotPage: "Target is not a Page";
|
|
9817
10411
|
readonly pageLoopBlocked: "Page loop blocked";
|
|
10412
|
+
readonly leadsBackHere: "leads back here";
|
|
9818
10413
|
readonly previewUnavailable: "Page preview unavailable";
|
|
9819
10414
|
readonly pageRootMissing: "Page root missing";
|
|
9820
10415
|
};
|
|
@@ -10438,6 +11033,13 @@ declare const en: {
|
|
|
10438
11033
|
readonly storyDescription: "Story scene preview diagnostics and warnings";
|
|
10439
11034
|
readonly storageDescription: "Project file writes: failed saves, retries, and recoveries";
|
|
10440
11035
|
};
|
|
11036
|
+
readonly sources: {
|
|
11037
|
+
readonly blueprintLog: "Blueprint Log";
|
|
11038
|
+
};
|
|
11039
|
+
readonly devModeStatus: {
|
|
11040
|
+
readonly idle: "Stopped";
|
|
11041
|
+
readonly error: "Stopped on an error";
|
|
11042
|
+
};
|
|
10441
11043
|
};
|
|
10442
11044
|
readonly project: {
|
|
10443
11045
|
readonly nav: {
|
|
@@ -10518,6 +11120,10 @@ declare const en: {
|
|
|
10518
11120
|
readonly live: "The project's own settings are read-only during a live session. What is still editable here is what the session carries.";
|
|
10519
11121
|
readonly frozen: "The project's own settings are read-only while the project is frozen.";
|
|
10520
11122
|
};
|
|
11123
|
+
readonly writeFailed: {
|
|
11124
|
+
readonly plain: "Could not save the project file.";
|
|
11125
|
+
readonly withReason: "Could not save the project file. {reason}";
|
|
11126
|
+
};
|
|
10521
11127
|
readonly details: {
|
|
10522
11128
|
readonly nameLabel: "Application Name";
|
|
10523
11129
|
readonly namePlaceholder: "Application name";
|
|
@@ -10631,6 +11237,10 @@ declare const en: {
|
|
|
10631
11237
|
readonly clearBackground: "Keep transparency";
|
|
10632
11238
|
readonly transparent: "None";
|
|
10633
11239
|
readonly icnsPreview: "ICNS preview";
|
|
11240
|
+
readonly pickFailed: "The file picker could not be opened.";
|
|
11241
|
+
readonly unsupported: "\u201C{name}\u201D cannot be used as an icon.";
|
|
11242
|
+
readonly readFailed: "\u201C{name}\u201D could not be read.";
|
|
11243
|
+
readonly failed: "Could not update the icons.";
|
|
10634
11244
|
readonly target: {
|
|
10635
11245
|
readonly macos: "macOS";
|
|
10636
11246
|
readonly windows: "Windows";
|
|
@@ -10908,8 +11518,34 @@ declare const en: {
|
|
|
10908
11518
|
readonly scanning: "Scanning project\u2026";
|
|
10909
11519
|
readonly empty: "No plugin dependencies.";
|
|
10910
11520
|
readonly banner: {
|
|
10911
|
-
readonly
|
|
10912
|
-
|
|
11521
|
+
readonly missing: {
|
|
11522
|
+
readonly one: "A plugin this project uses is not installed. Install it from the plugins panel.";
|
|
11523
|
+
readonly other: "{count} plugins this project uses are not installed. Install them from the plugins panel.";
|
|
11524
|
+
};
|
|
11525
|
+
readonly held: {
|
|
11526
|
+
readonly one: "A plugin is off for this project. Its installed version is incompatible with the one this project was authored against. Click Rescan to use the installed version.";
|
|
11527
|
+
readonly other: "{count} plugins are off for this project. Their installed versions are incompatible with the ones this project was authored against. Click Rescan to use the installed versions.";
|
|
11528
|
+
};
|
|
11529
|
+
readonly needsAuthorization: {
|
|
11530
|
+
readonly one: "A plugin this project uses needs authorization. Authorize it in the plugins panel.";
|
|
11531
|
+
readonly other: "{count} plugins this project uses need authorization. Authorize them in the plugins panel.";
|
|
11532
|
+
};
|
|
11533
|
+
readonly disabled: {
|
|
11534
|
+
readonly one: "A plugin this project uses is disabled. Enable it in the plugins panel.";
|
|
11535
|
+
readonly other: "{count} plugins this project uses are disabled. Enable them in the plugins panel.";
|
|
11536
|
+
};
|
|
11537
|
+
readonly failed: {
|
|
11538
|
+
readonly one: "A plugin this project uses failed to load. The plugins panel shows the error.";
|
|
11539
|
+
readonly other: "{count} plugins this project uses failed to load. The plugins panel shows the errors.";
|
|
11540
|
+
};
|
|
11541
|
+
readonly outdated: {
|
|
11542
|
+
readonly one: "A plugin is older than the version this project was authored against.";
|
|
11543
|
+
readonly other: "{count} plugins are older than the versions this project was authored against.";
|
|
11544
|
+
};
|
|
11545
|
+
readonly incompatible: {
|
|
11546
|
+
readonly one: "A plugin is installed at a version incompatible with the one this project was authored against.";
|
|
11547
|
+
readonly other: "{count} plugins are installed at versions incompatible with the ones this project was authored against.";
|
|
11548
|
+
};
|
|
10913
11549
|
};
|
|
10914
11550
|
readonly status: {
|
|
10915
11551
|
readonly ready: "Ready";
|
|
@@ -10922,7 +11558,6 @@ declare const en: {
|
|
|
10922
11558
|
readonly meta: {
|
|
10923
11559
|
readonly requires: "Requires {version}";
|
|
10924
11560
|
readonly installed: "Installed {version}";
|
|
10925
|
-
readonly notInstalled: "not installed";
|
|
10926
11561
|
readonly builtIn: "Built-in";
|
|
10927
11562
|
readonly dataOnly: "data only";
|
|
10928
11563
|
};
|
|
@@ -11071,6 +11706,7 @@ declare const en: {
|
|
|
11071
11706
|
readonly ownerLabel: "Owner";
|
|
11072
11707
|
readonly contributorsLabel: "Contributors";
|
|
11073
11708
|
readonly visitWebsite: "Visit website";
|
|
11709
|
+
readonly openSourceLicenses: "Open source licenses";
|
|
11074
11710
|
};
|
|
11075
11711
|
readonly actions: {
|
|
11076
11712
|
readonly devMode: {
|
|
@@ -11146,7 +11782,17 @@ declare const en: {
|
|
|
11146
11782
|
};
|
|
11147
11783
|
readonly export: {
|
|
11148
11784
|
readonly chooseFolder: "Choose a folder for the exported project package.";
|
|
11149
|
-
readonly failed: "
|
|
11785
|
+
readonly failed: "Could not export the project.";
|
|
11786
|
+
readonly failedWithReason: "{headline} {reason}";
|
|
11787
|
+
readonly reason: {
|
|
11788
|
+
readonly folderProtected: "The chosen folder is inside Studio's own storage. Choose another folder.";
|
|
11789
|
+
readonly folderReadOnly: "Studio is not allowed to write to the chosen folder.";
|
|
11790
|
+
readonly folderMissing: "The chosen folder no longer exists.";
|
|
11791
|
+
readonly diskFull: "The disk is full.";
|
|
11792
|
+
readonly projectUnreadable: "Studio is not allowed to read some of the project's files.";
|
|
11793
|
+
readonly projectFileBusy: "A file in the project is in use by another program.";
|
|
11794
|
+
readonly projectChanged: "A file in the project was moved or deleted during the export. Export again.";
|
|
11795
|
+
};
|
|
11150
11796
|
readonly success: {
|
|
11151
11797
|
readonly one: "Exported project package with {count} file.";
|
|
11152
11798
|
readonly other: "Exported project package with {count} files.";
|
|
@@ -11285,6 +11931,14 @@ declare const en: {
|
|
|
11285
11931
|
readonly generic: "The file could not be unpacked.";
|
|
11286
11932
|
readonly notAProjectTitle: "This is not a NarraLeaf Studio project";
|
|
11287
11933
|
readonly notAProject: "Unpacking finished, but the result holds no Studio project file. The unpacked contents are in {path}";
|
|
11934
|
+
readonly notAPackage: "The file is not a NarraLeaf Studio project package.";
|
|
11935
|
+
readonly newerVersion: "The package was made by a newer version of NarraLeaf Studio. Update Studio to import it.";
|
|
11936
|
+
readonly damaged: "The package is damaged or incomplete.";
|
|
11937
|
+
readonly packageMissing: "The package file no longer exists.";
|
|
11938
|
+
readonly packageUnreadable: "Studio is not allowed to read the package file.";
|
|
11939
|
+
readonly folderProtected: "The chosen folder is inside Studio's own storage. Choose another folder.";
|
|
11940
|
+
readonly diskFull: "The disk is full.";
|
|
11941
|
+
readonly leftBehind: "Part of the unpacked contents could not be removed from the folder. Empty the folder before trying again.";
|
|
11288
11942
|
};
|
|
11289
11943
|
};
|
|
11290
11944
|
readonly source: {
|
|
@@ -11348,21 +12002,26 @@ declare const en: {
|
|
|
11348
12002
|
readonly openInStudioFailed: "No workspace window is open for this project.";
|
|
11349
12003
|
readonly issues: {
|
|
11350
12004
|
readonly title: "Issues";
|
|
11351
|
-
readonly empty: "Nothing has failed";
|
|
12005
|
+
readonly empty: "Nothing has failed in this run";
|
|
11352
12006
|
readonly sessionFailure: "Session failed to start";
|
|
11353
12007
|
readonly atLine: "Line {line} \u00B7 {scene}";
|
|
11354
12008
|
readonly inScene: "In {scene}";
|
|
11355
12009
|
readonly onSurface: "On {surface}";
|
|
12010
|
+
readonly onSurfaceGone: "On a page no longer in this project";
|
|
11356
12011
|
readonly onPlugin: "Plugin {plugin}";
|
|
11357
12012
|
readonly pluginNotDeclared: "{plugin} is installed but not among this project's plugin dependencies. It does not run in this session and is not included in a build. Rescan them in Project \u25B8 App.";
|
|
11358
12013
|
readonly pluginUnusable: "{plugin} is among this project's plugin dependencies and cannot be loaded. It does not run in this session and is not included in a build. Check its status in Project \u25B8 App.";
|
|
11359
12014
|
readonly pluginEntryFailed: "{plugin} failed to load: {error}. Its blueprint nodes and widgets are not registered in this session.";
|
|
11360
12015
|
readonly pluginListFailed: "The runtime plugin list could not be read: {error}. No plugin runs in this session.";
|
|
12016
|
+
readonly assetMissing: "\u201C{property}\u201D on \u201C{element}\u201D refers to an asset that is no longer in this project.";
|
|
12017
|
+
readonly assetUnreadable: "\u201C{property}\u201D on \u201C{element}\u201D refers to an asset that could not be read.";
|
|
12018
|
+
readonly assetUnreadableNamed: "\u201C{property}\u201D on \u201C{element}\u201D refers to \u201C{asset}\u201D, which could not be read.";
|
|
12019
|
+
readonly assetNotAsset: "\u201C{property}\u201D on \u201C{element}\u201D is set to a value that is not an asset.";
|
|
11361
12020
|
readonly noLocation: "Could not be traced to a line";
|
|
11362
12021
|
readonly viaPlayHead: "where playback was";
|
|
11363
12022
|
readonly stack: "Stack";
|
|
11364
12023
|
readonly dismissAll: "Dismiss all ({count})";
|
|
11365
|
-
readonly
|
|
12024
|
+
readonly counts: "{errors} \u00B7 {warnings} in this run";
|
|
11366
12025
|
};
|
|
11367
12026
|
readonly devtools: {
|
|
11368
12027
|
readonly title: "Interface";
|
|
@@ -11589,6 +12248,7 @@ declare const en: {
|
|
|
11589
12248
|
readonly node: "Runs the plugin's own code as part of the game";
|
|
11590
12249
|
};
|
|
11591
12250
|
readonly buildDependencyHosts: "Downloads from {hosts}";
|
|
12251
|
+
readonly studioApi: "Studio API: {capability}";
|
|
11592
12252
|
readonly runtimeCapability: {
|
|
11593
12253
|
readonly store: "Store its own data alongside the player's saves";
|
|
11594
12254
|
readonly events: "Observe game progress (scenes, dialogue, choices, saves)";
|
|
@@ -11602,6 +12262,7 @@ declare const en: {
|
|
|
11602
12262
|
readonly menu: "Provide the game's menu bar";
|
|
11603
12263
|
readonly storyCompile: "Take part in compiling stories, and add actions to lines it did not write";
|
|
11604
12264
|
readonly diagnostics: "Read how much memory the game\u2019s caches are using";
|
|
12265
|
+
readonly processMemory: "Read how much of the computer\u2019s memory the game is using";
|
|
11605
12266
|
};
|
|
11606
12267
|
};
|
|
11607
12268
|
readonly button: {
|
|
@@ -11634,7 +12295,7 @@ declare const en: {
|
|
|
11634
12295
|
readonly projectTrust: {
|
|
11635
12296
|
readonly window: "Project Trust";
|
|
11636
12297
|
readonly title: "Trust this project?";
|
|
11637
|
-
readonly untrusted: "Studio did not create this project. Until it is trusted, it can be edited but not run, previewed, built or
|
|
12298
|
+
readonly untrusted: "Studio did not create this project. Until it is trusted, it can be edited but not run, previewed, built, tested or synced with its server.";
|
|
11638
12299
|
readonly meaning: "Once trusted, the code this project ships runs on this machine.";
|
|
11639
12300
|
readonly later: "This can be changed under Trusted projects in Settings.";
|
|
11640
12301
|
readonly confirm: "Trust";
|
|
@@ -11643,6 +12304,19 @@ declare const en: {
|
|
|
11643
12304
|
readonly load: "The project details could not be read.";
|
|
11644
12305
|
};
|
|
11645
12306
|
};
|
|
12307
|
+
readonly serverSession: {
|
|
12308
|
+
readonly window: "Server Sign-in";
|
|
12309
|
+
readonly title: "Use this sign-in for this project?";
|
|
12310
|
+
readonly signedInAs: "Signed in as {name}";
|
|
12311
|
+
readonly unused: "This project has not used this sign-in before.";
|
|
12312
|
+
readonly meaning: "Versions from this project are sent and received as {name}.";
|
|
12313
|
+
readonly later: "This can be changed under NarraLeaf Team in the project.";
|
|
12314
|
+
readonly confirm: "Use sign-in";
|
|
12315
|
+
readonly cancel: "Don't use";
|
|
12316
|
+
readonly error: {
|
|
12317
|
+
readonly load: "The sign-in details could not be read.";
|
|
12318
|
+
};
|
|
12319
|
+
};
|
|
11646
12320
|
readonly plugins: {
|
|
11647
12321
|
readonly installLocal: "Install from folder";
|
|
11648
12322
|
readonly search: {
|
|
@@ -11703,6 +12377,8 @@ declare const en: {
|
|
|
11703
12377
|
readonly uninstalled: "Plugin uninstalled.";
|
|
11704
12378
|
readonly reloading: "Reloading plugin\u2026";
|
|
11705
12379
|
readonly reloaded: "Plugin reloaded.";
|
|
12380
|
+
readonly starting: "Starting plugin\u2026";
|
|
12381
|
+
readonly started: "Plugin started.";
|
|
11706
12382
|
};
|
|
11707
12383
|
readonly error: {
|
|
11708
12384
|
readonly load: "Failed to load plugins";
|
|
@@ -11726,6 +12402,7 @@ declare const en: {
|
|
|
11726
12402
|
readonly authorized: "Authorized";
|
|
11727
12403
|
readonly notInRegistry: "Not in the registry";
|
|
11728
12404
|
readonly noCompatibleVersion: "No compatible version";
|
|
12405
|
+
readonly rescanInProject: "Click Rescan in Project \u25B8 App to use the installed version.";
|
|
11729
12406
|
readonly task: {
|
|
11730
12407
|
readonly running: "Installing dependencies\u2026";
|
|
11731
12408
|
readonly done: "Dependencies installed.";
|
|
@@ -11740,7 +12417,7 @@ declare const en: {
|
|
|
11740
12417
|
readonly runtimeOnly: "Game runtime only";
|
|
11741
12418
|
readonly runtimeOnlyHint: "This plugin only extends the running game. It contributes nothing to the editor.";
|
|
11742
12419
|
readonly suppressed: "Off for this project";
|
|
11743
|
-
readonly suppressedHint: "The installed version is incompatible with the one this project was authored against.
|
|
12420
|
+
readonly suppressedHint: "The installed version is incompatible with the one this project was authored against. Click Rescan in Project \u25B8 App to use the installed version.";
|
|
11744
12421
|
readonly failed: "Failed to load";
|
|
11745
12422
|
};
|
|
11746
12423
|
readonly pendingReopen: "Takes effect the next time this project opens.";
|
|
@@ -12179,7 +12856,6 @@ declare const en: {
|
|
|
12179
12856
|
readonly "build-dependency-unavailable": string;
|
|
12180
12857
|
readonly "sidecar-target-missing": "{plugin} ships no {sidecar} program for {platform}, so anything it provides is missing from that build.";
|
|
12181
12858
|
readonly "sidecar-crossbuild-exec-bit": string;
|
|
12182
|
-
readonly "encryption-key-unavailable": "Asset protection is on, but its key could not be read.";
|
|
12183
12859
|
readonly "web-unprotected": "Asset protection does not apply to the web export; its files ship unprotected.";
|
|
12184
12860
|
readonly "mobile-unprotected": "Asset protection does not apply to Android or iOS packages.";
|
|
12185
12861
|
readonly "progress-carry-unsupported": string;
|
|
@@ -12293,10 +12969,30 @@ declare const en: {
|
|
|
12293
12969
|
};
|
|
12294
12970
|
readonly contentDropped: "{scene} in {story} is not in this build.";
|
|
12295
12971
|
readonly contentCoverageGap: "{location} could not be read, so what the {variant} build leaves out cannot be decided.";
|
|
12296
|
-
readonly contentComputedPinGap: "{location} receives its asset from a computed value, so this build cannot tell which asset it needs.";
|
|
12297
12972
|
readonly contentComputedPinSummary: {
|
|
12298
|
-
readonly one: "Build stopped: {count}
|
|
12299
|
-
readonly other: "Build stopped: {count}
|
|
12973
|
+
readonly one: "Build stopped: {count} asset name is assembled at run time. See the console.";
|
|
12974
|
+
readonly other: "Build stopped: {count} asset names are assembled at run time. See the console.";
|
|
12975
|
+
};
|
|
12976
|
+
readonly contentUnloadedNodeSummary: {
|
|
12977
|
+
readonly one: "Build stopped: {count} asset name comes from a node type that is not loaded. See the console.";
|
|
12978
|
+
readonly other: "Build stopped: {count} asset names come from node types that are not loaded. See the console.";
|
|
12979
|
+
};
|
|
12980
|
+
readonly scriptsNotCompiled: {
|
|
12981
|
+
readonly one: "{count} script could not be compiled.";
|
|
12982
|
+
readonly other: "{count} scripts could not be compiled.";
|
|
12983
|
+
};
|
|
12984
|
+
readonly assetSet: {
|
|
12985
|
+
readonly inCharacters: "a character";
|
|
12986
|
+
readonly inInterface: "the interface";
|
|
12987
|
+
readonly inBlueprint: "a blueprint";
|
|
12988
|
+
readonly language: "the language {name}";
|
|
12989
|
+
readonly variant: "the variant {name}";
|
|
12990
|
+
readonly unfilled: "Asset set {set}, used in {location}, has no file for {value}.";
|
|
12991
|
+
readonly noLanguage: "Asset set {set}, used in {location}, has no file for the project's language.";
|
|
12992
|
+
readonly ambiguous: "Asset set {set}, used in {location}, has more than one file for {value}.";
|
|
12993
|
+
readonly nested: "Asset set {set}, used in {location}, has a set under one of its values. A build does not resolve nested sets.";
|
|
12994
|
+
readonly noValues: "Asset set {set}, used in {location}, declares no variants.";
|
|
12995
|
+
readonly variantUnset: "Asset set {set}, used in {location}, varies by variant, and {variant} does not say which art it uses. Choose it under Project \u25B8 App \u25B8 Build variants.";
|
|
12300
12996
|
};
|
|
12301
12997
|
readonly contentCoverageWholeProject: "The project";
|
|
12302
12998
|
readonly contentCoverageSummary: {
|
|
@@ -12418,7 +13114,10 @@ declare const en: {
|
|
|
12418
13114
|
readonly empty: "No builds recorded";
|
|
12419
13115
|
readonly emptyHint: "Builds run for this project are listed here.";
|
|
12420
13116
|
readonly logEmpty: "This build recorded no output.";
|
|
12421
|
-
readonly logOmitted:
|
|
13117
|
+
readonly logOmitted: {
|
|
13118
|
+
readonly one: "The first {count} line was dropped to keep the record small.";
|
|
13119
|
+
readonly other: "The first {count} lines were dropped to keep the record small.";
|
|
13120
|
+
};
|
|
12422
13121
|
};
|
|
12423
13122
|
readonly structure: {
|
|
12424
13123
|
readonly title: "Structure";
|
|
@@ -12666,6 +13365,14 @@ declare const en: {
|
|
|
12666
13365
|
readonly description: "A node whose type the project cannot load";
|
|
12667
13366
|
readonly message: "{type} is not loaded, so this node will not run in the game";
|
|
12668
13367
|
};
|
|
13368
|
+
readonly blueprintAssembledAssetName: {
|
|
13369
|
+
readonly title: "Asset name assembled at run time";
|
|
13370
|
+
readonly description: "An asset is chosen by a name the game puts together while it runs, and the game package does not carry it";
|
|
13371
|
+
readonly message: "\"{pin}\" on \"{node}\" receives an asset name assembled at run time (from \"{origin}\"). A game package carries only the assets whose names are written in the project, so nothing will be there in the released game. Choose the asset in the asset picker, or read one already chosen from a list row or a variable";
|
|
13372
|
+
readonly messageBinding: "\"{prop}\" on \"{element}\" is bound to an asset name assembled at run time (from \"{origin}\"). A game package carries only the assets whose names are written in the project, so nothing will be there in the released game. Choose the asset in the asset picker, or read one already chosen from a list row or a variable";
|
|
13373
|
+
readonly messageUnloadedNode: "\"{pin}\" on \"{node}\" receives an asset name from {origin}, which is not loaded, so the asset it names will not be in the released game. Install or switch on the plugin that provides this node type, then build again";
|
|
13374
|
+
readonly messageUnloadedNodeBinding: "\"{prop}\" on \"{element}\" is bound to an asset name from {origin}, which is not loaded, so the asset it names will not be in the released game. Install or switch on the plugin that provides this node type, then build again";
|
|
13375
|
+
};
|
|
12669
13376
|
readonly uiUnlocalizedText: {
|
|
12670
13377
|
readonly title: "Unlocalized text";
|
|
12671
13378
|
readonly description: "Text written straight onto a widget in a project that has a second language";
|
|
@@ -12696,6 +13403,11 @@ declare const en: {
|
|
|
12696
13403
|
readonly description: "A Page widget embedding a page the project does not have";
|
|
12697
13404
|
readonly message: "This Page widget embeds a page the project does not have";
|
|
12698
13405
|
};
|
|
13406
|
+
readonly uiFrameLoop: {
|
|
13407
|
+
readonly title: "Circular embedded page";
|
|
13408
|
+
readonly description: "A Page widget embedding a page that leads back to it";
|
|
13409
|
+
readonly message: "This Page widget embeds a page that leads back to it";
|
|
13410
|
+
};
|
|
12699
13411
|
readonly uiListItemFieldMissing: {
|
|
12700
13412
|
readonly title: "Missing item field";
|
|
12701
13413
|
readonly description: "A widget bound to an item field the list drawing it does not declare";
|
|
@@ -12744,7 +13456,11 @@ declare const en: {
|
|
|
12744
13456
|
readonly variablesReadNeverWritten: {
|
|
12745
13457
|
readonly title: "Condition nothing can change";
|
|
12746
13458
|
readonly description: "A variable a condition tests, that nothing in the project ever assigns";
|
|
12747
|
-
readonly message: "{variable} is tested by {
|
|
13459
|
+
readonly message: "{variable} is tested by {conditions} but nothing ever sets it";
|
|
13460
|
+
readonly conditionCount: {
|
|
13461
|
+
readonly one: "{count} condition";
|
|
13462
|
+
readonly other: "{count} conditions";
|
|
13463
|
+
};
|
|
12748
13464
|
};
|
|
12749
13465
|
readonly variablesRandomOutsideAssignment: {
|
|
12750
13466
|
readonly title: "Random outside an assignment";
|
|
@@ -12781,7 +13497,11 @@ declare const en: {
|
|
|
12781
13497
|
readonly localizationOrphan: {
|
|
12782
13498
|
readonly title: "Orphan translation";
|
|
12783
13499
|
readonly description: "A translation whose line no longer exists";
|
|
12784
|
-
readonly message: "{
|
|
13500
|
+
readonly message: "{translations} with no line";
|
|
13501
|
+
readonly translationCount: {
|
|
13502
|
+
readonly one: "{count} {locale} translation";
|
|
13503
|
+
readonly other: "{count} {locale} translations";
|
|
13504
|
+
};
|
|
12785
13505
|
};
|
|
12786
13506
|
readonly voiceMissing: {
|
|
12787
13507
|
readonly title: "Missing voice";
|
|
@@ -12796,7 +13516,11 @@ declare const en: {
|
|
|
12796
13516
|
readonly voiceOrphan: {
|
|
12797
13517
|
readonly title: "Orphan voice";
|
|
12798
13518
|
readonly description: "A recording whose line no longer exists";
|
|
12799
|
-
readonly message: "{
|
|
13519
|
+
readonly message: "{recordings} with no line";
|
|
13520
|
+
readonly recordingCount: {
|
|
13521
|
+
readonly one: "{count} {locale} recording";
|
|
13522
|
+
readonly other: "{count} {locale} recordings";
|
|
13523
|
+
};
|
|
12800
13524
|
};
|
|
12801
13525
|
readonly brandBrokenLink: {
|
|
12802
13526
|
readonly title: "Broken color link";
|
|
@@ -12808,10 +13532,18 @@ declare const en: {
|
|
|
12808
13532
|
readonly typographyGlyphCoverage: {
|
|
12809
13533
|
readonly title: "Missing glyphs";
|
|
12810
13534
|
readonly description: "Text using characters no font of the project can draw";
|
|
12811
|
-
readonly message: "No project font can draw \u201C{character}\u201D ({
|
|
12812
|
-
readonly
|
|
12813
|
-
|
|
12814
|
-
|
|
13535
|
+
readonly message: "No project font can draw \u201C{character}\u201D ({occurrences})";
|
|
13536
|
+
readonly occurrenceCount: {
|
|
13537
|
+
readonly one: "{count} time";
|
|
13538
|
+
readonly other: "{count} times";
|
|
13539
|
+
};
|
|
13540
|
+
readonly messageInLanguage: "No project font can draw \u201C{character}\u201D in {language} ({occurrences})";
|
|
13541
|
+
readonly messageMore: "{characters} no project font can draw";
|
|
13542
|
+
readonly moreCharacterCount: {
|
|
13543
|
+
readonly one: "{count} more character";
|
|
13544
|
+
readonly other: "{count} more characters";
|
|
13545
|
+
};
|
|
13546
|
+
readonly messageMoreInLanguage: "{characters} no project font can draw in {language}";
|
|
12815
13547
|
readonly messageUnreadable: "{font} could not be read, so glyph coverage was not checked";
|
|
12816
13548
|
readonly messageUnloadable: "{font} is a .{format} font, which the game cannot draw with";
|
|
12817
13549
|
};
|
|
@@ -12851,7 +13583,7 @@ declare const en: {
|
|
|
12851
13583
|
readonly title: "Problems";
|
|
12852
13584
|
readonly empty: "No problems found";
|
|
12853
13585
|
readonly running: "Checking\u2026";
|
|
12854
|
-
readonly
|
|
13586
|
+
readonly counts: "{errors}, {warnings}, {infos}";
|
|
12855
13587
|
readonly filtered: "{shown} of {total}";
|
|
12856
13588
|
readonly rerun: "Run again";
|
|
12857
13589
|
readonly filterAll: "All";
|
|
@@ -12861,6 +13593,7 @@ declare const en: {
|
|
|
12861
13593
|
readonly expand: "Expand";
|
|
12862
13594
|
readonly collapseAll: "Collapse all";
|
|
12863
13595
|
readonly expandAll: "Expand all";
|
|
13596
|
+
readonly showAll: "Show all {count}";
|
|
12864
13597
|
readonly lineAria: "Line {line}";
|
|
12865
13598
|
readonly findPlaceholder: "Find in problems";
|
|
12866
13599
|
};
|
|
@@ -12869,13 +13602,20 @@ declare const en: {
|
|
|
12869
13602
|
readonly category: "Lint";
|
|
12870
13603
|
};
|
|
12871
13604
|
readonly console: {
|
|
13605
|
+
readonly channel: "Lint";
|
|
13606
|
+
readonly channelDescription: "Project checks and the problems they find";
|
|
12872
13607
|
readonly started: "Check started";
|
|
12873
|
-
readonly
|
|
13608
|
+
readonly finishedCounts: "{errors}, {warnings} in {duration}";
|
|
12874
13609
|
readonly finding: "{location} {message} ({rule})";
|
|
13610
|
+
readonly byRule: "Findings by rule";
|
|
13611
|
+
readonly ruleCount: "{rule}: {count}";
|
|
12875
13612
|
};
|
|
12876
13613
|
readonly build: {
|
|
12877
13614
|
readonly started: "Checking the project\u2026";
|
|
12878
|
-
readonly blocked:
|
|
13615
|
+
readonly blocked: {
|
|
13616
|
+
readonly one: "Build stopped by {count} problem";
|
|
13617
|
+
readonly other: "Build stopped by {count} problems";
|
|
13618
|
+
};
|
|
12879
13619
|
readonly blockedHint: "Change this in Project \u25B8 Project \u25B8 Check before building";
|
|
12880
13620
|
readonly skipped: "Project check skipped";
|
|
12881
13621
|
};
|
|
@@ -12921,6 +13661,20 @@ declare const en: {
|
|
|
12921
13661
|
readonly element: "Item {index}";
|
|
12922
13662
|
readonly root: "The document itself";
|
|
12923
13663
|
};
|
|
13664
|
+
readonly units: {
|
|
13665
|
+
readonly rows: {
|
|
13666
|
+
readonly one: "{count} row";
|
|
13667
|
+
readonly other: "{count} rows";
|
|
13668
|
+
};
|
|
13669
|
+
readonly elements: {
|
|
13670
|
+
readonly one: "{count} element";
|
|
13671
|
+
readonly other: "{count} elements";
|
|
13672
|
+
};
|
|
13673
|
+
readonly nodes: {
|
|
13674
|
+
readonly one: "{count} node";
|
|
13675
|
+
readonly other: "{count} nodes";
|
|
13676
|
+
};
|
|
13677
|
+
};
|
|
12924
13678
|
readonly count: {
|
|
12925
13679
|
readonly appTags: "Build variants";
|
|
12926
13680
|
readonly dlc: "DLC";
|
|
@@ -12959,8 +13713,8 @@ declare const en: {
|
|
|
12959
13713
|
readonly chapterRenamed: "Chapter renamed";
|
|
12960
13714
|
readonly chapterScenes: "Scene list changed";
|
|
12961
13715
|
readonly chapterOrder: "Chapters reordered";
|
|
12962
|
-
readonly sceneAdded: "Scene added ({
|
|
12963
|
-
readonly sceneRemoved: "Scene removed ({
|
|
13716
|
+
readonly sceneAdded: "Scene added ({rowCount})";
|
|
13717
|
+
readonly sceneRemoved: "Scene removed ({rowCount})";
|
|
12964
13718
|
readonly sceneChanged: "Scene changed";
|
|
12965
13719
|
readonly sceneRenamed: "Renamed";
|
|
12966
13720
|
readonly sceneField: "Scene {field}";
|
|
@@ -13039,16 +13793,16 @@ declare const en: {
|
|
|
13039
13793
|
};
|
|
13040
13794
|
readonly uiDocument: {
|
|
13041
13795
|
readonly renamed: "Interface renamed";
|
|
13042
|
-
readonly surfaceAdded: "Surface added ({
|
|
13043
|
-
readonly surfaceRemoved: "Surface removed ({
|
|
13796
|
+
readonly surfaceAdded: "Surface added ({elementCount})";
|
|
13797
|
+
readonly surfaceRemoved: "Surface removed ({elementCount})";
|
|
13044
13798
|
readonly surfaceChanged: "Surface changed";
|
|
13045
13799
|
readonly surfaceRenamed: "Renamed";
|
|
13046
13800
|
readonly surfaceDesignSize: "Design size ({fromWidth}\u00D7{fromHeight} \u2192 {toWidth}\u00D7{toHeight})";
|
|
13047
13801
|
readonly surfaceSettings: "Background or page animation changed";
|
|
13048
13802
|
readonly surfaceRoot: "Root element changed";
|
|
13049
13803
|
readonly surfaceField: "{field} changed";
|
|
13050
|
-
readonly componentAdded: "Component added ({
|
|
13051
|
-
readonly componentRemoved: "Component removed ({
|
|
13804
|
+
readonly componentAdded: "Component added ({elementCount})";
|
|
13805
|
+
readonly componentRemoved: "Component removed ({elementCount})";
|
|
13052
13806
|
readonly componentChanged: "Component changed";
|
|
13053
13807
|
readonly componentRenamed: "Renamed";
|
|
13054
13808
|
readonly componentField: "{field} changed";
|
|
@@ -13068,8 +13822,8 @@ declare const en: {
|
|
|
13068
13822
|
};
|
|
13069
13823
|
readonly uiGraphs: {
|
|
13070
13824
|
readonly ownerRecord: "Active blueprint changed";
|
|
13071
|
-
readonly blueprintAdded: "Blueprint added ({
|
|
13072
|
-
readonly blueprintRemoved: "Blueprint removed ({
|
|
13825
|
+
readonly blueprintAdded: "Blueprint added ({nodeCount})";
|
|
13826
|
+
readonly blueprintRemoved: "Blueprint removed ({nodeCount})";
|
|
13073
13827
|
readonly blueprintChanged: "Blueprint changed";
|
|
13074
13828
|
readonly blueprintRenamed: "Renamed";
|
|
13075
13829
|
readonly blueprintSource: "Script file changed";
|
|
@@ -13077,8 +13831,8 @@ declare const en: {
|
|
|
13077
13831
|
readonly scriptRemoved: "Script removed";
|
|
13078
13832
|
readonly scriptChanged: "Script changed";
|
|
13079
13833
|
readonly blueprintField: "{field} changed";
|
|
13080
|
-
readonly graphAdded: "Graph added ({
|
|
13081
|
-
readonly graphRemoved: "Graph removed ({
|
|
13834
|
+
readonly graphAdded: "Graph added ({nodeCount})";
|
|
13835
|
+
readonly graphRemoved: "Graph removed ({nodeCount})";
|
|
13082
13836
|
readonly graphChanged: "Graph changed";
|
|
13083
13837
|
readonly graphRenamed: "Renamed";
|
|
13084
13838
|
readonly graphField: "{field} changed";
|
|
@@ -13356,7 +14110,17 @@ declare const en: {
|
|
|
13356
14110
|
readonly assetsOrder: "Asset order";
|
|
13357
14111
|
readonly characters: "Cast";
|
|
13358
14112
|
readonly assetContent: "Asset file";
|
|
14113
|
+
readonly assetOfType: {
|
|
14114
|
+
readonly image: "Image asset";
|
|
14115
|
+
readonly audio: "Audio asset";
|
|
14116
|
+
readonly video: "Video asset";
|
|
14117
|
+
readonly json: "JSON asset";
|
|
14118
|
+
readonly font: "Font asset";
|
|
14119
|
+
readonly model: "Model asset";
|
|
14120
|
+
readonly other: "Other asset";
|
|
14121
|
+
};
|
|
13359
14122
|
readonly qualified: "{name} ({qualifier})";
|
|
14123
|
+
readonly numbered: "{name} {index}";
|
|
13360
14124
|
};
|
|
13361
14125
|
readonly category: {
|
|
13362
14126
|
readonly story: "Story";
|
|
@@ -13399,7 +14163,10 @@ declare const en: {
|
|
|
13399
14163
|
readonly emptyWorkingTree: "Nothing has changed since the last version";
|
|
13400
14164
|
readonly readFailure: "This comparison could not be read: {error}";
|
|
13401
14165
|
readonly incomplete: "{shown} of {total} changed documents were compared.";
|
|
13402
|
-
readonly documentsOmitted:
|
|
14166
|
+
readonly documentsOmitted: {
|
|
14167
|
+
readonly one: "{count} more document is not listed here.";
|
|
14168
|
+
readonly other: "{count} more documents are not listed here.";
|
|
14169
|
+
};
|
|
13403
14170
|
readonly unavailable: "Version control is not available in this project.";
|
|
13404
14171
|
};
|
|
13405
14172
|
readonly split: {
|
|
@@ -13433,7 +14200,10 @@ declare const en: {
|
|
|
13433
14200
|
readonly takeTheirs: "Keep theirs";
|
|
13434
14201
|
readonly takeAllMine: "Keep mine everywhere";
|
|
13435
14202
|
readonly takeAllTheirs: "Keep theirs everywhere";
|
|
13436
|
-
readonly rowsOmitted:
|
|
14203
|
+
readonly rowsOmitted: {
|
|
14204
|
+
readonly one: "{count} more file is not listed here. Use the two links above to choose for all of them.";
|
|
14205
|
+
readonly other: "{count} more files are not listed here. Use the two links above to choose for all of them.";
|
|
14206
|
+
};
|
|
13437
14207
|
readonly fileList: "Conflicted files";
|
|
13438
14208
|
readonly decision: "Which side to keep";
|
|
13439
14209
|
readonly pending: "No side chosen";
|
|
@@ -13555,7 +14325,7 @@ declare const en: {
|
|
|
13555
14325
|
readonly rerun: "Run again";
|
|
13556
14326
|
readonly severityFilter: "Severity";
|
|
13557
14327
|
readonly filterAll: "All";
|
|
13558
|
-
readonly
|
|
14328
|
+
readonly findingCounts: "{errors}, {warnings}, {infos}";
|
|
13559
14329
|
readonly durationSeconds: "{seconds}s";
|
|
13560
14330
|
readonly durationMinutes: "{minutes}m {seconds}s";
|
|
13561
14331
|
};
|
|
@@ -13567,6 +14337,7 @@ declare const en: {
|
|
|
13567
14337
|
};
|
|
13568
14338
|
readonly console: {
|
|
13569
14339
|
readonly channel: "Test";
|
|
14340
|
+
readonly channelDescription: "Test runs and their verdicts";
|
|
13570
14341
|
readonly started: "{title} started";
|
|
13571
14342
|
readonly finished: "{title} {status} in {duration}";
|
|
13572
14343
|
readonly finding: "{severity} {message}";
|
|
@@ -13578,13 +14349,25 @@ declare const en: {
|
|
|
13578
14349
|
readonly cancelled: "{title} cancelled";
|
|
13579
14350
|
readonly errored: "{title} could not run";
|
|
13580
14351
|
};
|
|
14352
|
+
readonly entryPoint: {
|
|
14353
|
+
readonly target: {
|
|
14354
|
+
readonly story: "story";
|
|
14355
|
+
readonly scene: "scene";
|
|
14356
|
+
};
|
|
14357
|
+
readonly assembled: "Start Game in \"{blueprint}\" takes a {target} assembled at run time (from \"{origin}\")";
|
|
14358
|
+
readonly unreadNode: "Start Game in \"{blueprint}\" takes its {target} from \"{origin}\", whose data this test does not read";
|
|
14359
|
+
readonly unreadPluginData: "Start Game in \"{blueprint}\" takes its {target} from \"{origin}\", and the {plugin} data in this project cannot be read";
|
|
14360
|
+
readonly engineRows: "Start Game in \"{blueprint}\" takes its {target} from the rows of \"{list}\", which the story fills while it plays";
|
|
14361
|
+
readonly undeclaredVariable: "Start Game in \"{blueprint}\" takes its {target} from a variable the project does not declare";
|
|
14362
|
+
readonly unreadable: "Start Game in \"{blueprint}\" takes its {target} from a value this test cannot follow";
|
|
14363
|
+
};
|
|
13581
14364
|
readonly builtin: {
|
|
13582
14365
|
readonly projectDiagnostics: {
|
|
13583
14366
|
readonly title: "Project diagnostics";
|
|
13584
14367
|
readonly description: "All project check rules, run as one test";
|
|
13585
14368
|
readonly summary: {
|
|
13586
14369
|
readonly passed: "No problems found";
|
|
13587
|
-
readonly failed: "{errors}
|
|
14370
|
+
readonly failed: "Problems: errors {errors}, warnings {warnings}";
|
|
13588
14371
|
};
|
|
13589
14372
|
};
|
|
13590
14373
|
readonly walkthrough: {
|
|
@@ -13599,7 +14382,7 @@ declare const en: {
|
|
|
13599
14382
|
};
|
|
13600
14383
|
};
|
|
13601
14384
|
readonly log: {
|
|
13602
|
-
readonly planned: "Route planned: {scenes}
|
|
14385
|
+
readonly planned: "Route planned: scenes {scenes}, decisions {decisions}";
|
|
13603
14386
|
readonly choosing: "{scene}: choosing \"{option}\"";
|
|
13604
14387
|
readonly improvised: "Answered an unplanned choice with \"{option}\"";
|
|
13605
14388
|
};
|
|
@@ -13610,8 +14393,8 @@ declare const en: {
|
|
|
13610
14393
|
readonly optionMissing: "{scene} did not offer \"{option}\", so this route is not walkable";
|
|
13611
14394
|
readonly otherEnding: "Reached {reached} instead of {ending}";
|
|
13612
14395
|
readonly endedWithoutEnding: "The story ended without reaching {ending}";
|
|
13613
|
-
readonly stalled: "Stopped advancing
|
|
13614
|
-
readonly cancelled: "Cancelled
|
|
14396
|
+
readonly stalled: "Stopped advancing without reaching {ending}. Steps taken: {steps}";
|
|
14397
|
+
readonly cancelled: "Cancelled. Steps taken: {steps}";
|
|
13615
14398
|
readonly exit: {
|
|
13616
14399
|
readonly closed: "The game closed before reaching {ending}";
|
|
13617
14400
|
readonly stopped: "The game was stopped before reaching {ending}";
|
|
@@ -13628,7 +14411,7 @@ declare const en: {
|
|
|
13628
14411
|
readonly description: "Whether every scene, option and ending can be reached once conditions are read";
|
|
13629
14412
|
readonly skipped: {
|
|
13630
14413
|
readonly noEntryPoint: "No story marks where play begins";
|
|
13631
|
-
readonly undecidableEntry: "
|
|
14414
|
+
readonly undecidableEntry: "Where play begins cannot be read from Start Game in \"{blueprint}\"";
|
|
13632
14415
|
readonly storiesUnread: "A story could not be read";
|
|
13633
14416
|
};
|
|
13634
14417
|
readonly finding: {
|
|
@@ -13649,7 +14432,7 @@ declare const en: {
|
|
|
13649
14432
|
readonly skipped: {
|
|
13650
14433
|
readonly noEndings: "No story with an entry point marks an /ending";
|
|
13651
14434
|
readonly noEntryPoint: "No story marks where play begins";
|
|
13652
|
-
readonly undecidableEntry: "
|
|
14435
|
+
readonly undecidableEntry: "Where play begins cannot be read from Start Game in \"{blueprint}\"";
|
|
13653
14436
|
readonly storiesUnread: "A story could not be read";
|
|
13654
14437
|
};
|
|
13655
14438
|
readonly finding: {
|
|
@@ -13809,6 +14592,10 @@ declare const en: {
|
|
|
13809
14592
|
readonly title: "Trimming and looping a clip";
|
|
13810
14593
|
readonly body: string;
|
|
13811
14594
|
};
|
|
14595
|
+
readonly videoClips: {
|
|
14596
|
+
readonly title: "Inspecting a video";
|
|
14597
|
+
readonly body: string;
|
|
14598
|
+
};
|
|
13812
14599
|
readonly voice: {
|
|
13813
14600
|
readonly title: "Voice-over";
|
|
13814
14601
|
readonly body: string;
|
|
@@ -14134,6 +14921,42 @@ declare const en: {
|
|
|
14134
14921
|
readonly engine: "{error}";
|
|
14135
14922
|
};
|
|
14136
14923
|
};
|
|
14924
|
+
readonly run: {
|
|
14925
|
+
readonly voicePlayFailed: "The voice recording of this line could not be played.";
|
|
14926
|
+
readonly choiceVoicePlayFailed: "The voice recording of this option could not be played.";
|
|
14927
|
+
readonly savedVariableUndeclared: "\u201C{node}\u201D: the running story does not declare this saved variable.";
|
|
14928
|
+
readonly valueNotSerializable: "\u201C{node}\u201D: a saved variable can only hold a value that fits in a save file.";
|
|
14929
|
+
readonly variablesNotSerializable: "Saved and persistent variables can only hold values that fit in a save file.";
|
|
14930
|
+
readonly persistenceUnavailable: "Persistent variables are not available here.";
|
|
14931
|
+
readonly storyMissing: "\u201C{node}\u201D: the story it names is no longer in this project.";
|
|
14932
|
+
readonly sceneMissing: "\u201C{node}\u201D: the scene it names is no longer in this project.";
|
|
14933
|
+
readonly noChoiceMenu: "\u201C{node}\u201D: no menu is showing.";
|
|
14934
|
+
readonly noChoiceAtIndex: "\u201C{node}\u201D: the menu has no option {index}.";
|
|
14935
|
+
readonly saveCaptureFailed: "\u201C{node}\u201D: the screenshot for this save could not be taken. The save was written without one.";
|
|
14936
|
+
readonly relaunchUnavailable: "There is no running story to start again.";
|
|
14937
|
+
readonly storyNotRestartable: "The story that was running could not be started again.";
|
|
14938
|
+
readonly saveStoryMissing: "The story this save belongs to is not in this build.";
|
|
14939
|
+
readonly storyCannotStart: "A story cannot be started here.";
|
|
14940
|
+
readonly noGameToResume: "No game came up to resume into.";
|
|
14941
|
+
readonly resume: {
|
|
14942
|
+
readonly relaunchRowGone: "The row this run started from no longer exists; the scene started from its first row.";
|
|
14943
|
+
readonly sceneGone: "The scene being played no longer exists; the story started from the beginning.";
|
|
14944
|
+
readonly storyGone: "The story being played no longer exists; the game started from the beginning.";
|
|
14945
|
+
readonly rowGoneBefore: "The row being played no longer exists; play resumed from the row before it.";
|
|
14946
|
+
readonly rowGoneSceneStart: "The row being played no longer exists; play resumed from the start of the scene.";
|
|
14947
|
+
};
|
|
14948
|
+
readonly language: {
|
|
14949
|
+
readonly noRestart: "The language changed during a playthrough and the game cannot restart here. Text on screen, the backlog and any voice already playing stay in the previous language.";
|
|
14950
|
+
readonly restartFresh: "The language changed; the game restarts without keeping the playthrough.";
|
|
14951
|
+
readonly saveFailed: "The language changed, but the playthrough could not be saved, so the game did not restart: {error}";
|
|
14952
|
+
readonly parked: "The playthrough was set aside for the language change; the game restarts.";
|
|
14953
|
+
readonly restoring: "A playthrough set aside for a language change is being restored.";
|
|
14954
|
+
readonly resumeFailed: "The playthrough could not be resumed after the language change: {error}";
|
|
14955
|
+
readonly resumeRefused: "The playthrough set aside for the language change was not accepted; it is still stored.";
|
|
14956
|
+
readonly restored: "The playthrough set aside for the language change was restored.";
|
|
14957
|
+
readonly returnFailed: "The game could not return to its start after the language change: {error}";
|
|
14958
|
+
};
|
|
14959
|
+
};
|
|
14137
14960
|
readonly crash: {
|
|
14138
14961
|
readonly title: "The game stopped working";
|
|
14139
14962
|
readonly detail: "Saved games are not affected. Restarting reopens the game at its title screen.";
|
|
@@ -14434,6 +15257,11 @@ export type SearchJumpTarget = {
|
|
|
14434
15257
|
} | {
|
|
14435
15258
|
kind: "uiSurface";
|
|
14436
15259
|
surfaceId: string;
|
|
15260
|
+
}
|
|
15261
|
+
/** A component definition: its own editor tab, the one the component library opens. */
|
|
15262
|
+
| {
|
|
15263
|
+
kind: "uiComponent";
|
|
15264
|
+
componentId: string;
|
|
14437
15265
|
} | {
|
|
14438
15266
|
kind: "asset";
|
|
14439
15267
|
assetId: string;
|
|
@@ -14618,465 +15446,137 @@ export declare const AssetExtensions: {
|
|
|
14618
15446
|
model: string[];
|
|
14619
15447
|
other: string[];
|
|
14620
15448
|
};
|
|
14621
|
-
type
|
|
14622
|
-
|
|
14623
|
-
|
|
14624
|
-
|
|
15449
|
+
type ImageFillMode = "cover" | "contain" | "stretch" | "crop" | "tile";
|
|
15450
|
+
interface ImageFillCropPlacement {
|
|
15451
|
+
leftPct: number;
|
|
15452
|
+
topPct: number;
|
|
15453
|
+
widthPct: number;
|
|
15454
|
+
heightPct: number;
|
|
15455
|
+
}
|
|
15456
|
+
interface ImageFill {
|
|
15457
|
+
mode: ImageFillMode;
|
|
15458
|
+
assetId?: string | null;
|
|
15459
|
+
cropPlacement?: ImageFillCropPlacement;
|
|
15460
|
+
}
|
|
15461
|
+
type UIListItemScope = {
|
|
15462
|
+
item: unknown;
|
|
15463
|
+
index: number;
|
|
15464
|
+
count: number;
|
|
15465
|
+
key: string;
|
|
14625
15466
|
/**
|
|
14626
|
-
*
|
|
15467
|
+
* Whether this is the selected row.
|
|
14627
15468
|
*
|
|
14628
|
-
*
|
|
14629
|
-
* a
|
|
15469
|
+
* On the scope because it belongs to the row rather than to any one widget in it: everything in
|
|
15470
|
+
* a selected row reads as selected, and each widget decides for itself whether it has an
|
|
15471
|
+
* appearance row that says so.
|
|
15472
|
+
*/
|
|
15473
|
+
selected?: boolean;
|
|
15474
|
+
/**
|
|
15475
|
+
* The shape the owning list declared, carried rather than looked up.
|
|
14630
15476
|
*
|
|
14631
|
-
*
|
|
14632
|
-
*
|
|
14633
|
-
*
|
|
14634
|
-
* way is a claim about what can flow through it: it needs an argument at the declaration, not a
|
|
14635
|
-
* guess, because a wrong one hides a real reference.
|
|
15477
|
+
* A field binding is resolved deep inside the element merge, which holds an element and a scope
|
|
15478
|
+
* and no document. Putting the struct on the scope keeps that read a read - the list already
|
|
15479
|
+
* resolved it once for its own columns and keys.
|
|
14636
15480
|
*/
|
|
14637
|
-
|
|
15481
|
+
struct?: UIStructDef | null;
|
|
14638
15482
|
};
|
|
14639
|
-
|
|
14640
|
-
|
|
14641
|
-
|
|
14642
|
-
|
|
14643
|
-
|
|
14644
|
-
|
|
14645
|
-
|
|
14646
|
-
|
|
14647
|
-
|
|
14648
|
-
resolve(...paths: (Readonly<string[]> | string)[]): string;
|
|
14649
|
-
getConfig(): ProjectProps;
|
|
15483
|
+
type UIElementSelection = {
|
|
15484
|
+
editor: "ui";
|
|
15485
|
+
surfaceId: UISurfaceId;
|
|
15486
|
+
elementIds: UIElementId[];
|
|
15487
|
+
primaryId?: UIElementId;
|
|
15488
|
+
};
|
|
15489
|
+
export declare enum AssetSource {
|
|
15490
|
+
Local = "local",
|
|
15491
|
+
Remote = "remote"
|
|
14650
15492
|
}
|
|
15493
|
+
type AssetResolveMeta<Source extends AssetSource> = Source extends AssetSource.Local ? {} : Source extends AssetSource.Remote ? {
|
|
15494
|
+
/** The address the author gave, verbatim. The only field a refresh sends a request to. */
|
|
15495
|
+
url: string;
|
|
15496
|
+
/** When the stored snapshot was taken, ISO 8601. */
|
|
15497
|
+
fetchedAt: string;
|
|
15498
|
+
/**
|
|
15499
|
+
* The server's validators for the stored snapshot, when it offered any. Sent back as
|
|
15500
|
+
* `If-None-Match` / `If-Modified-Since`, so refreshing an unchanged asset transfers no bytes.
|
|
15501
|
+
*/
|
|
15502
|
+
etag?: string;
|
|
15503
|
+
lastModified?: string;
|
|
15504
|
+
/** The response's declared media type. Diagnostic only - the format gate reads the bytes. */
|
|
15505
|
+
contentType?: string;
|
|
15506
|
+
/**
|
|
15507
|
+
* Was to be the runtime cache lifetime, back when a remote asset was going to be fetched by the
|
|
15508
|
+
* shipped game. It never was: the runtime asset manifest carries no URL, so a packaged game has
|
|
15509
|
+
* only the baked bytes, and nothing has ever read this. Kept so records that carry it still
|
|
15510
|
+
* open; the next write drops it. Never write it.
|
|
15511
|
+
*
|
|
15512
|
+
* @deprecated
|
|
15513
|
+
*/
|
|
15514
|
+
lifetime?: number;
|
|
15515
|
+
} : never;
|
|
14651
15516
|
/**
|
|
14652
|
-
*
|
|
14653
|
-
*
|
|
14654
|
-
* "Test" here means a check an author runs against *their game*: does it reach an ending, does it
|
|
14655
|
-
* survive with no network, does a plugin's feature still behave. It is not vitest; nothing in this
|
|
14656
|
-
* file has anything to do with the repo's own unit tests.
|
|
14657
|
-
*
|
|
14658
|
-
* A test is a definition object in a registry that both Studio's built-in modules and plugins
|
|
14659
|
-
* populate (see `registry.ts`), started from Run > Test. Five decisions are load-bearing and worth
|
|
14660
|
-
* knowing before editing anything here:
|
|
14661
|
-
*
|
|
14662
|
-
* - **A test may only say passed / failed / skipped.** `cancelled` and `errored` are verdicts the
|
|
14663
|
-
* *host* reaches about a test, and a test that could claim them could lie about being killed.
|
|
14664
|
-
* Cancellation arrives as `ctx.signal`; a test that wants "the author aborted me" to count as a
|
|
14665
|
-
* failure is free to catch it and return `failed`, which is how a windowed test whose contract is
|
|
14666
|
-
* "close the window when satisfied" expresses termination.
|
|
14667
|
-
* - **Undeclared capabilities are absent, not throwing.** `requires` is the whole truth about what
|
|
14668
|
-
* a test can reach: `ctx.game` is `undefined` unless `game.launch` was declared, exactly as
|
|
14669
|
-
* `app.game`'s domains work for runtime plugins. What the picker lists and what the test can do
|
|
14670
|
-
* are the same set by construction. `parameters` obeys the same rule from the other direction:
|
|
14671
|
-
* `ctx.parameters` carries a value for every id the test *declared* and for no other, so it is a
|
|
14672
|
-
* resolved set rather than a free-form bag the picker could put anything into.
|
|
14673
|
-
* - **Tests never build prose.** Every author-visible string is a `TestText` - an i18n key for
|
|
14674
|
-
* Studio's own tests, a literal for a plugin's (a plugin has no `TranslationKey`s, and its own
|
|
14675
|
-
* translator produces plain strings). The console channel and the report tab each render it.
|
|
14676
|
-
* - **Severity is on the finding, unlike lint.** A lint rule defers severity to the project's
|
|
14677
|
-
* config; a test has no such table, and its verdict is stated separately by `run`. A finding here
|
|
14678
|
-
* is evidence for a verdict the test already reached, so it carries its own weight.
|
|
14679
|
-
* - **`presentation` is a declaration, not a mechanism.** Whether a window appears is a consequence
|
|
14680
|
-
* of asking the host for a game session. The field is what the picker badges and what lets the
|
|
14681
|
-
* author know a window is about to open; a headless test that launches one is a host error.
|
|
14682
|
-
*/
|
|
14683
|
-
/**
|
|
14684
|
-
* Bumped when a change here would break an already-published plugin.
|
|
14685
|
-
*
|
|
14686
|
-
* Recorded on every run record so a report kept across an upgrade still says which contract produced
|
|
14687
|
-
* it, and surfaced to plugins so a definition can refuse a host older than it needs.
|
|
14688
|
-
*
|
|
14689
|
-
* **2** added parameters: a test may declare values the author supplies before pressing Start
|
|
14690
|
-
* (`TestDefinition.parameters`), and every run context now carries `parameters` - a required member,
|
|
14691
|
-
* which is what makes this a break rather than an addition. A definition compiled against 1 keeps
|
|
14692
|
-
* working unchanged, since declaring none resolves to `{}`.
|
|
14693
|
-
*/
|
|
14694
|
-
export declare const TEST_PROTOCOL_VERSION = 2;
|
|
14695
|
-
/**
|
|
14696
|
-
* Stable identifier. Studio's own tests are `narraleaf-studio:<slug>`; a plugin's must be prefixed
|
|
14697
|
-
* with its plugin id, which the host enforces at registration rather than trusting.
|
|
14698
|
-
*/
|
|
14699
|
-
export type TestId = string;
|
|
14700
|
-
/** Grouping in the picker. `custom` is where a plugin lands when it claims nothing else. */
|
|
14701
|
-
export type TestCategory = "integrity" | "runtime" | "compatibility" | "custom";
|
|
14702
|
-
/**
|
|
14703
|
-
* Does this test put a game window on screen?
|
|
14704
|
-
*
|
|
14705
|
-
* `headless` is the interesting half: a test with no window can run while the author keeps working,
|
|
14706
|
-
* and is the only kind that can run on a frozen workspace.
|
|
14707
|
-
*/
|
|
14708
|
-
export type TestPresentation = "headless" | "windowed";
|
|
14709
|
-
/**
|
|
14710
|
-
* What the host lends a test. Anything not declared is absent from `TestRunContext`.
|
|
14711
|
-
*
|
|
14712
|
-
* Deliberately coarse and short. A capability is added here only when a test genuinely cannot be
|
|
14713
|
-
* written without it - the failure mode this vocabulary exists to prevent is the one where a narrow
|
|
14714
|
-
* API is nominally narrow but hands out a reference that reaches everything.
|
|
14715
|
-
*/
|
|
14716
|
-
export type TestCapability =
|
|
14717
|
-
/** Read the project's stories and scenes. Read-only by construction: there is no write half. */
|
|
14718
|
-
"project.read"
|
|
14719
|
-
/** Launch, observe and stop a game process. Implies a window unless the launch asks otherwise. */
|
|
14720
|
-
| "game.launch";
|
|
14721
|
-
/**
|
|
14722
|
-
* An author-visible string.
|
|
14723
|
-
*
|
|
14724
|
-
* Two shapes rather than one, because the two producers genuinely differ: Studio's tests name a key
|
|
14725
|
-
* in its catalogue and must re-render when the editor language changes, while a plugin has no key
|
|
14726
|
-
* space of its own and hands over whatever its own translator already produced.
|
|
14727
|
-
*/
|
|
14728
|
-
export type TestText = {
|
|
14729
|
-
key: TranslationKey;
|
|
14730
|
-
params?: Record<string, string | number>;
|
|
14731
|
-
text?: undefined;
|
|
14732
|
-
} | {
|
|
14733
|
-
text: string;
|
|
14734
|
-
key?: undefined;
|
|
14735
|
-
};
|
|
14736
|
-
/** Same ladder as the workspace console, so a test log line needs no translation at the boundary. */
|
|
14737
|
-
export type TestLogLevel = GameTestLogLevel;
|
|
14738
|
-
/**
|
|
14739
|
-
* Progress, or `null` to go back to indeterminate.
|
|
14740
|
-
*
|
|
14741
|
-
* `total` is optional because most interesting tests genuinely do not know it up front (how many
|
|
14742
|
-
* routes a story has is what walking it discovers). Omitting it renders the same indeterminate bar
|
|
14743
|
-
* the build uses rather than a fake fraction.
|
|
14744
|
-
*/
|
|
14745
|
-
export type TestProgress = {
|
|
14746
|
-
completed: number;
|
|
14747
|
-
total?: number;
|
|
14748
|
-
label?: TestText;
|
|
14749
|
-
};
|
|
14750
|
-
export type TestFindingSeverity = "error" | "warning" | "info";
|
|
14751
|
-
/** One piece of evidence. `target` reuses the global-search navigation layer, so the report tab's click-to-jump is existing machinery. */
|
|
14752
|
-
export type TestFinding = {
|
|
14753
|
-
severity: TestFindingSeverity;
|
|
14754
|
-
message: TestText;
|
|
14755
|
-
target?: SearchJumpTarget;
|
|
14756
|
-
};
|
|
14757
|
-
/**
|
|
14758
|
-
* What `run` may return. Note the absence of `cancelled` and `errored`: see the header.
|
|
14759
|
-
*
|
|
14760
|
-
* `skipped` exists so a test can decline for a reason it only discovers while running (a project
|
|
14761
|
-
* with no localisation configured, say) without pretending to have passed. A test that can tell
|
|
14762
|
-
* before it starts should say so from `checkAvailability` instead, so the picker greys it out.
|
|
15517
|
+
* Asset interface with user metadata
|
|
15518
|
+
* Stored in assets metadata files
|
|
14763
15519
|
*/
|
|
14764
|
-
export
|
|
14765
|
-
status: "passed";
|
|
14766
|
-
summary?: TestText;
|
|
14767
|
-
} | {
|
|
14768
|
-
status: "failed";
|
|
14769
|
-
summary: TestText;
|
|
14770
|
-
} | {
|
|
14771
|
-
status: "skipped";
|
|
14772
|
-
summary: TestText;
|
|
14773
|
-
};
|
|
14774
|
-
export type TestStoryRef = {
|
|
14775
|
-
id: string;
|
|
14776
|
-
name: string;
|
|
14777
|
-
};
|
|
14778
|
-
export type TestSceneRef = {
|
|
15520
|
+
export interface Asset<Type extends AssetType = AssetType, Source extends AssetSource = AssetSource> {
|
|
14779
15521
|
id: string;
|
|
15522
|
+
type: Type;
|
|
14780
15523
|
name: string;
|
|
14781
|
-
|
|
14782
|
-
|
|
14783
|
-
|
|
14784
|
-
|
|
14785
|
-
|
|
14786
|
-
|
|
14787
|
-
|
|
14788
|
-
* a version bump rather than something a test reaches around.
|
|
14789
|
-
*
|
|
14790
|
-
* Studio's own built-in tests do not go through this handle at all; they are registered from inside
|
|
14791
|
-
* the workspace and close over its context directly, the same way `builtInPanels` differ from
|
|
14792
|
-
* `services.ui.panels`. This handle exists so a *plugin* has a bounded way in.
|
|
14793
|
-
*/
|
|
14794
|
-
export type TestProjectHandle = {
|
|
14795
|
-
readonly projectPath: string;
|
|
14796
|
-
listStories(): Promise<TestStoryRef[]>;
|
|
14797
|
-
listScenes(storyId: string): Promise<TestSceneRef[]>;
|
|
14798
|
-
};
|
|
14799
|
-
/**
|
|
14800
|
-
* How a game process ended, and what it said on the way out.
|
|
14801
|
-
*
|
|
14802
|
-
* These are the wire shapes from `@shared/types/gameTest`, re-exported under the names an author
|
|
14803
|
-
* touches. The distinction they carry is the whole reason the pipeline needed main-process work:
|
|
14804
|
-
* before it, a crashed preview and an author closing the window were the same event to Studio (an
|
|
14805
|
-
* exit logged at `verbose`, status polled back to `idle`). A test whose pass condition is "the
|
|
14806
|
-
* author closed the window" cannot be written without it.
|
|
14807
|
-
*/
|
|
14808
|
-
export type TestGameExitReason = GameTestExitReason;
|
|
14809
|
-
export type TestGameExit = GameTestExit;
|
|
14810
|
-
export type TestGameEvent = GameTestEvent;
|
|
14811
|
-
type TestGameCommand = GameTestCommand;
|
|
14812
|
-
export type TestGameLaunchOptions = {
|
|
15524
|
+
hash: string;
|
|
15525
|
+
ext?: string;
|
|
15526
|
+
source: Source;
|
|
15527
|
+
meta: AssetResolveMeta<Source>;
|
|
15528
|
+
tags: string[];
|
|
15529
|
+
description: string;
|
|
15530
|
+
groupId?: string;
|
|
14813
15531
|
/**
|
|
14814
|
-
*
|
|
14815
|
-
*
|
|
15532
|
+
* Editor-authored data that rides with the asset record. Persisted in the assets metadata,
|
|
15533
|
+
* which is a project file under version control - so this is for things the *author* decided
|
|
15534
|
+
* (and would want to keep and share), never for derived caches. Anything recomputable belongs
|
|
15535
|
+
* under {@link ProjectNameConvention.EditorThumbnailCache}'s neighbours in `editor/cache/`.
|
|
14816
15536
|
*/
|
|
14817
|
-
|
|
14818
|
-
}
|
|
14819
|
-
|
|
14820
|
-
|
|
14821
|
-
/**
|
|
14822
|
-
|
|
15537
|
+
extras?: AssetExtras;
|
|
15538
|
+
}
|
|
15539
|
+
type AssetAudioLoop = StoredAudioClipRegion;
|
|
15540
|
+
interface AssetExtras {
|
|
15541
|
+
/** Audio only: the loop region shown and edited by the audio preview. */
|
|
15542
|
+
audioLoop?: AssetAudioLoop;
|
|
15543
|
+
/** Audio only: the gain set in the audio preview, to balance loudness across clips. */
|
|
15544
|
+
audioGain?: StoredAudioGain;
|
|
14823
15545
|
/**
|
|
14824
|
-
*
|
|
15546
|
+
* Model bundles only: the entry file the author chose, relative to the bundle root.
|
|
14825
15547
|
*
|
|
14826
|
-
*
|
|
14827
|
-
*
|
|
14828
|
-
*
|
|
14829
|
-
*
|
|
14830
|
-
*
|
|
14831
|
-
|
|
14832
|
-
|
|
14833
|
-
/** Resolves once the process is gone, whatever the reason. Safe to call more than once. */
|
|
14834
|
-
waitForExit(): Promise<TestGameExit>;
|
|
14835
|
-
/** Graceful shutdown, then force. Resolves when the process is gone. */
|
|
14836
|
-
stop(): Promise<void>;
|
|
14837
|
-
};
|
|
14838
|
-
/**
|
|
14839
|
-
* `game.launch`.
|
|
14840
|
-
*
|
|
14841
|
-
* One session at a time per run: the host refuses a second `launch()` while one is alive, because
|
|
14842
|
-
* two preview processes contend for the same compiled artifact directory and the second would
|
|
14843
|
-
* silently win.
|
|
14844
|
-
*/
|
|
14845
|
-
export type TestGameHandle = {
|
|
14846
|
-
launch(options?: TestGameLaunchOptions): Promise<TestGameSession>;
|
|
14847
|
-
};
|
|
14848
|
-
export type TestRunContext = {
|
|
14849
|
-
readonly runId: string;
|
|
14850
|
-
readonly protocolVersion: typeof TEST_PROTOCOL_VERSION;
|
|
14851
|
-
/**
|
|
14852
|
-
* Aborted when the author cancels. A test that ignores it is killed anyway once its promise
|
|
14853
|
-
* settles, but its findings are kept - a cancelled run is still evidence.
|
|
15548
|
+
* The only part of a bundle that is persisted rather than re-read from disk, because it is the
|
|
15549
|
+
* only part that is a *decision*. `files` and `size` are observations and are recomputed on
|
|
15550
|
+
* every read; the entry is a guess Studio made from the file tree that the author may have
|
|
15551
|
+
* corrected, and a guess that silently re-runs would undo the correction.
|
|
15552
|
+
*
|
|
15553
|
+
* Absent means "use the detected entry" - so a bundle whose detection is unambiguous carries no
|
|
15554
|
+
* extra state at all, and re-detection keeps working if a later Studio learns a new format.
|
|
14854
15555
|
*/
|
|
14855
|
-
|
|
15556
|
+
modelEntry?: string;
|
|
14856
15557
|
/**
|
|
14857
|
-
*
|
|
15558
|
+
* Text assets only: the encoding the author said this file is in.
|
|
14858
15559
|
*
|
|
14859
|
-
*
|
|
14860
|
-
*
|
|
14861
|
-
*
|
|
14862
|
-
*
|
|
15560
|
+
* A property of the *file*, not of the window, which is why it rides the record into version
|
|
15561
|
+
* control rather than sitting in session state: the point of a shared plan file is that the
|
|
15562
|
+
* colleague who opens the GBK spreadsheet next gets it right without having to know. Outranks
|
|
15563
|
+
* the byte-order-mark sniff on open, because an author who said so has said more than a
|
|
15564
|
+
* heuristic can.
|
|
15565
|
+
*
|
|
15566
|
+
* Written only when the author explicitly reopens or saves under an encoding. Absent - the
|
|
15567
|
+
* normal state - means "sniff the BOM, then UTF-8", so merely reading a file never produces a
|
|
15568
|
+
* change to commit.
|
|
14863
15569
|
*/
|
|
14864
|
-
|
|
14865
|
-
log(level: TestLogLevel, message: TestText): void;
|
|
14866
|
-
progress(progress: TestProgress | null): void;
|
|
14867
|
-
report(finding: TestFinding): void;
|
|
14868
|
-
/** Present iff `project.read` was declared. */
|
|
14869
|
-
readonly project?: TestProjectHandle;
|
|
14870
|
-
/** Present iff `game.launch` was declared. */
|
|
14871
|
-
readonly game?: TestGameHandle;
|
|
14872
|
-
};
|
|
14873
|
-
/** Everything `checkAvailability` is allowed to look at - deliberately cheap, it runs on every picker open. */
|
|
14874
|
-
export type TestAvailabilityContext = {
|
|
14875
|
-
readonly projectPath: string;
|
|
15570
|
+
textEncoding?: TextEncodingId;
|
|
14876
15571
|
/**
|
|
14877
|
-
*
|
|
14878
|
-
* freeze, an open merge, recovery mode.
|
|
15572
|
+
* Text assets only: the line ending this file uses.
|
|
14879
15573
|
*
|
|
14880
|
-
*
|
|
14881
|
-
*
|
|
14882
|
-
*
|
|
15574
|
+
* Recorded for the same reason as {@link textEncoding}, and needed at all because a *new* text
|
|
15575
|
+
* file is zero bytes: there is nothing in the content to detect, so the platform that created it
|
|
15576
|
+
* is the only thing that can answer. For a file that has content, the content wins - see
|
|
15577
|
+
* `resolveLineEnding` - and this is only the fallback.
|
|
14883
15578
|
*/
|
|
14884
|
-
|
|
14885
|
-
/**
|
|
14886
|
-
* Whether this project is one Studio will not run anything for - it arrived from a package or a
|
|
14887
|
-
* remote source and nobody has vouched for it yet.
|
|
14888
|
-
*
|
|
14889
|
-
* Passed in for the reason above and one more of its own: the ledger that answers it lives in
|
|
14890
|
-
* the main process, so asking costs a round trip, and everything here is synchronous. The host
|
|
14891
|
-
* settles the answer when the workspace comes up and hands the settled copy down.
|
|
14892
|
-
*
|
|
14893
|
-
* `checkAvailability` will not normally see this true - the host refuses every test before it
|
|
14894
|
-
* asks a definition anything, because a run is an execution of the project. It is here because
|
|
14895
|
-
* `options` is *not* gated: a list that would cost real work to build can decline to build it
|
|
14896
|
-
* for a project that cannot run it.
|
|
14897
|
-
*/
|
|
14898
|
-
readonly distrusted: boolean;
|
|
14899
|
-
};
|
|
14900
|
-
export type TestAvailability = {
|
|
14901
|
-
available: true;
|
|
14902
|
-
}
|
|
14903
|
-
/** Greys the row out and says why. Not an error: an unavailable test is a normal state. */
|
|
14904
|
-
| {
|
|
14905
|
-
available: false;
|
|
14906
|
-
reason: TestText;
|
|
14907
|
-
};
|
|
14908
|
-
/**
|
|
14909
|
-
* One row of a `select` parameter's list.
|
|
14910
|
-
*
|
|
14911
|
-
* `value` is what the test reads and what is remembered on disk; `label` is what the author picks
|
|
14912
|
-
* from. They are separate because the label is a display string that follows the editor language
|
|
14913
|
-
* while the value has to survive a language switch and a Studio upgrade unchanged.
|
|
14914
|
-
*/
|
|
14915
|
-
export type TestParameterOption = {
|
|
14916
|
-
value: string;
|
|
14917
|
-
label: TestText;
|
|
14918
|
-
};
|
|
14919
|
-
/** A parameter the author answers by picking from a list. */
|
|
14920
|
-
export type TestSelectParameterDefinition = {
|
|
14921
|
-
id: string;
|
|
14922
|
-
kind: "select";
|
|
14923
|
-
label: TestText;
|
|
14924
|
-
/** One clause about what the value selects, if it needs one. Not a sentence explaining the UI. */
|
|
14925
|
-
description?: TestText;
|
|
14926
|
-
/**
|
|
14927
|
-
* The list to offer, evaluated when the picker opens.
|
|
14928
|
-
*
|
|
14929
|
-
* Same contract as `checkAvailability`, and for the same reason: it runs on every open, so keep
|
|
14930
|
-
* it synchronous, cheap and free of side effects. It is handed the same context, so a list can
|
|
14931
|
-
* depend on the project without the definition holding a workspace of its own.
|
|
14932
|
-
*
|
|
14933
|
-
* **An empty list is a real answer**, not a failure - a project with no endings yet has nothing
|
|
14934
|
-
* to walk to. The host treats it as one: the whole test is greyed out naming this parameter,
|
|
14935
|
-
* rather than offering a dropdown with nothing in it and a Start that cannot work.
|
|
14936
|
-
*/
|
|
14937
|
-
options(ctx: TestAvailabilityContext): TestParameterOption[];
|
|
14938
|
-
/**
|
|
14939
|
-
* Which option to start on. Falls back to the first option when absent, and also when it names
|
|
14940
|
-
* an option that is not in the list any more.
|
|
14941
|
-
*/
|
|
14942
|
-
defaultValue?: string;
|
|
14943
|
-
};
|
|
14944
|
-
/** A parameter the author answers with a switch. */
|
|
14945
|
-
export type TestBooleanParameterDefinition = {
|
|
14946
|
-
id: string;
|
|
14947
|
-
kind: "boolean";
|
|
14948
|
-
label: TestText;
|
|
14949
|
-
/** One clause about what the value selects, if it needs one. Not a sentence explaining the UI. */
|
|
14950
|
-
description?: TestText;
|
|
14951
|
-
/** Absent means off. */
|
|
14952
|
-
defaultValue?: boolean;
|
|
14953
|
-
};
|
|
14954
|
-
export type TestParameterDefinition = TestSelectParameterDefinition | TestBooleanParameterDefinition;
|
|
14955
|
-
/** What one parameter resolves to. A `select` resolves to the chosen option's `value`. */
|
|
14956
|
-
export type TestParameterValue = string | boolean;
|
|
14957
|
-
/**
|
|
14958
|
-
* Resolved parameter values, keyed by parameter id.
|
|
14959
|
-
*
|
|
14960
|
-
* Only ids the test declared are present - see the header. A test that declares none is handed an
|
|
14961
|
-
* empty object, never `undefined`, so reading `ctx.parameters` needs no guard.
|
|
14962
|
-
*/
|
|
14963
|
-
export type TestParameterValues = Readonly<Record<string, TestParameterValue>>;
|
|
14964
|
-
export type TestDefinition = {
|
|
14965
|
-
id: TestId;
|
|
14966
|
-
title: TestText;
|
|
14967
|
-
description?: TestText;
|
|
14968
|
-
category?: TestCategory;
|
|
14969
|
-
presentation: TestPresentation;
|
|
14970
|
-
/** Omitted means "nothing" - a pure computation over what it was given. */
|
|
14971
|
-
requires?: readonly TestCapability[];
|
|
14972
|
-
/**
|
|
14973
|
-
* Values the author supplies before pressing Start, drawn as a row of controls in the picker and
|
|
14974
|
-
* handed to `run` as `ctx.parameters`.
|
|
14975
|
-
*
|
|
14976
|
-
* Omitted means the test needs none, which is every test that existed before this: select it,
|
|
14977
|
-
* press Start. Two parameters with the same id are one parameter - the first declaration wins,
|
|
14978
|
-
* because the resolved values are keyed by id and two rows writing one key could not both be
|
|
14979
|
-
* shown honestly.
|
|
14980
|
-
*/
|
|
14981
|
-
parameters?: readonly TestParameterDefinition[];
|
|
14982
|
-
/**
|
|
14983
|
-
* Evaluated when the picker opens, so keep it synchronous and cheap. Absent means always
|
|
14984
|
-
* available; the host still applies its own gates (a `windowed` test is unavailable while the
|
|
14985
|
-
* workspace is frozen, and no test runs at all in a project that is not trusted, no matter what
|
|
14986
|
-
* this returns).
|
|
14987
|
-
*/
|
|
14988
|
-
checkAvailability?(ctx: TestAvailabilityContext): TestAvailability;
|
|
14989
|
-
run(ctx: TestRunContext): Promise<TestVerdict> | TestVerdict;
|
|
14990
|
-
};
|
|
14991
|
-
export declare enum AssetSource {
|
|
14992
|
-
Local = "local",
|
|
14993
|
-
Remote = "remote"
|
|
14994
|
-
}
|
|
14995
|
-
type AssetResolveMeta<Source extends AssetSource> = Source extends AssetSource.Local ? {} : Source extends AssetSource.Remote ? {
|
|
14996
|
-
/** The address the author gave, verbatim. The only field a refresh sends a request to. */
|
|
14997
|
-
url: string;
|
|
14998
|
-
/** When the stored snapshot was taken, ISO 8601. */
|
|
14999
|
-
fetchedAt: string;
|
|
15000
|
-
/**
|
|
15001
|
-
* The server's validators for the stored snapshot, when it offered any. Sent back as
|
|
15002
|
-
* `If-None-Match` / `If-Modified-Since`, so refreshing an unchanged asset transfers no bytes.
|
|
15003
|
-
*/
|
|
15004
|
-
etag?: string;
|
|
15005
|
-
lastModified?: string;
|
|
15006
|
-
/** The response's declared media type. Diagnostic only - the format gate reads the bytes. */
|
|
15007
|
-
contentType?: string;
|
|
15008
|
-
/**
|
|
15009
|
-
* Was to be the runtime cache lifetime, back when a remote asset was going to be fetched by the
|
|
15010
|
-
* shipped game. It never was: the runtime asset manifest carries no URL, so a packaged game has
|
|
15011
|
-
* only the baked bytes, and nothing has ever read this. Kept so records that carry it still
|
|
15012
|
-
* open; the next write drops it. Never write it.
|
|
15013
|
-
*
|
|
15014
|
-
* @deprecated
|
|
15015
|
-
*/
|
|
15016
|
-
lifetime?: number;
|
|
15017
|
-
} : never;
|
|
15018
|
-
/**
|
|
15019
|
-
* Asset interface with user metadata
|
|
15020
|
-
* Stored in assets metadata files
|
|
15021
|
-
*/
|
|
15022
|
-
export interface Asset<Type extends AssetType = AssetType, Source extends AssetSource = AssetSource> {
|
|
15023
|
-
id: string;
|
|
15024
|
-
type: Type;
|
|
15025
|
-
name: string;
|
|
15026
|
-
hash: string;
|
|
15027
|
-
ext?: string;
|
|
15028
|
-
source: Source;
|
|
15029
|
-
meta: AssetResolveMeta<Source>;
|
|
15030
|
-
tags: string[];
|
|
15031
|
-
description: string;
|
|
15032
|
-
groupId?: string;
|
|
15033
|
-
/**
|
|
15034
|
-
* Editor-authored data that rides with the asset record. Persisted in the assets metadata,
|
|
15035
|
-
* which is a project file under version control - so this is for things the *author* decided
|
|
15036
|
-
* (and would want to keep and share), never for derived caches. Anything recomputable belongs
|
|
15037
|
-
* under {@link ProjectNameConvention.EditorThumbnailCache}'s neighbours in `editor/cache/`.
|
|
15038
|
-
*/
|
|
15039
|
-
extras?: AssetExtras;
|
|
15040
|
-
}
|
|
15041
|
-
type AssetAudioLoop = AudioClipRegion;
|
|
15042
|
-
interface AssetExtras {
|
|
15043
|
-
/** Audio only: the loop region shown and edited by the audio preview. */
|
|
15044
|
-
audioLoop?: AssetAudioLoop;
|
|
15045
|
-
/**
|
|
15046
|
-
* Model bundles only: the entry file the author chose, relative to the bundle root.
|
|
15047
|
-
*
|
|
15048
|
-
* The only part of a bundle that is persisted rather than re-read from disk, because it is the
|
|
15049
|
-
* only part that is a *decision*. `files` and `size` are observations and are recomputed on
|
|
15050
|
-
* every read; the entry is a guess Studio made from the file tree that the author may have
|
|
15051
|
-
* corrected, and a guess that silently re-runs would undo the correction.
|
|
15052
|
-
*
|
|
15053
|
-
* Absent means "use the detected entry" - so a bundle whose detection is unambiguous carries no
|
|
15054
|
-
* extra state at all, and re-detection keeps working if a later Studio learns a new format.
|
|
15055
|
-
*/
|
|
15056
|
-
modelEntry?: string;
|
|
15057
|
-
/**
|
|
15058
|
-
* Text assets only: the encoding the author said this file is in.
|
|
15059
|
-
*
|
|
15060
|
-
* A property of the *file*, not of the window, which is why it rides the record into version
|
|
15061
|
-
* control rather than sitting in session state: the point of a shared plan file is that the
|
|
15062
|
-
* colleague who opens the GBK spreadsheet next gets it right without having to know. Outranks
|
|
15063
|
-
* the byte-order-mark sniff on open, because an author who said so has said more than a
|
|
15064
|
-
* heuristic can.
|
|
15065
|
-
*
|
|
15066
|
-
* Written only when the author explicitly reopens or saves under an encoding. Absent - the
|
|
15067
|
-
* normal state - means "sniff the BOM, then UTF-8", so merely reading a file never produces a
|
|
15068
|
-
* change to commit.
|
|
15069
|
-
*/
|
|
15070
|
-
textEncoding?: TextEncodingId;
|
|
15071
|
-
/**
|
|
15072
|
-
* Text assets only: the line ending this file uses.
|
|
15073
|
-
*
|
|
15074
|
-
* Recorded for the same reason as {@link textEncoding}, and needed at all because a *new* text
|
|
15075
|
-
* file is zero bytes: there is nothing in the content to detect, so the platform that created it
|
|
15076
|
-
* is the only thing that can answer. For a file that has content, the content wins - see
|
|
15077
|
-
* `resolveLineEnding` - and this is only the fallback.
|
|
15078
|
-
*/
|
|
15079
|
-
textEol?: PersistedTextEol;
|
|
15579
|
+
textEol?: PersistedTextEol;
|
|
15080
15580
|
/**
|
|
15081
15581
|
* Superseded by {@link audioLoop}, which replaced a free list of markers with the one in/out
|
|
15082
15582
|
* pair a clip actually has. Read only so records written by the short-lived cue-point model
|
|
@@ -15108,11 +15608,6 @@ export interface AssetGroup {
|
|
|
15108
15608
|
createdAt: number;
|
|
15109
15609
|
updatedAt: number;
|
|
15110
15610
|
}
|
|
15111
|
-
declare class ServiceRegistry {
|
|
15112
|
-
private services;
|
|
15113
|
-
get<T extends Service>(service: Services): T;
|
|
15114
|
-
getAll(): Service[];
|
|
15115
|
-
}
|
|
15116
15611
|
type PuppetAppearanceKind = "puppet" | "live2d" | "spine";
|
|
15117
15612
|
type CharacterAppearanceKind = "preset" | "layered" | PuppetAppearanceKind;
|
|
15118
15613
|
type PortraitCrop = {
|
|
@@ -15658,58 +16153,6 @@ declare class Character {
|
|
|
15658
16153
|
subscribe(handler: () => void): () => void;
|
|
15659
16154
|
private handleProfileChange;
|
|
15660
16155
|
}
|
|
15661
|
-
type MoveRejectReason = "invalid_surface" | "invalid_target" | "invalid_movers" | "cycle" | "root_locked";
|
|
15662
|
-
type MoveUiElementsResult = {
|
|
15663
|
-
ok: true;
|
|
15664
|
-
} | {
|
|
15665
|
-
ok: false;
|
|
15666
|
-
reason: MoveRejectReason;
|
|
15667
|
-
};
|
|
15668
|
-
type UIElementSelection = {
|
|
15669
|
-
editor: "ui";
|
|
15670
|
-
surfaceId: UISurfaceId;
|
|
15671
|
-
elementIds: UIElementId[];
|
|
15672
|
-
primaryId?: UIElementId;
|
|
15673
|
-
};
|
|
15674
|
-
type ImageFillMode = "cover" | "contain" | "stretch" | "crop" | "tile";
|
|
15675
|
-
interface ImageFillCropPlacement {
|
|
15676
|
-
leftPct: number;
|
|
15677
|
-
topPct: number;
|
|
15678
|
-
widthPct: number;
|
|
15679
|
-
heightPct: number;
|
|
15680
|
-
}
|
|
15681
|
-
interface ImageFill {
|
|
15682
|
-
mode: ImageFillMode;
|
|
15683
|
-
assetId?: string | null;
|
|
15684
|
-
cropPlacement?: ImageFillCropPlacement;
|
|
15685
|
-
}
|
|
15686
|
-
type UIListItemScope = {
|
|
15687
|
-
item: unknown;
|
|
15688
|
-
index: number;
|
|
15689
|
-
count: number;
|
|
15690
|
-
key: string;
|
|
15691
|
-
/**
|
|
15692
|
-
* Whether this is the selected row.
|
|
15693
|
-
*
|
|
15694
|
-
* On the scope because it belongs to the row rather than to any one widget in it: everything in
|
|
15695
|
-
* a selected row reads as selected, and each widget decides for itself whether it has an
|
|
15696
|
-
* appearance row that says so.
|
|
15697
|
-
*/
|
|
15698
|
-
selected?: boolean;
|
|
15699
|
-
/**
|
|
15700
|
-
* The shape the owning list declared, carried rather than looked up.
|
|
15701
|
-
*
|
|
15702
|
-
* A field binding is resolved deep inside the element merge, which holds an element and a scope
|
|
15703
|
-
* and no document. Putting the struct on the scope keeps that read a read - the list already
|
|
15704
|
-
* resolved it once for its own columns and keys.
|
|
15705
|
-
*/
|
|
15706
|
-
struct?: UIStructDef | null;
|
|
15707
|
-
};
|
|
15708
|
-
type BehaviorNodeExecuteResult = {
|
|
15709
|
-
nextPort?: string;
|
|
15710
|
-
nextPorts?: string[];
|
|
15711
|
-
outputValues?: Record<string, unknown>;
|
|
15712
|
-
};
|
|
15713
16156
|
type StoryBlockSelection = {
|
|
15714
16157
|
editor: "story";
|
|
15715
16158
|
tabId: string;
|
|
@@ -15942,6 +16385,13 @@ type LiveUIOp =
|
|
|
15942
16385
|
*/
|
|
15943
16386
|
updates?: readonly LiveUIElementRef[];
|
|
15944
16387
|
};
|
|
16388
|
+
type MoveRejectReason = "invalid_surface" | "invalid_target" | "invalid_movers" | "cycle" | "root_locked";
|
|
16389
|
+
type MoveUiElementsResult = {
|
|
16390
|
+
ok: true;
|
|
16391
|
+
} | {
|
|
16392
|
+
ok: false;
|
|
16393
|
+
reason: MoveRejectReason;
|
|
16394
|
+
};
|
|
15945
16395
|
declare const UI_EDITOR_CLIPBOARD_VERSION: 1;
|
|
15946
16396
|
declare const UI_EDITOR_CLIPBOARD_KIND: "narraleaf.ui.elements";
|
|
15947
16397
|
type UIEditorClipboardSource = {
|
|
@@ -16022,8 +16472,28 @@ declare class UIDocumentService extends Service<UIDocumentService> implements IU
|
|
|
16022
16472
|
private readonly contentRevisions;
|
|
16023
16473
|
protected init(ctx: WorkspaceContext, depend: (services: Service[]) => Promise<void>): Promise<void>;
|
|
16024
16474
|
getDocument(): UIDocument;
|
|
16475
|
+
/**
|
|
16476
|
+
* The project's document: every page with its elements, and every component definition.
|
|
16477
|
+
*
|
|
16478
|
+
* The same object as {@link getDocument} here. It is its own method for the component editor,
|
|
16479
|
+
* whose document service answers `getDocument` with a view of one definition - the definition's
|
|
16480
|
+
* elements and none of the pages' - and answers this with the project's. Whatever asks where a
|
|
16481
|
+
* Page widget's page leads (what that page places, what its own Page widgets draw) asks this.
|
|
16482
|
+
*/
|
|
16483
|
+
getPageDocument(): UIDocument;
|
|
16025
16484
|
load(): Promise<UIDocument>;
|
|
16485
|
+
/**
|
|
16486
|
+
* Write `document` now instead of waiting for the auto-save.
|
|
16487
|
+
*
|
|
16488
|
+
* A write that fails is handed back to the auto-saver, which retries it on its backoff. This
|
|
16489
|
+
* cancels the saver's pending write because it supersedes it, and without handing it back the
|
|
16490
|
+
* change would wait for the author's next edit - while the save-failure notice, told this file
|
|
16491
|
+
* is one a saver retries, says it is being retried. Not before the document is loaded: a seed
|
|
16492
|
+
* written while the project opens has nothing for the saver to write, and its failure fails the
|
|
16493
|
+
* open.
|
|
16494
|
+
*/
|
|
16026
16495
|
save(document: UIDocument): Promise<void>;
|
|
16496
|
+
private writeDocument;
|
|
16027
16497
|
/**
|
|
16028
16498
|
* The one route `uidoc.json` goes out by.
|
|
16029
16499
|
*
|
|
@@ -16456,7 +16926,7 @@ declare class UIDocumentService extends Service<UIDocumentService> implements IU
|
|
|
16456
16926
|
private ensureDocumentDir;
|
|
16457
16927
|
}
|
|
16458
16928
|
type WidgetLogicEventDispatchKind = "lifecycle" | "interaction";
|
|
16459
|
-
type WidgetLogicEventDef = {
|
|
16929
|
+
export type WidgetLogicEventDef = {
|
|
16460
16930
|
id: string;
|
|
16461
16931
|
displayName: string;
|
|
16462
16932
|
description?: string;
|
|
@@ -16485,7 +16955,7 @@ type WidgetLogicWritablePropDef = {
|
|
|
16485
16955
|
displayName: string;
|
|
16486
16956
|
description?: string;
|
|
16487
16957
|
};
|
|
16488
|
-
type WidgetLogicApi = {
|
|
16958
|
+
export type WidgetLogicApi = {
|
|
16489
16959
|
supportsPrivateBlueprint: boolean;
|
|
16490
16960
|
blueprintLabel?: string;
|
|
16491
16961
|
events: readonly WidgetLogicEventDef[];
|
|
@@ -16819,6 +17289,14 @@ interface TagsFieldDefinition<TData = any> extends BaseFieldDefinition<TData> {
|
|
|
16819
17289
|
getValue: (data: TData) => string[];
|
|
16820
17290
|
addTag: (data: TData, tag: string) => void | Promise<void>;
|
|
16821
17291
|
removeTag: (data: TData, tag: string) => void | Promise<void>;
|
|
17292
|
+
/**
|
|
17293
|
+
* What a stored tag's chip says, or null for a tag that gets no chip. Absent: every tag is its
|
|
17294
|
+
* own chip, as written.
|
|
17295
|
+
*
|
|
17296
|
+
* Only the display changes. The list still holds every stored tag, so adding one keeps the tags
|
|
17297
|
+
* that are not drawn, and removing a chip removes exactly the tag it stands for.
|
|
17298
|
+
*/
|
|
17299
|
+
formatTag?: (data: TData, tag: string) => string | null;
|
|
16822
17300
|
}
|
|
16823
17301
|
interface InfoFieldDefinition<TData = any> extends BaseFieldDefinition<TData> {
|
|
16824
17302
|
type: "info";
|
|
@@ -16912,254 +17390,668 @@ type UIInspectorData = {
|
|
|
16912
17390
|
/** Set when inspecting a canvas widget; required for Blueprint M2 binding UI. */
|
|
16913
17391
|
surfaceId?: string;
|
|
16914
17392
|
};
|
|
16915
|
-
type DockerBarItem = DockerBarButton | DockerBarSelect | DockerBarNumberInput | DockerBarSeparator;
|
|
16916
|
-
type DockerBarButton = {
|
|
16917
|
-
kind: "button";
|
|
16918
|
-
id: string;
|
|
16919
|
-
icon?: LucideIcon;
|
|
16920
|
-
label?: string;
|
|
16921
|
-
tooltip?: string;
|
|
16922
|
-
disabled?: boolean;
|
|
16923
|
-
active?: boolean;
|
|
16924
|
-
onClick: () => void;
|
|
17393
|
+
type DockerBarItem = DockerBarButton | DockerBarSelect | DockerBarNumberInput | DockerBarSeparator;
|
|
17394
|
+
type DockerBarButton = {
|
|
17395
|
+
kind: "button";
|
|
17396
|
+
id: string;
|
|
17397
|
+
icon?: LucideIcon;
|
|
17398
|
+
label?: string;
|
|
17399
|
+
tooltip?: string;
|
|
17400
|
+
disabled?: boolean;
|
|
17401
|
+
active?: boolean;
|
|
17402
|
+
onClick: () => void;
|
|
17403
|
+
};
|
|
17404
|
+
type DockerBarSelect = {
|
|
17405
|
+
kind: "select";
|
|
17406
|
+
id: string;
|
|
17407
|
+
label?: string;
|
|
17408
|
+
tooltip?: string;
|
|
17409
|
+
value: string | number;
|
|
17410
|
+
options: {
|
|
17411
|
+
value: string | number;
|
|
17412
|
+
label: string;
|
|
17413
|
+
}[];
|
|
17414
|
+
/** Added for the read-only surface: without it a frozen workspace still offered the dropdown. */
|
|
17415
|
+
disabled?: boolean;
|
|
17416
|
+
onChange: (value: string | number) => void;
|
|
17417
|
+
};
|
|
17418
|
+
type DockerBarNumberInput = {
|
|
17419
|
+
kind: "number";
|
|
17420
|
+
id: string;
|
|
17421
|
+
label?: string;
|
|
17422
|
+
tooltip?: string;
|
|
17423
|
+
value: number;
|
|
17424
|
+
min?: number;
|
|
17425
|
+
max?: number;
|
|
17426
|
+
step?: number;
|
|
17427
|
+
disabled?: boolean;
|
|
17428
|
+
readOnly?: boolean;
|
|
17429
|
+
onChange: (value: number) => void;
|
|
17430
|
+
placeholder?: string;
|
|
17431
|
+
inputProps?: React$1.InputHTMLAttributes<HTMLInputElement>;
|
|
17432
|
+
};
|
|
17433
|
+
type DockerBarSeparator = {
|
|
17434
|
+
kind: "separator";
|
|
17435
|
+
id: string;
|
|
17436
|
+
};
|
|
17437
|
+
type FloatingToolbarButton = {
|
|
17438
|
+
kind: "button";
|
|
17439
|
+
id: string;
|
|
17440
|
+
icon?: LucideIcon;
|
|
17441
|
+
label?: string;
|
|
17442
|
+
tooltip?: string;
|
|
17443
|
+
disabled?: boolean;
|
|
17444
|
+
onClick: () => void;
|
|
17445
|
+
};
|
|
17446
|
+
type FloatingToolbarItem = FloatingToolbarButton;
|
|
17447
|
+
type DefaultChildElementContext = {
|
|
17448
|
+
element: UIElement;
|
|
17449
|
+
generateId: () => string;
|
|
17450
|
+
};
|
|
17451
|
+
type DefaultChildElementResult = {
|
|
17452
|
+
elementPatch?: Partial<UIElement>;
|
|
17453
|
+
children: UIElement[];
|
|
17454
|
+
};
|
|
17455
|
+
type BehaviorNodeExecuteResult = {
|
|
17456
|
+
nextPort?: string;
|
|
17457
|
+
nextPorts?: string[];
|
|
17458
|
+
outputValues?: Record<string, unknown>;
|
|
17459
|
+
};
|
|
17460
|
+
type BlueprintPinSemantic = "exec" | "data";
|
|
17461
|
+
export type BlueprintNodePinDef = {
|
|
17462
|
+
id: string;
|
|
17463
|
+
kind: "input" | "output";
|
|
17464
|
+
semantic: BlueprintPinSemantic;
|
|
17465
|
+
/** Loose type tag for data pins (e.g. boolean, string) */
|
|
17466
|
+
valueType?: string;
|
|
17467
|
+
label?: string;
|
|
17468
|
+
/** Optional inputs render as inactive until wired and resolve to runtime default/undefined when omitted. */
|
|
17469
|
+
optional?: boolean;
|
|
17470
|
+
/**
|
|
17471
|
+
* When true, the flow node may show a hover-only control to open an on-card input for this pin
|
|
17472
|
+
* when it is unwired. Only valid with kind=input, semantic=data, and valueType
|
|
17473
|
+
* string|integer|float|boolean.
|
|
17474
|
+
*/
|
|
17475
|
+
allowInlineLiteral?: boolean;
|
|
17476
|
+
/**
|
|
17477
|
+
* Set when this pin carries a library asset id. Read by the asset reverse-lookup index, which
|
|
17478
|
+
* walks the catalogue rather than a hard-coded list of param names - so a node added later is
|
|
17479
|
+
* covered by declaring it here and nowhere else.
|
|
17480
|
+
*/
|
|
17481
|
+
assetRef?: BlueprintAssetPinRef;
|
|
17482
|
+
/**
|
|
17483
|
+
* This output's own answer to {@link BlueprintNodeDeclaration.assetNames}, for the one node in
|
|
17484
|
+
* which outputs differ: `Get All Properties` reads a font the project picked beside a text the
|
|
17485
|
+
* game may have written.
|
|
17486
|
+
*/
|
|
17487
|
+
assetName?: BlueprintAssetNameFlow;
|
|
17488
|
+
};
|
|
17489
|
+
/**
|
|
17490
|
+
* Where the strings a node outputs come from, as far as an asset name is concerned.
|
|
17491
|
+
*
|
|
17492
|
+
* A game package carries every library asset whose name is written down somewhere in the project,
|
|
17493
|
+
* so an asset name that reaches a picture, a sound or a typeface is only a problem when it is put
|
|
17494
|
+
* together while the game runs. Every node whose outputs can carry a string says which of three
|
|
17495
|
+
* things it does, and the asset-name judgement (`assetNameFlow`) follows values through it by that:
|
|
17496
|
+
*
|
|
17497
|
+
* - `"forward"`: every output is one of the node's inputs, part of one, or a collection of them -
|
|
17498
|
+
* Memo, Array Get, Get JSON Field, Make Object. An asset name comes out only if one went in.
|
|
17499
|
+
* - `"written"`: every output is written down in the project - a literal, the Gallery catalogue, a
|
|
17500
|
+
* localized string, the picture an element holds (every write to which is itself checked).
|
|
17501
|
+
* - `"assembled"`: an output may be a string that exists only while the game runs - Concat, Format,
|
|
17502
|
+
* what the player typed, what a server sent. A name out of one of these is refused where it is
|
|
17503
|
+
* used as an asset.
|
|
17504
|
+
*
|
|
17505
|
+
* **Undeclared means `"assembled"`.** The bar only moves the safe way: a node that says nothing is
|
|
17506
|
+
* assumed to make its strings up, and a registry test fails for any built-in node with a
|
|
17507
|
+
* string-carrying output that has not said which. Plugins declare it the same way; a plugin node
|
|
17508
|
+
* that says nothing is treated as assembling.
|
|
17509
|
+
*/
|
|
17510
|
+
export type BlueprintAssetNameFlow = "forward" | "written" | "assembled";
|
|
17511
|
+
type BlueprintNodeDynamicInputPinsConfig = {
|
|
17512
|
+
/** Param key on node.params for string[] of additional input pin ids. */
|
|
17513
|
+
storageKey: string;
|
|
17514
|
+
/** Data input pin ids from def.pins that cannot be removed. */
|
|
17515
|
+
fixedDataInputIds: readonly string[];
|
|
17516
|
+
/** Generated ids use `${prefix}_${n}` with n increasing until unused. */
|
|
17517
|
+
generatedIdPrefix: string;
|
|
17518
|
+
valueType: string;
|
|
17519
|
+
allowInlineLiteral: boolean;
|
|
17520
|
+
/**
|
|
17521
|
+
* Optional grouped pins generated from one add action. When omitted, one pin id
|
|
17522
|
+
* `${prefix}_${n}` is created with valueType / allowInlineLiteral above.
|
|
17523
|
+
*/
|
|
17524
|
+
generatedPinTemplates?: readonly {
|
|
17525
|
+
/** Generated ids use `${prefix}_${n}_${idSuffix}`. */
|
|
17526
|
+
idSuffix: string;
|
|
17527
|
+
label: string;
|
|
17528
|
+
kind?: "input" | "output";
|
|
17529
|
+
semantic?: BlueprintPinSemantic;
|
|
17530
|
+
valueType?: string;
|
|
17531
|
+
optional?: boolean;
|
|
17532
|
+
allowInlineLiteral?: boolean;
|
|
17533
|
+
}[];
|
|
17534
|
+
/**
|
|
17535
|
+
* Number the labels of generated pins by the add that produced them: the first add reads
|
|
17536
|
+
* `Button 1` / `Pressed 1`, the second `Button 2` / `Pressed 2`.
|
|
17537
|
+
*
|
|
17538
|
+
* Off by default, and deliberately so. A template label is otherwise rendered verbatim, which
|
|
17539
|
+
* is right where the pin already carries its own meaning - `Switch String` puts the value it
|
|
17540
|
+
* compares on the pin, so every generated `Case` is told apart by what is written in it. It is
|
|
17541
|
+
* wrong where the pins are interchangeable and their ORDER is the meaning, which is the case
|
|
17542
|
+
* for a row of buttons: unnumbered, the third button and its exec output are indistinguishable
|
|
17543
|
+
* from the first, and an author cannot tell which branch they are wiring.
|
|
17544
|
+
*/
|
|
17545
|
+
numberGeneratedPinLabels?: boolean;
|
|
17546
|
+
/** When dynamic output pins exist, insert them before this static output pin id. */
|
|
17547
|
+
outputInsertBeforePinId?: string;
|
|
17548
|
+
/** Optional display label prefix for generated pins. Defaults to "Input". */
|
|
17549
|
+
labelPrefix?: string;
|
|
17550
|
+
/** Optional label for the node-card add button. */
|
|
17551
|
+
addButtonLabel?: string;
|
|
17552
|
+
/** Optional param key storing user-visible labels by generated pin id. */
|
|
17553
|
+
pinLabelParamKey?: string;
|
|
17554
|
+
/** Optional prefix used when initializing labels in pinLabelParamKey. */
|
|
17555
|
+
defaultPinLabelPrefix?: string;
|
|
17556
|
+
/** Optional param key storing per-pin valueType overrides (Record<pinId, valueType>). */
|
|
17557
|
+
pinValueTypeParamKey?: string;
|
|
17558
|
+
/** Allowed valueTypes for the on-card per-pin type picker; presence enables the picker. */
|
|
17559
|
+
pinValueTypeOptions?: readonly string[];
|
|
17560
|
+
/** When true, generated OUTPUT pins also get remove/label/type controls (default: inputs only). */
|
|
17561
|
+
editableGeneratedOutputPins?: boolean;
|
|
17562
|
+
};
|
|
17563
|
+
type BlueprintJsonValueSchema = {
|
|
17564
|
+
kind: "object" | "array" | "string" | "number" | "boolean" | "null";
|
|
17565
|
+
label?: string;
|
|
17566
|
+
/** Object fields are fixed schema entries. Unknown fields are rejected unless allowExtraFields is true. */
|
|
17567
|
+
fields?: readonly {
|
|
17568
|
+
key: string;
|
|
17569
|
+
label?: string;
|
|
17570
|
+
kind: "object" | "array" | "string" | "number" | "boolean" | "null";
|
|
17571
|
+
required?: boolean;
|
|
17572
|
+
}[];
|
|
17573
|
+
allowExtraFields?: boolean;
|
|
17574
|
+
};
|
|
17575
|
+
type BlueprintInspectorParamKind = "string" | "number" | "json" | "color" | "keyboardBinding" | "literal" | "variableRef" | "persistentVariableRef" | "sceneVariableRef" | "savedVariableRef" | "select" | "imageAsset"
|
|
17576
|
+
/** Bare asset-id string (audio has no ImageAsset-style envelope). */
|
|
17577
|
+
| "audioAsset" | "buttonCursor";
|
|
17578
|
+
export type BlueprintInspectorParamSelectOption = {
|
|
17579
|
+
value: string;
|
|
17580
|
+
label: string;
|
|
17581
|
+
meta?: Record<string, string>;
|
|
17582
|
+
};
|
|
17583
|
+
type BlueprintInspectorParamDef = {
|
|
17584
|
+
key: string;
|
|
17585
|
+
label: string;
|
|
17586
|
+
kind: BlueprintInspectorParamKind;
|
|
17587
|
+
/** Optional fixed schema for structured JSON-like values such as Vector2D. */
|
|
17588
|
+
jsonSchema?: BlueprintJsonValueSchema;
|
|
17589
|
+
/**
|
|
17590
|
+
* For `kind: "select"`: static options rendered as a `<select>` dropdown.
|
|
17591
|
+
* When omitted with `kind: "select"`, the node card will look for
|
|
17592
|
+
* dynamically provided options via `dynamicOptionsSource`.
|
|
17593
|
+
*/
|
|
17594
|
+
options?: BlueprintInspectorParamSelectOption[];
|
|
17595
|
+
/**
|
|
17596
|
+
* For `kind: "select"` without static `options`: the flow projection
|
|
17597
|
+
* populates options from context data keyed by this source id.
|
|
17598
|
+
* Known sources include `"surfaces"` (available App Surfaces) and
|
|
17599
|
+
* `"frameTargetSurfaces"` (Page targets filtered for the inferred Frame).
|
|
17600
|
+
*/
|
|
17601
|
+
dynamicOptionsSource?: string;
|
|
17602
|
+
/** Label for the empty select option. Defaults to "-". */
|
|
17603
|
+
emptyOptionLabel?: string;
|
|
17604
|
+
/**
|
|
17605
|
+
* Filter dynamic select options by comparing another param value with option metadata.
|
|
17606
|
+
* Used for dependent dropdowns such as Story -> Scene.
|
|
17607
|
+
*/
|
|
17608
|
+
dynamicOptionsFilter?: {
|
|
17609
|
+
paramKey: string;
|
|
17610
|
+
optionMetaKey: string;
|
|
17611
|
+
};
|
|
17612
|
+
};
|
|
17613
|
+
type BlueprintNodeRole = "normal" | "eventHead" | "fnHead" | "functionEntry" | "reroute" | "dataLiteral" | "elementLiteral" | "elementEventHead" | "imageAssetLiteral" | "valueReturn" | "comment";
|
|
17614
|
+
type BlueprintNodeDeclaration = {
|
|
17615
|
+
type: string;
|
|
17616
|
+
displayName: string;
|
|
17617
|
+
category: string;
|
|
17618
|
+
keywords?: string[];
|
|
17619
|
+
/** Graph kinds where this node may appear */
|
|
17620
|
+
graphKinds: BlueprintGraphKind[];
|
|
17621
|
+
/** Keep registered for old graphs/runtime, but omit from add-node palette. */
|
|
17622
|
+
hideInPalette?: boolean;
|
|
17623
|
+
/** Creates palette entries for bound Element outputs that can be manually wired to this input. */
|
|
17624
|
+
magicElementTarget?: {
|
|
17625
|
+
inputPinId: string;
|
|
17626
|
+
elementTypes?: readonly string[];
|
|
17627
|
+
};
|
|
17628
|
+
/** Pure nodes have no side effects; used for validation hints */
|
|
17629
|
+
isPure: boolean;
|
|
17630
|
+
/**
|
|
17631
|
+
* Opt in to Blueprint Value graphs - the per-property value providers behind a widget's
|
|
17632
|
+
* `valueBindings`.
|
|
17633
|
+
*
|
|
17634
|
+
* Only meaningful on a node the host did not define. The built-in catalogue is admitted there by
|
|
17635
|
+
* review instead (see `isBlueprintNodeAllowedInBlueprintValueGraph`), and there is no way to
|
|
17636
|
+
* review a plugin's node the same way - `isPure` on one is the plugin's own word - so a plugin
|
|
17637
|
+
* declares for itself and what the value runtime already does is the real limit. It is executed
|
|
17638
|
+
* like any other node, its capability-gated domains are absent while the editor previews it, and
|
|
17639
|
+
* a graph that never reaches Return Value leaves the binding on whatever it resolved last. The
|
|
17640
|
+
* sharpest of those limits: the runtime records the Element and property reads it resolves and
|
|
17641
|
+
* reruns the binding when those change, and it cannot see what a plugin node read - so a binding
|
|
17642
|
+
* built on one refreshes on the host's dependencies, never on the plugin's.
|
|
17643
|
+
*/
|
|
17644
|
+
allowInBlueprintValueGraph?: boolean;
|
|
17645
|
+
/**
|
|
17646
|
+
* The node reads the list row that is in scope while it runs, so it belongs only where a row can
|
|
17647
|
+
* be: on an element a list draws once per row, or on the list itself, whose item heads each run
|
|
17648
|
+
* for one row. Enforced by `isBlueprintNodeAllowedInGraphContext`, so the palette and the graph
|
|
17649
|
+
* validator answer it the same way.
|
|
17650
|
+
*/
|
|
17651
|
+
requiresListItemContext?: boolean;
|
|
17652
|
+
/**
|
|
17653
|
+
* Where this node's string-carrying outputs come from - see {@link BlueprintAssetNameFlow}.
|
|
17654
|
+
* Absent reads as `"assembled"`.
|
|
17655
|
+
*/
|
|
17656
|
+
assetNames?: BlueprintAssetNameFlow;
|
|
17657
|
+
/** Latent/async execution (delay, host awaits) - disallowed in function graphs */
|
|
17658
|
+
isLatent?: boolean;
|
|
17659
|
+
pins: BlueprintNodePinDef[];
|
|
17660
|
+
/** When set, users may add/remove extra data input pins (persisted in params). */
|
|
17661
|
+
dynamicInputPins?: BlueprintNodeDynamicInputPinsConfig;
|
|
17662
|
+
/**
|
|
17663
|
+
* Grow one pin per field the project's save schema declares (see `@shared/types/saveSchema`).
|
|
17664
|
+
*
|
|
17665
|
+
* Unlike {@link dynamicInputPins}, these come from a project document rather than from this
|
|
17666
|
+
* node's params - which is the point. `Save Game` and `Get Save Metadata` are a contract across
|
|
17667
|
+
* time, so both read one list and grow the same pins in the same order; a per-node list would
|
|
17668
|
+
* be as many copies as there are save nodes, drifting by hand.
|
|
17669
|
+
*/
|
|
17670
|
+
saveSchemaPins?: {
|
|
17671
|
+
kind: "input" | "output";
|
|
17672
|
+
};
|
|
17673
|
+
inspectorParams?: BlueprintInspectorParamDef[];
|
|
17674
|
+
role?: BlueprintNodeRole;
|
|
17675
|
+
};
|
|
17676
|
+
interface ProjectProps {
|
|
17677
|
+
projectPath: string;
|
|
17678
|
+
}
|
|
17679
|
+
declare class Porject {
|
|
17680
|
+
private config;
|
|
17681
|
+
constructor(config: ProjectProps);
|
|
17682
|
+
getFileName(dest: string[]): string;
|
|
17683
|
+
getTargetPath(dest: string[]): string;
|
|
17684
|
+
isDir(dest: string[]): boolean;
|
|
17685
|
+
resolve(...paths: (Readonly<string[]> | string)[]): string;
|
|
17686
|
+
getConfig(): ProjectProps;
|
|
17687
|
+
}
|
|
17688
|
+
/**
|
|
17689
|
+
* The test pipeline - the vocabulary.
|
|
17690
|
+
*
|
|
17691
|
+
* "Test" here means a check an author runs against *their game*: does it reach an ending, does it
|
|
17692
|
+
* survive with no network, does a plugin's feature still behave. It is not vitest; nothing in this
|
|
17693
|
+
* file has anything to do with the repo's own unit tests.
|
|
17694
|
+
*
|
|
17695
|
+
* A test is a definition object in a registry that both Studio's built-in modules and plugins
|
|
17696
|
+
* populate (see `registry.ts`), started from Run > Test. Five decisions are load-bearing and worth
|
|
17697
|
+
* knowing before editing anything here:
|
|
17698
|
+
*
|
|
17699
|
+
* - **A test may only say passed / failed / skipped.** `cancelled` and `errored` are verdicts the
|
|
17700
|
+
* *host* reaches about a test, and a test that could claim them could lie about being killed.
|
|
17701
|
+
* Cancellation arrives as `ctx.signal`; a test that wants "the author aborted me" to count as a
|
|
17702
|
+
* failure is free to catch it and return `failed`, which is how a windowed test whose contract is
|
|
17703
|
+
* "close the window when satisfied" expresses termination.
|
|
17704
|
+
* - **Undeclared capabilities are absent, not throwing.** `requires` is the whole truth about what
|
|
17705
|
+
* a test can reach: `ctx.game` is `undefined` unless `game.launch` was declared, exactly as
|
|
17706
|
+
* `app.game`'s domains work for runtime plugins. What the picker lists and what the test can do
|
|
17707
|
+
* are the same set by construction. `parameters` obeys the same rule from the other direction:
|
|
17708
|
+
* `ctx.parameters` carries a value for every id the test *declared* and for no other, so it is a
|
|
17709
|
+
* resolved set rather than a free-form bag the picker could put anything into.
|
|
17710
|
+
* - **Tests never build prose.** Every author-visible string is a `TestText` - an i18n key for
|
|
17711
|
+
* Studio's own tests, a literal for a plugin's (a plugin has no `TranslationKey`s, and its own
|
|
17712
|
+
* translator produces plain strings). The console channel and the report tab each render it.
|
|
17713
|
+
* - **Severity is on the finding, unlike lint.** A lint rule defers severity to the project's
|
|
17714
|
+
* config; a test has no such table, and its verdict is stated separately by `run`. A finding here
|
|
17715
|
+
* is evidence for a verdict the test already reached, so it carries its own weight.
|
|
17716
|
+
* - **`presentation` is a declaration, not a mechanism.** Whether a window appears is a consequence
|
|
17717
|
+
* of asking the host for a game session. The field is what the picker badges and what lets the
|
|
17718
|
+
* author know a window is about to open; a headless test that launches one is a host error.
|
|
17719
|
+
*/
|
|
17720
|
+
/**
|
|
17721
|
+
* Bumped when a change here would break an already-published plugin.
|
|
17722
|
+
*
|
|
17723
|
+
* Recorded on every run record so a report kept across an upgrade still says which contract produced
|
|
17724
|
+
* it, and surfaced to plugins so a definition can refuse a host older than it needs.
|
|
17725
|
+
*
|
|
17726
|
+
* **2** added parameters: a test may declare values the author supplies before pressing Start
|
|
17727
|
+
* (`TestDefinition.parameters`), and every run context now carries `parameters` - a required member,
|
|
17728
|
+
* which is what makes this a break rather than an addition. A definition compiled against 1 keeps
|
|
17729
|
+
* working unchanged, since declaring none resolves to `{}`.
|
|
17730
|
+
*/
|
|
17731
|
+
export declare const TEST_PROTOCOL_VERSION = 2;
|
|
17732
|
+
/**
|
|
17733
|
+
* Stable identifier. Studio's own tests are `narraleaf-studio:<slug>`; a plugin's must be prefixed
|
|
17734
|
+
* with its plugin id, which the host enforces at registration rather than trusting.
|
|
17735
|
+
*/
|
|
17736
|
+
export type TestId = string;
|
|
17737
|
+
/** Grouping in the picker. `custom` is where a plugin lands when it claims nothing else. */
|
|
17738
|
+
export type TestCategory = "integrity" | "runtime" | "compatibility" | "custom";
|
|
17739
|
+
/**
|
|
17740
|
+
* Does this test put a game window on screen?
|
|
17741
|
+
*
|
|
17742
|
+
* `headless` is the interesting half: a test with no window can run while the author keeps working,
|
|
17743
|
+
* and is the only kind that can run on a frozen workspace.
|
|
17744
|
+
*/
|
|
17745
|
+
export type TestPresentation = "headless" | "windowed";
|
|
17746
|
+
/**
|
|
17747
|
+
* What the host lends a test. Anything not declared is absent from `TestRunContext`.
|
|
17748
|
+
*
|
|
17749
|
+
* Deliberately coarse and short. A capability is added here only when a test genuinely cannot be
|
|
17750
|
+
* written without it - the failure mode this vocabulary exists to prevent is the one where a narrow
|
|
17751
|
+
* API is nominally narrow but hands out a reference that reaches everything.
|
|
17752
|
+
*/
|
|
17753
|
+
export type TestCapability =
|
|
17754
|
+
/** Read the project's stories and scenes. Read-only by construction: there is no write half. */
|
|
17755
|
+
"project.read"
|
|
17756
|
+
/** Launch, observe and stop a game process. Implies a window unless the launch asks otherwise. */
|
|
17757
|
+
| "game.launch";
|
|
17758
|
+
/**
|
|
17759
|
+
* An author-visible string.
|
|
17760
|
+
*
|
|
17761
|
+
* Two shapes rather than one, because the two producers genuinely differ: Studio's tests name a key
|
|
17762
|
+
* in its catalogue and must re-render when the editor language changes, while a plugin has no key
|
|
17763
|
+
* space of its own and hands over whatever its own translator already produced.
|
|
17764
|
+
*/
|
|
17765
|
+
export type TestText = {
|
|
17766
|
+
key: TranslationKey;
|
|
17767
|
+
params?: Record<string, string | number>;
|
|
17768
|
+
text?: undefined;
|
|
17769
|
+
} | {
|
|
17770
|
+
text: string;
|
|
17771
|
+
key?: undefined;
|
|
17772
|
+
};
|
|
17773
|
+
/** Same ladder as the workspace console, so a test log line needs no translation at the boundary. */
|
|
17774
|
+
export type TestLogLevel = GameTestLogLevel;
|
|
17775
|
+
/**
|
|
17776
|
+
* Progress, or `null` to go back to indeterminate.
|
|
17777
|
+
*
|
|
17778
|
+
* `total` is optional because most interesting tests genuinely do not know it up front (how many
|
|
17779
|
+
* routes a story has is what walking it discovers). Omitting it renders the same indeterminate bar
|
|
17780
|
+
* the build uses rather than a fake fraction.
|
|
17781
|
+
*/
|
|
17782
|
+
export type TestProgress = {
|
|
17783
|
+
completed: number;
|
|
17784
|
+
total?: number;
|
|
17785
|
+
label?: TestText;
|
|
16925
17786
|
};
|
|
16926
|
-
type
|
|
16927
|
-
|
|
16928
|
-
|
|
16929
|
-
|
|
16930
|
-
|
|
16931
|
-
|
|
16932
|
-
options: {
|
|
16933
|
-
value: string | number;
|
|
16934
|
-
label: string;
|
|
16935
|
-
}[];
|
|
16936
|
-
/** Added for the read-only surface: without it a frozen workspace still offered the dropdown. */
|
|
16937
|
-
disabled?: boolean;
|
|
16938
|
-
onChange: (value: string | number) => void;
|
|
17787
|
+
export type TestFindingSeverity = "error" | "warning" | "info";
|
|
17788
|
+
/** One piece of evidence. `target` reuses the global-search navigation layer, so the report tab's click-to-jump is existing machinery. */
|
|
17789
|
+
export type TestFinding = {
|
|
17790
|
+
severity: TestFindingSeverity;
|
|
17791
|
+
message: TestText;
|
|
17792
|
+
target?: SearchJumpTarget;
|
|
16939
17793
|
};
|
|
16940
|
-
|
|
16941
|
-
|
|
16942
|
-
|
|
16943
|
-
|
|
16944
|
-
|
|
16945
|
-
|
|
16946
|
-
|
|
16947
|
-
|
|
16948
|
-
|
|
16949
|
-
|
|
16950
|
-
|
|
16951
|
-
|
|
16952
|
-
|
|
16953
|
-
|
|
17794
|
+
/**
|
|
17795
|
+
* What `run` may return. Note the absence of `cancelled` and `errored`: see the header.
|
|
17796
|
+
*
|
|
17797
|
+
* `skipped` exists so a test can decline for a reason it only discovers while running (a project
|
|
17798
|
+
* with no localisation configured, say) without pretending to have passed. A test that can tell
|
|
17799
|
+
* before it starts should say so from `checkAvailability` instead, so the picker greys it out.
|
|
17800
|
+
*/
|
|
17801
|
+
export type TestVerdict = {
|
|
17802
|
+
status: "passed";
|
|
17803
|
+
summary?: TestText;
|
|
17804
|
+
} | {
|
|
17805
|
+
status: "failed";
|
|
17806
|
+
summary: TestText;
|
|
17807
|
+
} | {
|
|
17808
|
+
status: "skipped";
|
|
17809
|
+
summary: TestText;
|
|
16954
17810
|
};
|
|
16955
|
-
type
|
|
16956
|
-
kind: "separator";
|
|
17811
|
+
export type TestStoryRef = {
|
|
16957
17812
|
id: string;
|
|
17813
|
+
name: string;
|
|
16958
17814
|
};
|
|
16959
|
-
type
|
|
16960
|
-
kind: "button";
|
|
17815
|
+
export type TestSceneRef = {
|
|
16961
17816
|
id: string;
|
|
16962
|
-
|
|
16963
|
-
label?: string;
|
|
16964
|
-
tooltip?: string;
|
|
16965
|
-
disabled?: boolean;
|
|
16966
|
-
onClick: () => void;
|
|
16967
|
-
};
|
|
16968
|
-
type FloatingToolbarItem = FloatingToolbarButton;
|
|
16969
|
-
type DefaultChildElementContext = {
|
|
16970
|
-
element: UIElement;
|
|
16971
|
-
generateId: () => string;
|
|
17817
|
+
name: string;
|
|
16972
17818
|
};
|
|
16973
|
-
|
|
16974
|
-
|
|
16975
|
-
|
|
17819
|
+
/**
|
|
17820
|
+
* `project.read`.
|
|
17821
|
+
*
|
|
17822
|
+
* Intentionally thin in v1 - it is the read half of the story service a plugin already has, and no
|
|
17823
|
+
* more. This is the protocol's designated extension point: a test that needs the scene *graph*
|
|
17824
|
+
* (route reachability, dead ends) needs a shape added here, and adding it is a protocol change with
|
|
17825
|
+
* a version bump rather than something a test reaches around.
|
|
17826
|
+
*
|
|
17827
|
+
* Studio's own built-in tests do not go through this handle at all; they are registered from inside
|
|
17828
|
+
* the workspace and close over its context directly, the same way `builtInPanels` differ from
|
|
17829
|
+
* `services.ui.panels`. This handle exists so a *plugin* has a bounded way in.
|
|
17830
|
+
*/
|
|
17831
|
+
export type TestProjectHandle = {
|
|
17832
|
+
readonly projectPath: string;
|
|
17833
|
+
listStories(): Promise<TestStoryRef[]>;
|
|
17834
|
+
listScenes(storyId: string): Promise<TestSceneRef[]>;
|
|
16976
17835
|
};
|
|
16977
|
-
|
|
16978
|
-
|
|
16979
|
-
|
|
16980
|
-
|
|
16981
|
-
|
|
16982
|
-
|
|
16983
|
-
|
|
16984
|
-
|
|
16985
|
-
|
|
16986
|
-
|
|
16987
|
-
|
|
16988
|
-
|
|
16989
|
-
|
|
16990
|
-
|
|
16991
|
-
*/
|
|
16992
|
-
allowInlineLiteral?: boolean;
|
|
17836
|
+
/**
|
|
17837
|
+
* How a game process ended, and what it said on the way out.
|
|
17838
|
+
*
|
|
17839
|
+
* These are the wire shapes from `@shared/types/gameTest`, re-exported under the names an author
|
|
17840
|
+
* touches. The distinction they carry is the whole reason the pipeline needed main-process work:
|
|
17841
|
+
* before it, a crashed preview and an author closing the window were the same event to Studio (an
|
|
17842
|
+
* exit logged at `verbose`, status polled back to `idle`). A test whose pass condition is "the
|
|
17843
|
+
* author closed the window" cannot be written without it.
|
|
17844
|
+
*/
|
|
17845
|
+
export type TestGameExitReason = GameTestExitReason;
|
|
17846
|
+
export type TestGameExit = GameTestExit;
|
|
17847
|
+
export type TestGameEvent = GameTestEvent;
|
|
17848
|
+
type TestGameCommand = GameTestCommand;
|
|
17849
|
+
export type TestGameLaunchOptions = {
|
|
16993
17850
|
/**
|
|
16994
|
-
*
|
|
16995
|
-
*
|
|
16996
|
-
* covered by declaring it here and nowhere else.
|
|
17851
|
+
* `"blocked"` starts the game with no network access at all - the host applies it to the
|
|
17852
|
+
* launched process, so a game that reaches for the network fails there rather than in a mock.
|
|
16997
17853
|
*/
|
|
16998
|
-
|
|
17854
|
+
network?: "allow" | "blocked";
|
|
16999
17855
|
};
|
|
17000
|
-
type
|
|
17001
|
-
|
|
17002
|
-
|
|
17003
|
-
|
|
17004
|
-
fixedDataInputIds: readonly string[];
|
|
17005
|
-
/** Generated ids use `${prefix}_${n}` with n increasing until unused. */
|
|
17006
|
-
generatedIdPrefix: string;
|
|
17007
|
-
valueType: string;
|
|
17008
|
-
allowInlineLiteral: boolean;
|
|
17009
|
-
/**
|
|
17010
|
-
* Optional grouped pins generated from one add action. When omitted, one pin id
|
|
17011
|
-
* `${prefix}_${n}` is created with valueType / allowInlineLiteral above.
|
|
17012
|
-
*/
|
|
17013
|
-
generatedPinTemplates?: readonly {
|
|
17014
|
-
/** Generated ids use `${prefix}_${n}_${idSuffix}`. */
|
|
17015
|
-
idSuffix: string;
|
|
17016
|
-
label: string;
|
|
17017
|
-
kind?: "input" | "output";
|
|
17018
|
-
semantic?: BlueprintPinSemantic;
|
|
17019
|
-
valueType?: string;
|
|
17020
|
-
optional?: boolean;
|
|
17021
|
-
allowInlineLiteral?: boolean;
|
|
17022
|
-
}[];
|
|
17856
|
+
export type TestGameSession = {
|
|
17857
|
+
readonly id: string;
|
|
17858
|
+
/** Returns an unsubscribe. Events emitted before the first listener are replayed to it. */
|
|
17859
|
+
onEvent(listener: (event: TestGameEvent) => void): () => void;
|
|
17023
17860
|
/**
|
|
17024
|
-
*
|
|
17025
|
-
* `Button 1` / `Pressed 1`, the second `Button 2` / `Pressed 2`.
|
|
17861
|
+
* Ask the game to do something: start a story, advance a line, pick an option.
|
|
17026
17862
|
*
|
|
17027
|
-
*
|
|
17028
|
-
*
|
|
17029
|
-
*
|
|
17030
|
-
*
|
|
17031
|
-
*
|
|
17032
|
-
* from the first, and an author cannot tell which branch they are wiring.
|
|
17863
|
+
* Resolves `true` when the command reached the game and `false` when it could not - a session
|
|
17864
|
+
* that has already exited, or one whose game never opened its control channel. It never says the
|
|
17865
|
+
* game *did* it: the game is a separate process, and what happened comes back through
|
|
17866
|
+
* {@link onEvent} like everything else it says. A test that needs to know waits for the
|
|
17867
|
+
* observation, and treats one that never arrives as the answer it is.
|
|
17033
17868
|
*/
|
|
17034
|
-
|
|
17035
|
-
/**
|
|
17036
|
-
|
|
17037
|
-
/**
|
|
17038
|
-
|
|
17039
|
-
/** Optional label for the node-card add button. */
|
|
17040
|
-
addButtonLabel?: string;
|
|
17041
|
-
/** Optional param key storing user-visible labels by generated pin id. */
|
|
17042
|
-
pinLabelParamKey?: string;
|
|
17043
|
-
/** Optional prefix used when initializing labels in pinLabelParamKey. */
|
|
17044
|
-
defaultPinLabelPrefix?: string;
|
|
17045
|
-
/** Optional param key storing per-pin valueType overrides (Record<pinId, valueType>). */
|
|
17046
|
-
pinValueTypeParamKey?: string;
|
|
17047
|
-
/** Allowed valueTypes for the on-card per-pin type picker; presence enables the picker. */
|
|
17048
|
-
pinValueTypeOptions?: readonly string[];
|
|
17049
|
-
/** When true, generated OUTPUT pins also get remove/label/type controls (default: inputs only). */
|
|
17050
|
-
editableGeneratedOutputPins?: boolean;
|
|
17051
|
-
};
|
|
17052
|
-
type BlueprintJsonValueSchema = {
|
|
17053
|
-
kind: "object" | "array" | "string" | "number" | "boolean" | "null";
|
|
17054
|
-
label?: string;
|
|
17055
|
-
/** Object fields are fixed schema entries. Unknown fields are rejected unless allowExtraFields is true. */
|
|
17056
|
-
fields?: readonly {
|
|
17057
|
-
key: string;
|
|
17058
|
-
label?: string;
|
|
17059
|
-
kind: "object" | "array" | "string" | "number" | "boolean" | "null";
|
|
17060
|
-
required?: boolean;
|
|
17061
|
-
}[];
|
|
17062
|
-
allowExtraFields?: boolean;
|
|
17869
|
+
sendCommand(command: TestGameCommand): Promise<boolean>;
|
|
17870
|
+
/** Resolves once the process is gone, whatever the reason. Safe to call more than once. */
|
|
17871
|
+
waitForExit(): Promise<TestGameExit>;
|
|
17872
|
+
/** Graceful shutdown, then force. Resolves when the process is gone. */
|
|
17873
|
+
stop(): Promise<void>;
|
|
17063
17874
|
};
|
|
17064
|
-
|
|
17065
|
-
|
|
17066
|
-
|
|
17067
|
-
|
|
17068
|
-
|
|
17069
|
-
|
|
17070
|
-
|
|
17875
|
+
/**
|
|
17876
|
+
* `game.launch`.
|
|
17877
|
+
*
|
|
17878
|
+
* One session at a time per run: the host refuses a second `launch()` while one is alive, because
|
|
17879
|
+
* two preview processes contend for the same compiled artifact directory and the second would
|
|
17880
|
+
* silently win.
|
|
17881
|
+
*/
|
|
17882
|
+
export type TestGameHandle = {
|
|
17883
|
+
launch(options?: TestGameLaunchOptions): Promise<TestGameSession>;
|
|
17071
17884
|
};
|
|
17072
|
-
type
|
|
17073
|
-
|
|
17074
|
-
|
|
17075
|
-
kind: BlueprintInspectorParamKind;
|
|
17076
|
-
/** Optional fixed schema for structured JSON-like values such as Vector2D. */
|
|
17077
|
-
jsonSchema?: BlueprintJsonValueSchema;
|
|
17885
|
+
export type TestRunContext = {
|
|
17886
|
+
readonly runId: string;
|
|
17887
|
+
readonly protocolVersion: typeof TEST_PROTOCOL_VERSION;
|
|
17078
17888
|
/**
|
|
17079
|
-
*
|
|
17080
|
-
*
|
|
17081
|
-
* dynamically provided options via `dynamicOptionsSource`.
|
|
17889
|
+
* Aborted when the author cancels. A test that ignores it is killed anyway once its promise
|
|
17890
|
+
* settles, but its findings are kept - a cancelled run is still evidence.
|
|
17082
17891
|
*/
|
|
17083
|
-
|
|
17892
|
+
readonly signal: AbortSignal;
|
|
17084
17893
|
/**
|
|
17085
|
-
*
|
|
17086
|
-
*
|
|
17087
|
-
*
|
|
17088
|
-
*
|
|
17894
|
+
* What the author chose, keyed by parameter id.
|
|
17895
|
+
*
|
|
17896
|
+
* Resolved by the host from the declarations, never passed through from the picker: an id the
|
|
17897
|
+
* test did not declare is dropped, and a value the declaration cannot account for (an option
|
|
17898
|
+
* that has since disappeared) falls back to the default. So a test reads its own vocabulary and
|
|
17899
|
+
* nothing else, and `{}` for a test that declares none.
|
|
17089
17900
|
*/
|
|
17090
|
-
|
|
17091
|
-
|
|
17092
|
-
|
|
17901
|
+
readonly parameters: TestParameterValues;
|
|
17902
|
+
log(level: TestLogLevel, message: TestText): void;
|
|
17903
|
+
progress(progress: TestProgress | null): void;
|
|
17904
|
+
report(finding: TestFinding): void;
|
|
17905
|
+
/** Present iff `project.read` was declared. */
|
|
17906
|
+
readonly project?: TestProjectHandle;
|
|
17907
|
+
/** Present iff `game.launch` was declared. */
|
|
17908
|
+
readonly game?: TestGameHandle;
|
|
17909
|
+
};
|
|
17910
|
+
/** Everything `checkAvailability` is allowed to look at - deliberately cheap, it runs on every picker open. */
|
|
17911
|
+
export type TestAvailabilityContext = {
|
|
17912
|
+
readonly projectPath: string;
|
|
17093
17913
|
/**
|
|
17094
|
-
*
|
|
17095
|
-
*
|
|
17914
|
+
* Whether a freeze that forbids launching a game is in force - a revision view, a manual
|
|
17915
|
+
* freeze, an open merge, recovery mode.
|
|
17916
|
+
*
|
|
17917
|
+
* False during a live session even though the workspace IS frozen: what a session shows every
|
|
17918
|
+
* participant is the working tree, so a game launched from it runs what everybody is looking at
|
|
17919
|
+
* and there is nothing for the refusal to protect.
|
|
17096
17920
|
*/
|
|
17097
|
-
|
|
17098
|
-
|
|
17099
|
-
|
|
17100
|
-
|
|
17921
|
+
readonly frozen: boolean;
|
|
17922
|
+
/**
|
|
17923
|
+
* Whether this project is one Studio will not run anything for - it arrived from a package or a
|
|
17924
|
+
* remote source and nobody has vouched for it yet.
|
|
17925
|
+
*
|
|
17926
|
+
* Passed in for the reason above and one more of its own: the ledger that answers it lives in
|
|
17927
|
+
* the main process, so asking costs a round trip, and everything here is synchronous. The host
|
|
17928
|
+
* settles the answer when the workspace comes up and hands the settled copy down.
|
|
17929
|
+
*
|
|
17930
|
+
* `checkAvailability` will not normally see this true - the host refuses every test before it
|
|
17931
|
+
* asks a definition anything, because a run is an execution of the project. It is here because
|
|
17932
|
+
* `options` is *not* gated: a list that would cost real work to build can decline to build it
|
|
17933
|
+
* for a project that cannot run it.
|
|
17934
|
+
*/
|
|
17935
|
+
readonly distrusted: boolean;
|
|
17101
17936
|
};
|
|
17102
|
-
type
|
|
17103
|
-
|
|
17104
|
-
|
|
17105
|
-
|
|
17106
|
-
|
|
17107
|
-
|
|
17108
|
-
|
|
17109
|
-
|
|
17110
|
-
|
|
17111
|
-
|
|
17112
|
-
|
|
17113
|
-
|
|
17114
|
-
|
|
17115
|
-
|
|
17116
|
-
|
|
17117
|
-
|
|
17118
|
-
|
|
17937
|
+
export type TestAvailability = {
|
|
17938
|
+
available: true;
|
|
17939
|
+
}
|
|
17940
|
+
/** Greys the row out and says why. Not an error: an unavailable test is a normal state. */
|
|
17941
|
+
| {
|
|
17942
|
+
available: false;
|
|
17943
|
+
reason: TestText;
|
|
17944
|
+
};
|
|
17945
|
+
/**
|
|
17946
|
+
* One row of a `select` parameter's list.
|
|
17947
|
+
*
|
|
17948
|
+
* `value` is what the test reads and what is remembered on disk; `label` is what the author picks
|
|
17949
|
+
* from. They are separate because the label is a display string that follows the editor language
|
|
17950
|
+
* while the value has to survive a language switch and a Studio upgrade unchanged.
|
|
17951
|
+
*
|
|
17952
|
+
* `name` is what a command line calls the row, for a list whose values are generated ids. A value is
|
|
17953
|
+
* the right thing to remember and the wrong thing to type: `--test-list` would have to print it, and
|
|
17954
|
+
* no id belongs in front of a person. With a name, `--test-list` prints the name in the value's
|
|
17955
|
+
* place and `--test-parameter` takes it (matched without regard to case); the value never leaves the
|
|
17956
|
+
* workspace. Unique among the rows, written in words the author already knows the row by, and not a
|
|
17957
|
+
* translated string - a line has to mean the same thing whatever language Studio is in. A list whose
|
|
17958
|
+
* values are already words needs none.
|
|
17959
|
+
*/
|
|
17960
|
+
export type TestParameterOption = {
|
|
17961
|
+
value: string;
|
|
17962
|
+
label: TestText;
|
|
17963
|
+
name?: string;
|
|
17964
|
+
};
|
|
17965
|
+
/** A parameter the author answers by picking from a list. */
|
|
17966
|
+
export type TestSelectParameterDefinition = {
|
|
17967
|
+
id: string;
|
|
17968
|
+
kind: "select";
|
|
17969
|
+
label: TestText;
|
|
17970
|
+
/** One clause about what the value selects, if it needs one. Not a sentence explaining the UI. */
|
|
17971
|
+
description?: TestText;
|
|
17119
17972
|
/**
|
|
17120
|
-
*
|
|
17121
|
-
* `valueBindings`.
|
|
17973
|
+
* The list to offer, evaluated when the picker opens.
|
|
17122
17974
|
*
|
|
17123
|
-
*
|
|
17124
|
-
*
|
|
17125
|
-
*
|
|
17126
|
-
*
|
|
17127
|
-
*
|
|
17128
|
-
*
|
|
17129
|
-
*
|
|
17130
|
-
* reruns the binding when those change, and it cannot see what a plugin node read - so a binding
|
|
17131
|
-
* built on one refreshes on the host's dependencies, never on the plugin's.
|
|
17975
|
+
* Same contract as `checkAvailability`, and for the same reason: it runs on every open, so keep
|
|
17976
|
+
* it synchronous, cheap and free of side effects. It is handed the same context, so a list can
|
|
17977
|
+
* depend on the project without the definition holding a workspace of its own.
|
|
17978
|
+
*
|
|
17979
|
+
* **An empty list is a real answer**, not a failure - a project with no endings yet has nothing
|
|
17980
|
+
* to walk to. The host treats it as one: the whole test is greyed out naming this parameter,
|
|
17981
|
+
* rather than offering a dropdown with nothing in it and a Start that cannot work.
|
|
17132
17982
|
*/
|
|
17133
|
-
|
|
17983
|
+
options(ctx: TestAvailabilityContext): TestParameterOption[];
|
|
17134
17984
|
/**
|
|
17135
|
-
*
|
|
17136
|
-
*
|
|
17137
|
-
* for one row. Enforced by `isBlueprintNodeAllowedInGraphContext`, so the palette and the graph
|
|
17138
|
-
* validator answer it the same way.
|
|
17985
|
+
* Which option to start on. Falls back to the first option when absent, and also when it names
|
|
17986
|
+
* an option that is not in the list any more.
|
|
17139
17987
|
*/
|
|
17140
|
-
|
|
17141
|
-
|
|
17142
|
-
|
|
17143
|
-
|
|
17144
|
-
|
|
17145
|
-
|
|
17988
|
+
defaultValue?: string;
|
|
17989
|
+
};
|
|
17990
|
+
/** A parameter the author answers with a switch. */
|
|
17991
|
+
export type TestBooleanParameterDefinition = {
|
|
17992
|
+
id: string;
|
|
17993
|
+
kind: "boolean";
|
|
17994
|
+
label: TestText;
|
|
17995
|
+
/** One clause about what the value selects, if it needs one. Not a sentence explaining the UI. */
|
|
17996
|
+
description?: TestText;
|
|
17997
|
+
/** Absent means off. */
|
|
17998
|
+
defaultValue?: boolean;
|
|
17999
|
+
};
|
|
18000
|
+
export type TestParameterDefinition = TestSelectParameterDefinition | TestBooleanParameterDefinition;
|
|
18001
|
+
/** What one parameter resolves to. A `select` resolves to the chosen option's `value`. */
|
|
18002
|
+
export type TestParameterValue = string | boolean;
|
|
18003
|
+
/**
|
|
18004
|
+
* Resolved parameter values, keyed by parameter id.
|
|
18005
|
+
*
|
|
18006
|
+
* Only ids the test declared are present - see the header. A test that declares none is handed an
|
|
18007
|
+
* empty object, never `undefined`, so reading `ctx.parameters` needs no guard.
|
|
18008
|
+
*/
|
|
18009
|
+
export type TestParameterValues = Readonly<Record<string, TestParameterValue>>;
|
|
18010
|
+
export type TestDefinition = {
|
|
18011
|
+
id: TestId;
|
|
18012
|
+
title: TestText;
|
|
18013
|
+
description?: TestText;
|
|
18014
|
+
category?: TestCategory;
|
|
18015
|
+
presentation: TestPresentation;
|
|
18016
|
+
/** Omitted means "nothing" - a pure computation over what it was given. */
|
|
18017
|
+
requires?: readonly TestCapability[];
|
|
17146
18018
|
/**
|
|
17147
|
-
*
|
|
18019
|
+
* Values the author supplies before pressing Start, drawn as a row of controls in the picker and
|
|
18020
|
+
* handed to `run` as `ctx.parameters`.
|
|
17148
18021
|
*
|
|
17149
|
-
*
|
|
17150
|
-
*
|
|
17151
|
-
*
|
|
17152
|
-
*
|
|
18022
|
+
* Omitted means the test needs none, which is every test that existed before this: select it,
|
|
18023
|
+
* press Start. Two parameters with the same id are one parameter - the first declaration wins,
|
|
18024
|
+
* because the resolved values are keyed by id and two rows writing one key could not both be
|
|
18025
|
+
* shown honestly.
|
|
17153
18026
|
*/
|
|
17154
|
-
|
|
17155
|
-
|
|
17156
|
-
|
|
17157
|
-
|
|
17158
|
-
|
|
18027
|
+
parameters?: readonly TestParameterDefinition[];
|
|
18028
|
+
/**
|
|
18029
|
+
* Evaluated when the picker opens, so keep it synchronous and cheap. Absent means always
|
|
18030
|
+
* available; the host still applies its own gates (a `windowed` test is unavailable while the
|
|
18031
|
+
* workspace is frozen, and no test runs at all in a project that is not trusted, no matter what
|
|
18032
|
+
* this returns).
|
|
18033
|
+
*/
|
|
18034
|
+
checkAvailability?(ctx: TestAvailabilityContext): TestAvailability;
|
|
18035
|
+
run(ctx: TestRunContext): Promise<TestVerdict> | TestVerdict;
|
|
17159
18036
|
};
|
|
18037
|
+
declare class ServiceRegistry {
|
|
18038
|
+
private services;
|
|
18039
|
+
get<T extends Service>(service: Services): T;
|
|
18040
|
+
getAll(): Service[];
|
|
18041
|
+
}
|
|
17160
18042
|
interface WorkspaceContext {
|
|
17161
18043
|
project: Porject;
|
|
17162
18044
|
services: ServiceRegistry;
|
|
18045
|
+
/**
|
|
18046
|
+
* Whether this window was opened to answer a command line - `--build`, `--test` or `--lint` -
|
|
18047
|
+
* rather than for somebody to work in.
|
|
18048
|
+
*
|
|
18049
|
+
* Read from the window's props when the context is built, so a service knows it before its own
|
|
18050
|
+
* `init` runs. Everything a workspace does *because an author is here* has to ask: a run is a
|
|
18051
|
+
* machine passing through, and what it records about the person whose profile it borrowed is a
|
|
18052
|
+
* fiction nobody can correct afterwards.
|
|
18053
|
+
*/
|
|
18054
|
+
commandLineRun: boolean;
|
|
17163
18055
|
}
|
|
17164
18056
|
interface IService {
|
|
17165
18057
|
activate(ctx: WorkspaceContext): Promise<void> | void;
|
|
@@ -17372,6 +18264,7 @@ declare const HELP_TOPIC_IDS: readonly [
|
|
|
17372
18264
|
"puppetRuntimes",
|
|
17373
18265
|
"audio",
|
|
17374
18266
|
"audioClips",
|
|
18267
|
+
"videoClips",
|
|
17375
18268
|
"voice",
|
|
17376
18269
|
"localization",
|
|
17377
18270
|
"brand",
|
|
@@ -17794,6 +18687,120 @@ export interface StoryCompilePass {
|
|
|
17794
18687
|
/** Called once per scene, before that scene's rows are compiled. */
|
|
17795
18688
|
scene(ctx: SceneCompileContext): void;
|
|
17796
18689
|
}
|
|
18690
|
+
/**
|
|
18691
|
+
* The detail on `nl.launch`: where this page sits on the launch's own timeline.
|
|
18692
|
+
*
|
|
18693
|
+
* Every entry's `startTime` is measured from the page's time origin. Add `pageOrigin` to it and it
|
|
18694
|
+
* is measured from the launch instead, which is how a boot phase and the process start end up on
|
|
18695
|
+
* one axis.
|
|
18696
|
+
*/
|
|
18697
|
+
type GameLaunchEntryDetail = {
|
|
18698
|
+
/**
|
|
18699
|
+
* What zero is.
|
|
18700
|
+
*
|
|
18701
|
+
* - `process` - the game's process was created (a packaged game, a preview).
|
|
18702
|
+
* - `devMode` - an author asked Studio to run the game (a Dev Mode window).
|
|
18703
|
+
* - `page` - nothing earlier is known, so zero is this page's own origin (the web export).
|
|
18704
|
+
*/
|
|
18705
|
+
origin: "process" | "devMode" | "page";
|
|
18706
|
+
/** Milliseconds from zero to this page's time origin. Zero when `origin` is `page`. */
|
|
18707
|
+
pageOrigin: number;
|
|
18708
|
+
/**
|
|
18709
|
+
* What happened between zero and the page, in milliseconds from zero: `appReady` (Electron has
|
|
18710
|
+
* started) and `windowCreated` (the window exists and its page has been asked for) on a
|
|
18711
|
+
* packaged game, `windowCreated` alone in Dev Mode. Empty when `origin` is `page`.
|
|
18712
|
+
*/
|
|
18713
|
+
milestones: {
|
|
18714
|
+
name: string;
|
|
18715
|
+
at: number;
|
|
18716
|
+
}[];
|
|
18717
|
+
};
|
|
18718
|
+
/** `nl.story.compile` - a story compiled outside the boot. The boot's own is `nl.boot.story`. */
|
|
18719
|
+
type GameStoryCompileDetail = {
|
|
18720
|
+
storyId: string;
|
|
18721
|
+
sceneId: string | null;
|
|
18722
|
+
};
|
|
18723
|
+
/**
|
|
18724
|
+
* `nl.scene.load` - a scene's gate: from the player asking what to warm for the scene to the last
|
|
18725
|
+
* picture its first frame waits for having landed.
|
|
18726
|
+
*
|
|
18727
|
+
* That is the part of entering a scene that loading decides; a transition the author wrote plays
|
|
18728
|
+
* after it and is not included. A scene whose gate was already warm - or that had nothing in it -
|
|
18729
|
+
* records a span of about zero, which is the honest answer rather than a missing one.
|
|
18730
|
+
*/
|
|
18731
|
+
type GameSceneLoadDetail = {
|
|
18732
|
+
/** The scene as the author named it, or null for a scene Studio did not compile (a row launch). */
|
|
18733
|
+
scene: string | null;
|
|
18734
|
+
/** Pictures the scene's first frame waits for. */
|
|
18735
|
+
gated: number;
|
|
18736
|
+
/** Of those, how many were not warm yet when the scene was asked for. */
|
|
18737
|
+
waited: number;
|
|
18738
|
+
/** False when it gave up waiting: something in the gate never landed. */
|
|
18739
|
+
complete: boolean;
|
|
18740
|
+
};
|
|
18741
|
+
/**
|
|
18742
|
+
* `nl.preload.asset` - one asset warmed, from the moment the work on it started to the moment it
|
|
18743
|
+
* settled, loaded or not.
|
|
18744
|
+
*
|
|
18745
|
+
* - `pass: "interface"` - the pass that warms the pages' pictures, sounds and fonts before the first
|
|
18746
|
+
* screen and behind it. `firstScreen` says whether the first screen was waiting for it.
|
|
18747
|
+
* - `pass: "scene"` / `"advance"` - the player warming a picture a scene will show, asked for when
|
|
18748
|
+
* the scene was entered or as the story moved. `band` is how urgently: `gate` holds the frame,
|
|
18749
|
+
* `soon` is a click away, `idle` is speculative. Only pictures that were actually fetched and
|
|
18750
|
+
* decoded appear; speculative ones the player merely noted cost nothing and are not listed. A
|
|
18751
|
+
* picture it already held without a bitmap - fetched earlier as look-ahead, which is how most
|
|
18752
|
+
* scenes' opening pictures arrive, or released by the decoded-image budget - is decoded again,
|
|
18753
|
+
* and its span runs from the moment the scene or the story asked for it to the bitmap being held.
|
|
18754
|
+
*/
|
|
18755
|
+
type GamePreloadAssetDetail = {
|
|
18756
|
+
pass: "interface" | "scene" | "advance";
|
|
18757
|
+
kind: "image" | "audio" | "video" | "font";
|
|
18758
|
+
/** The project's id for the asset, or null where only its address is known. */
|
|
18759
|
+
assetId: string | null;
|
|
18760
|
+
/** The address it was loaded from. Opaque; differs between Dev Mode and a build. */
|
|
18761
|
+
url: string;
|
|
18762
|
+
band?: "gate" | "soon" | "idle";
|
|
18763
|
+
firstScreen?: boolean;
|
|
18764
|
+
/** The scene it was warmed for, as the author named it. */
|
|
18765
|
+
scene?: string | null;
|
|
18766
|
+
ok: boolean;
|
|
18767
|
+
};
|
|
18768
|
+
/** `nl.surface.mount` - a page or layer, from being asked for to its first paint being allowed. */
|
|
18769
|
+
type GameSurfaceMountDetail = {
|
|
18770
|
+
surfaceId: string;
|
|
18771
|
+
/** The page's name as the author gave it. */
|
|
18772
|
+
surface: string | null;
|
|
18773
|
+
kind: "page" | "layer";
|
|
18774
|
+
};
|
|
18775
|
+
/** `nl.save.write` - a save, from the request to the file being written. */
|
|
18776
|
+
type GameSaveWriteDetail = {
|
|
18777
|
+
slot: string;
|
|
18778
|
+
screenshot: boolean;
|
|
18779
|
+
ok: boolean;
|
|
18780
|
+
};
|
|
18781
|
+
/** `nl.save.load` - a load, from the request to the player being back on the stage. */
|
|
18782
|
+
type GameSaveLoadDetail = {
|
|
18783
|
+
slot: string;
|
|
18784
|
+
/** `refused`: the save did not fit this build and the run was left where it was. */
|
|
18785
|
+
outcome: "loaded" | "refused" | "failed";
|
|
18786
|
+
};
|
|
18787
|
+
type GameTimelineSpanDetails = {
|
|
18788
|
+
"nl.story.compile": GameStoryCompileDetail;
|
|
18789
|
+
"nl.scene.load": GameSceneLoadDetail;
|
|
18790
|
+
"nl.preload.asset": GamePreloadAssetDetail;
|
|
18791
|
+
"nl.surface.mount": GameSurfaceMountDetail;
|
|
18792
|
+
"nl.save.write": GameSaveWriteDetail;
|
|
18793
|
+
"nl.save.load": GameSaveLoadDetail;
|
|
18794
|
+
};
|
|
18795
|
+
type GameTimelineSpanName = keyof GameTimelineSpanDetails;
|
|
18796
|
+
/**
|
|
18797
|
+
* Every name the game writes to the performance timeline.
|
|
18798
|
+
*
|
|
18799
|
+
* `nl.launch` and `nl.boot.firstFrame` are marks; `nl.boot` and every `nl.boot.<phase>` are measures
|
|
18800
|
+
* with `.start` / `.end` marks beside them; the rest are measures whose `detail` is described by
|
|
18801
|
+
* {@link RuntimePluginTimelineSpanDetails}.
|
|
18802
|
+
*/
|
|
18803
|
+
export type RuntimePluginTimelineName = "nl.launch" | "nl.boot" | "nl.boot.firstFrame" | `nl.boot.${"bundle" | "story" | "preload"}` | `nl.boot.${"bundle" | "story" | "preload"}.${"start" | "end"}` | GameTimelineSpanName;
|
|
17797
18804
|
export type RuntimePluginLogLevel = "info" | "warning" | "error";
|
|
17798
18805
|
/**
|
|
17799
18806
|
* What a plugin's node execute actually receives.
|
|
@@ -17896,14 +18903,17 @@ export type RuntimeWidgetRendererProps = {
|
|
|
17896
18903
|
/**
|
|
17897
18904
|
* Raise one of this element's own event slots, running whatever the author wired to it.
|
|
17898
18905
|
*
|
|
17899
|
-
* The
|
|
17900
|
-
*
|
|
17901
|
-
*
|
|
17902
|
-
*
|
|
18906
|
+
* The route a plugin widget's own events take to the author's graph - a rating picked, a
|
|
18907
|
+
* page turned - and the reason the host's blueprint runtime cannot simply be withheld. The
|
|
18908
|
+
* host raises the pointer, key and lifecycle events it raises for every widget itself, for
|
|
18909
|
+
* the ones the widget's `logicApi` declares; everything else only the widget knows happened.
|
|
18910
|
+
* An event its `logicApi` does not declare starts nothing.
|
|
17903
18911
|
*
|
|
17904
18912
|
* Bound to the element being drawn - a widget cannot raise an event on another one - and
|
|
17905
|
-
* to the
|
|
17906
|
-
*
|
|
18913
|
+
* to the drawing it is in: the row, so a dispatch from inside a repeated row addresses that
|
|
18914
|
+
* row, and the component placement, so a widget placed inside a component reaches the
|
|
18915
|
+
* graph authored on the component. Pass `options` only to address a different row than the
|
|
18916
|
+
* one being drawn.
|
|
17907
18917
|
*
|
|
17908
18918
|
* A new function on every render, like anything bound to the current drawing: call it
|
|
17909
18919
|
* from a handler, and keep it in a ref rather than in an effect's dependency list.
|
|
@@ -17923,6 +18933,14 @@ export type RuntimeWidgetRendererProps = {
|
|
|
17923
18933
|
export type RuntimeWidgetRendererDef = {
|
|
17924
18934
|
type: string;
|
|
17925
18935
|
render: (props: RuntimeWidgetRendererProps) => React$1.ReactElement | null;
|
|
18936
|
+
/**
|
|
18937
|
+
* The events this widget raises - the same object the studio entry's widget module declares.
|
|
18938
|
+
*
|
|
18939
|
+
* The game has no widget module to read it from, so without it here a `dispatchEvent` from
|
|
18940
|
+
* `render` reaches no graph in a game or in Dev Mode, whatever the editor showed. Put the
|
|
18941
|
+
* declaration in the module both entries import, as with the render function.
|
|
18942
|
+
*/
|
|
18943
|
+
logicApi?: WidgetLogicApi;
|
|
17926
18944
|
};
|
|
17927
18945
|
/** Removes a subscription. Also tracked by the host, so a failed plugin cannot leak listeners. */
|
|
17928
18946
|
export type RuntimePluginCleanup = () => void;
|
|
@@ -18182,6 +19200,16 @@ export type RuntimePluginDiagnostics = {
|
|
|
18182
19200
|
/** The engine's image cache, or null when no session is live. */
|
|
18183
19201
|
imageCache(): RuntimePluginImageCacheStats | null;
|
|
18184
19202
|
};
|
|
19203
|
+
/**
|
|
19204
|
+
* `process.memory` — how much memory the game's processes hold, as the operating system counts it:
|
|
19205
|
+
* the number a task manager shows, across the main, renderer, GPU and utility processes.
|
|
19206
|
+
*
|
|
19207
|
+
* Asynchronous because only the main process can see them. Polled rather than subscribed, like
|
|
19208
|
+
* `diagnostics`: a plugin asks on its own clock, and each call is a fresh reading.
|
|
19209
|
+
*/
|
|
19210
|
+
export type RuntimePluginProcess = {
|
|
19211
|
+
memory(): Promise<GameProcessMemoryReading>;
|
|
19212
|
+
};
|
|
18185
19213
|
/** `assets` — turn an asset id from the pack into a URL this shell can load. */
|
|
18186
19214
|
export type RuntimePluginAssets = {
|
|
18187
19215
|
url(assetId: string): string;
|
|
@@ -18314,6 +19342,11 @@ export type RuntimePluginGame = {
|
|
|
18314
19342
|
story?: RuntimePluginStory;
|
|
18315
19343
|
/** Present with `"diagnostics"`. */
|
|
18316
19344
|
diagnostics?: RuntimePluginDiagnostics;
|
|
19345
|
+
/**
|
|
19346
|
+
* Present with `"process.memory"`, on shells that have processes of their own to count: the
|
|
19347
|
+
* packaged game, a preview, and Dev Mode (narrowed to its window). Absent on the web export.
|
|
19348
|
+
*/
|
|
19349
|
+
process?: RuntimePluginProcess;
|
|
18317
19350
|
/** Present when `contributes.sidecars` is non-empty. */
|
|
18318
19351
|
sidecar?: RuntimePluginSidecars;
|
|
18319
19352
|
/** Present when `contributes.externalLinks` is non-empty. */
|
|
@@ -18473,8 +19506,43 @@ export type PluginWidgetModule = {
|
|
|
18473
19506
|
readonly type: string;
|
|
18474
19507
|
/** Widget type this one specialises. */
|
|
18475
19508
|
readonly extends?: string;
|
|
18476
|
-
/**
|
|
19509
|
+
/**
|
|
19510
|
+
* The events this widget raises, and whether it has a blueprint of its own to raise them on.
|
|
19511
|
+
*
|
|
19512
|
+
* With `supportsPrivateBlueprint: true` the element gets a blueprint like a built-in widget's,
|
|
19513
|
+
* the properties panel lists `events`, and each event starts the graphs whose head is one of its
|
|
19514
|
+
* `headNodeTypes` when `render` calls `dispatchEvent(event.id, payload)` - or, for the pointer,
|
|
19515
|
+
* key and lifecycle events, when the host raises them as it does for its own widgets.
|
|
19516
|
+
*
|
|
19517
|
+
* A head is either one a built-in widget uses for the same event (`blueprint.event.head.mouseClick`,
|
|
19518
|
+
* `blueprint.event.head.init`, `blueprint.event.head.onBroadcast`, ...) or an event-head node this
|
|
19519
|
+
* plugin registers through `app.services.blueprintNodes` with `role: "eventHead"`; its output pins
|
|
19520
|
+
* read the fields of the payload of the same name. An event naming neither is dropped with a
|
|
19521
|
+
* console warning, because nothing could start on it. The runtime entry declares the same object
|
|
19522
|
+
* on its `app.game.widgets.register`, or the game does not know the events exist.
|
|
19523
|
+
*/
|
|
18477
19524
|
readonly logicApi?: WidgetLogicApi;
|
|
19525
|
+
/**
|
|
19526
|
+
* Whether an author may put other elements inside this widget, as they can inside a Container.
|
|
19527
|
+
*
|
|
19528
|
+
* When true the canvas, the layer outline and the insert commands let elements be placed in it,
|
|
19529
|
+
* and `render` receives them already drawn as `children` - placing them is the widget's own job.
|
|
19530
|
+
* Absent or false, it is a leaf.
|
|
19531
|
+
*/
|
|
19532
|
+
readonly acceptsChildren?: boolean;
|
|
19533
|
+
/**
|
|
19534
|
+
* The parts this widget builds for itself, when it holds those and nothing else - as the built-in
|
|
19535
|
+
* Slider holds its track and handle.
|
|
19536
|
+
*
|
|
19537
|
+
* Each entry names a slot. `createDefaultChildElements` builds the parts, and each part says which
|
|
19538
|
+
* slot it fills with `extra: { partSlot: "<slot>" }`. The widget then holds exactly those: the
|
|
19539
|
+
* canvas, the layer outline, paste and the insert tool put nothing else inside it, a part cannot
|
|
19540
|
+
* be dragged out of it, and the interface command line refuses a child that names no declared slot.
|
|
19541
|
+
* An author can still select, restyle and delete a part. Declaring slots makes `acceptsChildren`
|
|
19542
|
+
* irrelevant - a widget with parts takes nothing else - and `render` receives the parts as
|
|
19543
|
+
* `children`, like any other children.
|
|
19544
|
+
*/
|
|
19545
|
+
readonly partSlots?: readonly string[];
|
|
18478
19546
|
readonly displayName: string;
|
|
18479
19547
|
readonly icon: LucideIcon;
|
|
18480
19548
|
createDefaultElement(): Partial<UIElement>;
|
|
@@ -19265,8 +20333,12 @@ export type PluginStorageService = {
|
|
|
19265
20333
|
* stays writable, and everything else in the project - a plugin's own stored documents included -
|
|
19266
20334
|
* does not. Nothing a plugin can write is on the writable side of it, so for a plugin it behaves
|
|
19267
20335
|
* exactly like the others: `frozen` is true, and the buttons come off.
|
|
20336
|
+
*
|
|
20337
|
+
* `taken-over` means another NarraLeaf Studio has opened this project and this window has stopped
|
|
20338
|
+
* writing it for good - there is no way back within the window. The workspace replaces its editor
|
|
20339
|
+
* with a screen that says so, so a plugin sees it at most once, on its way out.
|
|
19268
20340
|
*/
|
|
19269
|
-
export type PluginFreezeReason = "revision" | "manual" | "merge" | "recovery" | "live-session";
|
|
20341
|
+
export type PluginFreezeReason = "revision" | "manual" | "merge" | "recovery" | "live-session" | "taken-over";
|
|
19270
20342
|
/**
|
|
19271
20343
|
* The state of the project a plugin's data lives in.
|
|
19272
20344
|
*
|
|
@@ -19542,6 +20614,18 @@ export declare function isPluginDefinition(value: unknown): value is PluginDefin
|
|
|
19542
20614
|
|
|
19543
20615
|
export {
|
|
19544
20616
|
BehaviorNodeExecuteResult as RuntimeBlueprintNodeResult,
|
|
20617
|
+
GameLaunchEntryDetail as RuntimePluginLaunchTimelineDetail,
|
|
20618
|
+
GamePreloadAssetDetail as RuntimePluginPreloadAssetTimelineDetail,
|
|
20619
|
+
GameProcessKind as RuntimePluginProcessKind,
|
|
20620
|
+
GameProcessMemoryEntry as RuntimePluginProcessMemoryEntry,
|
|
20621
|
+
GameProcessMemoryReading as RuntimePluginProcessMemory,
|
|
20622
|
+
GameSaveLoadDetail as RuntimePluginSaveLoadTimelineDetail,
|
|
20623
|
+
GameSaveWriteDetail as RuntimePluginSaveWriteTimelineDetail,
|
|
20624
|
+
GameSceneLoadDetail as RuntimePluginSceneLoadTimelineDetail,
|
|
20625
|
+
GameStoryCompileDetail as RuntimePluginStoryCompileTimelineDetail,
|
|
20626
|
+
GameSurfaceMountDetail as RuntimePluginSurfaceMountTimelineDetail,
|
|
20627
|
+
GameTimelineSpanDetails as RuntimePluginTimelineSpanDetails,
|
|
20628
|
+
GameTimelineSpanName as RuntimePluginTimelineSpanName,
|
|
19545
20629
|
SelectOption$1 as SelectOption,
|
|
19546
20630
|
};
|
|
19547
20631
|
|