@almadar/ui 5.41.0 → 5.43.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.
@@ -2502,6 +2502,73 @@ function useDropZone({ accepts, onDrop, disabled = false }) {
2502
2502
  );
2503
2503
  return { dropProps, isOver };
2504
2504
  }
2505
+ function useRenderInterpolation(options = {}) {
2506
+ const tickIntervalMs = options.tickIntervalMs ?? 1e3 / 30;
2507
+ const prevRef = useRef(null);
2508
+ const currRef = useRef(null);
2509
+ const rafRef = useRef(null);
2510
+ const onSnapshot = useCallback((entities2) => {
2511
+ prevRef.current = currRef.current;
2512
+ currRef.current = { entities: entities2, arrivedAt: performance.now() };
2513
+ }, []);
2514
+ const getInterpolated = useCallback((now) => {
2515
+ const out = /* @__PURE__ */ new Map();
2516
+ const curr = currRef.current;
2517
+ if (!curr) return out;
2518
+ const prev = prevRef.current;
2519
+ if (!prev) {
2520
+ for (const e of curr.entities) out.set(e.id, { x: e.x, y: e.y });
2521
+ return out;
2522
+ }
2523
+ const rawAlpha = (now - curr.arrivedAt) / tickIntervalMs;
2524
+ const alpha = rawAlpha < 0 ? 0 : rawAlpha > 1 ? 1 : rawAlpha;
2525
+ const prevMap = /* @__PURE__ */ new Map();
2526
+ for (const e of prev.entities) prevMap.set(e.id, e);
2527
+ for (const c of curr.entities) {
2528
+ const p = prevMap.get(c.id);
2529
+ if (!p) {
2530
+ out.set(c.id, { x: c.x, y: c.y });
2531
+ } else {
2532
+ out.set(c.id, {
2533
+ x: p.x + (c.x - p.x) * alpha,
2534
+ y: p.y + (c.y - p.y) * alpha
2535
+ });
2536
+ }
2537
+ }
2538
+ return out;
2539
+ }, [tickIntervalMs]);
2540
+ const startLoop = useCallback(
2541
+ (draw) => {
2542
+ let active = true;
2543
+ const loop = () => {
2544
+ if (!active) return;
2545
+ try {
2546
+ draw(getInterpolated(performance.now()));
2547
+ } catch {
2548
+ }
2549
+ rafRef.current = requestAnimationFrame(loop);
2550
+ };
2551
+ rafRef.current = requestAnimationFrame(loop);
2552
+ return () => {
2553
+ active = false;
2554
+ if (rafRef.current !== null) {
2555
+ cancelAnimationFrame(rafRef.current);
2556
+ rafRef.current = null;
2557
+ }
2558
+ };
2559
+ },
2560
+ [getInterpolated]
2561
+ );
2562
+ useEffect(() => {
2563
+ return () => {
2564
+ if (rafRef.current !== null) {
2565
+ cancelAnimationFrame(rafRef.current);
2566
+ rafRef.current = null;
2567
+ }
2568
+ };
2569
+ }, []);
2570
+ return { onSnapshot, getInterpolated, startLoop };
2571
+ }
2505
2572
  var API_BASE = typeof process !== "undefined" && process.env?.VITE_API_URL ? process.env.VITE_API_URL : "http://localhost:3000";
2506
2573
  function getUserId() {
2507
2574
  return localStorage.getItem("userId") || "anonymous";
@@ -2578,4 +2645,4 @@ function useGitHubBranches(owner, repo, enabled = true) {
2578
2645
  });
2579
2646
  }
2580
2647
 
2581
- export { ALMADAR_DND_MIME, DEFAULT_SLOTS, I18nProvider, clearEntities, createTranslate, getAllEntities, getByType, getEntity, getSingleton, parseQueryBinding, removeEntity, spawnEntity, updateEntity, updateSingleton, useAgentChat, useAuthContext, useCompile, useConnectGitHub, useDeepAgentGeneration, useDisconnectGitHub, useDragReorder, useDraggable, useDropZone, useEmitEvent, useEntities, useEntitiesByType, useEntity as useEntityById, useEventBus, useEventListener, useExtensions, useFileEditor, useFileSystem, useGitHubBranches, useGitHubRepo, useGitHubRepos, useGitHubStatus, useInfiniteScroll, useInput, useLongPress, useOrbitalHistory, usePhysics, usePinchZoom, usePlayer, usePreview, usePullToRefresh, useQuerySingleton, useSingletonEntity, useSwipeGesture, useTraitListens, useTranslate, useUIEvents, useUISlotManager, useValidation };
2648
+ export { ALMADAR_DND_MIME, DEFAULT_SLOTS, I18nProvider, clearEntities, createTranslate, getAllEntities, getByType, getEntity, getSingleton, parseQueryBinding, removeEntity, spawnEntity, updateEntity, updateSingleton, useAgentChat, useAuthContext, useCompile, useConnectGitHub, useDeepAgentGeneration, useDisconnectGitHub, useDragReorder, useDraggable, useDropZone, useEmitEvent, useEntities, useEntitiesByType, useEntity as useEntityById, useEventBus, useEventListener, useExtensions, useFileEditor, useFileSystem, useGitHubBranches, useGitHubRepo, useGitHubRepos, useGitHubStatus, useInfiniteScroll, useInput, useLongPress, useOrbitalHistory, usePhysics, usePinchZoom, usePlayer, usePreview, usePullToRefresh, useQuerySingleton, useRenderInterpolation, useSingletonEntity, useSwipeGesture, useTraitListens, useTranslate, useUIEvents, useUISlotManager, useValidation };
@@ -0,0 +1,33 @@
1
+ export interface Positioned {
2
+ id: string;
3
+ x: number;
4
+ y: number;
5
+ }
6
+ export interface RenderInterpolationOptions {
7
+ /** Expected tick interval in ms (default: 1000/30 ≈ 33.3ms) */
8
+ tickIntervalMs?: number;
9
+ }
10
+ export interface RenderInterpolationHandle<T extends Positioned> {
11
+ /** Call when a new authoritative snapshot arrives from the model */
12
+ onSnapshot: (entities: readonly T[]) => void;
13
+ /** Returns interpolated positions for the current rAF timestamp; falls back to authoritative values */
14
+ getInterpolated: (now: number) => Map<string, {
15
+ x: number;
16
+ y: number;
17
+ }>;
18
+ /** Start the rAF loop; call the supplied draw fn on every frame */
19
+ startLoop: (draw: (positions: Map<string, {
20
+ x: number;
21
+ y: number;
22
+ }>) => void) => () => void;
23
+ }
24
+ /**
25
+ * Fixed-timestep render interpolation between the last two authoritative model snapshots.
26
+ *
27
+ * Buffers two snapshots. On each rAF frame computes
28
+ * alpha = clamp((now - lastArrival) / tickIntervalMs, 0, 1)
29
+ * and lerps x/y between prev and curr, matched by entity id.
30
+ * New or removed entities fall back to their authoritative value directly.
31
+ * Never throws; never causes a React re-render per frame.
32
+ */
33
+ export declare function useRenderInterpolation<T extends Positioned>(options?: RenderInterpolationOptions): RenderInterpolationHandle<T>;