Fix findUsages/undo/node-lookup bugs, split Viewport and Editor, share command and inspector helpers

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
rootandClaude Opus 5 committed 2026-09-08 09:22:49 +02:00
1 parent 1eb28314cf
commit f140c2fd77
58 files changed
+1969 -1171

No files matched your search

+58
View File
@@ -0,0 +1,58 @@
/**
* How world coordinates map onto a viewport. Pure geometry – no Pixi, no editor state – so
* both viewports share one definition of "where does this world point land on screen".
*/
import type { PropertyBag, Vec2 } from '../core/model/Properties';
import { cameraFrame, rectAround, type WorldRect } from '../core/properties/camera';
/**
* The world point (`x`, `y`) sits at the centre of the screen rectangle `rect` (viewport-local
* pixels) at `scale` pixels per world unit. In the scene view the rectangle is the whole
* viewport; in the game view it is the camera's frame fitted into it (letterboxed).
*/
export interface View {
x: number;
y: number;
scale: number;
rect: { x: number; y: number; w: number; h: number };
}
/** Free-panning view: the whole viewport shows the world around (`x`, `y`) at `zoom`. */
export function freeView(x: number, y: number, zoom: number, w: number, h: number): View {
return { x, y, scale: zoom, rect: { x: 0, y: 0, w, h } };
}
/**
* The camera's frame scaled to fit inside `w`×`h` and centred – the remaining margin is the
* letterbox, which is not part of the game area (see `isInside`).
*/
export function cameraView(camera: { x: number; y: number; props: PropertyBag }, w: number, h: number): View {
const frame = cameraFrame(camera.props);
const scale = Math.min(w / frame.w, h / frame.h);
const fw = frame.w * scale;
const fh = frame.h * scale;
return { x: camera.x, y: camera.y, scale, rect: { x: (w - fw) / 2, y: (h - fh) / 2, w: fw, h: fh } };
}
export function screenToWorld(view: View, sx: number, sy: number): Vec2 {
const cx = view.rect.x + view.rect.w / 2;
const cy = view.rect.y + view.rect.h / 2;
return { x: (sx - cx) / view.scale + view.x, y: (sy - cy) / view.scale + view.y };
}
export function worldToScreen(view: View, wx: number, wy: number): Vec2 {
const cx = view.rect.x + view.rect.w / 2;
const cy = view.rect.y + view.rect.h / 2;
return { x: (wx - view.x) * view.scale + cx, y: (wy - view.y) * view.scale + cy };
}
/** World region the view covers – what a redraw has to consider at all. */
export function worldBounds(view: View): WorldRect {
return rectAround(view.x, view.y, view.rect.w / view.scale, view.rect.h / view.scale);
}
/** Whether a viewport-local point lies on the drawn rectangle rather than in the letterbox. */
export function isInside(view: View, sx: number, sy: number): boolean {
const { x, y, w, h } = view.rect;
return sx >= x && sx <= x + w && sy >= y && sy <= y + h;
}