@vibevibes/sdk 0.1.0 → 0.2.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/index.d.cts CHANGED
@@ -1,4 +1,4 @@
1
- import React from 'react';
1
+ import React$1 from 'react';
2
2
  import { z } from 'zod';
3
3
 
4
4
  /**
@@ -65,6 +65,48 @@ type ExperienceManifest = {
65
65
  /** State keys routed through fast ephemeral channel (no tool gate). */
66
66
  hotKeys?: string[];
67
67
  };
68
+ /**
69
+ * Room configuration schema + metadata.
70
+ *
71
+ * Experience authors declare what values a room accepts when spawned.
72
+ * Each room becomes an instance of the experience with a specific config.
73
+ * Think of it as: experience = game engine, config = level parameters.
74
+ *
75
+ * Example:
76
+ * roomConfig: defineRoomConfig({
77
+ * schema: z.object({
78
+ * mode: z.enum(["combat", "explore", "dialogue"]).describe("Room game mode"),
79
+ * difficulty: z.number().min(1).max(10).default(5).describe("Difficulty level"),
80
+ * theme: z.string().default("forest").describe("Visual theme"),
81
+ * }),
82
+ * defaults: { mode: "explore", difficulty: 5, theme: "forest" },
83
+ * presets: {
84
+ * "boss-fight": { mode: "combat", difficulty: 10, theme: "volcano" },
85
+ * "peaceful": { mode: "explore", difficulty: 1, theme: "meadow" },
86
+ * },
87
+ * })
88
+ */
89
+ type RoomConfigDef<TConfig extends Record<string, any> = Record<string, any>> = {
90
+ /** Zod schema defining the config shape. Used for validation + JSON schema generation. */
91
+ schema: z.ZodTypeAny;
92
+ /** Default config values for rooms that don't specify config at spawn time. */
93
+ defaults?: Partial<TConfig>;
94
+ /** Named presets: quick ways to spawn rooms with predefined configs. */
95
+ presets?: Record<string, TConfig>;
96
+ /** Human-readable description of what this config controls. */
97
+ description?: string;
98
+ };
99
+ /** Stream definition for high-frequency continuous state updates.
100
+ * Bypasses the full tool handler pipeline but still validates and persists to state. */
101
+ type StreamDef<TInput = any> = {
102
+ name: string;
103
+ description?: string;
104
+ input_schema: z.ZodTypeAny;
105
+ /** Pure merge function: takes current state, stream input, and actorId, returns new state. */
106
+ merge: (state: Record<string, any>, input: TInput, actorId: string) => Record<string, any>;
107
+ /** Max inputs per second per actor (server-enforced). Default: 60. */
108
+ rateLimit?: number;
109
+ };
68
110
  /**
69
111
  * Simplified Tool Context (no yjs, no events array)
70
112
  *
@@ -73,7 +115,7 @@ type ExperienceManifest = {
73
115
  * const current = ctx.state.count; // typed
74
116
  * }
75
117
  */
76
- type ToolCtx<TState extends Record<string, any> = Record<string, any>> = {
118
+ type ToolCtx<TState extends Record<string, any> = Record<string, any>, TConfig extends Record<string, any> = Record<string, any>> = {
77
119
  roomId: string;
78
120
  actorId: string;
79
121
  owner?: string;
@@ -82,12 +124,22 @@ type ToolCtx<TState extends Record<string, any> = Record<string, any>> = {
82
124
  timestamp: number;
83
125
  memory: Record<string, any>;
84
126
  setMemory: (updates: Record<string, any>) => void;
127
+ /**
128
+ * This room's config values. Set at spawn time, immutable after creation.
129
+ * Allows tools to behave differently based on the room's modality.
130
+ * e.g. `ctx.roomConfig.mode === "combat"` to branch tool behavior.
131
+ */
132
+ roomConfig: TConfig;
85
133
  /**
86
134
  * Spawn a child room with a specified experience.
87
135
  * Only available when manifest declares "room.spawn" in requested_capabilities.
88
136
  * Rate limited to 5 spawns per room per 5 minutes.
89
137
  */
90
138
  spawnRoom?: (opts: SpawnRoomOpts) => Promise<SpawnRoomResult>;
139
+ /** Store a binary blob (pixel buffers, audio, etc). Returns the blob key. */
140
+ setBlob?: (key: string, data: ArrayBuffer) => string;
141
+ /** Retrieve a binary blob by key. */
142
+ getBlob?: (key: string) => ArrayBuffer | undefined;
91
143
  };
92
144
  type ToolDef<TInput = any, TOutput = any> = {
93
145
  name: string;
@@ -113,7 +165,7 @@ type ToolDef<TInput = any, TOutput = any> = {
113
165
  * const count = sharedState.count; // fully typed
114
166
  * };
115
167
  */
116
- type CanvasProps<TState extends Record<string, any> = Record<string, any>> = {
168
+ type CanvasProps<TState extends Record<string, any> = Record<string, any>, TConfig extends Record<string, any> = Record<string, any>> = {
117
169
  roomId: string;
118
170
  actorId: string;
119
171
  sharedState: TState;
@@ -134,7 +186,15 @@ type CanvasProps<TState extends Record<string, any> = Record<string, any>> = {
134
186
  actorId: string;
135
187
  ts: number;
136
188
  }) => void) => () => void;
189
+ /** Send high-frequency continuous input via WebSocket stream. Bypasses tool gate. */
190
+ stream?: (name: string, input: any) => void;
137
191
  participants: string[];
192
+ /**
193
+ * This room's config values, set at spawn time.
194
+ * Use this to adapt the UI based on the room's modality.
195
+ * e.g. render a combat UI vs exploration UI based on `roomConfig.mode`.
196
+ */
197
+ roomConfig: TConfig;
138
198
  };
139
199
  /**
140
200
  * Assertion chain returned by `expect()` in test helpers.
@@ -165,6 +225,7 @@ type TestHelpers = {
165
225
  actorId?: string;
166
226
  roomId?: string;
167
227
  owner?: string;
228
+ roomConfig?: Record<string, any>;
168
229
  }) => ToolCtx & {
169
230
  getState: () => Record<string, any>;
170
231
  };
@@ -180,20 +241,15 @@ type TestDef = {
180
241
  run: (helpers: TestHelpers) => Promise<void>;
181
242
  };
182
243
  /**
183
- * Declarative hint for agents about when to act.
184
- * Experience authors include these to guide agent behavior.
244
+ * Combined context for the agent's Stop hook.
245
+ * Returned by the /agent-context endpoint everything the agent needs
246
+ * to decide what to do next in a single HTTP call.
185
247
  */
186
- type AgentHint = {
187
- trigger: string;
188
- condition?: string;
189
- suggestedTools: string[];
190
- priority?: 'low' | 'medium' | 'high';
191
- cooldownMs?: number;
192
- /** Cross-room agent coordination: follow linked rooms and react to activity there. */
193
- crossRoom?: {
194
- linkTypes?: string[];
195
- watchFor?: string[];
196
- };
248
+ type AgentContext = {
249
+ events: ToolEvent[];
250
+ observation: Record<string, any>;
251
+ participants: string[];
252
+ sharedState: Record<string, any>;
197
253
  };
198
254
  /**
199
255
  * Client-authoritative action that bypasses the tool gate entirely.
@@ -261,10 +317,18 @@ type SpawnRoomOpts = {
261
317
  initialState?: Record<string, any>;
262
318
  /** If true, store parent roomId in child state as _parentRoom */
263
319
  linkBack?: boolean;
320
+ /**
321
+ * Config values for the new room. Validated against the experience's roomConfig schema.
322
+ * If a preset name is given as a string, the preset's config is used.
323
+ * If omitted, the experience's default config is applied.
324
+ */
325
+ config?: Record<string, any> | string;
264
326
  };
265
327
  type SpawnRoomResult = {
266
328
  roomId: string;
267
329
  url: string;
330
+ /** The resolved config applied to the spawned room. */
331
+ config: Record<string, any>;
268
332
  };
269
333
  /**
270
334
  * A link between two rooms (parent/child relationship).
@@ -276,16 +340,75 @@ type RoomLink = {
276
340
  metadata?: Record<string, any>;
277
341
  createdAt: string;
278
342
  };
343
+ /**
344
+ * A single entry in the experience registry (vibevibes.registry.json).
345
+ * Maps an experience ID to its source path for cross-experience room spawning.
346
+ */
347
+ type RegistryEntry = {
348
+ path: string;
349
+ };
350
+ /**
351
+ * Per-project experience registry format (vibevibes.registry.json).
352
+ * Enables cross-experience room spawning by mapping experience IDs to source paths.
353
+ */
354
+ type ExperienceRegistry = {
355
+ experiences: Record<string, RegistryEntry>;
356
+ };
279
357
  type ExperienceModule = {
280
358
  manifest: ExperienceManifest;
281
- Canvas: React.FC<CanvasProps>;
359
+ Canvas: React$1.FC<CanvasProps>;
282
360
  tools: ToolDef[];
283
361
  tests?: TestDef[];
284
- agentHints?: AgentHint[];
285
362
  /** Client-authoritative actions that bypass the tool gate. */
286
363
  ephemeralActions?: EphemeralActionDef[];
287
364
  /** State migrations for version upgrades. */
288
365
  migrations?: StateMigration[];
366
+ /**
367
+ * Zod schema for the shared state shape. Provides:
368
+ * - Type safety: ctx.state and sharedState are typed throughout
369
+ * - Runtime validation: tool mutations are validated against the schema
370
+ * - Auto-generated initialState: defaults from the schema populate initial state
371
+ * - Agent legibility: agents can inspect the schema to understand state shape
372
+ *
373
+ * Usage:
374
+ * stateSchema: z.object({
375
+ * count: z.number().default(0).describe("Current counter value"),
376
+ * players: z.array(z.object({
377
+ * name: z.string(),
378
+ * score: z.number().default(0),
379
+ * })).default([]).describe("Active players"),
380
+ * phase: z.enum(["setup", "playing", "finished"]).default("setup"),
381
+ * })
382
+ *
383
+ * If both stateSchema and initialState are provided, initialState takes
384
+ * precedence but is validated against the schema at startup.
385
+ */
386
+ stateSchema?: z.ZodTypeAny;
387
+ /**
388
+ * Room configuration schema.
389
+ * Declares what values each room instance accepts at spawn time.
390
+ * Turns your experience into a configurable engine:
391
+ * experience = engine, roomConfig = level/mode parameters.
392
+ *
393
+ * Example: A dungeon crawler where each room is a different biome:
394
+ * roomConfig: defineRoomConfig({
395
+ * schema: z.object({
396
+ * biome: z.enum(["forest", "cave", "desert"]),
397
+ * enemyDensity: z.number().min(0).max(1).default(0.5),
398
+ * }),
399
+ * presets: {
400
+ * "dark-cave": { biome: "cave", enemyDensity: 0.8 },
401
+ * "peaceful-forest": { biome: "forest", enemyDensity: 0.1 },
402
+ * },
403
+ * })
404
+ */
405
+ roomConfig?: RoomConfigDef;
406
+ /** Stream definitions for high-frequency continuous state updates (brush strokes, sliders, dragging).
407
+ * Bypasses the full tool handler pipeline but still validates and persists to state. */
408
+ streams?: StreamDef[];
409
+ /** Agent observation function. Computes a curated view of state for MCP agents.
410
+ * Called after each tool execution. If not defined, agents see the full state. */
411
+ observe?: (state: Record<string, any>, event: ToolEvent | null, actorId: string) => Record<string, any>;
289
412
  };
290
413
 
291
414
  declare function defineTool<TInput, TOutput>(config: {
@@ -316,10 +439,108 @@ declare function defineEphemeralAction(config: {
316
439
  * })
317
440
  */
318
441
  declare function quickTool<TInput>(name: string, description: string, input_schema: z.ZodType<TInput>, handler: ToolDef<TInput, any>["handler"]): ToolDef<TInput, any>;
319
- declare function defineExperience(module: ExperienceModule): ExperienceModule;
320
- declare function validateExperience(module: ExperienceModule): {
442
+ /**
443
+ * Pre-built tool that restores shared state to a previous snapshot.
444
+ * Required for useUndo/useRedo to work. Add it to your tools array:
445
+ *
446
+ * tools: [...yourTools, undoTool(z)]
447
+ */
448
+ declare function undoTool(zod: any): ToolDef<{
449
+ state: Record<string, any>;
450
+ }, {
451
+ restored: boolean;
452
+ }>;
453
+ /**
454
+ * Pre-built tool for phase transitions. Required for usePhase to work.
455
+ * Add it to your tools array:
456
+ *
457
+ * tools: [...yourTools, phaseTool(z)]
458
+ *
459
+ * Optionally pass the list of valid phases for validation:
460
+ * phaseTool(z, ["setup", "playing", "scoring", "finished"])
461
+ */
462
+ declare function phaseTool(zod: any, validPhases?: readonly string[]): ToolDef<{
463
+ phase: string;
464
+ }, {
465
+ phase: string;
466
+ }>;
467
+ /**
468
+ * Define a room configuration schema.
469
+ * Rooms spawned with this experience will be validated against this schema.
470
+ *
471
+ * Usage:
472
+ * import { defineRoomConfig } from "@vibevibes/sdk";
473
+ * import { z } from "zod";
474
+ *
475
+ * const roomConfig = defineRoomConfig({
476
+ * schema: z.object({
477
+ * mode: z.enum(["combat", "explore", "dialogue"]),
478
+ * difficulty: z.number().min(1).max(10).default(5),
479
+ * }),
480
+ * defaults: { mode: "explore", difficulty: 5 },
481
+ * presets: {
482
+ * "boss-fight": { mode: "combat", difficulty: 10 },
483
+ * "peaceful": { mode: "explore", difficulty: 1 },
484
+ * },
485
+ * description: "Configure the room's game mode and difficulty",
486
+ * });
487
+ */
488
+ declare function defineRoomConfig<TConfig extends Record<string, any>>(config: RoomConfigDef<TConfig>): RoomConfigDef<TConfig>;
489
+ /**
490
+ * Define a continuous state stream for high-frequency human input.
491
+ * Streams bypass the full tool handler pipeline but still validate input
492
+ * and persist to shared state via a pure merge function.
493
+ *
494
+ * Usage:
495
+ * import { defineStream } from "@vibevibes/sdk";
496
+ * import { z } from "zod";
497
+ *
498
+ * const brushStream = defineStream({
499
+ * name: "brush.stroke",
500
+ * description: "Continuous brush stroke data",
501
+ * input_schema: z.object({
502
+ * x: z.number(),
503
+ * y: z.number(),
504
+ * pressure: z.number().min(0).max(1),
505
+ * color: z.string(),
506
+ * }),
507
+ * merge: (state, input, actorId) => ({
508
+ * ...state,
509
+ * strokes: [...(state.strokes || []), { ...input, actorId, ts: Date.now() }],
510
+ * }),
511
+ * rateLimit: 60, // max 60 inputs/sec/actor
512
+ * });
513
+ */
514
+ declare function defineStream<TInput>(config: {
515
+ name: string;
516
+ description?: string;
517
+ input_schema: z.ZodType<TInput>;
518
+ merge: (state: Record<string, any>, input: TInput, actorId: string) => Record<string, any>;
519
+ rateLimit?: number;
520
+ }): StreamDef<TInput>;
521
+ declare function defineExperience(module: ExperienceModule & {
522
+ /** Initial state for the experience. If stateSchema is provided and initialState is not,
523
+ * defaults are extracted from the schema automatically. */
524
+ initialState?: Record<string, any>;
525
+ /** Agent slot configurations. */
526
+ agents?: Array<{
527
+ role: string;
528
+ systemPrompt: string;
529
+ allowedTools?: string[];
530
+ autoSpawn?: boolean;
531
+ maxInstances?: number;
532
+ }>;
533
+ /** Display name (convenience, copied to manifest.title if manifest.title is missing). */
534
+ name?: string;
535
+ }): ExperienceModule & {
536
+ initialState?: Record<string, any>;
537
+ };
538
+ declare function validateExperience(module: ExperienceModule & {
539
+ initialState?: Record<string, any>;
540
+ }): {
321
541
  valid: boolean;
322
542
  errors: string[];
543
+ warnings: string[];
323
544
  };
324
545
 
325
546
  /**
@@ -333,7 +554,7 @@ declare function validateExperience(module: ExperienceModule): {
333
554
  *
334
555
  * Hooks rely on React being available as a global (provided by the bundler runtime).
335
556
  */
336
- type CallToolFn = (name: string, input: any) => Promise<any>;
557
+ type CallToolFn$3 = (name: string, input: any) => Promise<any>;
337
558
  type UseToolCallReturn = {
338
559
  call: (name: string, input: any) => Promise<any>;
339
560
  loading: boolean;
@@ -346,7 +567,7 @@ type UseToolCallReturn = {
346
567
  * const { call, loading, error } = useToolCall(callTool);
347
568
  * <button onClick={() => call('counter.increment', {})} disabled={loading}>
348
569
  */
349
- declare function useToolCall(callTool: CallToolFn): UseToolCallReturn;
570
+ declare function useToolCall(callTool: CallToolFn$3): UseToolCallReturn;
350
571
  /**
351
572
  * Typed accessor for a specific key in shared state.
352
573
  *
@@ -366,7 +587,7 @@ type UseOptimisticToolReturn = {
366
587
  * const { call, state, pending } = useOptimisticTool(callTool, sharedState);
367
588
  * call('counter.increment', {}, { count: sharedState.count + 1 });
368
589
  */
369
- declare function useOptimisticTool(callTool: CallToolFn, sharedState: Record<string, any>): UseOptimisticToolReturn;
590
+ declare function useOptimisticTool(callTool: CallToolFn$3, sharedState: Record<string, any>): UseOptimisticToolReturn;
370
591
  /**
371
592
  * Decouples render frequency from state sync frequency.
372
593
  * State updates are buffered and applied at most once per animation frame.
@@ -451,6 +672,117 @@ declare function useTypingIndicator(actorId: string, ephemeralState: Record<stri
451
672
  setTyping: (isTyping: boolean) => void;
452
673
  typingUsers: string[];
453
674
  };
675
+ type UseUndoReturn = {
676
+ /** Undo the last state change. No-op if nothing to undo. */
677
+ undo: () => void;
678
+ /** Redo the last undone state change. No-op if nothing to redo. */
679
+ redo: () => void;
680
+ /** Whether undo is available. */
681
+ canUndo: boolean;
682
+ /** Whether redo is available. */
683
+ canRedo: boolean;
684
+ /** Number of states in the undo stack. */
685
+ undoCount: number;
686
+ /** Number of states in the redo stack. */
687
+ redoCount: number;
688
+ };
689
+ /**
690
+ * Undo/redo for shared state via tool calls.
691
+ *
692
+ * Tracks state snapshots as sharedState changes. Undo/redo restore
693
+ * previous/next snapshots by calling a tool (default: "_state.restore").
694
+ *
695
+ * The server needs a `_state.restore` tool registered (or pass a custom
696
+ * restoreTool name). If the tool doesn't exist, undo triggers callTool
697
+ * which will return an error — but it won't crash.
698
+ *
699
+ * Usage:
700
+ * const { undo, redo, canUndo, canRedo } = useUndo(sharedState, callTool);
701
+ * <button onClick={undo} disabled={!canUndo}>Undo</button>
702
+ * <button onClick={redo} disabled={!canRedo}>Redo</button>
703
+ */
704
+ declare function useUndo(sharedState: Record<string, any>, callTool: CallToolFn$3, opts?: {
705
+ maxHistory?: number;
706
+ restoreTool?: string;
707
+ }): UseUndoReturn;
708
+ /**
709
+ * Returns a debounced version of callTool. Calls are delayed by `delayMs`
710
+ * and collapsed — only the last call within the window fires.
711
+ *
712
+ * Perfect for search inputs, text fields, sliders.
713
+ *
714
+ * Usage:
715
+ * const debouncedCall = useDebounce(callTool, 300);
716
+ * <input onChange={(e) => debouncedCall('search.update', { query: e.target.value })} />
717
+ */
718
+ declare function useDebounce(callTool: CallToolFn$3, delayMs?: number): CallToolFn$3;
719
+ /**
720
+ * Returns a throttled version of callTool. At most one call fires per
721
+ * `intervalMs`. Trailing calls are queued and fire after the interval.
722
+ *
723
+ * Perfect for cursor positions, brush strokes, drag events.
724
+ *
725
+ * Usage:
726
+ * const throttledCall = useThrottle(callTool, 50);
727
+ * onMouseMove={(e) => throttledCall('cursor.move', { x: e.clientX, y: e.clientY })}
728
+ */
729
+ declare function useThrottle(callTool: CallToolFn$3, intervalMs?: number): CallToolFn$3;
730
+ type PhaseConfig<TPhase extends string = string> = {
731
+ /** Ordered list of phase names. */
732
+ phases: readonly TPhase[];
733
+ /** The state key that stores the current phase. Default: "phase". */
734
+ stateKey?: string;
735
+ /** Tool name for phase transitions. Default: "_phase.set". */
736
+ toolName?: string;
737
+ };
738
+ type UsePhaseReturn<TPhase extends string = string> = {
739
+ /** Current phase name. */
740
+ current: TPhase;
741
+ /** Index of current phase (0-based). */
742
+ index: number;
743
+ /** Whether current phase is the first. */
744
+ isFirst: boolean;
745
+ /** Whether current phase is the last. */
746
+ isLast: boolean;
747
+ /** Advance to the next phase. No-op if already last. */
748
+ next: () => void;
749
+ /** Go back to the previous phase. No-op if already first. */
750
+ prev: () => void;
751
+ /** Jump to a specific phase by name. */
752
+ goTo: (phase: TPhase) => void;
753
+ /** Check if the current phase matches. */
754
+ is: (phase: TPhase) => boolean;
755
+ };
756
+ /**
757
+ * Manages a linear phase/stage machine via shared state.
758
+ *
759
+ * Almost every experience has phases: setup → active → review,
760
+ * ideate → cluster → prioritize, listen → improvise → refine.
761
+ * This hook compresses that pattern into a one-liner.
762
+ *
763
+ * Usage:
764
+ * const phase = usePhase(sharedState, callTool, {
765
+ * phases: ["setup", "playing", "scoring", "finished"] as const,
766
+ * });
767
+ *
768
+ * if (phase.is("setup")) return <SetupScreen />;
769
+ * if (phase.is("playing")) return <GameBoard />;
770
+ *
771
+ * <button onClick={phase.next} disabled={phase.isLast}>Next Phase</button>
772
+ *
773
+ * Requires a tool to be registered (or use the built-in phaseTool):
774
+ * tools: [...yourTools, phaseTool(z)]
775
+ */
776
+ declare function usePhase<TPhase extends string>(sharedState: Record<string, any>, callTool: CallToolFn$3, config: PhaseConfig<TPhase>): UsePhaseReturn<TPhase>;
777
+ /**
778
+ * Fetches and caches a binary blob from the server.
779
+ * Returns the ArrayBuffer when loaded, null while loading.
780
+ *
781
+ * Usage:
782
+ * const pixels = useBlob(sharedState.canvasBlobId);
783
+ * if (pixels) { // render pixels }
784
+ */
785
+ declare function useBlob(blobKey: string | null | undefined, serverUrl?: string): ArrayBuffer | null;
454
786
 
455
787
  /**
456
788
  * Pre-built UI components for experiences.
@@ -508,6 +840,65 @@ type GridProps = {
508
840
  style?: Record<string, any>;
509
841
  };
510
842
  declare function Grid({ children, columns, gap, style }: GridProps): any;
843
+ type SliderProps = {
844
+ value?: number;
845
+ onChange?: (value: number) => void;
846
+ min?: number;
847
+ max?: number;
848
+ step?: number;
849
+ disabled?: boolean;
850
+ label?: string;
851
+ style?: Record<string, any>;
852
+ };
853
+ declare function Slider({ value, onChange, min, max, step, disabled, label, style }: SliderProps): any;
854
+ type TextareaProps = {
855
+ value?: string;
856
+ onChange?: (value: string) => void;
857
+ placeholder?: string;
858
+ rows?: number;
859
+ disabled?: boolean;
860
+ style?: Record<string, any>;
861
+ };
862
+ declare function Textarea({ value, onChange, placeholder, rows, disabled, style }: TextareaProps): any;
863
+ type ModalProps = {
864
+ children?: any;
865
+ open?: boolean;
866
+ onClose?: () => void;
867
+ title?: string;
868
+ style?: Record<string, any>;
869
+ };
870
+ declare function Modal({ children, open, onClose, title, style }: ModalProps): any;
871
+ type ColorPickerProps = {
872
+ value?: string;
873
+ onChange?: (color: string) => void;
874
+ presets?: string[];
875
+ disabled?: boolean;
876
+ style?: Record<string, any>;
877
+ };
878
+ declare function ColorPicker({ value, onChange, presets, disabled, style }: ColorPickerProps): any;
879
+ type DropdownProps = {
880
+ value?: string;
881
+ onChange?: (value: string) => void;
882
+ options: Array<{
883
+ value: string;
884
+ label: string;
885
+ }>;
886
+ placeholder?: string;
887
+ disabled?: boolean;
888
+ style?: Record<string, any>;
889
+ };
890
+ declare function Dropdown({ value, onChange, options, placeholder, disabled, style }: DropdownProps): any;
891
+ type TabsProps = {
892
+ tabs: Array<{
893
+ id: string;
894
+ label: string;
895
+ }>;
896
+ activeTab?: string;
897
+ onTabChange?: (id: string) => void;
898
+ children?: any;
899
+ style?: Record<string, any>;
900
+ };
901
+ declare function Tabs({ tabs, activeTab, onTabChange, children, style }: TabsProps): any;
511
902
 
512
903
  /**
513
904
  * Multi-agent negotiation protocol.
@@ -516,12 +907,6 @@ declare function Grid({ children, columns, gap, style }: GridProps): any;
516
907
 
517
908
  declare function createAgentProtocolTools(namespace: string, z: any): ToolDef[];
518
909
 
519
- /**
520
- * Pre-built agent hints for the negotiation protocol.
521
- */
522
-
523
- declare function createAgentProtocolHints(namespace: string): AgentHint[];
524
-
525
910
  /**
526
911
  * State migration runner for experience versioning.
527
912
  *
@@ -619,4 +1004,873 @@ declare class InMemoryAdapter implements StorageAdapter {
619
1004
  loadUserProfile(userId: string): Promise<any | null>;
620
1005
  }
621
1006
 
622
- export { type AgentHint, type AgentMessage, type AgentSlot, Badge, Button, type CanvasProps, Card, type EphemeralActionDef, type ExpectChain, type ExperienceImport, type ExperienceListing, type ExperienceManifest, type ExperienceModule, type FollowState, Grid, InMemoryAdapter, Input, type JsonPatchOp, type MigrationResult, type NetcodeMode, type ParsedParticipant, type PerfMetrics, type RoomLink, type RoomState, type SpawnRoomOpts, type SpawnRoomResult, Stack, type StateMigration, type StorageAdapter, type StorageToolEvent, type TestDef, type TestHelpers, type ToolCtx, type ToolDef, type ToolEvent, type ToolRisk, type UseFollowReturn, type UseOptimisticToolReturn, type UseToolCallReturn, type WebhookEventType, compareSemver, createAgentProtocolHints, createAgentProtocolTools, defineEphemeralAction, defineExperience, defineTest, defineTool, getStateVersion, migrateState, quickTool, useAnimationFrame, useFollow, useOptimisticTool, useParticipants, useSharedState, useToolCall, useTypingIndicator, validateExperience };
1007
+ /**
1008
+ * Scene Graph Type Definitions
1009
+ *
1010
+ * The scene graph is a serializable JSON structure that lives in sharedState._scene.
1011
+ * Both humans (via Canvas UI) and agents (via MCP tools) read and write this structure.
1012
+ * The renderer reads it and produces SVG output.
1013
+ *
1014
+ * Every type here MUST be JSON-serializable (no functions, no class instances, no circular refs).
1015
+ */
1016
+ type Vec2 = {
1017
+ x: number;
1018
+ y: number;
1019
+ };
1020
+ type Transform = {
1021
+ x?: number;
1022
+ y?: number;
1023
+ rotation?: number;
1024
+ scaleX?: number;
1025
+ scaleY?: number;
1026
+ originX?: number;
1027
+ originY?: number;
1028
+ };
1029
+ type GradientStop = {
1030
+ offset: number;
1031
+ color: string;
1032
+ };
1033
+ type LinearGradient = {
1034
+ type: 'linear';
1035
+ id: string;
1036
+ x1: number;
1037
+ y1: number;
1038
+ x2: number;
1039
+ y2: number;
1040
+ stops: GradientStop[];
1041
+ };
1042
+ type RadialGradient = {
1043
+ type: 'radial';
1044
+ id: string;
1045
+ cx: number;
1046
+ cy: number;
1047
+ r: number;
1048
+ fx?: number;
1049
+ fy?: number;
1050
+ stops: GradientStop[];
1051
+ };
1052
+ type Gradient = LinearGradient | RadialGradient;
1053
+ type FilterType = 'blur' | 'shadow' | 'glow' | 'brightness' | 'contrast' | 'saturate' | 'hue-rotate';
1054
+ type FilterDef = {
1055
+ id: string;
1056
+ type: FilterType;
1057
+ params: Record<string, number | string>;
1058
+ };
1059
+ type Style = {
1060
+ fill?: string;
1061
+ stroke?: string;
1062
+ strokeWidth?: number;
1063
+ strokeDasharray?: string;
1064
+ strokeLinecap?: 'butt' | 'round' | 'square';
1065
+ strokeLinejoin?: 'miter' | 'round' | 'bevel';
1066
+ opacity?: number;
1067
+ fillOpacity?: number;
1068
+ strokeOpacity?: number;
1069
+ filter?: string;
1070
+ cursor?: string;
1071
+ pointerEvents?: 'auto' | 'none';
1072
+ visible?: boolean;
1073
+ };
1074
+ type TextStyle = Style & {
1075
+ fontSize?: number;
1076
+ fontFamily?: string;
1077
+ fontWeight?: number | string;
1078
+ textAnchor?: 'start' | 'middle' | 'end';
1079
+ dominantBaseline?: 'auto' | 'middle' | 'hanging' | 'text-top';
1080
+ letterSpacing?: number;
1081
+ };
1082
+ type SceneNodeBase = {
1083
+ id: string;
1084
+ name?: string;
1085
+ transform?: Transform;
1086
+ style?: Style;
1087
+ interactive?: boolean;
1088
+ data?: Record<string, any>;
1089
+ tween?: TweenDef;
1090
+ };
1091
+ type RectNode = SceneNodeBase & {
1092
+ type: 'rect';
1093
+ width: number;
1094
+ height: number;
1095
+ rx?: number;
1096
+ ry?: number;
1097
+ };
1098
+ type CircleNode = SceneNodeBase & {
1099
+ type: 'circle';
1100
+ radius: number;
1101
+ };
1102
+ type EllipseNode = SceneNodeBase & {
1103
+ type: 'ellipse';
1104
+ rx: number;
1105
+ ry: number;
1106
+ };
1107
+ type LineNode = SceneNodeBase & {
1108
+ type: 'line';
1109
+ x2: number;
1110
+ y2: number;
1111
+ };
1112
+ type PolylineNode = SceneNodeBase & {
1113
+ type: 'polyline';
1114
+ points: Vec2[];
1115
+ };
1116
+ type PolygonNode = SceneNodeBase & {
1117
+ type: 'polygon';
1118
+ points: Vec2[];
1119
+ };
1120
+ type PathNode = SceneNodeBase & {
1121
+ type: 'path';
1122
+ d: string;
1123
+ };
1124
+ type TextNode = SceneNodeBase & {
1125
+ type: 'text';
1126
+ text: string;
1127
+ style?: TextStyle;
1128
+ };
1129
+ type ImageNode = SceneNodeBase & {
1130
+ type: 'image';
1131
+ href: string;
1132
+ width: number;
1133
+ height: number;
1134
+ preserveAspectRatio?: string;
1135
+ };
1136
+ type GroupNode = SceneNodeBase & {
1137
+ type: 'group';
1138
+ children: SceneNode[];
1139
+ clipPath?: string;
1140
+ };
1141
+ type SpriteAnimation = {
1142
+ frames: number[];
1143
+ fps: number;
1144
+ loop?: boolean;
1145
+ playing?: boolean;
1146
+ };
1147
+ type SpriteNode = SceneNodeBase & {
1148
+ type: 'sprite';
1149
+ href: string;
1150
+ frameWidth: number;
1151
+ frameHeight: number;
1152
+ frame: number;
1153
+ columns?: number;
1154
+ animation?: SpriteAnimation;
1155
+ };
1156
+ type TilemapNode = SceneNodeBase & {
1157
+ type: 'tilemap';
1158
+ href: string;
1159
+ tileWidth: number;
1160
+ tileHeight: number;
1161
+ columns: number;
1162
+ data: number[][];
1163
+ width: number;
1164
+ height: number;
1165
+ };
1166
+ type ParticleEmitter = {
1167
+ x: number;
1168
+ y: number;
1169
+ rate: number;
1170
+ lifetime: number;
1171
+ speed: {
1172
+ min: number;
1173
+ max: number;
1174
+ };
1175
+ direction: {
1176
+ min: number;
1177
+ max: number;
1178
+ };
1179
+ gravity?: number;
1180
+ color?: string | string[];
1181
+ size?: {
1182
+ min: number;
1183
+ max: number;
1184
+ };
1185
+ fadeOut?: boolean;
1186
+ shape?: 'circle' | 'square';
1187
+ };
1188
+ type Particle = {
1189
+ x: number;
1190
+ y: number;
1191
+ vx: number;
1192
+ vy: number;
1193
+ age: number;
1194
+ lifetime: number;
1195
+ size: number;
1196
+ color: string;
1197
+ };
1198
+ type ParticlesNode = SceneNodeBase & {
1199
+ type: 'particles';
1200
+ emitters: ParticleEmitter[];
1201
+ maxParticles?: number;
1202
+ _particles?: Particle[];
1203
+ };
1204
+ type SceneNode = RectNode | CircleNode | EllipseNode | LineNode | PolylineNode | PolygonNode | PathNode | TextNode | ImageNode | GroupNode | SpriteNode | TilemapNode | ParticlesNode;
1205
+ type SceneNodeType = SceneNode['type'];
1206
+ type EasingType = 'linear' | 'ease-in' | 'ease-out' | 'ease-in-out' | 'ease-in-quad' | 'ease-out-quad' | 'ease-in-out-quad' | 'ease-in-cubic' | 'ease-out-cubic' | 'ease-in-out-cubic' | 'ease-in-elastic' | 'ease-out-elastic' | 'ease-in-bounce' | 'ease-out-bounce';
1207
+ type TweenDef = {
1208
+ property: string;
1209
+ from: number;
1210
+ to: number;
1211
+ duration: number;
1212
+ easing?: EasingType;
1213
+ delay?: number;
1214
+ repeat?: number;
1215
+ yoyo?: boolean;
1216
+ startedAt?: number;
1217
+ };
1218
+ type Camera = {
1219
+ x: number;
1220
+ y: number;
1221
+ zoom: number;
1222
+ rotation?: number;
1223
+ bounds?: {
1224
+ minX: number;
1225
+ minY: number;
1226
+ maxX: number;
1227
+ maxY: number;
1228
+ };
1229
+ };
1230
+ type SceneGraph = {
1231
+ _sceneVersion?: number;
1232
+ root: GroupNode;
1233
+ camera?: Camera;
1234
+ background?: string;
1235
+ gradients?: Gradient[];
1236
+ filters?: FilterDef[];
1237
+ width?: number;
1238
+ height?: number;
1239
+ };
1240
+ type SceneRendererProps = {
1241
+ scene: SceneGraph;
1242
+ width?: number;
1243
+ height?: number;
1244
+ className?: string;
1245
+ style?: Record<string, any>;
1246
+ onNodeClick?: (nodeId: string, event: {
1247
+ x: number;
1248
+ y: number;
1249
+ }) => void;
1250
+ onNodeHover?: (nodeId: string | null) => void;
1251
+ onNodeDragStart?: (nodeId: string, pos: Vec2) => void;
1252
+ onNodeDrag?: (nodeId: string, pos: Vec2) => void;
1253
+ onNodeDragEnd?: (nodeId: string, pos: Vec2) => void;
1254
+ onViewportClick?: (pos: Vec2) => void;
1255
+ onViewportPan?: (delta: Vec2) => void;
1256
+ onViewportZoom?: (zoom: number, center: Vec2) => void;
1257
+ selectedNodeIds?: string[];
1258
+ debug?: boolean;
1259
+ };
1260
+ type SceneHitEvent = {
1261
+ nodeId: string;
1262
+ x: number;
1263
+ y: number;
1264
+ screenX: number;
1265
+ screenY: number;
1266
+ };
1267
+
1268
+ /**
1269
+ * Unified SceneRenderer component.
1270
+ * Defaults to PixiJS (WebGL) renderer. Falls back to SVG if pixi.js is not available.
1271
+ */
1272
+
1273
+ /**
1274
+ * Auto-selecting SceneRenderer.
1275
+ * Uses PixiJS (WebGL) when available, falls back to SVG.
1276
+ * Experience authors can also import PixiSceneRenderer or SvgSceneRenderer directly.
1277
+ */
1278
+ declare function SceneRenderer(props: SceneRendererProps): any;
1279
+
1280
+ /**
1281
+ * SVG Scene Renderer.
1282
+ *
1283
+ * Takes a SceneGraph and renders it as SVG using React createElement calls.
1284
+ * Uses the same getReact()/h() pattern as components.ts — no JSX, no import.
1285
+ */
1286
+
1287
+ declare function SvgSceneRenderer(props: SceneRendererProps): any;
1288
+
1289
+ /**
1290
+ * PixiJS WebGL Scene Renderer.
1291
+ *
1292
+ * Takes a SceneGraph and renders it to a WebGL canvas using PixiJS v8.
1293
+ * Uses retained-mode rendering: on scene change, diffs and updates Pixi display objects
1294
+ * rather than recreating the tree. Implements the same SceneRendererProps interface
1295
+ * as SvgSceneRenderer.
1296
+ *
1297
+ * PixiJS is an optional dependency. If not available, the component renders a fallback
1298
+ * message instructing the user to install pixi.js.
1299
+ *
1300
+ * Uses the getReact()/h() pattern — no JSX, no import React.
1301
+ */
1302
+
1303
+ declare function PixiSceneRenderer(props: SceneRendererProps): any;
1304
+
1305
+ /**
1306
+ * Pre-built scene manipulation tools.
1307
+ *
1308
+ * Factory function createSceneTools(namespace, z) returns ToolDef[] ready to
1309
+ * spread into defineExperience({ tools: [...sceneTools(z)] }).
1310
+ *
1311
+ * Follows the same pattern as createAgentProtocolTools in agent-protocol.ts.
1312
+ *
1313
+ * 5 tools total — minimal surface area, maximum expressiveness:
1314
+ * scene.add — add nodes
1315
+ * scene.update — update any node (props, transform, style, tween)
1316
+ * scene.remove — remove nodes
1317
+ * scene.set — scene-level settings (camera, background, gradients, clear)
1318
+ * scene.batch — multiple operations in one state update
1319
+ */
1320
+
1321
+ declare function createSceneTools(namespace: string, z: any): ToolDef[];
1322
+
1323
+ /**
1324
+ * Scene-specific React hooks.
1325
+ *
1326
+ * These hooks handle client-side concerns: interaction tracking, drag,
1327
+ * selection, viewport pan/zoom, tween interpolation, and particle simulation.
1328
+ *
1329
+ * Uses the same lazy React access pattern as sdk/src/hooks.ts.
1330
+ */
1331
+
1332
+ type CallToolFn$2 = (name: string, input: any) => Promise<any>;
1333
+ type SceneInteractionEvent = {
1334
+ type: 'click' | 'hover' | 'hoverEnd';
1335
+ nodeId: string;
1336
+ x: number;
1337
+ y: number;
1338
+ };
1339
+ type UseSceneInteractionReturn = {
1340
+ lastEvent: SceneInteractionEvent | null;
1341
+ hoveredNodeId: string | null;
1342
+ onNodeClick: (nodeId: string, event: {
1343
+ x: number;
1344
+ y: number;
1345
+ }) => void;
1346
+ onNodeHover: (nodeId: string | null) => void;
1347
+ };
1348
+ /**
1349
+ * Track click/hover events on scene nodes.
1350
+ * Returns callbacks to wire into SceneRenderer props.
1351
+ */
1352
+ declare function useSceneInteraction(): UseSceneInteractionReturn;
1353
+ type UseSceneDragReturn = {
1354
+ dragging: string | null;
1355
+ dragOffset: Vec2 | null;
1356
+ onNodeDragStart: (nodeId: string, pos: Vec2) => void;
1357
+ onNodeDrag: (nodeId: string, pos: Vec2) => void;
1358
+ onNodeDragEnd: (nodeId: string, pos: Vec2) => void;
1359
+ };
1360
+ /**
1361
+ * Drag scene nodes. On drag end, commits position via scene.transform tool call.
1362
+ */
1363
+ declare function useSceneDrag(callTool: CallToolFn$2, toolNamespace?: string): UseSceneDragReturn;
1364
+ type UseSceneSelectionReturn = {
1365
+ selectedIds: string[];
1366
+ select: (nodeId: string) => void;
1367
+ deselect: (nodeId: string) => void;
1368
+ toggle: (nodeId: string) => void;
1369
+ clear: () => void;
1370
+ isSelected: (nodeId: string) => boolean;
1371
+ };
1372
+ /**
1373
+ * Local multi-select state for scene nodes.
1374
+ */
1375
+ declare function useSceneSelection(): UseSceneSelectionReturn;
1376
+ type UseSceneViewportReturn = {
1377
+ camera: Camera;
1378
+ onViewportPan: (delta: Vec2) => void;
1379
+ onViewportZoom: (newZoom: number, center: Vec2) => void;
1380
+ };
1381
+ /**
1382
+ * Pan/zoom the scene camera. Debounces tool calls to persist camera changes.
1383
+ */
1384
+ declare function useSceneViewport(callTool: CallToolFn$2, scene: SceneGraph, toolNamespace?: string): UseSceneViewportReturn;
1385
+ /**
1386
+ * Client-side tween interpolation at 60fps.
1387
+ * Walks the scene graph, finds nodes with active tweens, interpolates
1388
+ * their values, and returns a new SceneGraph with interpolated properties.
1389
+ *
1390
+ * Does NOT modify shared state — purely display-side.
1391
+ */
1392
+ declare function useSceneTweens(scene: SceneGraph): SceneGraph;
1393
+ /**
1394
+ * Client-side particle simulation at 60fps.
1395
+ * Finds ParticlesNode nodes, spawns and ticks particles, returns scene
1396
+ * with updated _particles arrays.
1397
+ *
1398
+ * Does NOT modify shared state — purely display-side.
1399
+ */
1400
+ declare function useParticleTick(scene: SceneGraph): SceneGraph;
1401
+
1402
+ /**
1403
+ * Scene graph utility functions.
1404
+ *
1405
+ * These are pure functions that operate on the SceneGraph type.
1406
+ * Used by tool handlers, experience authors, and hooks.
1407
+ */
1408
+
1409
+ /**
1410
+ * Create an empty scene graph with sensible defaults.
1411
+ */
1412
+ declare function createScene(opts?: {
1413
+ width?: number;
1414
+ height?: number;
1415
+ background?: string;
1416
+ }): SceneGraph;
1417
+ /**
1418
+ * Create a new scene node with an auto-generated ID.
1419
+ *
1420
+ * Usage:
1421
+ * createNode('rect', { width: 100, height: 50, style: { fill: '#f00' } })
1422
+ * createNode('circle', { radius: 30 })
1423
+ * createNode('text', { text: 'Hello' })
1424
+ */
1425
+ declare function createNode(type: SceneNodeType, props: Omit<any, 'id' | 'type'> & {
1426
+ id?: string;
1427
+ }): SceneNode;
1428
+ /**
1429
+ * Find a node by ID anywhere in the scene graph.
1430
+ * Returns null if not found.
1431
+ */
1432
+ declare function nodeById(scene: SceneGraph, id: string): SceneNode | null;
1433
+ /**
1434
+ * Find all nodes matching a predicate.
1435
+ */
1436
+ declare function findNodes(scene: SceneGraph, predicate: (node: SceneNode) => boolean): SceneNode[];
1437
+ /**
1438
+ * Walk all nodes in the scene graph, calling the visitor for each.
1439
+ */
1440
+ declare function walkNodes(node: SceneNode, visitor: (node: SceneNode) => void): void;
1441
+ /**
1442
+ * Get a flat list of all node IDs in the scene.
1443
+ */
1444
+ declare function allNodeIds(scene: SceneGraph): string[];
1445
+ /**
1446
+ * Count total nodes in the scene graph.
1447
+ */
1448
+ declare function nodeCount(scene: SceneGraph): number;
1449
+ /**
1450
+ * Deep clone a scene graph (JSON round-trip).
1451
+ */
1452
+ declare function cloneScene(scene: SceneGraph): SceneGraph;
1453
+ /**
1454
+ * Remove a node from the scene graph by ID. Returns true if found and removed.
1455
+ */
1456
+ declare function removeNodeById(root: GroupNode, id: string): boolean;
1457
+ /**
1458
+ * Find a node's parent group. Returns null if node is the root or not found.
1459
+ */
1460
+ declare function findParent(root: GroupNode, nodeId: string): GroupNode | null;
1461
+ /**
1462
+ * Return all pre-built scene tools ready to spread into defineExperience.
1463
+ *
1464
+ * Usage:
1465
+ * import { sceneTools } from "@vibevibes/sdk";
1466
+ * export default defineExperience({
1467
+ * tools: [...myTools, ...sceneTools(z)],
1468
+ * });
1469
+ */
1470
+ declare function sceneTools(z: any, namespace?: string): ToolDef[];
1471
+
1472
+ /**
1473
+ * Fluent API for building SVG path `d` strings.
1474
+ *
1475
+ * Agents can also construct d strings directly, but this gives experience
1476
+ * authors a programmatic API for generating complex paths in tool handlers
1477
+ * or Canvas components.
1478
+ *
1479
+ * Usage:
1480
+ * const d = PathBuilder.from()
1481
+ * .moveTo(0, 0)
1482
+ * .lineTo(100, 0)
1483
+ * .lineTo(100, 100)
1484
+ * .close()
1485
+ * .build();
1486
+ * // "M 0 0 L 100 0 L 100 100 Z"
1487
+ */
1488
+ declare class PathBuilder {
1489
+ private commands;
1490
+ moveTo(x: number, y: number): this;
1491
+ lineTo(x: number, y: number): this;
1492
+ horizontalTo(x: number): this;
1493
+ verticalTo(y: number): this;
1494
+ quadTo(cx: number, cy: number, x: number, y: number): this;
1495
+ cubicTo(c1x: number, c1y: number, c2x: number, c2y: number, x: number, y: number): this;
1496
+ arcTo(rx: number, ry: number, rotation: number, largeArc: boolean, sweep: boolean, x: number, y: number): this;
1497
+ close(): this;
1498
+ rect(x: number, y: number, w: number, h: number): this;
1499
+ roundedRect(x: number, y: number, w: number, h: number, rx: number, ry?: number): this;
1500
+ circle(cx: number, cy: number, r: number): this;
1501
+ ellipse(cx: number, cy: number, rx: number, ry: number): this;
1502
+ star(cx: number, cy: number, points: number, outerR: number, innerR: number): this;
1503
+ arrow(x1: number, y1: number, x2: number, y2: number, headSize?: number): this;
1504
+ build(): string;
1505
+ static from(): PathBuilder;
1506
+ }
1507
+
1508
+ /**
1509
+ * Easing functions and tween interpolation logic.
1510
+ *
1511
+ * All easing functions take t (0-1) and return a value (0-1).
1512
+ * Used by the renderer for client-side animation interpolation.
1513
+ */
1514
+
1515
+ type EasingFn = (t: number) => number;
1516
+ declare const easingFunctions: Record<EasingType, EasingFn>;
1517
+ /**
1518
+ * Get the value at a given dot-path on an object.
1519
+ * e.g. getPath({ transform: { x: 10 } }, 'transform.x') => 10
1520
+ */
1521
+ declare function getPath(obj: any, path: string): any;
1522
+ /**
1523
+ * Set a value at a given dot-path on an object (immutable - returns new object).
1524
+ * e.g. setPath({ transform: { x: 10 } }, 'transform.x', 20) => { transform: { x: 20 } }
1525
+ */
1526
+ declare function setPath(obj: any, path: string, value: any): any;
1527
+ /**
1528
+ * Compute the interpolated value for a tween at a given timestamp.
1529
+ * Returns null if the tween hasn't started yet or has completed (non-repeating).
1530
+ */
1531
+ declare function interpolateTween(tween: {
1532
+ from: number;
1533
+ to: number;
1534
+ duration: number;
1535
+ easing?: EasingType;
1536
+ delay?: number;
1537
+ repeat?: number;
1538
+ yoyo?: boolean;
1539
+ startedAt?: number;
1540
+ }, now: number): number | null;
1541
+
1542
+ /**
1543
+ * Particle system tick logic.
1544
+ *
1545
+ * Pure functions for simulating particles. Used by useParticleTick hook
1546
+ * for client-side particle simulation at 60fps.
1547
+ */
1548
+
1549
+ /**
1550
+ * Spawn new particles from an emitter based on elapsed time.
1551
+ */
1552
+ declare function spawnParticles(emitter: ParticleEmitter, dt: number): Particle[];
1553
+ /**
1554
+ * Tick all particles: update positions, apply gravity, age.
1555
+ * Returns the surviving particles (age < lifetime).
1556
+ */
1557
+ declare function tickParticles(particles: Particle[], emitters: ParticleEmitter[], dt: number): Particle[];
1558
+ /**
1559
+ * Full particle system tick for a ParticlesNode.
1560
+ * Spawns new particles, ticks existing ones, caps at maxParticles.
1561
+ */
1562
+ declare function tickParticleNode(node: ParticlesNode, dt: number): Particle[];
1563
+
1564
+ /**
1565
+ * Zod schemas for scene graph validation.
1566
+ *
1567
+ * These schemas are used by scene tools to validate agent input.
1568
+ * They accept `z` as a parameter (same pattern as agent-protocol.ts)
1569
+ * so we don't import zod directly — it's provided by the experience.
1570
+ */
1571
+ declare function createSceneSchemas(z: any): {
1572
+ vec2: any;
1573
+ transform: any;
1574
+ style: any;
1575
+ textStyle: any;
1576
+ gradientStop: any;
1577
+ linearGradient: any;
1578
+ radialGradient: any;
1579
+ gradient: any;
1580
+ particleEmitter: any;
1581
+ spriteAnimation: any;
1582
+ nodeSchema: any;
1583
+ };
1584
+
1585
+ /**
1586
+ * Rule Engine for declarative client-side simulation.
1587
+ *
1588
+ * The agent writes rules as JSON via tool calls. The client evaluates them
1589
+ * at ~10 ticks/sec via useRuleTick. Rules are a delegation mechanism — the
1590
+ * agent teaches the client how to run parts of the simulation at tick speed
1591
+ * so the agent can focus on high-level world design and evolution.
1592
+ *
1593
+ * Exports:
1594
+ * Types: Rule, WorldMeta, RuleStats
1595
+ * Hook: useRuleTick(scene, rules, worldMeta, callTool)
1596
+ * Matching: nodeMatchesSelector(node, selector)
1597
+ * Tools: createRuleTools(z) → ToolDef[]
1598
+ * Shorthand: ruleTools(z) → ToolDef[]
1599
+ */
1600
+
1601
+ type Rule = {
1602
+ id: string;
1603
+ name: string;
1604
+ description: string;
1605
+ enabled: boolean;
1606
+ trigger: "tick" | "interaction" | "proximity" | "timer";
1607
+ condition: {
1608
+ selector: string;
1609
+ proximity?: {
1610
+ target: string;
1611
+ distance: number;
1612
+ };
1613
+ state?: Record<string, any>;
1614
+ cooldownMs?: number;
1615
+ probability?: number;
1616
+ };
1617
+ effect: {
1618
+ type: "transform" | "style" | "data" | "counter" | "spawn" | "remove" | "tween";
1619
+ dx?: number;
1620
+ dy?: number;
1621
+ dRotation?: number;
1622
+ styleUpdates?: Record<string, any>;
1623
+ dataUpdates?: Record<string, any>;
1624
+ field?: string;
1625
+ delta?: number;
1626
+ spawnNode?: any;
1627
+ spawnOffset?: {
1628
+ x: number;
1629
+ y: number;
1630
+ };
1631
+ tween?: {
1632
+ property: string;
1633
+ from: number;
1634
+ to: number;
1635
+ duration: number;
1636
+ easing?: string;
1637
+ repeat?: number;
1638
+ yoyo?: boolean;
1639
+ };
1640
+ variance?: number;
1641
+ probability?: number;
1642
+ };
1643
+ };
1644
+ type WorldMeta = {
1645
+ name: string;
1646
+ description: string;
1647
+ paused: boolean;
1648
+ tickSpeed: number;
1649
+ };
1650
+ type RuleStats = {
1651
+ rulesEvaluated: number;
1652
+ rulesFired: number;
1653
+ nodesAffected: number;
1654
+ ticksElapsed: number;
1655
+ };
1656
+ /**
1657
+ * Check if a scene node matches a selector string.
1658
+ *
1659
+ * Selector syntax:
1660
+ * "*" — any node with data.entityType
1661
+ * "entityType:fish" — data.entityType === "fish"
1662
+ * "tag:swimming" — data.tags includes "swimming"
1663
+ * "name:hero" — node.name === "hero"
1664
+ * "type:circle" — node.type === "circle"
1665
+ */
1666
+ declare function nodeMatchesSelector(node: any, selector: string): boolean;
1667
+ type CallToolFn$1 = (name: string, input: any) => Promise<any>;
1668
+ /**
1669
+ * Client-side tick engine. Evaluates enabled tick rules against the scene
1670
+ * graph at ~tickSpeed ms intervals using requestAnimationFrame.
1671
+ *
1672
+ * Transform/style/data/counter/tween effects are applied locally for instant
1673
+ * visual feedback. Spawn/remove effects are batched and flushed through
1674
+ * scene.batch tool calls (debounced 300ms) so they persist in shared state.
1675
+ */
1676
+ declare function useRuleTick(scene: SceneGraph, rules: Rule[], worldMeta: WorldMeta, callTool: CallToolFn$1): {
1677
+ simulatedScene: SceneGraph;
1678
+ stats: RuleStats;
1679
+ };
1680
+ /**
1681
+ * Create rule management tools for an experience.
1682
+ *
1683
+ * Returns 3 tools:
1684
+ * _rules.set — create or update a rule
1685
+ * _rules.remove — delete a rule by ID
1686
+ * _rules.world — set world metadata (name, description, paused, tickSpeed)
1687
+ */
1688
+ declare function createRuleTools(z: any): ToolDef[];
1689
+ /**
1690
+ * Return all pre-built rule tools ready to spread into defineExperience.
1691
+ *
1692
+ * Usage:
1693
+ * import { ruleTools } from "@vibevibes/sdk";
1694
+ * export default defineExperience({
1695
+ * tools: [...sceneTools(z), ...ruleTools(z)],
1696
+ * });
1697
+ */
1698
+ declare function ruleTools(z: any): ToolDef[];
1699
+
1700
+ /**
1701
+ * Standardized chat for experiences.
1702
+ *
1703
+ * Provides a collapsible ChatPanel component, a useChat hook,
1704
+ * and tool factories for agent participation.
1705
+ *
1706
+ * Messages are stored in shared state under `_chat` so agents
1707
+ * see them via the stop hook's /agent-context endpoint.
1708
+ *
1709
+ * Usage:
1710
+ * import { ChatPanel, createChatTools } from "@vibevibes/sdk";
1711
+ *
1712
+ * const tools = [...myTools, ...createChatTools(z)];
1713
+ *
1714
+ * function Canvas(props) {
1715
+ * return <div>
1716
+ * <ChatPanel {...props} />
1717
+ * </div>;
1718
+ * }
1719
+ */
1720
+
1721
+ type ChatMessage = {
1722
+ id: string;
1723
+ actorId: string;
1724
+ message: string;
1725
+ replyTo?: string;
1726
+ ts: number;
1727
+ };
1728
+ type CallToolFn = (name: string, input: any) => Promise<any>;
1729
+ type UseChatReturn = {
1730
+ messages: ChatMessage[];
1731
+ sendMessage: (message: string, replyTo?: string) => Promise<void>;
1732
+ clearChat: () => Promise<void>;
1733
+ setTyping: (isTyping: boolean) => void;
1734
+ typingUsers: string[];
1735
+ };
1736
+ declare function createChatTools(z: any): ToolDef[];
1737
+ declare function useChat(sharedState: Record<string, any>, callTool: CallToolFn, actorId: string, ephemeralState: Record<string, Record<string, any>>, setEphemeral: (data: Record<string, any>) => void): UseChatReturn;
1738
+ type ChatPanelProps = {
1739
+ sharedState: Record<string, any>;
1740
+ callTool: (name: string, input: any) => Promise<any>;
1741
+ actorId: string;
1742
+ ephemeralState: Record<string, Record<string, any>>;
1743
+ setEphemeral: (data: Record<string, any>) => void;
1744
+ participants: string[];
1745
+ style?: Record<string, any>;
1746
+ /** When true, renders inline (flex column, 100% height) instead of fixed-position floating panel. No toggle button. */
1747
+ embedded?: boolean;
1748
+ };
1749
+ declare function ChatPanel({ sharedState, callTool, actorId, ephemeralState, setEphemeral, style, embedded, }: ChatPanelProps): any;
1750
+
1751
+ /**
1752
+ * Standardized bug reporting for experiences.
1753
+ *
1754
+ * Provides a collapsible ReportBug button that captures a screenshot,
1755
+ * shows a form for an optional description, and submits the report
1756
+ * as a tool call stored in shared state.
1757
+ *
1758
+ * Bug reports are stored in shared state under `_bugReports`,
1759
+ * so agents see them via the stop hook's /agent-context endpoint.
1760
+ *
1761
+ * Usage:
1762
+ * import { ReportBug, createBugReportTools } from "@vibevibes/sdk";
1763
+ *
1764
+ * const tools = [...myTools, ...createBugReportTools(z)];
1765
+ *
1766
+ * function Canvas(props) {
1767
+ * return <div>
1768
+ * <ReportBug callTool={props.callTool} actorId={props.actorId} />
1769
+ * </div>;
1770
+ * }
1771
+ */
1772
+
1773
+ type BugReport = {
1774
+ id: string;
1775
+ actorId: string;
1776
+ description: string;
1777
+ screenshot?: string;
1778
+ metadata?: Record<string, any>;
1779
+ ts: number;
1780
+ status: 'open' | 'resolved';
1781
+ };
1782
+ declare function createBugReportTools(z: any): ToolDef[];
1783
+ type ReportBugProps = {
1784
+ callTool: (name: string, input: any) => Promise<any>;
1785
+ actorId: string;
1786
+ style?: Record<string, any>;
1787
+ };
1788
+ declare function ReportBug({ callTool, actorId, style }: ReportBugProps): any;
1789
+
1790
+ /**
1791
+ * Inter-Experience Composability
1792
+ *
1793
+ * Level 1: importTools — Import tools from another experience's npm package
1794
+ * Level 2: EmbeddedExperience — Embed another experience's Canvas with scoped state
1795
+ */
1796
+
1797
+ /**
1798
+ * Import tools from another experience module.
1799
+ *
1800
+ * Usage:
1801
+ * import chatExp from "@vibevibes/chat";
1802
+ * const chatTools = importTools(chatExp, ["chat.send", "chat.clear"]);
1803
+ * export default defineExperience({ tools: [...myTools, ...chatTools], ... });
1804
+ *
1805
+ * Or import all tools:
1806
+ * const allChatTools = importTools(chatExp, "*");
1807
+ *
1808
+ * Optional prefix to namespace imported tools:
1809
+ * const chatTools = importTools(chatExp, "*", "chat");
1810
+ * // "send" becomes "chat.send"
1811
+ */
1812
+ declare function importTools(experienceModule: {
1813
+ tools: ToolDef[];
1814
+ }, toolNames: string[] | '*', prefix?: string): ToolDef[];
1815
+ /**
1816
+ * Props for the EmbeddedExperience component.
1817
+ */
1818
+ type EmbeddedExperienceProps = {
1819
+ /** The child experience module to embed. */
1820
+ experience: {
1821
+ Canvas: React.FC<CanvasProps>;
1822
+ tools: ToolDef[];
1823
+ };
1824
+ /** Key in parent state where child experience state lives. */
1825
+ stateKey: string;
1826
+ /** Parent's shared state. */
1827
+ sharedState: Record<string, any>;
1828
+ /** Parent's callTool function. */
1829
+ callTool: (name: string, input: any) => Promise<any>;
1830
+ /** Parent's room ID. */
1831
+ roomId: string;
1832
+ /** Parent's actor ID. */
1833
+ actorId: string;
1834
+ /** Parent's participants. */
1835
+ participants: string[];
1836
+ /** Parent's ephemeral state. */
1837
+ ephemeralState: Record<string, Record<string, any>>;
1838
+ /** Parent's setEphemeral. */
1839
+ setEphemeral: (data: Record<string, any>) => void;
1840
+ /** Parent's room config. */
1841
+ roomConfig?: Record<string, any>;
1842
+ /** Container style. */
1843
+ style?: Record<string, any>;
1844
+ /** Container className. */
1845
+ className?: string;
1846
+ };
1847
+ /**
1848
+ * Embeds another experience's Canvas as a sub-component with scoped state.
1849
+ *
1850
+ * The child experience reads/writes state under `sharedState[stateKey]` instead
1851
+ * of the root state. Tool calls from the child are namespaced and scoped.
1852
+ *
1853
+ * Usage:
1854
+ * import chatExp from "@vibevibes/chat";
1855
+ *
1856
+ * function Canvas(props) {
1857
+ * return h('div', {},
1858
+ * h(MyGameUI, props),
1859
+ * h(EmbeddedExperience, {
1860
+ * experience: chatExp,
1861
+ * stateKey: "_chat",
1862
+ * sharedState: props.sharedState,
1863
+ * callTool: props.callTool,
1864
+ * roomId: props.roomId,
1865
+ * actorId: props.actorId,
1866
+ * participants: props.participants,
1867
+ * ephemeralState: props.ephemeralState,
1868
+ * setEphemeral: props.setEphemeral,
1869
+ * style: { position: 'absolute', bottom: 0, right: 0, width: 300, height: 400 },
1870
+ * }),
1871
+ * );
1872
+ * }
1873
+ */
1874
+ declare function EmbeddedExperience(props: EmbeddedExperienceProps): any;
1875
+
1876
+ export { type AgentContext, type AgentMessage, type AgentSlot, Badge, type BugReport, Button, type Camera, type CanvasProps, Card, type ChatMessage, ChatPanel, type CircleNode, ColorPicker, Dropdown, type EasingType, type EllipseNode, EmbeddedExperience, type EmbeddedExperienceProps, type EphemeralActionDef, type ExpectChain, type ExperienceImport, type ExperienceListing, type ExperienceManifest, type ExperienceModule, type ExperienceRegistry, type FilterDef, type FilterType, type FollowState, type Gradient, type GradientStop, Grid, type GroupNode, type ImageNode, InMemoryAdapter, Input, type JsonPatchOp, type LineNode, type LinearGradient, type MigrationResult, Modal, type NetcodeMode, type ParsedParticipant, type Particle, type ParticleEmitter, type ParticlesNode, PathBuilder, type PathNode, type PerfMetrics, type PhaseConfig, PixiSceneRenderer, type PolygonNode, type PolylineNode, type RadialGradient, type RectNode, type RegistryEntry, ReportBug, type RoomConfigDef, type RoomLink, type RoomState, type Rule, type RuleStats, type SceneGraph, type SceneHitEvent, type SceneInteractionEvent, type SceneNode, type SceneNodeBase, type SceneNodeType, SceneRenderer, type SceneRendererProps, Slider, type SpawnRoomOpts, type SpawnRoomResult, type SpriteAnimation, type SpriteNode, Stack, type StateMigration, type StorageAdapter, type StorageToolEvent, type StreamDef, type Style, SvgSceneRenderer, Tabs, type TestDef, type TestHelpers, type TextNode, type TextStyle, Textarea, type TilemapNode, type ToolCtx, type ToolDef, type ToolEvent, type ToolRisk, type Transform, type TweenDef, type UseChatReturn, type UseFollowReturn, type UseOptimisticToolReturn, type UsePhaseReturn, type UseSceneDragReturn, type UseSceneInteractionReturn, type UseSceneSelectionReturn, type UseSceneViewportReturn, type UseToolCallReturn, type UseUndoReturn, type Vec2, type WebhookEventType, type WorldMeta, allNodeIds, cloneScene, compareSemver, createAgentProtocolTools, createBugReportTools, createChatTools, createNode, createRuleTools, createScene, createSceneSchemas, createSceneTools, defineEphemeralAction, defineExperience, defineRoomConfig, defineStream, defineTest, defineTool, easingFunctions, findNodes, findParent, getPath, getStateVersion, importTools, interpolateTween, migrateState, nodeById, nodeCount, nodeMatchesSelector, phaseTool, quickTool, removeNodeById, ruleTools, sceneTools, setPath, spawnParticles, tickParticleNode, tickParticles, undoTool, useAnimationFrame, useBlob, useChat, useDebounce, useFollow, useOptimisticTool, useParticipants, useParticleTick, usePhase, useRuleTick, useSceneDrag, useSceneInteraction, useSceneSelection, useSceneTweens, useSceneViewport, useSharedState, useThrottle, useToolCall, useTypingIndicator, useUndo, validateExperience, walkNodes };