@react-arch/core 0.1.1 → 0.1.3

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.
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","names":[],"sources":["../src/model.ts","../src/commands.ts","../src/history.ts","../src/serialize.ts","../src/defaults.ts","../src/furniture.ts"],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","names":[],"sources":["../src/model.ts","../src/commands.ts","../src/history.ts","../src/serialize.ts","../src/defaults.ts","../src/furniture.ts"],"mappings":"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"}
package/dist/index.js CHANGED
@@ -54,14 +54,17 @@ function requireFloor(doc, floorId) {
54
54
  if (!found) throw new Error(`Floor not found: ${floorId}`);
55
55
  return found.floor;
56
56
  }
57
+ function cloneVec2(v) {
58
+ return [v[0], v[1]];
59
+ }
57
60
  function createWall(doc, input) {
58
61
  return mutate(doc, (draft) => {
59
62
  const floor = requireFloor(draft, input.floorId);
60
63
  const wall = {
61
64
  id: input.id ?? createId("wall"),
62
65
  floorId: input.floorId,
63
- start: input.start,
64
- end: input.end,
66
+ start: cloneVec2(input.start),
67
+ end: cloneVec2(input.end),
65
68
  thickness: input.thickness ?? .2,
66
69
  height: input.height ?? floor.height,
67
70
  materialId: input.materialId
@@ -79,7 +82,7 @@ function updateWall(doc, wallId, patch) {
79
82
  for (const floor of allFloorsOf(draft)) {
80
83
  const wall = floor.walls.find((w) => w.id === wallId);
81
84
  if (!wall) continue;
82
- Object.assign(wall, patch);
85
+ Object.assign(wall, deepClone(patch));
83
86
  reattachOpenings(floor, wall, warnings);
84
87
  return [{
85
88
  kind: "update",
@@ -113,6 +116,15 @@ function deleteWall(doc, wallId) {
113
116
  entity: "wall",
114
117
  id: wallId
115
118
  });
119
+ for (const room of floor.rooms) {
120
+ if (!room.boundaryWallIds?.includes(wallId)) continue;
121
+ room.boundaryWallIds = room.boundaryWallIds.filter((id) => id !== wallId);
122
+ changes.push({
123
+ kind: "update",
124
+ entity: "room",
125
+ id: room.id
126
+ });
127
+ }
116
128
  floor.openings = floor.openings.filter((o) => {
117
129
  if (o.wallId === wallId) {
118
130
  changes.push({
@@ -145,7 +157,7 @@ function createRoom(doc, input) {
145
157
  id: input.id ?? createId("room"),
146
158
  floorId: input.floorId,
147
159
  name: input.name,
148
- polygon: input.polygon,
160
+ polygon: input.polygon.map(cloneVec2),
149
161
  floorMaterialId: input.floorMaterialId,
150
162
  ceilingMaterialId: input.ceilingMaterialId,
151
163
  usageType: input.usageType
@@ -163,7 +175,7 @@ function updateRoom(doc, roomId, patch) {
163
175
  for (const floor of allFloorsOf(draft)) {
164
176
  const room = floor.rooms.find((r) => r.id === roomId);
165
177
  if (!room) continue;
166
- Object.assign(room, patch);
178
+ Object.assign(room, deepClone(patch));
167
179
  return [{
168
180
  kind: "update",
169
181
  entity: "room",
@@ -321,6 +333,7 @@ function duplicateFloor(doc, floorId) {
321
333
  copy.rooms.forEach((r) => {
322
334
  r.id = createId("room");
323
335
  r.floorId = copy.id;
336
+ if (r.boundaryWallIds) r.boundaryWallIds = r.boundaryWallIds.map((id) => idMap.get(id) ?? id);
324
337
  });
325
338
  copy.objects.forEach((ob) => {
326
339
  ob.id = createId("object");
@@ -413,8 +426,8 @@ var History = class {
413
426
  this.past.push({
414
427
  id: createId("hist"),
415
428
  label,
416
- before,
417
- after
429
+ before: deepClone(before),
430
+ after: deepClone(after)
418
431
  });
419
432
  if (this.past.length > this.limit) this.past.shift();
420
433
  this.future = [];
@@ -429,13 +442,13 @@ var History = class {
429
442
  const entry = this.past.pop();
430
443
  if (!entry) return null;
431
444
  this.future.push(entry);
432
- return entry.before;
445
+ return deepClone(entry.before);
433
446
  }
434
447
  redo() {
435
448
  const entry = this.future.pop();
436
449
  if (!entry) return null;
437
450
  this.past.push(entry);
438
- return entry.after;
451
+ return deepClone(entry.after);
439
452
  }
440
453
  get undoLabel() {
441
454
  return this.past.at(-1)?.label ?? null;
@@ -541,7 +554,7 @@ function createEmptyDocument(options = {}) {
541
554
  name: options.buildingName ?? options.name ?? "Building",
542
555
  floors: []
543
556
  }],
544
- materials: [...DEFAULT_MATERIALS],
557
+ materials: DEFAULT_MATERIALS.map((m) => ({ ...m })),
545
558
  assets: [],
546
559
  metadata: {}
547
560
  };
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":["wl"],"sources":["../src/model.ts","../src/commands.ts","../src/history.ts","../src/serialize.ts","../src/defaults.ts","../src/furniture.ts"],"sourcesContent":["import type { Units, Vec2, Vec3 } from \"@react-arch/shared\";\n\n/** The current on-disk model version. Bump when the schema changes. */\nexport const MODEL_VERSION = \"0.1.0\";\n\nexport type OpeningType = \"door\" | \"window\" | \"opening\";\nexport type SwingDirection = \"in\" | \"out\";\nexport type HingeSide = \"left\" | \"right\";\n\nexport interface Wall {\n id: string;\n floorId: string;\n start: Vec2;\n end: Vec2;\n thickness: number;\n height: number;\n materialId?: string;\n layerId?: string;\n locked?: boolean;\n}\n\nexport interface Opening {\n id: string;\n floorId: string;\n wallId: string;\n type: OpeningType;\n /** Distance along the wall centerline to the opening center. */\n offset: number;\n width: number;\n height: number;\n sillHeight: number;\n swing?: SwingDirection;\n hinge?: HingeSide;\n materialId?: string;\n}\n\nexport interface Room {\n id: string;\n floorId: string;\n name: string;\n /** Explicit polygon (metres). Rooms may also be derived from wall loops. */\n polygon: Vec2[];\n boundaryWallIds?: string[];\n floorMaterialId?: string;\n ceilingMaterialId?: string;\n usageType?: string;\n height?: number;\n}\n\nexport interface BuildingObject {\n id: string;\n floorId: string;\n type: string;\n position: Vec3;\n rotation: Vec3;\n scale: Vec3;\n assetId?: string;\n metadata?: Record<string, unknown>;\n}\n\nexport interface Floor {\n id: string;\n buildingId: string;\n name: string;\n elevation: number;\n height: number;\n visible: boolean;\n locked: boolean;\n walls: Wall[];\n rooms: Room[];\n openings: Opening[];\n objects: BuildingObject[];\n}\n\nexport interface Building {\n id: string;\n name: string;\n floors: Floor[];\n}\n\nexport type MaterialCategory =\n | \"wall\"\n | \"floor\"\n | \"ceiling\"\n | \"glass\"\n | \"wood\"\n | \"metal\"\n | \"ceramic\"\n | \"custom\";\n\nexport interface Material {\n id: string;\n name: string;\n category: MaterialCategory;\n baseColor: string;\n roughness?: number;\n metalness?: number;\n opacity?: number;\n textureUrl?: string;\n}\n\nexport interface Asset {\n id: string;\n name: string;\n url?: string;\n kind: string;\n}\n\nexport interface Site {\n id: string;\n name: string;\n polygon?: Vec2[];\n}\n\nexport interface BuildingDocument {\n id: string;\n version: string;\n name: string;\n units: Units;\n site?: Site;\n buildings: Building[];\n materials: Material[];\n assets: Asset[];\n metadata: Record<string, unknown>;\n}\n\n/** A single semantic change emitted by a command. */\nexport interface ModelChange {\n kind: \"create\" | \"update\" | \"delete\";\n entity: \"wall\" | \"room\" | \"opening\" | \"floor\" | \"object\" | \"document\";\n id: string;\n}\n\nexport interface ModelWarning {\n code: string;\n message: string;\n entityId?: string;\n}\n\nexport interface CommandResult {\n document: BuildingDocument;\n changes: ModelChange[];\n warnings: ModelWarning[];\n}\n\n// ---------------------------------------------------------------------------\n// Read helpers\n// ---------------------------------------------------------------------------\n\nexport function findFloor(\n doc: BuildingDocument,\n floorId: string,\n): { building: Building; floor: Floor } | undefined {\n for (const building of doc.buildings) {\n const floor = building.floors.find((f) => f.id === floorId);\n if (floor) return { building, floor };\n }\n return undefined;\n}\n\nexport function allFloors(doc: BuildingDocument): Floor[] {\n return doc.buildings.flatMap((b) => b.floors);\n}\n\nexport function findWall(doc: BuildingDocument, wallId: string): Wall | undefined {\n for (const floor of allFloors(doc)) {\n const w = floor.walls.find((x) => x.id === wallId);\n if (w) return w;\n }\n return undefined;\n}\n\nexport function findRoom(doc: BuildingDocument, roomId: string): Room | undefined {\n for (const floor of allFloors(doc)) {\n const r = floor.rooms.find((x) => x.id === roomId);\n if (r) return r;\n }\n return undefined;\n}\n\nexport function findOpening(\n doc: BuildingDocument,\n openingId: string,\n): Opening | undefined {\n for (const floor of allFloors(doc)) {\n const o = floor.openings.find((x) => x.id === openingId);\n if (o) return o;\n }\n return undefined;\n}\n\nexport type EntityKind = \"wall\" | \"room\" | \"opening\" | \"floor\" | \"object\";\n\nexport interface EntityRef {\n kind: EntityKind;\n id: string;\n}\n","import { createId, deepClone, type Vec2 } from \"@react-arch/shared\";\nimport { openingFits, wallLength, type WallLike } from \"@react-arch/geometry\";\nimport {\n type BuildingDocument,\n type CommandResult,\n type Floor,\n type ModelChange,\n type ModelWarning,\n type Opening,\n type OpeningType,\n type Room,\n type Wall,\n findFloor,\n} from \"./model.js\";\n\n/**\n * Commands are pure: they take a document and return a brand-new document plus\n * a list of changes and warnings. They never mutate the input. The studio /\n * editor layers feed these into the history stack for undo/redo.\n */\n\nfunction mutate(\n doc: BuildingDocument,\n fn: (draft: BuildingDocument, warnings: ModelWarning[]) => ModelChange[],\n): CommandResult {\n const draft = deepClone(doc);\n const warnings: ModelWarning[] = [];\n const changes = fn(draft, warnings);\n return { document: draft, changes, warnings };\n}\n\nfunction requireFloor(doc: BuildingDocument, floorId: string): Floor {\n const found = findFloor(doc, floorId);\n if (!found) throw new Error(`Floor not found: ${floorId}`);\n return found.floor;\n}\n\n// --- Walls -----------------------------------------------------------------\n\nexport interface CreateWallInput {\n floorId: string;\n start: Vec2;\n end: Vec2;\n thickness?: number;\n height?: number;\n materialId?: string;\n id?: string;\n}\n\nexport function createWall(\n doc: BuildingDocument,\n input: CreateWallInput,\n): CommandResult {\n return mutate(doc, (draft) => {\n const floor = requireFloor(draft, input.floorId);\n const wall: Wall = {\n id: input.id ?? createId(\"wall\"),\n floorId: input.floorId,\n start: input.start,\n end: input.end,\n thickness: input.thickness ?? 0.2,\n height: input.height ?? floor.height,\n materialId: input.materialId,\n };\n floor.walls.push(wall);\n return [{ kind: \"create\", entity: \"wall\", id: wall.id }];\n });\n}\n\nexport function updateWall(\n doc: BuildingDocument,\n wallId: string,\n patch: Partial<Omit<Wall, \"id\" | \"floorId\">>,\n): CommandResult {\n return mutate(doc, (draft, warnings) => {\n for (const floor of allFloorsOf(draft)) {\n const wall = floor.walls.find((w) => w.id === wallId);\n if (!wall) continue;\n Object.assign(wall, patch);\n reattachOpenings(floor, wall, warnings);\n return [{ kind: \"update\", entity: \"wall\", id: wallId }];\n }\n warnings.push({ code: \"wall-missing\", message: `Wall ${wallId} not found` });\n return [];\n });\n}\n\n/** Move a wall's endpoints, keeping attached openings within bounds. */\nexport function moveWall(\n doc: BuildingDocument,\n wallId: string,\n start: Vec2,\n end: Vec2,\n): CommandResult {\n return updateWall(doc, wallId, { start, end });\n}\n\nexport function deleteWall(doc: BuildingDocument, wallId: string): CommandResult {\n return mutate(doc, (draft) => {\n const changes: ModelChange[] = [];\n for (const floor of allFloorsOf(draft)) {\n const idx = floor.walls.findIndex((w) => w.id === wallId);\n if (idx === -1) continue;\n floor.walls.splice(idx, 1);\n changes.push({ kind: \"delete\", entity: \"wall\", id: wallId });\n // Cascade: drop openings attached to the wall.\n floor.openings = floor.openings.filter((o) => {\n if (o.wallId === wallId) {\n changes.push({ kind: \"delete\", entity: \"opening\", id: o.id });\n return false;\n }\n return true;\n });\n break;\n }\n return changes;\n });\n}\n\n// --- Rooms -----------------------------------------------------------------\n\nexport interface CreateRoomInput {\n floorId: string;\n name: string;\n polygon: Vec2[];\n id?: string;\n floorMaterialId?: string;\n ceilingMaterialId?: string;\n usageType?: string;\n}\n\n/** Convenience: build a rectangular room from origin + size. */\nexport function rectRoomPolygon(\n x: number,\n y: number,\n width: number,\n depth: number,\n): Vec2[] {\n return [\n [x, y],\n [x + width, y],\n [x + width, y + depth],\n [x, y + depth],\n ];\n}\n\nexport function createRoom(\n doc: BuildingDocument,\n input: CreateRoomInput,\n): CommandResult {\n return mutate(doc, (draft) => {\n const floor = requireFloor(draft, input.floorId);\n const room: Room = {\n id: input.id ?? createId(\"room\"),\n floorId: input.floorId,\n name: input.name,\n polygon: input.polygon,\n floorMaterialId: input.floorMaterialId,\n ceilingMaterialId: input.ceilingMaterialId,\n usageType: input.usageType,\n };\n floor.rooms.push(room);\n return [{ kind: \"create\", entity: \"room\", id: room.id }];\n });\n}\n\nexport function updateRoom(\n doc: BuildingDocument,\n roomId: string,\n patch: Partial<Omit<Room, \"id\" | \"floorId\">>,\n): CommandResult {\n return mutate(doc, (draft, warnings) => {\n for (const floor of allFloorsOf(draft)) {\n const room = floor.rooms.find((r) => r.id === roomId);\n if (!room) continue;\n Object.assign(room, patch);\n return [{ kind: \"update\", entity: \"room\", id: roomId }];\n }\n warnings.push({ code: \"room-missing\", message: `Room ${roomId} not found` });\n return [];\n });\n}\n\nexport function deleteRoom(doc: BuildingDocument, roomId: string): CommandResult {\n return mutate(doc, (draft) => {\n for (const floor of allFloorsOf(draft)) {\n const idx = floor.rooms.findIndex((r) => r.id === roomId);\n if (idx === -1) continue;\n floor.rooms.splice(idx, 1);\n return [{ kind: \"delete\", entity: \"room\", id: roomId }];\n }\n return [];\n });\n}\n\n// --- Openings --------------------------------------------------------------\n\nexport interface CreateOpeningInput {\n wallId: string;\n type: OpeningType;\n offset: number;\n width: number;\n height: number;\n sillHeight?: number;\n id?: string;\n}\n\nexport function createOpening(\n doc: BuildingDocument,\n input: CreateOpeningInput,\n): CommandResult {\n return mutate(doc, (draft, warnings) => {\n for (const floor of allFloorsOf(draft)) {\n const wall = floor.walls.find((w) => w.id === input.wallId);\n if (!wall) continue;\n const opening: Opening = {\n id: input.id ?? createId(\"opening\"),\n floorId: floor.id,\n wallId: input.wallId,\n type: input.type,\n offset: input.offset,\n width: input.width,\n height: input.height,\n sillHeight: input.sillHeight ?? (input.type === \"window\" ? 0.9 : 0),\n };\n if (!openingFits(wall, opening)) {\n warnings.push({\n code: \"opening-overflow\",\n message: `Opening ${opening.id} does not fit within wall ${wall.id}`,\n entityId: opening.id,\n });\n }\n floor.openings.push(opening);\n return [{ kind: \"create\", entity: \"opening\", id: opening.id }];\n }\n warnings.push({\n code: \"wall-missing\",\n message: `Wall ${input.wallId} not found for opening`,\n });\n return [];\n });\n}\n\nexport function updateOpening(\n doc: BuildingDocument,\n openingId: string,\n patch: Partial<Omit<Opening, \"id\" | \"floorId\" | \"wallId\">>,\n): CommandResult {\n return mutate(doc, (draft, warnings) => {\n for (const floor of allFloorsOf(draft)) {\n const opening = floor.openings.find((o) => o.id === openingId);\n if (!opening) continue;\n Object.assign(opening, patch);\n const wall = floor.walls.find((w) => w.id === opening.wallId);\n if (wall && !openingFits(wall, opening)) {\n warnings.push({\n code: \"opening-overflow\",\n message: `Opening ${opening.id} no longer fits its wall`,\n entityId: opening.id,\n });\n }\n return [{ kind: \"update\", entity: \"opening\", id: openingId }];\n }\n return [];\n });\n}\n\nexport function moveOpening(\n doc: BuildingDocument,\n openingId: string,\n offset: number,\n): CommandResult {\n return updateOpening(doc, openingId, { offset });\n}\n\nexport function deleteOpening(\n doc: BuildingDocument,\n openingId: string,\n): CommandResult {\n return mutate(doc, (draft) => {\n for (const floor of allFloorsOf(draft)) {\n const idx = floor.openings.findIndex((o) => o.id === openingId);\n if (idx === -1) continue;\n floor.openings.splice(idx, 1);\n return [{ kind: \"delete\", entity: \"opening\", id: openingId }];\n }\n return [];\n });\n}\n\n// --- Floors ----------------------------------------------------------------\n\nexport interface CreateFloorInput {\n buildingId: string;\n name: string;\n elevation: number;\n height?: number;\n id?: string;\n}\n\nexport function createFloor(\n doc: BuildingDocument,\n input: CreateFloorInput,\n): CommandResult {\n return mutate(doc, (draft, warnings) => {\n const building = draft.buildings.find((b) => b.id === input.buildingId);\n if (!building) {\n warnings.push({ code: \"building-missing\", message: \"Building not found\" });\n return [];\n }\n const floor: Floor = {\n id: input.id ?? createId(\"floor\"),\n buildingId: building.id,\n name: input.name,\n elevation: input.elevation,\n height: input.height ?? 2.8,\n visible: true,\n locked: false,\n walls: [],\n rooms: [],\n openings: [],\n objects: [],\n };\n building.floors.push(floor);\n building.floors.sort((a, b) => a.elevation - b.elevation);\n return [{ kind: \"create\", entity: \"floor\", id: floor.id }];\n });\n}\n\nexport function duplicateFloor(\n doc: BuildingDocument,\n floorId: string,\n): CommandResult {\n return mutate(doc, (draft) => {\n for (const building of draft.buildings) {\n const floor = building.floors.find((f) => f.id === floorId);\n if (!floor) continue;\n const idMap = new Map<string, string>();\n const copy: Floor = deepClone(floor);\n copy.id = createId(\"floor\");\n copy.name = `${floor.name} (copy)`;\n copy.elevation = floor.elevation + floor.height;\n // Re-id child entities and keep opening→wall references consistent.\n copy.walls.forEach((w) => {\n const nid = createId(\"wall\");\n idMap.set(w.id, nid);\n w.id = nid;\n w.floorId = copy.id;\n });\n copy.openings.forEach((o) => {\n o.id = createId(\"opening\");\n o.floorId = copy.id;\n o.wallId = idMap.get(o.wallId) ?? o.wallId;\n });\n copy.rooms.forEach((r) => {\n r.id = createId(\"room\");\n r.floorId = copy.id;\n });\n copy.objects.forEach((ob) => {\n ob.id = createId(\"object\");\n ob.floorId = copy.id;\n });\n building.floors.push(copy);\n building.floors.sort((a, b) => a.elevation - b.elevation);\n return [{ kind: \"create\", entity: \"floor\", id: copy.id }];\n }\n return [];\n });\n}\n\nexport function reorderFloor(\n doc: BuildingDocument,\n floorId: string,\n newElevation: number,\n): CommandResult {\n return mutate(doc, (draft) => {\n const floor = requireFloor(draft, floorId);\n floor.elevation = newElevation;\n for (const building of draft.buildings) {\n building.floors.sort((a, b) => a.elevation - b.elevation);\n }\n return [{ kind: \"update\", entity: \"floor\", id: floorId }];\n });\n}\n\nexport function updateFloor(\n doc: BuildingDocument,\n floorId: string,\n patch: Partial<Pick<Floor, \"name\" | \"elevation\" | \"height\" | \"visible\" | \"locked\">>,\n): CommandResult {\n return mutate(doc, (draft) => {\n const floor = requireFloor(draft, floorId);\n Object.assign(floor, patch);\n return [{ kind: \"update\", entity: \"floor\", id: floorId }];\n });\n}\n\nexport function deleteFloor(doc: BuildingDocument, floorId: string): CommandResult {\n return mutate(doc, (draft) => {\n for (const building of draft.buildings) {\n const idx = building.floors.findIndex((f) => f.id === floorId);\n if (idx === -1) continue;\n building.floors.splice(idx, 1);\n return [{ kind: \"delete\", entity: \"floor\", id: floorId }];\n }\n return [];\n });\n}\n\n// --- internals -------------------------------------------------------------\n\nfunction allFloorsOf(doc: BuildingDocument): Floor[] {\n return doc.buildings.flatMap((b) => b.floors);\n}\n\n/** Clamp openings so they stay attached after a wall changes length. */\nfunction reattachOpenings(floor: Floor, wall: Wall, warnings: ModelWarning[]): void {\n const wl: WallLike = wall;\n const len = wallLength(wl);\n for (const opening of floor.openings) {\n if (opening.wallId !== wall.id) continue;\n const half = opening.width / 2;\n const clamped = Math.min(Math.max(opening.offset, half), Math.max(half, len - half));\n if (clamped !== opening.offset) {\n opening.offset = clamped;\n warnings.push({\n code: \"opening-reclamped\",\n message: `Opening ${opening.id} re-positioned to stay on wall`,\n entityId: opening.id,\n });\n }\n }\n}\n","import { createId } from \"@react-arch/shared\";\nimport type { BuildingDocument } from \"./model.js\";\n\nexport interface HistoryEntry {\n id: string;\n label: string;\n before: BuildingDocument;\n after: BuildingDocument;\n}\n\n/**\n * Command-based undo/redo. Keeps full document snapshots per entry which is\n * simple and correct for the MVP; this can later move to patches / op logs\n * without changing the public surface.\n */\nexport class History {\n private past: HistoryEntry[] = [];\n private future: HistoryEntry[] = [];\n\n constructor(private limit = 200) {}\n\n push(label: string, before: BuildingDocument, after: BuildingDocument): void {\n this.past.push({ id: createId(\"hist\"), label, before, after });\n if (this.past.length > this.limit) this.past.shift();\n this.future = [];\n }\n\n canUndo(): boolean {\n return this.past.length > 0;\n }\n\n canRedo(): boolean {\n return this.future.length > 0;\n }\n\n undo(): BuildingDocument | null {\n const entry = this.past.pop();\n if (!entry) return null;\n this.future.push(entry);\n return entry.before;\n }\n\n redo(): BuildingDocument | null {\n const entry = this.future.pop();\n if (!entry) return null;\n this.past.push(entry);\n return entry.after;\n }\n\n get undoLabel(): string | null {\n return this.past.at(-1)?.label ?? null;\n }\n\n get redoLabel(): string | null {\n return this.future.at(-1)?.label ?? null;\n }\n\n clear(): void {\n this.past = [];\n this.future = [];\n }\n}\n","import { MODEL_VERSION, type BuildingDocument } from \"./model.js\";\n\n/**\n * Migration registry. Each migration upgrades a document one version forward.\n * Add new entries as the schema evolves; `migrate` chains them in order.\n */\ntype Migration = (doc: Record<string, unknown>) => Record<string, unknown>;\n\nconst migrations: Record<string, Migration> = {\n // Example placeholder for the first real migration:\n // \"0.0.1\": (doc) => ({ ...doc, version: \"0.1.0\", assets: doc.assets ?? [] }),\n};\n\nexport function migrate(input: Record<string, unknown>): Record<string, unknown> {\n let doc = { ...input };\n let guard = 0;\n while (doc.version !== MODEL_VERSION && guard < 50) {\n const m = migrations[doc.version as string];\n if (!m) break; // No path forward; validation will report the mismatch.\n doc = m(doc);\n guard += 1;\n }\n return doc;\n}\n\nexport function serialize(doc: BuildingDocument): string {\n return JSON.stringify(doc, null, 2);\n}\n\nexport function deserialize(json: string): BuildingDocument {\n const raw = JSON.parse(json) as Record<string, unknown>;\n return migrate(raw) as unknown as BuildingDocument;\n}\n\nexport function isCompatibleVersion(version: string): boolean {\n // Same major.minor is considered compatible for the MVP.\n const [a, b] = version.split(\".\");\n const [ca, cb] = MODEL_VERSION.split(\".\");\n return a === ca && b === cb;\n}\n","import { createId } from \"@react-arch/shared\";\nimport type { BuildingDocument, Material } from \"./model.js\";\nimport { MODEL_VERSION } from \"./model.js\";\n\nexport const DEFAULT_MATERIALS: Material[] = [\n { id: \"mat-plaster\", name: \"White Plaster\", category: \"wall\", baseColor: \"#e8e6e1\", roughness: 0.9 },\n { id: \"mat-concrete\", name: \"Concrete\", category: \"wall\", baseColor: \"#9b9b97\", roughness: 0.8 },\n { id: \"mat-oak\", name: \"Oak Floor\", category: \"floor\", baseColor: \"#b88a52\", roughness: 0.6 },\n { id: \"mat-dark-wood\", name: \"Dark Wood\", category: \"wood\", baseColor: \"#4a3525\", roughness: 0.5 },\n { id: \"mat-glass\", name: \"Glass\", category: \"glass\", baseColor: \"#bcd6e6\", opacity: 0.35, roughness: 0.05, metalness: 0.1 },\n { id: \"mat-metal\", name: \"Metal\", category: \"metal\", baseColor: \"#8a8d91\", metalness: 0.9, roughness: 0.3 },\n { id: \"mat-tile\", name: \"Ceramic Tile\", category: \"ceramic\", baseColor: \"#d8dcdd\", roughness: 0.4 },\n];\n\nexport interface EmptyDocumentOptions {\n name?: string;\n units?: \"metric\" | \"imperial\";\n buildingName?: string;\n}\n\nexport function createEmptyDocument(\n options: EmptyDocumentOptions = {},\n): BuildingDocument {\n const buildingId = createId(\"bld\");\n return {\n id: createId(\"doc\"),\n version: MODEL_VERSION,\n name: options.name ?? \"Untitled\",\n units: options.units ?? \"metric\",\n buildings: [\n {\n id: buildingId,\n name: options.buildingName ?? options.name ?? \"Building\",\n floors: [],\n },\n ],\n materials: [...DEFAULT_MATERIALS],\n assets: [],\n metadata: {},\n };\n}\n","import type { Vec3 } from \"@react-arch/shared\";\n\n/**\n * Placeholder furniture geometry. Each entry is the base footprint (metres) at\n * scale 1: `w` along plan X, `d` along plan Y, `h` vertical. A building object's\n * `scale` multiplies these. Intentionally simple boxes for the MVP — no\n * photorealistic assets.\n */\nexport interface FurnitureDims {\n width: number;\n depth: number;\n height: number;\n}\n\nconst CATALOG: Record<string, FurnitureDims> = {\n bed: { width: 1.0, depth: 1.0, height: 0.5 },\n sofa: { width: 2.0, depth: 0.9, height: 0.75 },\n table: { width: 1.2, depth: 0.8, height: 0.74 },\n desk: { width: 1.2, depth: 0.6, height: 0.74 },\n chair: { width: 0.5, depth: 0.5, height: 0.9 },\n sink: { width: 0.5, depth: 0.42, height: 0.85 },\n toilet: { width: 0.4, depth: 0.6, height: 0.78 },\n shower: { width: 0.9, depth: 0.9, height: 0.12 },\n \"kitchen counter\": { width: 1.0, depth: 0.6, height: 0.9 },\n wardrobe: { width: 1.2, depth: 0.6, height: 2.0 },\n};\n\nconst DEFAULT_DIMS: FurnitureDims = { width: 0.6, depth: 0.6, height: 0.6 };\n\nexport const FURNITURE_TYPES = Object.keys(CATALOG);\n\n/** Resolve the footprint of a furniture type, applying its scale. */\nexport function furnitureDims(type: string, scale: Vec3 = [1, 1, 1]): FurnitureDims {\n const base = CATALOG[type] ?? DEFAULT_DIMS;\n return {\n width: base.width * scale[0],\n depth: base.depth * scale[1],\n height: base.height * scale[2],\n };\n}\n\n/** A subtle per-category colour for the placeholder geometry. */\nexport function furnitureColor(type: string): string {\n if (type === \"shower\" || type === \"sink\" || type === \"toilet\") return \"#9fb6c2\";\n if (type.includes(\"counter\") || type === \"table\" || type === \"desk\") return \"#9c7b54\";\n if (type === \"bed\" || type === \"sofa\") return \"#7c8aa0\";\n return \"#8a8f99\";\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","names":["wl"],"sources":["../src/model.ts","../src/commands.ts","../src/history.ts","../src/serialize.ts","../src/defaults.ts","../src/furniture.ts"],"sourcesContent":["import type { Units, Vec2, Vec3 } from \"@react-arch/shared\";\n\n/** The current on-disk model version. Bump when the schema changes. */\nexport const MODEL_VERSION = \"0.1.0\";\n\nexport type OpeningType = \"door\" | \"window\" | \"opening\";\nexport type SwingDirection = \"in\" | \"out\";\nexport type HingeSide = \"left\" | \"right\";\n\nexport interface Wall {\n id: string;\n floorId: string;\n start: Vec2;\n end: Vec2;\n thickness: number;\n height: number;\n materialId?: string;\n layerId?: string;\n locked?: boolean;\n}\n\nexport interface Opening {\n id: string;\n floorId: string;\n wallId: string;\n type: OpeningType;\n /** Distance along the wall centerline to the opening center. */\n offset: number;\n width: number;\n height: number;\n sillHeight: number;\n swing?: SwingDirection;\n hinge?: HingeSide;\n materialId?: string;\n}\n\nexport interface Room {\n id: string;\n floorId: string;\n name: string;\n /** Explicit polygon (metres). Rooms may also be derived from wall loops. */\n polygon: Vec2[];\n boundaryWallIds?: string[];\n floorMaterialId?: string;\n ceilingMaterialId?: string;\n usageType?: string;\n height?: number;\n}\n\nexport interface BuildingObject {\n id: string;\n floorId: string;\n type: string;\n position: Vec3;\n rotation: Vec3;\n scale: Vec3;\n assetId?: string;\n metadata?: Record<string, unknown>;\n}\n\nexport interface Floor {\n id: string;\n buildingId: string;\n name: string;\n elevation: number;\n height: number;\n visible: boolean;\n locked: boolean;\n walls: Wall[];\n rooms: Room[];\n openings: Opening[];\n objects: BuildingObject[];\n}\n\nexport interface Building {\n id: string;\n name: string;\n floors: Floor[];\n}\n\nexport type MaterialCategory =\n | \"wall\"\n | \"floor\"\n | \"ceiling\"\n | \"glass\"\n | \"wood\"\n | \"metal\"\n | \"ceramic\"\n | \"custom\";\n\nexport interface Material {\n id: string;\n name: string;\n category: MaterialCategory;\n baseColor: string;\n roughness?: number;\n metalness?: number;\n opacity?: number;\n textureUrl?: string;\n}\n\nexport interface Asset {\n id: string;\n name: string;\n url?: string;\n kind: string;\n}\n\nexport interface Site {\n id: string;\n name: string;\n polygon?: Vec2[];\n}\n\nexport interface BuildingDocument {\n id: string;\n version: string;\n name: string;\n units: Units;\n site?: Site;\n buildings: Building[];\n materials: Material[];\n assets: Asset[];\n metadata: Record<string, unknown>;\n}\n\n/** A single semantic change emitted by a command. */\nexport interface ModelChange {\n kind: \"create\" | \"update\" | \"delete\";\n entity: \"wall\" | \"room\" | \"opening\" | \"floor\" | \"object\" | \"document\";\n id: string;\n}\n\nexport interface ModelWarning {\n code: string;\n message: string;\n entityId?: string;\n}\n\nexport interface CommandResult {\n document: BuildingDocument;\n changes: ModelChange[];\n warnings: ModelWarning[];\n}\n\n// ---------------------------------------------------------------------------\n// Read helpers\n// ---------------------------------------------------------------------------\n\nexport function findFloor(\n doc: BuildingDocument,\n floorId: string,\n): { building: Building; floor: Floor } | undefined {\n for (const building of doc.buildings) {\n const floor = building.floors.find((f) => f.id === floorId);\n if (floor) return { building, floor };\n }\n return undefined;\n}\n\nexport function allFloors(doc: BuildingDocument): Floor[] {\n return doc.buildings.flatMap((b) => b.floors);\n}\n\nexport function findWall(doc: BuildingDocument, wallId: string): Wall | undefined {\n for (const floor of allFloors(doc)) {\n const w = floor.walls.find((x) => x.id === wallId);\n if (w) return w;\n }\n return undefined;\n}\n\nexport function findRoom(doc: BuildingDocument, roomId: string): Room | undefined {\n for (const floor of allFloors(doc)) {\n const r = floor.rooms.find((x) => x.id === roomId);\n if (r) return r;\n }\n return undefined;\n}\n\nexport function findOpening(\n doc: BuildingDocument,\n openingId: string,\n): Opening | undefined {\n for (const floor of allFloors(doc)) {\n const o = floor.openings.find((x) => x.id === openingId);\n if (o) return o;\n }\n return undefined;\n}\n\nexport type EntityKind = \"wall\" | \"room\" | \"opening\" | \"floor\" | \"object\";\n\nexport interface EntityRef {\n kind: EntityKind;\n id: string;\n}\n","import { createId, deepClone, type Vec2 } from \"@react-arch/shared\";\nimport { openingFits, wallLength, type WallLike } from \"@react-arch/geometry\";\nimport {\n type BuildingDocument,\n type CommandResult,\n type Floor,\n type ModelChange,\n type ModelWarning,\n type Opening,\n type OpeningType,\n type Room,\n type Wall,\n findFloor,\n} from \"./model.js\";\n\n/**\n * Commands are pure: they take a document and return a brand-new document plus\n * a list of changes and warnings. They never mutate the input. The studio /\n * editor layers feed these into the history stack for undo/redo.\n */\n\nfunction mutate(\n doc: BuildingDocument,\n fn: (draft: BuildingDocument, warnings: ModelWarning[]) => ModelChange[],\n): CommandResult {\n const draft = deepClone(doc);\n const warnings: ModelWarning[] = [];\n const changes = fn(draft, warnings);\n return { document: draft, changes, warnings };\n}\n\nfunction requireFloor(doc: BuildingDocument, floorId: string): Floor {\n const found = findFloor(doc, floorId);\n if (!found) throw new Error(`Floor not found: ${floorId}`);\n return found.floor;\n}\n\nfunction cloneVec2(v: Vec2): Vec2 {\n return [v[0], v[1]];\n}\n\n// --- Walls -----------------------------------------------------------------\n\nexport interface CreateWallInput {\n floorId: string;\n start: Vec2;\n end: Vec2;\n thickness?: number;\n height?: number;\n materialId?: string;\n id?: string;\n}\n\nexport function createWall(\n doc: BuildingDocument,\n input: CreateWallInput,\n): CommandResult {\n return mutate(doc, (draft) => {\n const floor = requireFloor(draft, input.floorId);\n const wall: Wall = {\n id: input.id ?? createId(\"wall\"),\n floorId: input.floorId,\n start: cloneVec2(input.start),\n end: cloneVec2(input.end),\n thickness: input.thickness ?? 0.2,\n height: input.height ?? floor.height,\n materialId: input.materialId,\n };\n floor.walls.push(wall);\n return [{ kind: \"create\", entity: \"wall\", id: wall.id }];\n });\n}\n\nexport function updateWall(\n doc: BuildingDocument,\n wallId: string,\n patch: Partial<Omit<Wall, \"id\" | \"floorId\">>,\n): CommandResult {\n return mutate(doc, (draft, warnings) => {\n for (const floor of allFloorsOf(draft)) {\n const wall = floor.walls.find((w) => w.id === wallId);\n if (!wall) continue;\n Object.assign(wall, deepClone(patch));\n reattachOpenings(floor, wall, warnings);\n return [{ kind: \"update\", entity: \"wall\", id: wallId }];\n }\n warnings.push({ code: \"wall-missing\", message: `Wall ${wallId} not found` });\n return [];\n });\n}\n\n/** Move a wall's endpoints, keeping attached openings within bounds. */\nexport function moveWall(\n doc: BuildingDocument,\n wallId: string,\n start: Vec2,\n end: Vec2,\n): CommandResult {\n return updateWall(doc, wallId, { start, end });\n}\n\nexport function deleteWall(doc: BuildingDocument, wallId: string): CommandResult {\n return mutate(doc, (draft) => {\n const changes: ModelChange[] = [];\n for (const floor of allFloorsOf(draft)) {\n const idx = floor.walls.findIndex((w) => w.id === wallId);\n if (idx === -1) continue;\n floor.walls.splice(idx, 1);\n changes.push({ kind: \"delete\", entity: \"wall\", id: wallId });\n for (const room of floor.rooms) {\n if (!room.boundaryWallIds?.includes(wallId)) continue;\n room.boundaryWallIds = room.boundaryWallIds.filter((id) => id !== wallId);\n changes.push({ kind: \"update\", entity: \"room\", id: room.id });\n }\n // Cascade: drop openings attached to the wall.\n floor.openings = floor.openings.filter((o) => {\n if (o.wallId === wallId) {\n changes.push({ kind: \"delete\", entity: \"opening\", id: o.id });\n return false;\n }\n return true;\n });\n break;\n }\n return changes;\n });\n}\n\n// --- Rooms -----------------------------------------------------------------\n\nexport interface CreateRoomInput {\n floorId: string;\n name: string;\n polygon: Vec2[];\n id?: string;\n floorMaterialId?: string;\n ceilingMaterialId?: string;\n usageType?: string;\n}\n\n/** Convenience: build a rectangular room from origin + size. */\nexport function rectRoomPolygon(\n x: number,\n y: number,\n width: number,\n depth: number,\n): Vec2[] {\n return [\n [x, y],\n [x + width, y],\n [x + width, y + depth],\n [x, y + depth],\n ];\n}\n\nexport function createRoom(\n doc: BuildingDocument,\n input: CreateRoomInput,\n): CommandResult {\n return mutate(doc, (draft) => {\n const floor = requireFloor(draft, input.floorId);\n const room: Room = {\n id: input.id ?? createId(\"room\"),\n floorId: input.floorId,\n name: input.name,\n polygon: input.polygon.map(cloneVec2),\n floorMaterialId: input.floorMaterialId,\n ceilingMaterialId: input.ceilingMaterialId,\n usageType: input.usageType,\n };\n floor.rooms.push(room);\n return [{ kind: \"create\", entity: \"room\", id: room.id }];\n });\n}\n\nexport function updateRoom(\n doc: BuildingDocument,\n roomId: string,\n patch: Partial<Omit<Room, \"id\" | \"floorId\">>,\n): CommandResult {\n return mutate(doc, (draft, warnings) => {\n for (const floor of allFloorsOf(draft)) {\n const room = floor.rooms.find((r) => r.id === roomId);\n if (!room) continue;\n Object.assign(room, deepClone(patch));\n return [{ kind: \"update\", entity: \"room\", id: roomId }];\n }\n warnings.push({ code: \"room-missing\", message: `Room ${roomId} not found` });\n return [];\n });\n}\n\nexport function deleteRoom(doc: BuildingDocument, roomId: string): CommandResult {\n return mutate(doc, (draft) => {\n for (const floor of allFloorsOf(draft)) {\n const idx = floor.rooms.findIndex((r) => r.id === roomId);\n if (idx === -1) continue;\n floor.rooms.splice(idx, 1);\n return [{ kind: \"delete\", entity: \"room\", id: roomId }];\n }\n return [];\n });\n}\n\n// --- Openings --------------------------------------------------------------\n\nexport interface CreateOpeningInput {\n wallId: string;\n type: OpeningType;\n offset: number;\n width: number;\n height: number;\n sillHeight?: number;\n id?: string;\n}\n\nexport function createOpening(\n doc: BuildingDocument,\n input: CreateOpeningInput,\n): CommandResult {\n return mutate(doc, (draft, warnings) => {\n for (const floor of allFloorsOf(draft)) {\n const wall = floor.walls.find((w) => w.id === input.wallId);\n if (!wall) continue;\n const opening: Opening = {\n id: input.id ?? createId(\"opening\"),\n floorId: floor.id,\n wallId: input.wallId,\n type: input.type,\n offset: input.offset,\n width: input.width,\n height: input.height,\n sillHeight: input.sillHeight ?? (input.type === \"window\" ? 0.9 : 0),\n };\n if (!openingFits(wall, opening)) {\n warnings.push({\n code: \"opening-overflow\",\n message: `Opening ${opening.id} does not fit within wall ${wall.id}`,\n entityId: opening.id,\n });\n }\n floor.openings.push(opening);\n return [{ kind: \"create\", entity: \"opening\", id: opening.id }];\n }\n warnings.push({\n code: \"wall-missing\",\n message: `Wall ${input.wallId} not found for opening`,\n });\n return [];\n });\n}\n\nexport function updateOpening(\n doc: BuildingDocument,\n openingId: string,\n patch: Partial<Omit<Opening, \"id\" | \"floorId\" | \"wallId\">>,\n): CommandResult {\n return mutate(doc, (draft, warnings) => {\n for (const floor of allFloorsOf(draft)) {\n const opening = floor.openings.find((o) => o.id === openingId);\n if (!opening) continue;\n Object.assign(opening, patch);\n const wall = floor.walls.find((w) => w.id === opening.wallId);\n if (wall && !openingFits(wall, opening)) {\n warnings.push({\n code: \"opening-overflow\",\n message: `Opening ${opening.id} no longer fits its wall`,\n entityId: opening.id,\n });\n }\n return [{ kind: \"update\", entity: \"opening\", id: openingId }];\n }\n return [];\n });\n}\n\nexport function moveOpening(\n doc: BuildingDocument,\n openingId: string,\n offset: number,\n): CommandResult {\n return updateOpening(doc, openingId, { offset });\n}\n\nexport function deleteOpening(\n doc: BuildingDocument,\n openingId: string,\n): CommandResult {\n return mutate(doc, (draft) => {\n for (const floor of allFloorsOf(draft)) {\n const idx = floor.openings.findIndex((o) => o.id === openingId);\n if (idx === -1) continue;\n floor.openings.splice(idx, 1);\n return [{ kind: \"delete\", entity: \"opening\", id: openingId }];\n }\n return [];\n });\n}\n\n// --- Floors ----------------------------------------------------------------\n\nexport interface CreateFloorInput {\n buildingId: string;\n name: string;\n elevation: number;\n height?: number;\n id?: string;\n}\n\nexport function createFloor(\n doc: BuildingDocument,\n input: CreateFloorInput,\n): CommandResult {\n return mutate(doc, (draft, warnings) => {\n const building = draft.buildings.find((b) => b.id === input.buildingId);\n if (!building) {\n warnings.push({ code: \"building-missing\", message: \"Building not found\" });\n return [];\n }\n const floor: Floor = {\n id: input.id ?? createId(\"floor\"),\n buildingId: building.id,\n name: input.name,\n elevation: input.elevation,\n height: input.height ?? 2.8,\n visible: true,\n locked: false,\n walls: [],\n rooms: [],\n openings: [],\n objects: [],\n };\n building.floors.push(floor);\n building.floors.sort((a, b) => a.elevation - b.elevation);\n return [{ kind: \"create\", entity: \"floor\", id: floor.id }];\n });\n}\n\nexport function duplicateFloor(\n doc: BuildingDocument,\n floorId: string,\n): CommandResult {\n return mutate(doc, (draft) => {\n for (const building of draft.buildings) {\n const floor = building.floors.find((f) => f.id === floorId);\n if (!floor) continue;\n const idMap = new Map<string, string>();\n const copy: Floor = deepClone(floor);\n copy.id = createId(\"floor\");\n copy.name = `${floor.name} (copy)`;\n copy.elevation = floor.elevation + floor.height;\n // Re-id child entities and keep opening→wall references consistent.\n copy.walls.forEach((w) => {\n const nid = createId(\"wall\");\n idMap.set(w.id, nid);\n w.id = nid;\n w.floorId = copy.id;\n });\n copy.openings.forEach((o) => {\n o.id = createId(\"opening\");\n o.floorId = copy.id;\n o.wallId = idMap.get(o.wallId) ?? o.wallId;\n });\n copy.rooms.forEach((r) => {\n r.id = createId(\"room\");\n r.floorId = copy.id;\n if (r.boundaryWallIds) {\n r.boundaryWallIds = r.boundaryWallIds.map((id) => idMap.get(id) ?? id);\n }\n });\n copy.objects.forEach((ob) => {\n ob.id = createId(\"object\");\n ob.floorId = copy.id;\n });\n building.floors.push(copy);\n building.floors.sort((a, b) => a.elevation - b.elevation);\n return [{ kind: \"create\", entity: \"floor\", id: copy.id }];\n }\n return [];\n });\n}\n\nexport function reorderFloor(\n doc: BuildingDocument,\n floorId: string,\n newElevation: number,\n): CommandResult {\n return mutate(doc, (draft) => {\n const floor = requireFloor(draft, floorId);\n floor.elevation = newElevation;\n for (const building of draft.buildings) {\n building.floors.sort((a, b) => a.elevation - b.elevation);\n }\n return [{ kind: \"update\", entity: \"floor\", id: floorId }];\n });\n}\n\nexport function updateFloor(\n doc: BuildingDocument,\n floorId: string,\n patch: Partial<Pick<Floor, \"name\" | \"elevation\" | \"height\" | \"visible\" | \"locked\">>,\n): CommandResult {\n return mutate(doc, (draft) => {\n const floor = requireFloor(draft, floorId);\n Object.assign(floor, patch);\n return [{ kind: \"update\", entity: \"floor\", id: floorId }];\n });\n}\n\nexport function deleteFloor(doc: BuildingDocument, floorId: string): CommandResult {\n return mutate(doc, (draft) => {\n for (const building of draft.buildings) {\n const idx = building.floors.findIndex((f) => f.id === floorId);\n if (idx === -1) continue;\n building.floors.splice(idx, 1);\n return [{ kind: \"delete\", entity: \"floor\", id: floorId }];\n }\n return [];\n });\n}\n\n// --- internals -------------------------------------------------------------\n\nfunction allFloorsOf(doc: BuildingDocument): Floor[] {\n return doc.buildings.flatMap((b) => b.floors);\n}\n\n/** Clamp openings so they stay attached after a wall changes length. */\nfunction reattachOpenings(floor: Floor, wall: Wall, warnings: ModelWarning[]): void {\n const wl: WallLike = wall;\n const len = wallLength(wl);\n for (const opening of floor.openings) {\n if (opening.wallId !== wall.id) continue;\n const half = opening.width / 2;\n const clamped = Math.min(Math.max(opening.offset, half), Math.max(half, len - half));\n if (clamped !== opening.offset) {\n opening.offset = clamped;\n warnings.push({\n code: \"opening-reclamped\",\n message: `Opening ${opening.id} re-positioned to stay on wall`,\n entityId: opening.id,\n });\n }\n }\n}\n","import { createId, deepClone } from \"@react-arch/shared\";\nimport type { BuildingDocument } from \"./model.js\";\n\nexport interface HistoryEntry {\n id: string;\n label: string;\n before: BuildingDocument;\n after: BuildingDocument;\n}\n\n/**\n * Command-based undo/redo. Keeps full document snapshots per entry which is\n * simple and correct for the MVP; this can later move to patches / op logs\n * without changing the public surface.\n */\nexport class History {\n private past: HistoryEntry[] = [];\n private future: HistoryEntry[] = [];\n\n constructor(private limit = 200) {}\n\n push(label: string, before: BuildingDocument, after: BuildingDocument): void {\n this.past.push({ id: createId(\"hist\"), label, before: deepClone(before), after: deepClone(after) });\n if (this.past.length > this.limit) this.past.shift();\n this.future = [];\n }\n\n canUndo(): boolean {\n return this.past.length > 0;\n }\n\n canRedo(): boolean {\n return this.future.length > 0;\n }\n\n undo(): BuildingDocument | null {\n const entry = this.past.pop();\n if (!entry) return null;\n this.future.push(entry);\n return deepClone(entry.before);\n }\n\n redo(): BuildingDocument | null {\n const entry = this.future.pop();\n if (!entry) return null;\n this.past.push(entry);\n return deepClone(entry.after);\n }\n\n get undoLabel(): string | null {\n return this.past.at(-1)?.label ?? null;\n }\n\n get redoLabel(): string | null {\n return this.future.at(-1)?.label ?? null;\n }\n\n clear(): void {\n this.past = [];\n this.future = [];\n }\n}\n","import { MODEL_VERSION, type BuildingDocument } from \"./model.js\";\n\n/**\n * Migration registry. Each migration upgrades a document one version forward.\n * Add new entries as the schema evolves; `migrate` chains them in order.\n */\ntype Migration = (doc: Record<string, unknown>) => Record<string, unknown>;\n\nconst migrations: Record<string, Migration> = {\n // Example placeholder for the first real migration:\n // \"0.0.1\": (doc) => ({ ...doc, version: \"0.1.0\", assets: doc.assets ?? [] }),\n};\n\nexport function migrate(input: Record<string, unknown>): Record<string, unknown> {\n let doc = { ...input };\n let guard = 0;\n while (doc.version !== MODEL_VERSION && guard < 50) {\n const m = migrations[doc.version as string];\n if (!m) break; // No path forward; validation will report the mismatch.\n doc = m(doc);\n guard += 1;\n }\n return doc;\n}\n\nexport function serialize(doc: BuildingDocument): string {\n return JSON.stringify(doc, null, 2);\n}\n\nexport function deserialize(json: string): BuildingDocument {\n const raw = JSON.parse(json) as Record<string, unknown>;\n return migrate(raw) as unknown as BuildingDocument;\n}\n\nexport function isCompatibleVersion(version: string): boolean {\n // Same major.minor is considered compatible for the MVP.\n const [a, b] = version.split(\".\");\n const [ca, cb] = MODEL_VERSION.split(\".\");\n return a === ca && b === cb;\n}\n","import { createId } from \"@react-arch/shared\";\nimport type { BuildingDocument, Material } from \"./model.js\";\nimport { MODEL_VERSION } from \"./model.js\";\n\nexport const DEFAULT_MATERIALS: Material[] = [\n { id: \"mat-plaster\", name: \"White Plaster\", category: \"wall\", baseColor: \"#e8e6e1\", roughness: 0.9 },\n { id: \"mat-concrete\", name: \"Concrete\", category: \"wall\", baseColor: \"#9b9b97\", roughness: 0.8 },\n { id: \"mat-oak\", name: \"Oak Floor\", category: \"floor\", baseColor: \"#b88a52\", roughness: 0.6 },\n { id: \"mat-dark-wood\", name: \"Dark Wood\", category: \"wood\", baseColor: \"#4a3525\", roughness: 0.5 },\n { id: \"mat-glass\", name: \"Glass\", category: \"glass\", baseColor: \"#bcd6e6\", opacity: 0.35, roughness: 0.05, metalness: 0.1 },\n { id: \"mat-metal\", name: \"Metal\", category: \"metal\", baseColor: \"#8a8d91\", metalness: 0.9, roughness: 0.3 },\n { id: \"mat-tile\", name: \"Ceramic Tile\", category: \"ceramic\", baseColor: \"#d8dcdd\", roughness: 0.4 },\n];\n\nexport interface EmptyDocumentOptions {\n name?: string;\n units?: \"metric\" | \"imperial\";\n buildingName?: string;\n}\n\nexport function createEmptyDocument(\n options: EmptyDocumentOptions = {},\n): BuildingDocument {\n const buildingId = createId(\"bld\");\n return {\n id: createId(\"doc\"),\n version: MODEL_VERSION,\n name: options.name ?? \"Untitled\",\n units: options.units ?? \"metric\",\n buildings: [\n {\n id: buildingId,\n name: options.buildingName ?? options.name ?? \"Building\",\n floors: [],\n },\n ],\n materials: DEFAULT_MATERIALS.map((m) => ({ ...m })),\n assets: [],\n metadata: {},\n };\n}\n","import type { Vec3 } from \"@react-arch/shared\";\n\n/**\n * Placeholder furniture geometry. Each entry is the base footprint (metres) at\n * scale 1: `w` along plan X, `d` along plan Y, `h` vertical. A building object's\n * `scale` multiplies these. Intentionally simple boxes for the MVP — no\n * photorealistic assets.\n */\nexport interface FurnitureDims {\n width: number;\n depth: number;\n height: number;\n}\n\nconst CATALOG: Record<string, FurnitureDims> = {\n bed: { width: 1.0, depth: 1.0, height: 0.5 },\n sofa: { width: 2.0, depth: 0.9, height: 0.75 },\n table: { width: 1.2, depth: 0.8, height: 0.74 },\n desk: { width: 1.2, depth: 0.6, height: 0.74 },\n chair: { width: 0.5, depth: 0.5, height: 0.9 },\n sink: { width: 0.5, depth: 0.42, height: 0.85 },\n toilet: { width: 0.4, depth: 0.6, height: 0.78 },\n shower: { width: 0.9, depth: 0.9, height: 0.12 },\n \"kitchen counter\": { width: 1.0, depth: 0.6, height: 0.9 },\n wardrobe: { width: 1.2, depth: 0.6, height: 2.0 },\n};\n\nconst DEFAULT_DIMS: FurnitureDims = { width: 0.6, depth: 0.6, height: 0.6 };\n\nexport const FURNITURE_TYPES = Object.keys(CATALOG);\n\n/** Resolve the footprint of a furniture type, applying its scale. */\nexport function furnitureDims(type: string, scale: Vec3 = [1, 1, 1]): FurnitureDims {\n const base = CATALOG[type] ?? DEFAULT_DIMS;\n return {\n width: base.width * scale[0],\n depth: base.depth * scale[1],\n height: base.height * scale[2],\n };\n}\n\n/** A subtle per-category colour for the placeholder geometry. */\nexport function furnitureColor(type: string): string {\n if (type === \"shower\" || type === \"sink\" || type === \"toilet\") return \"#9fb6c2\";\n if (type.includes(\"counter\") || type === \"table\" || type === \"desk\") return \"#9c7b54\";\n if (type === \"bed\" || type === \"sofa\") return \"#7c8aa0\";\n return \"#8a8f99\";\n}\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@react-arch/core",
3
- "version": "0.1.1",
3
+ "version": "0.1.3",
4
4
  "type": "module",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.js",
@@ -12,8 +12,8 @@
12
12
  }
13
13
  },
14
14
  "dependencies": {
15
- "@react-arch/shared": "0.1.1",
16
- "@react-arch/geometry": "0.1.1"
15
+ "@react-arch/shared": "0.1.3",
16
+ "@react-arch/geometry": "0.1.3"
17
17
  },
18
18
  "devDependencies": {
19
19
  "typescript": "^5.7.2",