auto-git:
[change] src/app/App.tsx [change] src/document/migrate-scene-document.ts [change] src/document/scene-document-validation.ts [change] src/rendering/world-background-renderer.ts [change] src/rendering/world-shader-sky.ts [change] tests/domain/scene-document-validation.test.ts
This commit is contained in:
303
src/app/App.tsx
303
src/app/App.tsx
@@ -2539,9 +2539,7 @@ export function App({ store, initialStatusMessage }: AppProps) {
|
||||
label: getScenePathLabel(path, index)
|
||||
}));
|
||||
const getCameraRigPathById = (pathId: string) =>
|
||||
editorState.document.paths[pathId] ??
|
||||
cameraRigPathOptions[0]?.path ??
|
||||
null;
|
||||
editorState.document.paths[pathId] ?? cameraRigPathOptions[0]?.path ?? null;
|
||||
const getDefaultCameraRigRailMappingDraft = (pathId: string) => {
|
||||
const authoredPath = getCameraRigPathById(pathId);
|
||||
const startPoint =
|
||||
@@ -2657,12 +2655,10 @@ export function App({ store, initialStatusMessage }: AppProps) {
|
||||
const [cameraRigRigTypeDraft, setCameraRigRigTypeDraft] =
|
||||
useState<CameraRigType>("fixed");
|
||||
const [cameraRigPathIdDraft, setCameraRigPathIdDraft] = useState("");
|
||||
const [
|
||||
cameraRigRailPlacementModeDraft,
|
||||
setCameraRigRailPlacementModeDraft
|
||||
] = useState<CameraRigRailPlacementMode>(
|
||||
DEFAULT_CAMERA_RIG_RAIL_PLACEMENT_MODE
|
||||
);
|
||||
const [cameraRigRailPlacementModeDraft, setCameraRigRailPlacementModeDraft] =
|
||||
useState<CameraRigRailPlacementMode>(
|
||||
DEFAULT_CAMERA_RIG_RAIL_PLACEMENT_MODE
|
||||
);
|
||||
const [cameraRigTrackStartPointDraft, setCameraRigTrackStartPointDraft] =
|
||||
useState(createVec3Draft(DEFAULT_CAMERA_RIG_TRACK_START_POINT));
|
||||
const [cameraRigTrackEndPointDraft, setCameraRigTrackEndPointDraft] =
|
||||
@@ -3682,14 +3678,14 @@ export function App({ store, initialStatusMessage }: AppProps) {
|
||||
|
||||
const selectedEntityPosition =
|
||||
selectedEntity.kind === "cameraRig"
|
||||
? resolveCameraRigDocumentPosition(
|
||||
? (resolveCameraRigDocumentPosition(
|
||||
selectedEntity,
|
||||
editorState.document.entities,
|
||||
editorState.document.paths,
|
||||
{
|
||||
fallbackToPathStart: true
|
||||
}
|
||||
) ?? DEFAULT_ENTITY_POSITION
|
||||
) ?? DEFAULT_ENTITY_POSITION)
|
||||
: selectedEntity.position;
|
||||
|
||||
setEntityPositionDraft(createVec3Draft(selectedEntityPosition));
|
||||
@@ -9443,7 +9439,10 @@ export function App({ store, initialStatusMessage }: AppProps) {
|
||||
const effectOptionId =
|
||||
options.effectOptionId ??
|
||||
effectOptions.find((effectOption) => {
|
||||
if (options.previousEffect === undefined || options.previousEffect === null) {
|
||||
if (
|
||||
options.previousEffect === undefined ||
|
||||
options.previousEffect === null
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -9563,7 +9562,9 @@ export function App({ store, initialStatusMessage }: AppProps) {
|
||||
createUpsertInteractionLinkCommand({
|
||||
link: createInteractionControlLinkFromTargetOption({
|
||||
sourceEntity: selectedInteractionSource,
|
||||
trigger: getDefaultInteractionLinkTrigger(selectedInteractionSource),
|
||||
trigger: getDefaultInteractionLinkTrigger(
|
||||
selectedInteractionSource
|
||||
),
|
||||
targetOption
|
||||
}),
|
||||
label: "Add control interaction link"
|
||||
@@ -10413,9 +10414,12 @@ export function App({ store, initialStatusMessage }: AppProps) {
|
||||
return;
|
||||
}
|
||||
|
||||
const effectOptions = listProjectInteractionControlEffectOptions(targetOption);
|
||||
const effectOptions =
|
||||
listProjectInteractionControlEffectOptions(targetOption);
|
||||
|
||||
if (!effectOptions.some((effectOption) => effectOption.id === effectOptionId)) {
|
||||
if (
|
||||
!effectOptions.some((effectOption) => effectOption.id === effectOptionId)
|
||||
) {
|
||||
setStatusMessage(
|
||||
"Selected control effect is not available for the current target."
|
||||
);
|
||||
@@ -11086,7 +11090,9 @@ export function App({ store, initialStatusMessage }: AppProps) {
|
||||
const effectOptions =
|
||||
targetOption === null
|
||||
? []
|
||||
: listProjectInteractionControlEffectOptions(targetOption);
|
||||
: listProjectInteractionControlEffectOptions(
|
||||
targetOption
|
||||
);
|
||||
const effectOptionId =
|
||||
targetOption === null
|
||||
? null
|
||||
@@ -11137,7 +11143,9 @@ export function App({ store, initialStatusMessage }: AppProps) {
|
||||
<input
|
||||
className="text-input"
|
||||
type="text"
|
||||
value={formatControlEffectValue(link.action.effect)}
|
||||
value={formatControlEffectValue(
|
||||
link.action.effect
|
||||
)}
|
||||
readOnly
|
||||
/>
|
||||
</label>
|
||||
@@ -11205,7 +11213,9 @@ export function App({ store, initialStatusMessage }: AppProps) {
|
||||
min={selectedEffectOption.min ?? 0}
|
||||
step={selectedEffectOption.step ?? 0.1}
|
||||
defaultValue={
|
||||
getControlEffectNumericValue(link.action.effect) ?? 0
|
||||
getControlEffectNumericValue(
|
||||
link.action.effect
|
||||
) ?? 0
|
||||
}
|
||||
onBlur={(event) =>
|
||||
updateControlInteractionLinkNumericValue(
|
||||
@@ -11264,10 +11274,9 @@ export function App({ store, initialStatusMessage }: AppProps) {
|
||||
)
|
||||
}
|
||||
>
|
||||
{(
|
||||
link.action.effect.type === "playActorAnimation"
|
||||
? targetOption.defaults.actorAnimationClipNames
|
||||
: targetOption.defaults.animationClipNames
|
||||
{(link.action.effect.type === "playActorAnimation"
|
||||
? targetOption.defaults.actorAnimationClipNames
|
||||
: targetOption.defaults.animationClipNames
|
||||
)?.map((clipName) => (
|
||||
<option key={clipName} value={clipName}>
|
||||
{clipName}
|
||||
@@ -19028,138 +19037,138 @@ export function App({ store, initialStatusMessage }: AppProps) {
|
||||
}
|
||||
/>
|
||||
</label>
|
||||
<div className="material-summary">
|
||||
Hidden entities stay active for authored runtime behavior.
|
||||
Disable them to remove them from the editor viewport,
|
||||
picking, and runtime build.
|
||||
<div className="material-summary">
|
||||
Hidden entities stay active for authored runtime behavior.
|
||||
Disable them to remove them from the editor viewport,
|
||||
picking, and runtime build.
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{selectedEntity.kind !== "cameraRig" ||
|
||||
selectedEntity.rigType === "fixed" ? (
|
||||
<div className="form-section">
|
||||
<div className="label">Position</div>
|
||||
<div className="vector-inputs">
|
||||
<label className="form-field">
|
||||
<span className="label">X</span>
|
||||
<input
|
||||
data-testid={
|
||||
selectedEntity.kind === "playerStart"
|
||||
? "player-start-position-x"
|
||||
: `${selectedEntity.kind}-position-x`
|
||||
}
|
||||
className="text-input"
|
||||
type="number"
|
||||
step={DEFAULT_GRID_SIZE}
|
||||
value={entityPositionDraft.x}
|
||||
onChange={(event) => {
|
||||
const nextValue = event.currentTarget.value;
|
||||
setEntityPositionDraft((draft) => ({
|
||||
...draft,
|
||||
x: nextValue
|
||||
}));
|
||||
}}
|
||||
onBlur={applySelectedEntityDraftChange}
|
||||
onKeyDown={(event) =>
|
||||
handleDraftVectorKeyDown(
|
||||
event,
|
||||
applySelectedEntityDraftChange
|
||||
)
|
||||
}
|
||||
onKeyUp={(event) =>
|
||||
handleNumberInputKeyUp(
|
||||
event,
|
||||
applySelectedEntityDraftChange
|
||||
)
|
||||
}
|
||||
onPointerUp={(event) =>
|
||||
handleNumberInputPointerUp(
|
||||
event,
|
||||
applySelectedEntityDraftChange
|
||||
)
|
||||
}
|
||||
/>
|
||||
</label>
|
||||
<label className="form-field">
|
||||
<span className="label">Y</span>
|
||||
<input
|
||||
data-testid={
|
||||
selectedEntity.kind === "playerStart"
|
||||
? "player-start-position-y"
|
||||
: `${selectedEntity.kind}-position-y`
|
||||
}
|
||||
className="text-input"
|
||||
type="number"
|
||||
step={DEFAULT_GRID_SIZE}
|
||||
value={entityPositionDraft.y}
|
||||
onChange={(event) => {
|
||||
const nextValue = event.currentTarget.value;
|
||||
setEntityPositionDraft((draft) => ({
|
||||
...draft,
|
||||
y: nextValue
|
||||
}));
|
||||
}}
|
||||
onBlur={applySelectedEntityDraftChange}
|
||||
onKeyDown={(event) =>
|
||||
handleDraftVectorKeyDown(
|
||||
event,
|
||||
applySelectedEntityDraftChange
|
||||
)
|
||||
}
|
||||
onKeyUp={(event) =>
|
||||
handleNumberInputKeyUp(
|
||||
event,
|
||||
applySelectedEntityDraftChange
|
||||
)
|
||||
}
|
||||
onPointerUp={(event) =>
|
||||
handleNumberInputPointerUp(
|
||||
event,
|
||||
applySelectedEntityDraftChange
|
||||
)
|
||||
}
|
||||
/>
|
||||
</label>
|
||||
<label className="form-field">
|
||||
<span className="label">Z</span>
|
||||
<input
|
||||
data-testid={
|
||||
selectedEntity.kind === "playerStart"
|
||||
? "player-start-position-z"
|
||||
: `${selectedEntity.kind}-position-z`
|
||||
}
|
||||
className="text-input"
|
||||
type="number"
|
||||
step={DEFAULT_GRID_SIZE}
|
||||
value={entityPositionDraft.z}
|
||||
onChange={(event) => {
|
||||
const nextValue = event.currentTarget.value;
|
||||
setEntityPositionDraft((draft) => ({
|
||||
...draft,
|
||||
z: nextValue
|
||||
}));
|
||||
}}
|
||||
onBlur={applySelectedEntityDraftChange}
|
||||
onKeyDown={(event) =>
|
||||
handleDraftVectorKeyDown(
|
||||
event,
|
||||
applySelectedEntityDraftChange
|
||||
)
|
||||
}
|
||||
onKeyUp={(event) =>
|
||||
handleNumberInputKeyUp(
|
||||
event,
|
||||
applySelectedEntityDraftChange
|
||||
)
|
||||
}
|
||||
onPointerUp={(event) =>
|
||||
handleNumberInputPointerUp(
|
||||
event,
|
||||
applySelectedEntityDraftChange
|
||||
)
|
||||
}
|
||||
/>
|
||||
</label>
|
||||
<label className="form-field">
|
||||
<span className="label">X</span>
|
||||
<input
|
||||
data-testid={
|
||||
selectedEntity.kind === "playerStart"
|
||||
? "player-start-position-x"
|
||||
: `${selectedEntity.kind}-position-x`
|
||||
}
|
||||
className="text-input"
|
||||
type="number"
|
||||
step={DEFAULT_GRID_SIZE}
|
||||
value={entityPositionDraft.x}
|
||||
onChange={(event) => {
|
||||
const nextValue = event.currentTarget.value;
|
||||
setEntityPositionDraft((draft) => ({
|
||||
...draft,
|
||||
x: nextValue
|
||||
}));
|
||||
}}
|
||||
onBlur={applySelectedEntityDraftChange}
|
||||
onKeyDown={(event) =>
|
||||
handleDraftVectorKeyDown(
|
||||
event,
|
||||
applySelectedEntityDraftChange
|
||||
)
|
||||
}
|
||||
onKeyUp={(event) =>
|
||||
handleNumberInputKeyUp(
|
||||
event,
|
||||
applySelectedEntityDraftChange
|
||||
)
|
||||
}
|
||||
onPointerUp={(event) =>
|
||||
handleNumberInputPointerUp(
|
||||
event,
|
||||
applySelectedEntityDraftChange
|
||||
)
|
||||
}
|
||||
/>
|
||||
</label>
|
||||
<label className="form-field">
|
||||
<span className="label">Y</span>
|
||||
<input
|
||||
data-testid={
|
||||
selectedEntity.kind === "playerStart"
|
||||
? "player-start-position-y"
|
||||
: `${selectedEntity.kind}-position-y`
|
||||
}
|
||||
className="text-input"
|
||||
type="number"
|
||||
step={DEFAULT_GRID_SIZE}
|
||||
value={entityPositionDraft.y}
|
||||
onChange={(event) => {
|
||||
const nextValue = event.currentTarget.value;
|
||||
setEntityPositionDraft((draft) => ({
|
||||
...draft,
|
||||
y: nextValue
|
||||
}));
|
||||
}}
|
||||
onBlur={applySelectedEntityDraftChange}
|
||||
onKeyDown={(event) =>
|
||||
handleDraftVectorKeyDown(
|
||||
event,
|
||||
applySelectedEntityDraftChange
|
||||
)
|
||||
}
|
||||
onKeyUp={(event) =>
|
||||
handleNumberInputKeyUp(
|
||||
event,
|
||||
applySelectedEntityDraftChange
|
||||
)
|
||||
}
|
||||
onPointerUp={(event) =>
|
||||
handleNumberInputPointerUp(
|
||||
event,
|
||||
applySelectedEntityDraftChange
|
||||
)
|
||||
}
|
||||
/>
|
||||
</label>
|
||||
<label className="form-field">
|
||||
<span className="label">Z</span>
|
||||
<input
|
||||
data-testid={
|
||||
selectedEntity.kind === "playerStart"
|
||||
? "player-start-position-z"
|
||||
: `${selectedEntity.kind}-position-z`
|
||||
}
|
||||
className="text-input"
|
||||
type="number"
|
||||
step={DEFAULT_GRID_SIZE}
|
||||
value={entityPositionDraft.z}
|
||||
onChange={(event) => {
|
||||
const nextValue = event.currentTarget.value;
|
||||
setEntityPositionDraft((draft) => ({
|
||||
...draft,
|
||||
z: nextValue
|
||||
}));
|
||||
}}
|
||||
onBlur={applySelectedEntityDraftChange}
|
||||
onKeyDown={(event) =>
|
||||
handleDraftVectorKeyDown(
|
||||
event,
|
||||
applySelectedEntityDraftChange
|
||||
)
|
||||
}
|
||||
onKeyUp={(event) =>
|
||||
handleNumberInputKeyUp(
|
||||
event,
|
||||
applySelectedEntityDraftChange
|
||||
)
|
||||
}
|
||||
onPointerUp={(event) =>
|
||||
handleNumberInputPointerUp(
|
||||
event,
|
||||
applySelectedEntityDraftChange
|
||||
)
|
||||
}
|
||||
/>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
) : null}
|
||||
|
||||
@@ -3374,7 +3374,10 @@ function readCameraRigEntity(value: unknown, label: string): EntityInstance {
|
||||
trackStartPoint:
|
||||
value.trackStartPoint === undefined
|
||||
? undefined
|
||||
: readVec3(value.trackStartPoint, `${label}.trackStartPoint`),
|
||||
: readVec3(
|
||||
value.trackStartPoint,
|
||||
`${label}.trackStartPoint`
|
||||
),
|
||||
trackEndPoint:
|
||||
value.trackEndPoint === undefined
|
||||
? undefined
|
||||
|
||||
@@ -3878,7 +3878,10 @@ function validateCameraRigControlTarget(
|
||||
return;
|
||||
}
|
||||
|
||||
if (targetEntity.kind !== target.entityKind || targetEntity.kind !== "cameraRig") {
|
||||
if (
|
||||
targetEntity.kind !== target.entityKind ||
|
||||
targetEntity.kind !== "cameraRig"
|
||||
) {
|
||||
diagnostics.push(
|
||||
createDiagnostic(
|
||||
"error",
|
||||
|
||||
@@ -904,14 +904,11 @@ function applyShaderSkyStateToMaterial(
|
||||
material.uniforms.uAuroraHeight.value = state.aurora.height;
|
||||
material.uniforms.uAuroraThickness.value = state.aurora.thickness;
|
||||
material.uniforms.uAuroraSpeed.value = state.aurora.speed;
|
||||
material.uniforms.uAuroraPrimaryColor.value.set(
|
||||
state.aurora.primaryColorHex
|
||||
);
|
||||
material.uniforms.uAuroraPrimaryColor.value.set(state.aurora.primaryColorHex);
|
||||
material.uniforms.uAuroraSecondaryColor.value.set(
|
||||
state.aurora.secondaryColorHex
|
||||
);
|
||||
material.uniforms.uAuroraRotationRadians.value =
|
||||
state.aurora.rotationRadians;
|
||||
material.uniforms.uAuroraRotationRadians.value = state.aurora.rotationRadians;
|
||||
material.uniforms.uAuroraTimeHours.value = state.aurora.timeHours;
|
||||
}
|
||||
|
||||
|
||||
@@ -315,11 +315,10 @@ export function resolveWorldShaderSkyRenderState(
|
||||
const starVisibility =
|
||||
clamp(phaseWeights.night + twilightFactor * 0.45, 0, 1) *
|
||||
clamp(1 - resolvedWorld.daylightFactor * 0.85, 0, 1);
|
||||
const auroraVisibility =
|
||||
world.shaderSky.aurora.enabled
|
||||
? clamp(phaseWeights.night + twilightFactor * 0.32, 0, 1) *
|
||||
clamp(1 - resolvedWorld.daylightFactor * 1.15, 0, 1)
|
||||
: 0;
|
||||
const auroraVisibility = world.shaderSky.aurora.enabled
|
||||
? clamp(phaseWeights.night + twilightFactor * 0.32, 0, 1) *
|
||||
clamp(1 - resolvedWorld.daylightFactor * 1.15, 0, 1)
|
||||
: 0;
|
||||
const cloudDriftDirectionRadians =
|
||||
(world.shaderSky.clouds.driftDirectionDegrees * Math.PI) / 180;
|
||||
const cloudDriftDistance =
|
||||
|
||||
@@ -445,15 +445,14 @@ describe("validateSceneDocument", () => {
|
||||
target: createCameraRigControlTargetRef(cameraRig.id)
|
||||
})
|
||||
});
|
||||
document.interactionLinks["link-camera-override"] = createControlInteractionLink(
|
||||
{
|
||||
document.interactionLinks["link-camera-override"] =
|
||||
createControlInteractionLink({
|
||||
id: "link-camera-override",
|
||||
sourceEntityId: triggerVolume.id,
|
||||
effect: createActivateCameraRigOverrideControlEffect({
|
||||
target: createCameraRigControlTargetRef(cameraRig.id)
|
||||
})
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
const validation = validateSceneDocument(document);
|
||||
|
||||
@@ -1421,7 +1420,8 @@ describe("validateSceneDocument", () => {
|
||||
document.world.shaderSky.celestial.sunDiscSizeDegrees = 0;
|
||||
document.world.shaderSky.clouds.coverage = 2;
|
||||
document.world.shaderSky.aurora.intensity = -1;
|
||||
document.world.shaderSky.aurora.primaryColorHex = "bad-color" as `#${string}`;
|
||||
document.world.shaderSky.aurora.primaryColorHex =
|
||||
"bad-color" as `#${string}`;
|
||||
document.world.timeOfDay.dawn.background = {
|
||||
mode: "shader"
|
||||
} as typeof document.world.timeOfDay.dawn.background;
|
||||
|
||||
@@ -17,12 +17,12 @@ import { createScenePath } from "../../src/document/paths";
|
||||
import { createDefaultProjectTimeSettings } from "../../src/document/project-time-settings";
|
||||
import { createTerrain } from "../../src/document/terrains";
|
||||
import {
|
||||
AUTHORED_TERRAIN_PAINT_SCENE_DOCUMENT_VERSION,
|
||||
AUTHORED_TERRAIN_FOUNDATION_SCENE_DOCUMENT_VERSION,
|
||||
CAMERA_RIG_MAPPED_RAIL_SCENE_DOCUMENT_VERSION,
|
||||
CAMERA_RIG_CONTROL_SURFACE_SCENE_DOCUMENT_VERSION,
|
||||
CAMERA_RIG_ENTITY_SCENE_DOCUMENT_VERSION,
|
||||
CELESTIAL_BODY_OVERLAY_SCENE_DOCUMENT_VERSION,
|
||||
AUTHORED_TERRAIN_PAINT_SCENE_DOCUMENT_VERSION,
|
||||
AUTHORED_TERRAIN_FOUNDATION_SCENE_DOCUMENT_VERSION,
|
||||
CAMERA_RIG_MAPPED_RAIL_SCENE_DOCUMENT_VERSION,
|
||||
CAMERA_RIG_CONTROL_SURFACE_SCENE_DOCUMENT_VERSION,
|
||||
CAMERA_RIG_ENTITY_SCENE_DOCUMENT_VERSION,
|
||||
CELESTIAL_BODY_OVERLAY_SCENE_DOCUMENT_VERSION,
|
||||
DAWN_DUSK_BACKGROUND_IMAGE_SCENE_DOCUMENT_VERSION,
|
||||
FOLLOW_ACTOR_PATH_SMOOTH_SCENE_DOCUMENT_VERSION,
|
||||
ANIMATION_PLAYBACK_SCENE_DOCUMENT_VERSION,
|
||||
@@ -141,28 +141,28 @@ describe("scene document JSON", () => {
|
||||
const document = createEmptySceneDocument({ name: "Camera Control Scene" });
|
||||
document.entities[cameraRig.id] = cameraRig;
|
||||
document.entities[triggerVolume.id] = triggerVolume;
|
||||
document.interactionLinks["link-camera-activate"] = createControlInteractionLink(
|
||||
{
|
||||
document.interactionLinks["link-camera-activate"] =
|
||||
createControlInteractionLink({
|
||||
id: "link-camera-activate",
|
||||
sourceEntityId: triggerVolume.id,
|
||||
effect: createActivateCameraRigOverrideControlEffect({
|
||||
target: createCameraRigControlTargetRef(cameraRig.id)
|
||||
})
|
||||
}
|
||||
);
|
||||
document.sequences.sequences["sequence-camera-clear"] = createProjectSequence({
|
||||
id: "sequence-camera-clear",
|
||||
title: "Camera Clear",
|
||||
steps: [
|
||||
{
|
||||
stepClass: "held",
|
||||
type: "controlEffect",
|
||||
effect: createClearCameraRigOverrideControlEffect({
|
||||
target: createCameraRigControlTargetRef(cameraRig.id)
|
||||
})
|
||||
}
|
||||
]
|
||||
});
|
||||
});
|
||||
document.sequences.sequences["sequence-camera-clear"] =
|
||||
createProjectSequence({
|
||||
id: "sequence-camera-clear",
|
||||
title: "Camera Clear",
|
||||
steps: [
|
||||
{
|
||||
stepClass: "held",
|
||||
type: "controlEffect",
|
||||
effect: createClearCameraRigOverrideControlEffect({
|
||||
target: createCameraRigControlTargetRef(cameraRig.id)
|
||||
})
|
||||
}
|
||||
]
|
||||
});
|
||||
document.scheduler.routines["routine-camera-activate"] =
|
||||
createProjectScheduleRoutine({
|
||||
id: "routine-camera-activate",
|
||||
|
||||
Reference in New Issue
Block a user