@zylem/editor 0.8.8 → 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.
@@ -1,23 +1,25 @@
1
1
  import * as _zylem_bridge from '@zylem/bridge';
2
- import { BridgePose, BridgeVec3, BridgeQuat, SnapSettingsPayload, BridgeDebugTool, SceneOperationPayload, EntityTypeDescriptor } from '@zylem/bridge';
2
+ import { BridgePose, EntitySelectMode, BridgeVec3, BridgeQuat, SnapSettingsPayload, BridgeDebugTool, SceneOperationPayload, EntityTypeDescriptor } from '@zylem/bridge';
3
3
  import { LucideProps } from 'lucide-solid';
4
4
  import { Component } from 'solid-js';
5
5
 
6
- declare const channel: _zylem_bridge.BridgeChannel;
7
6
  /**
8
- * Subscribe the editor stores to game→editor bridge messages and hydrate
9
- * from the channel's retained state.
7
+ * The editor's handle on the shared editor ↔ game bridge channel.
10
8
  *
11
- * Reference-counted: the game gates expensive editor-only work (thumbnails,
12
- * entity summaries) on these subscriptions existing, so the last editor to
13
- * unmount must actually release them, while any editor still mounted must
14
- * keep them alive.
9
+ * Owned here, and only here, so the game→editor sync modules, the
10
+ * editor→game commands, and stores such as `history-store` can all reach the
11
+ * same singleton without importing each other.
12
+ */
13
+ declare const channel: _zylem_bridge.BridgeChannel;
14
+
15
+ /**
16
+ * Editor → game commands.
15
17
  *
16
- * @returns A release function; safe to call more than once.
18
+ * Thin, typed wrappers over `channel.send` so UI code never has to spell out
19
+ * message names or payload shapes, and has no runtime dependency on game-lib
20
+ * internals.
17
21
  */
18
- declare function connectEditorBridge(): () => void;
19
- /** Tear down all bridge subscriptions, ignoring the reference count. */
20
- declare function disconnectEditorBridge(): void;
22
+
21
23
  /** Toggle the game's debug mode. */
22
24
  declare function sendDebugEnabled(enabled: boolean): void;
23
25
  /** Switch the active editor tool in the game. */
@@ -26,6 +28,12 @@ declare function sendTool(tool: BridgeDebugTool): void;
26
28
  declare function sendPlayback(paused: boolean): void;
27
29
  /** Select an entity in the game (null clears the selection). */
28
30
  declare function sendEntitySelect(uuid: string | null): void;
31
+ /**
32
+ * Replace, extend, reduce, or toggle the game's selection with several
33
+ * entities at once. `uuid` mirrors the first entry for single-select
34
+ * consumers.
35
+ */
36
+ declare function sendEntitySelectMany(uuids: string[], mode?: EntitySelectMode): void;
29
37
  /** Focus/frame the game debug camera on an entity. */
30
38
  declare function sendEntityFocus(uuid: string): void;
31
39
  /** Write a stage variable in the running game. */
@@ -54,6 +62,28 @@ declare function sendSnapSettings(snap: SnapSettingsPayload): void;
54
62
  /** Show or hide the game's construction-plane grid. */
55
63
  declare function sendGridVisible(visible: boolean): void;
56
64
 
65
+ /**
66
+ * Connection lifecycle for the editor side of the bridge.
67
+ *
68
+ * Subscribes the game→editor sync modules to the channel and hydrates from
69
+ * `channel.getState()` on connect, so an editor mounted after the game started
70
+ * shows current config/entities immediately.
71
+ */
72
+ /**
73
+ * Subscribe the editor stores to game→editor bridge messages and hydrate
74
+ * from the channel's retained state.
75
+ *
76
+ * Reference-counted: the game gates expensive editor-only work (thumbnails,
77
+ * entity summaries) on these subscriptions existing, so the last editor to
78
+ * unmount must actually release them, while any editor still mounted must
79
+ * keep them alive.
80
+ *
81
+ * @returns A release function; safe to call more than once.
82
+ */
83
+ declare function connectEditorBridge(): () => void;
84
+ /** Tear down all bridge subscriptions, ignoring the reference count. */
85
+ declare function disconnectEditorBridge(): void;
86
+
57
87
  /**
58
88
  * Shared types for the editor store.
59
89
  * These mirror types from game-lib to avoid direct dependencies.
@@ -437,6 +467,172 @@ declare function setArmedType(typeId: string | null): void;
437
467
  /** Drop the armed placement type and return to the neutral tool. */
438
468
  declare function disarmTools(): boolean;
439
469
 
470
+ /**
471
+ * What each toolbar button does when pressed, as plain functions.
472
+ *
473
+ * Kept out of the components so the keyboard shortcuts run the same code. Where
474
+ * a key and its button differ — the tool keys select, the tool buttons toggle —
475
+ * both variants live here over one shared primitive, so the two cannot drift.
476
+ * The components keep the reactive reads that drive `selected` and `disabled`,
477
+ * and call in here on click.
478
+ *
479
+ * Everything reads the valtio proxies rather than their Solid mirrors. These run
480
+ * outside any tracking scope — from a `keydown` on `window` as often as from a
481
+ * click — and the mirrors lag the proxies by a microtask.
482
+ */
483
+
484
+ type TransformTool = Extract<DebugTools, 'translate' | 'rotate' | 'scale'>;
485
+ type ClickTool = Extract<DebugTools, 'select' | 'delete'>;
486
+ /** Debug mode on or off, in the editor and the game. */
487
+ declare function toggleDebug(): void;
488
+ /**
489
+ * Make a click tool the active one. Pressing the key of the tool already active
490
+ * keeps it, so the keyboard behaves like a row of radio buttons; Escape is the
491
+ * way out.
492
+ */
493
+ declare function selectTool(tool: ClickTool): void;
494
+ /** Toggle a click tool from its button: a second press returns to the neutral tool. */
495
+ declare function toggleTool(tool: ClickTool): void;
496
+ /**
497
+ * Enter a gizmo mode from its key. Pressing the key of the mode already active
498
+ * keeps it — and still counts as handled, so the keystroke goes nowhere else.
499
+ */
500
+ declare function selectTransformTool(tool: TransformTool): boolean;
501
+ /** Toggle a gizmo mode from its button: a second press returns to the neutral tool. */
502
+ declare function toggleTransformTool(tool: TransformTool): boolean;
503
+ /**
504
+ * Arm placement with a catalog type. Arming an armed tool leaves it armed —
505
+ * Escape is the way out — so placing ten of something is one arm and ten clicks.
506
+ *
507
+ * @returns `false` when the catalog has no such type.
508
+ */
509
+ declare function armAddType(typeId: string): boolean;
510
+ /**
511
+ * Arm placement with what the Add button's face shows.
512
+ *
513
+ * @returns `false` on an empty catalog, the one state with nothing to arm.
514
+ */
515
+ declare function armAddTool(): boolean;
516
+ /** Open the Add palette, if a toolbar is showing one. */
517
+ declare function openAddPalette(): boolean;
518
+ declare function toggleSnap(): void;
519
+ declare function toggleGrid(): void;
520
+ /** Pause or resume the simulation, in the editor and the game. */
521
+ declare function togglePlayback(): void;
522
+
523
+ /**
524
+ * Keyboard shortcuts for the toolbar.
525
+ *
526
+ * The tool row follows the Godot/Unreal layout — Q select, W move, E rotate,
527
+ * R scale — with mnemonics for the rest: A add, X delete, D debug, S snap,
528
+ * G grid. Every key sits under the left hand on a QWERTY board, so the right
529
+ * hand can stay on the mouse.
530
+ *
531
+ * The keys are live whenever the editor panel is open, playing or paused: the
532
+ * panel being up is the signal that the keyboard is addressing the editor. The
533
+ * same letters are gameplay input — game-lib's keyboard provider listens on the
534
+ * same `window`, maps `a`, `s`, `q`, `e`, `x`, `z` and `Enter` for its default
535
+ * pad, and pays no attention to `preventDefault` — so while the panel is open
536
+ * the shortcuts are stopped here, in the capture phase, before any other
537
+ * listener sees them. Close the panel and the keys are the game's again.
538
+ *
539
+ * Undo and redo keep Cmd/Ctrl+Z and Cmd/Ctrl+Shift+Z from `history-shortcuts`,
540
+ * behind their own option; they are listed here so the tooltips can show them.
541
+ */
542
+ interface ShortcutChord {
543
+ /** `KeyboardEvent.key`, matched case-insensitively so Caps Lock changes nothing. */
544
+ key: string;
545
+ shift?: boolean;
546
+ /** Cmd on macOS, Ctrl elsewhere; either is accepted. */
547
+ mod?: boolean;
548
+ }
549
+ /** Every toolbar action's chord, keyed by the button it belongs to. */
550
+ declare const TOOLBAR_SHORTCUTS: {
551
+ readonly debug: {
552
+ readonly key: "d";
553
+ };
554
+ readonly select: {
555
+ readonly key: "q";
556
+ };
557
+ readonly translate: {
558
+ readonly key: "w";
559
+ };
560
+ readonly rotate: {
561
+ readonly key: "e";
562
+ };
563
+ readonly scale: {
564
+ readonly key: "r";
565
+ };
566
+ readonly add: {
567
+ readonly key: "a";
568
+ };
569
+ readonly addPalette: {
570
+ readonly key: "a";
571
+ readonly shift: true;
572
+ };
573
+ readonly delete: {
574
+ readonly key: "x";
575
+ };
576
+ readonly snap: {
577
+ readonly key: "s";
578
+ };
579
+ readonly grid: {
580
+ readonly key: "g";
581
+ };
582
+ readonly undo: {
583
+ readonly key: "z";
584
+ readonly mod: true;
585
+ };
586
+ readonly redo: {
587
+ readonly key: "z";
588
+ readonly mod: true;
589
+ readonly shift: true;
590
+ };
591
+ readonly playback: {
592
+ readonly key: "Enter";
593
+ readonly mod: true;
594
+ };
595
+ };
596
+ type ToolbarShortcutId = keyof typeof TOOLBAR_SHORTCUTS;
597
+ /** The shortcuts this module runs; undo and redo are `history-shortcuts`'. */
598
+ declare const TOOLBAR_ACTIONS: readonly ["debug", "select", "translate", "rotate", "scale", "add", "addPalette", "delete", "snap", "grid", "playback"];
599
+ type ToolbarAction = (typeof TOOLBAR_ACTIONS)[number];
600
+ /**
601
+ * A chord as tooltip text: `W`, `Shift+A`, `Cmd+Enter`.
602
+ *
603
+ * Words rather than ⌘ and ⇧, because the toolbar buttons use one string for
604
+ * both the tooltip and the accessible name.
605
+ */
606
+ declare function formatShortcut(chord: ShortcutChord, apple?: boolean): string;
607
+ /**
608
+ * Run the action a shortcut stands for.
609
+ *
610
+ * The tool keys select rather than toggle: W in Move stays in Move, and Escape
611
+ * is the way out. The buttons keep their toggle, since a lit button is its own
612
+ * "press again to leave" affordance. Everything else is a toggle by nature.
613
+ *
614
+ * @returns Whether anything happened. `false` mirrors a disabled button: Move
615
+ * with nothing to move, Add with an empty catalog, the palette with no toolbar.
616
+ */
617
+ declare function runToolbarAction(action: ToolbarAction): boolean;
618
+ interface ToolbarShortcutOptions {
619
+ /** @default true */
620
+ enabled?: boolean;
621
+ /**
622
+ * Whether the keys belong to the editor right now — the web component passes
623
+ * "the panel is open". Read per keystroke, so it can follow UI state.
624
+ * @default always
625
+ */
626
+ isActive?: () => boolean;
627
+ target?: Window;
628
+ }
629
+ /**
630
+ * Install the toolbar shortcuts.
631
+ *
632
+ * @returns An uninstall function.
633
+ */
634
+ declare function installToolbarShortcuts(options?: ToolbarShortcutOptions): () => void;
635
+
440
636
  /**
441
637
  * Keeps the gizmo modes from outliving the selection they act on.
442
638
  *
@@ -535,6 +731,18 @@ interface ZylemEditorConfig {
535
731
  * @default true
536
732
  */
537
733
  enableEscapeShortcut?: boolean;
734
+ /**
735
+ * Whether the toolbar's keys are installed: Q/W/E/R for the tools, A to arm
736
+ * placement, X for delete, D/S/G for debug, snap and grid, and Cmd/Ctrl+Enter
737
+ * for play/pause. They are live while the editor panel is open, whether the
738
+ * simulation is playing or paused, and are stopped before the game's own key
739
+ * bindings see them; with the panel closed the keys are the game's.
740
+ *
741
+ * Disable it to bind the keys yourself; the actions are exported as
742
+ * `selectTool`, `selectTransformTool`, `togglePlayback` and friends.
743
+ * @default true
744
+ */
745
+ enableToolbarShortcuts?: boolean;
538
746
  }
539
747
  /**
540
748
  * ZylemEditorElement - A web component that wraps the Zylem Editor.
@@ -596,6 +804,8 @@ declare class ZylemEditorElement extends HTMLElement {
596
804
  openPanel(): void;
597
805
  closePanel(): void;
598
806
  togglePanel(): void;
807
+ /** Whether the main panel is showing. Collapsed counts as showing; closed does not. */
808
+ isPanelOpen(): boolean;
599
809
  /**
600
810
  * Dock a panel to a viewport edge, or pass `null` to float it again.
601
811
  * Defaults to the main editor panel.
@@ -756,4 +966,4 @@ type SceneOperationListener = (op: SceneOperationPayload) => void;
756
966
  */
757
967
  declare function onSceneOperation(listener: SceneOperationListener): () => void;
758
968
 
759
- export { type CatalogState, DEFAULT_ROTATE_SNAP, DOCK_SIDES, type DockPanelId, type DockRect, type DockRegistry, type DockSide, type DockZoneState, type EditorDockDefaults, type EditorEvent, type EditorEventType, type EditorStateBridge, type EditorStateBridgeOptions, type EditorUpdatePayload, type HistoryState, Icon, MAIN_PANEL_ID, MAX_HISTORY_DEPTH, type MountZylemEditorOptions, type MountedZylemEditor, type SceneOperationListener, type StageExport, type StageExportEntity, type TransformState, type TransformToolGuardOptions, type ZylemEditorConfig, ZylemEditorElement, attachEditorStateBridge, channel as bridgeChannel, buildStageExport, canRedo, canUndo, catalogState, clearHistory, computeDockLayout, connectEditorBridge, copyStageExport, debugState, debugStore, disarmTools, disconnectEditorBridge, dispatchEditorUpdate, dispatchToEditor, dockPanelToSide, editorEvents, findDockedSide, gameState, getDockedSide, historyState, installTransformToolGuard, mountZylemEditor, onSceneOperation, redo, redoLabel, registerZylemEditor, releaseOrphanedTransformTool, sendAddType, sendDebugEnabled, sendEntityCreate, sendEntityFocus, sendEntitySelect, sendEntityTransform, sendGridVisible, sendPlayback, sendSnapSettings, sendStageVariable, sendTool, setArmedType, setEntityCatalog, setGridVisible, setSnapEnabled, setSnapIncrements, stageExportToString, stageState, transformState, undo, undoLabel, undockPanelFromSides };
969
+ export { type CatalogState, type ClickTool, DEFAULT_ROTATE_SNAP, DOCK_SIDES, type DockPanelId, type DockRect, type DockRegistry, type DockSide, type DockZoneState, type EditorDockDefaults, type EditorEvent, type EditorEventType, type EditorStateBridge, type EditorStateBridgeOptions, type EditorUpdatePayload, type HistoryState, Icon, MAIN_PANEL_ID, MAX_HISTORY_DEPTH, type MountZylemEditorOptions, type MountedZylemEditor, type SceneOperationListener, type ShortcutChord, type StageExport, type StageExportEntity, TOOLBAR_SHORTCUTS, type ToolbarAction, type ToolbarShortcutId, type ToolbarShortcutOptions, type TransformState, type TransformTool, type TransformToolGuardOptions, type ZylemEditorConfig, ZylemEditorElement, armAddTool, armAddType, attachEditorStateBridge, channel as bridgeChannel, buildStageExport, canRedo, canUndo, catalogState, clearHistory, computeDockLayout, connectEditorBridge, copyStageExport, debugState, debugStore, disarmTools, disconnectEditorBridge, dispatchEditorUpdate, dispatchToEditor, dockPanelToSide, editorEvents, findDockedSide, formatShortcut, gameState, getDockedSide, historyState, installToolbarShortcuts, installTransformToolGuard, mountZylemEditor, onSceneOperation, openAddPalette, redo, redoLabel, registerZylemEditor, releaseOrphanedTransformTool, runToolbarAction, selectTool, selectTransformTool, sendAddType, sendDebugEnabled, sendEntityCreate, sendEntityFocus, sendEntitySelect, sendEntitySelectMany, sendEntityTransform, sendGridVisible, sendPlayback, sendSnapSettings, sendStageVariable, sendTool, setArmedType, setEntityCatalog, setGridVisible, setSnapEnabled, setSnapIncrements, stageExportToString, stageState, toggleDebug, toggleGrid, togglePlayback, toggleSnap, toggleTool, toggleTransformTool, transformState, undo, undoLabel, undockPanelFromSides };