auto-git:

[change] src/runtime-three/runtime-scene-build.ts
 [change] src/viewport-three/transform-surface-snap.ts
 [change] src/viewport-three/viewport-host.ts
 [change] tests/domain/runtime-interaction-system.test.ts
 [change] tests/domain/transform-session.command.test.ts
 [change] tests/serialization/scene-document-json.test.ts
 [change] tests/unit/runtime-interaction-system.test.ts
 [change] tests/unit/transform-foundation.integration.test.tsx
This commit is contained in:
2026-05-11 14:15:15 +02:00
parent 01ef204dcc
commit 4b76f1a719
8 changed files with 214 additions and 158 deletions

View File

@@ -159,7 +159,7 @@ function createRuntimeSceneFixture(): RuntimeSceneDefinition {
prompt: "Disabled Prompt",
interactionEnabled: false
}
],
]
},
interactionLinks: [],
control: createEmptyRuntimeControlSurfaceDefinition(),
@@ -288,7 +288,7 @@ describe("RuntimeInteractionSystem", () => {
playAnimation: () => {},
stopAnimation: () => {},
playSound: () => {},
stopSound: () => {},
stopSound: () => {}
}
);
interactionSystem.updatePlayerPosition(
@@ -309,7 +309,7 @@ describe("RuntimeInteractionSystem", () => {
playAnimation: () => {},
stopAnimation: () => {},
playSound: () => {},
stopSound: () => {},
stopSound: () => {}
}
);
@@ -423,7 +423,7 @@ describe("RuntimeInteractionSystem", () => {
dispatches.push(`${link.id}:${instanceId}`);
},
playSound: () => {},
stopSound: () => {},
stopSound: () => {}
}
);
@@ -462,7 +462,9 @@ describe("RuntimeInteractionSystem", () => {
throw new Error("Expected a camera rig entity control target.");
}
dispatches.push(`${link.id}:${effect.type}:${effect.target.entityId}`);
dispatches.push(
`${link.id}:${effect.type}:${effect.target.entityId}`
);
}
})
);
@@ -480,7 +482,9 @@ describe("RuntimeInteractionSystem", () => {
throw new Error("Expected a camera rig entity control target.");
}
dispatches.push(`${link.id}:${effect.type}:${effect.target.entityId}`);
dispatches.push(
`${link.id}:${effect.type}:${effect.target.entityId}`
);
}
})
);
@@ -515,7 +519,9 @@ describe("RuntimeInteractionSystem", () => {
throw new Error("Expected a camera rig entity control target.");
}
dispatches.push(`${link.id}:${effect.type}:${effect.target.entityId}`);
dispatches.push(
`${link.id}:${effect.type}:${effect.target.entityId}`
);
}
})
);
@@ -564,7 +570,7 @@ describe("RuntimeInteractionSystem", () => {
playAnimation: () => {},
stopAnimation: () => {},
playSound: () => {},
stopSound: () => {},
stopSound: () => {}
}
);
interactionSystem.updatePlayerPosition(
@@ -590,7 +596,7 @@ describe("RuntimeInteractionSystem", () => {
playAnimation: () => {},
stopAnimation: () => {},
playSound: () => {},
stopSound: () => {},
stopSound: () => {}
}
);
@@ -728,7 +734,7 @@ describe("RuntimeInteractionSystem", () => {
playAnimation: () => {},
stopAnimation: () => {},
playSound: () => {},
stopSound: () => {},
stopSound: () => {}
}
);
@@ -779,7 +785,7 @@ describe("RuntimeInteractionSystem", () => {
},
stopSound: (soundEmitterId, link) => {
dispatches.push(`${link.id}:${soundEmitterId}`);
},
}
}
);
@@ -1402,7 +1408,9 @@ describe("RuntimeInteractionSystem", () => {
runtimeScene,
{
teleportPlayer: () => {
throw new Error("Teleport should not dispatch for a scene transition.");
throw new Error(
"Teleport should not dispatch for a scene transition."
);
},
startSceneTransition: (request) => {
dispatches.push(
@@ -1410,12 +1418,14 @@ describe("RuntimeInteractionSystem", () => {
);
},
toggleBrushVisibility: () => {
throw new Error("Visibility should not dispatch for a scene transition.");
throw new Error(
"Visibility should not dispatch for a scene transition."
);
},
playAnimation: () => {},
stopAnimation: () => {},
playSound: () => {},
stopSound: () => {},
stopSound: () => {}
}
);

View File

@@ -248,19 +248,25 @@ describe("transform session commit commands", () => {
expect(
supportsTransformOperation(
pathPointResolved.target as NonNullable<typeof pathPointResolved.target>,
pathPointResolved.target as NonNullable<
typeof pathPointResolved.target
>,
"translate"
)
).toBe(true);
expect(
supportsTransformOperation(
pathPointResolved.target as NonNullable<typeof pathPointResolved.target>,
pathPointResolved.target as NonNullable<
typeof pathPointResolved.target
>,
"rotate"
)
).toBe(false);
expect(
supportsTransformOperation(
pathPointResolved.target as NonNullable<typeof pathPointResolved.target>,
pathPointResolved.target as NonNullable<
typeof pathPointResolved.target
>,
"scale"
)
).toBe(false);
@@ -1343,12 +1349,13 @@ describe("transform session commit commands", () => {
};
store.executeCommand(
createCommitTransformSessionCommand(store.getState().document, scaleSession)
createCommitTransformSessionCommand(
store.getState().document,
scaleSession
)
);
expect(
store.getState().document.entities[triggerVolume.id]
).toMatchObject({
expect(store.getState().document.entities[triggerVolume.id]).toMatchObject({
position: {
x: 1,
y: 1,
@@ -1367,9 +1374,7 @@ describe("transform session commit commands", () => {
});
expect(store.undo()).toBe(true);
expect(
store.getState().document.entities[triggerVolume.id]
).toMatchObject({
expect(store.getState().document.entities[triggerVolume.id]).toMatchObject({
rotationDegrees: {
x: 0,
y: 45,
@@ -1379,9 +1384,7 @@ describe("transform session commit commands", () => {
});
expect(store.redo()).toBe(true);
expect(
store.getState().document.entities[triggerVolume.id]
).toMatchObject({
expect(store.getState().document.entities[triggerVolume.id]).toMatchObject({
size: {
x: 4,
y: 3,
@@ -1726,7 +1729,9 @@ describe("transform session commit commands", () => {
createCommitTransformSessionCommand(store.getState().document, session)
);
expect(store.getState().document.modelInstances[modelInstanceA.id]).toMatchObject({
expect(
store.getState().document.modelInstances[modelInstanceA.id]
).toMatchObject({
position: {
x: -2,
y: 0,
@@ -1738,7 +1743,9 @@ describe("transform session commit commands", () => {
z: 2
}
});
expect(store.getState().document.modelInstances[modelInstanceB.id]).toMatchObject({
expect(
store.getState().document.modelInstances[modelInstanceB.id]
).toMatchObject({
position: {
x: 2,
y: 0,
@@ -1760,7 +1767,9 @@ describe("transform session commit commands", () => {
);
expect(store.redo()).toBe(true);
expect(store.getState().document.modelInstances[modelInstanceA.id]).toMatchObject({
expect(
store.getState().document.modelInstances[modelInstanceA.id]
).toMatchObject({
position: {
x: -2,
y: 0,

View File

@@ -237,9 +237,11 @@ describe("scene document JSON", () => {
) as Record<string, unknown>;
legacyDocument.version = FOLIAGE_FOUNDATION_SCENE_DOCUMENT_VERSION;
delete ((legacyDocument.terrains as Record<string, Record<string, unknown>>)[
terrain.id
] as Record<string, unknown>).foliageMasks;
delete (
(legacyDocument.terrains as Record<string, Record<string, unknown>>)[
terrain.id
] as Record<string, unknown>
).foliageMasks;
const migratedDocument = parseSceneDocumentJson(
JSON.stringify(legacyDocument)
@@ -264,18 +266,18 @@ describe("scene document JSON", () => {
) as Record<string, unknown>;
legacyDocument.version = FOLIAGE_QUALITY_SCENE_DOCUMENT_VERSION;
delete ((legacyDocument.terrains as Record<string, Record<string, unknown>>)[
terrain.id
] as Record<string, unknown>).foliageBlockerMask;
delete (
(legacyDocument.terrains as Record<string, Record<string, unknown>>)[
terrain.id
] as Record<string, unknown>
).foliageBlockerMask;
const migratedDocument = parseSceneDocumentJson(
JSON.stringify(legacyDocument)
);
expect(migratedDocument.version).toBe(SCENE_DOCUMENT_VERSION);
expect(
migratedDocument.terrains[terrain.id]?.foliageBlockerMask
).toEqual({
expect(migratedDocument.terrains[terrain.id]?.foliageBlockerMask).toEqual({
resolutionX: 2,
resolutionZ: 2,
values: [0, 0, 0, 0]
@@ -805,9 +807,7 @@ describe("scene document JSON", () => {
const migratedDocument = migrateSceneDocument(legacyDocument);
expect(migratedDocument.version).toBe(SCENE_DOCUMENT_VERSION);
expect(
migratedDocument.brushes[brush.id].faces.posZ.climbable
).toBe(false);
expect(migratedDocument.brushes[brush.id].faces.posZ.climbable).toBe(false);
});
it("round-trips whitebox box volume settings", () => {

View File

@@ -26,7 +26,9 @@ function createClickLink(sourceEntityId: string): InteractionLink {
};
}
function createNpc(overrides: Partial<RuntimeNpc> & { entityId: string }): RuntimeNpc {
function createNpc(
overrides: Partial<RuntimeNpc> & { entityId: string }
): RuntimeNpc {
return {
entityId: overrides.entityId,
actorId: overrides.actorId ?? "",
@@ -38,13 +40,12 @@ function createNpc(overrides: Partial<RuntimeNpc> & { entityId: string }): Runti
modelAssetId: overrides.modelAssetId ?? null,
dialogues: overrides.dialogues ?? [],
defaultDialogueId: overrides.defaultDialogueId ?? null,
collider:
overrides.collider ?? {
mode: "capsule",
radius: 0.35,
height: 1.8,
eyeHeight: 1.6
},
collider: overrides.collider ?? {
mode: "capsule",
radius: 0.35,
height: 1.8,
eyeHeight: 1.6
},
activeRoutineTitle: overrides.activeRoutineTitle ?? null,
animationClipName: overrides.animationClipName ?? null,
animationLoop: overrides.animationLoop,
@@ -102,7 +103,10 @@ describe("runtime interaction targeting", () => {
const scene = createRuntimeSceneFixture({
npcs: [centerNpc],
interactables: [sideInteractable],
links: [createClickLink(centerNpc.entityId), createClickLink(sideInteractable.entityId)]
links: [
createClickLink(centerNpc.entityId),
createClickLink(sideInteractable.entityId)
]
});
const candidates = resolveRuntimeTargetCandidates({

View File

@@ -9,9 +9,7 @@ import {
createProjectAssetStorageKey,
type ModelAssetRecord
} from "../../src/assets/project-assets";
import type {
ActiveTransformSession
} from "../../src/core/transform-session";
import type { ActiveTransformSession } from "../../src/core/transform-session";
import { createBoxBrush } from "../../src/document/brushes";
import { createEmptySceneDocument } from "../../src/document/scene-document";
import { createPlayerStartEntity } from "../../src/entities/entity-instances";
@@ -275,7 +273,9 @@ async function renderMultiSelectionFixtureApp() {
await waitFor(() => {
expect(viewportHostInstances.length).toBeGreaterThan(0);
expect(getTopLeftViewportHost().setBrushSelectionChangeHandler).toHaveBeenCalled();
expect(
getTopLeftViewportHost().setBrushSelectionChangeHandler
).toHaveBeenCalled();
});
return {
@@ -611,9 +611,10 @@ describe("transform foundation integration", () => {
});
expect(store.getState().whiteboxSelectionMode).toBe("edge");
expect(
screen.getByTestId("whitebox-selection-mode-edge")
).toHaveAttribute("aria-pressed", "true");
expect(screen.getByTestId("whitebox-selection-mode-edge")).toHaveAttribute(
"aria-pressed",
"true"
);
fireEvent.keyDown(window, {
key: "3",
@@ -635,7 +636,9 @@ describe("transform foundation integration", () => {
expect(
screen.getByTestId("whitebox-selection-mode-object")
).toHaveAttribute("aria-pressed", "true");
expect(screen.getByText(/selection mode set to object/i)).toBeInTheDocument();
expect(
screen.getByText(/selection mode set to object/i)
).toBeInTheDocument();
});
it("keeps outliner and viewport selection state synchronized for same-kind multi-selection", async () => {
@@ -660,9 +663,10 @@ describe("transform foundation integration", () => {
expect(screen.getByText("2 selected")).toBeInTheDocument();
expect(screen.getByText("Brush Multi B")).toBeInTheDocument();
const selectionHandler = viewportHost.setBrushSelectionChangeHandler.mock.calls.at(
-1
)?.[0] as ((selection: { kind: "entities"; ids: string[] }) => void);
const selectionHandler =
viewportHost.setBrushSelectionChangeHandler.mock.calls.at(
-1
)?.[0] as (selection: { kind: "entities"; ids: string[] }) => void;
act(() => {
selectionHandler({