feat(viewer): add Vue-based HUD, ops strip, and history window

This commit is contained in:
2026-03-19 13:49:56 -04:00
parent 710addf1f5
commit 3ca568c05d
36 changed files with 2648 additions and 1017 deletions

View File

@@ -1,10 +1,10 @@
import * as THREE from "three";
import { createHistoryWindowState, refreshHistoryWindow } from "./viewerHistory";
import type { HistoryWindowState, Selectable, WorldState } from "./viewerTypes";
import type { HistoryWindowState } from "./viewerHudState";
import type { Selectable, WorldState } from "./viewerTypes";
export function openHistoryWindow(
historyWindows: HistoryWindowState[],
historyLayerEl: HTMLDivElement,
target: Selectable,
nextCounter: number,
bringToFront: (windowState: HistoryWindowState) => void,
@@ -17,9 +17,8 @@ export function openHistoryWindow(
return nextCounter;
}
const windowState = createHistoryWindowState(document, target, historyWindows.length, nextCounter);
const windowState = createHistoryWindowState(target, historyWindows.length, nextCounter);
historyWindows.push(windowState);
historyLayerEl.append(windowState.root);
bringToFront(windowState);
refreshWindows();
return nextCounter;
@@ -56,8 +55,7 @@ export function destroyHistoryWindow(
};
}
const [removed] = historyWindows.splice(index, 1);
removed.root.remove();
historyWindows.splice(index, 1);
if (historyWindowDragId === id) {
return {
historyWindowDragId: undefined,
@@ -72,7 +70,7 @@ export function destroyHistoryWindow(
}
export function bringHistoryWindowToFront(windowState: HistoryWindowState, nextZIndex: number) {
windowState.root.style.zIndex = `${nextZIndex}`;
windowState.zIndex = nextZIndex;
}
export function beginHistoryWindowDrag(
@@ -91,9 +89,7 @@ export function beginHistoryWindowDrag(
};
}
const bounds = windowState.root.getBoundingClientRect();
historyWindowDragOffset.set(clientX - bounds.left, clientY - bounds.top);
windowState.root.setPointerCapture?.(pointerId);
historyWindowDragOffset.set(clientX - windowState.x, clientY - windowState.y);
return {
historyWindowDragId: windowId,
historyWindowDragPointerId: pointerId,
@@ -118,16 +114,12 @@ export function updateHistoryWindowDrag(
return;
}
const width = windowState.root.offsetWidth;
const height = windowState.root.offsetHeight;
const left = THREE.MathUtils.clamp(clientX - historyWindowDragOffset.x, 20, window.innerWidth - width - 20);
const top = THREE.MathUtils.clamp(clientY - historyWindowDragOffset.y, 20, window.innerHeight - height - 20);
windowState.root.style.left = `${left}px`;
windowState.root.style.top = `${top}px`;
windowState.x = THREE.MathUtils.clamp(clientX - historyWindowDragOffset.x, 20, window.innerWidth - windowState.width - 20);
windowState.y = THREE.MathUtils.clamp(clientY - historyWindowDragOffset.y, 20, window.innerHeight - windowState.height - 20);
}
export function endHistoryWindowDrag(
historyWindows: HistoryWindowState[],
_historyWindows: HistoryWindowState[],
historyWindowDragId: string | undefined,
historyWindowDragPointerId: number | undefined,
pointerId: number,
@@ -139,8 +131,6 @@ export function endHistoryWindowDrag(
};
}
const windowState = historyWindows.find((candidate) => candidate.id === historyWindowDragId);
windowState?.root.releasePointerCapture?.(pointerId);
return {
historyWindowDragId: undefined,
historyWindowDragPointerId: undefined,