events handlers

This commit is contained in:
wass08
2026-01-16 11:42:10 +09:00
parent d657f4125f
commit 1b954d3416
12 changed files with 135 additions and 266 deletions
+32 -31
View File
@@ -1,45 +1,46 @@
import mitt from "mitt";
import { ItemNode, WallNode } from "../schema";
import { AnyNode } from "../schema/types";
// Base event interfaces
export interface GridEvent {
position: [number, number];
}
export interface NodeEvent {
node: AnyNode;
position: [number, number, number]; // [x, y, z] world coordinates
normal?: [number, number, number]; // [x, y, z] normal vector
export interface NodeEvent<T extends AnyNode = AnyNode> {
node: T;
position: [number, number, number];
normal?: [number, number, number];
stopPropagation: () => void;
}
export interface WallEvent extends NodeEvent {
node: WallNode;
}
export type WallEvent = NodeEvent<WallNode>;
export type ItemEvent = NodeEvent<ItemNode>;
export interface ItemEvent extends NodeEvent {
node: ItemNode;
}
// Event suffixes - exported for use in hooks
export const eventSuffixes = [
"click",
"move",
"enter",
"leave",
"pointerdown",
"pointerup",
"context-menu",
"double-click",
] as const;
type EditorEvents = {
"grid:click": GridEvent;
"grid:rightclick": GridEvent;
"grid:move": GridEvent;
"grid:double-click": GridEvent;
"grid:enter": GridEvent;
"grid:leave": GridEvent;
"grid:pointerdown": GridEvent;
"grid:pointerup": GridEvent;
"wall:click": WallEvent;
"wall:move": WallEvent;
"wall:enter": WallEvent;
"wall:leave": WallEvent;
"wall:pointerdown": WallEvent;
"wall:pointerup": WallEvent;
"item:click": ItemEvent;
"item:move": ItemEvent;
"item:enter": ItemEvent;
"item:leave": ItemEvent;
"item:pointerdown": ItemEvent;
"item:pointerup": ItemEvent;
export type EventSuffix = (typeof eventSuffixes)[number];
type NodeEvents<T extends string, E> = {
[K in `${T}:${EventSuffix}`]: E;
};
type GridEvents = {
[K in `grid:${EventSuffix}`]: GridEvent;
};
type EditorEvents = GridEvents &
NodeEvents<"wall", WallEvent> &
NodeEvents<"item", ItemEvent>;
export const emitter = mitt<EditorEvents>();
@@ -9,6 +9,7 @@ export const sceneRegistry = {
// Categorized lookups: Type -> Set of IDs
// Using a Set is faster for adding/deleting than an Array
byType: {
building: new Set<string>(),
level: new Set<string>(),
wall: new Set<string>(),
item: new Set<string>(),
+2 -1
View File
@@ -12,7 +12,8 @@ export { LevelSystem } from "../../viewer/src/systems/level/level-system";
export { WallSystem } from "./systems/wall/wall-system";
// Events
export { emitter } from "./events/bus";
export { emitter, eventSuffixes } from "./events/bus";
export type { ItemEvent, WallEvent, NodeEvent, GridEvent, EventSuffix } from "./events/bus";
// Schema
export * from "./schema";
+1 -1
View File
@@ -6,7 +6,7 @@ import { LevelNode } from "./level";
export const BuildingNode = BaseNode.extend({
id: objectId("building"),
type: nodeType("building"),
children: z.array(LevelNode).default([LevelNode.parse({})]),
children: z.array(LevelNode.shape.id).default([]),
position: z.tuple([z.number(), z.number(), z.number()]).default([0, 0, 0]),
rotation: z.tuple([z.number(), z.number(), z.number()]).default([0, 0, 0]),
}).describe(
+11 -2
View File
@@ -1,7 +1,7 @@
"use client";
import { create } from "zustand";
import { ItemNode } from "../schema";
import { BuildingNode, ItemNode } from "../schema";
import { LevelNode } from "../schema/nodes/level";
import { WallNode } from "../schema/nodes/wall";
import { AnyNode, AnyNodeId } from "../schema/types";
@@ -33,6 +33,12 @@ const useScene = create<SceneState>()((set, get) => ({
dirtyNodes: new Set<AnyNodeId>(),
loadScene: () => {
const building = BuildingNode.parse({
children: [],
});
const level0 = LevelNode.parse({
level: 0,
children: [],
@@ -85,8 +91,11 @@ const useScene = create<SceneState>()((set, get) => ({
level0.children.push(wall0.id, wall1.id, wall2.id, wall3.id);
building.children.push(level0.id, level1.id, level2.id);
// Define all nodes flat
const nodes: Record<AnyNodeId, AnyNode> = {
[building.id]: building,
[level0.id]: level0,
[level1.id]: level1,
[level2.id]: level2,
@@ -98,7 +107,7 @@ const useScene = create<SceneState>()((set, get) => ({
};
// Root nodes are the levels
const rootNodeIds = [level0.id, level1.id, level2.id];
const rootNodeIds = [building.id];
get().dirtyNodes.add(wall0.id);
get().dirtyNodes.add(wall1.id);