fix: close phase 2 journey blockers

This commit is contained in:
2026-09-02 06:04:20 +03:00
parent a86767cdc6
commit 77895c01ff
19 changed files with 378 additions and 26 deletions

View File

@@ -13,6 +13,7 @@ import {
type QualityDecision,
} from '@/journey/adaptive-quality';
import type { QualityTier } from '@/journey/motion-policy';
import { lowerTier } from '@/journey/motion-policy';
const PASSIVE_LISTENER: AddEventListenerOptions = { passive: true };
@@ -70,7 +71,7 @@ export function useAdaptiveQuality(sources: AdaptiveQualitySources): AdaptiveQua
tier: QualityTier,
reason: 'resize' | 'manual',
): QualityDecision | null => {
const decision = controller.setMaximum(tier, reason);
const decision = controller.setMaximum(lowerTier(tier, sources.maximum.value), reason);
reconcileEpoch();
return decision;
};

View File

@@ -1,4 +1,5 @@
import {
computed,
onMounted,
onUnmounted,
readonly,
@@ -41,7 +42,12 @@ export function useJourneySections(
throw new Error("At least one canonical journey section is required.");
}
const drive = useScrollDrive();
const snapshot = shallowRef<JourneySnapshot>(initialJourney(firstId));
const sectionSnapshot = shallowRef<JourneySnapshot>(initialJourney(firstId));
const snapshot = computed<JourneySnapshot>(() => ({
...sectionSnapshot.value,
...drive.value,
routeProgress: sectionSnapshot.value.arrived ? 1 : drive.value.routeProgress,
}));
let scheduleMeasurement = (): void => {};
let teardown = (): void => {};
@@ -100,7 +106,7 @@ export function useJourneySections(
const activeIndex = canonicalIds.indexOf(activeSectionId);
const crossedBoundaries = Math.abs(activeIndex - previousActiveIndex);
const deltaY = scrollY - previousScrollY;
const currentSign = snapshot.value.sign;
const currentSign = sectionSnapshot.value.sign;
const signTargetId =
currentSign?.targetId ?? canonicalIds[activeIndex + 1] ?? null;
const signTarget = headings.find(
@@ -119,7 +125,7 @@ export function useJourneySections(
motionAllowed: motionAllowed?.value ?? true,
});
const sectionState = deriveSectionState(activeSectionId);
snapshot.value = {
sectionSnapshot.value = {
...drive.value,
routeProgress: atDocumentEnd ? 1 : drive.value.routeProgress,
...sectionState,

View File

@@ -25,6 +25,7 @@ export interface SceneControllerSources {
journey: Readonly<Ref<JourneySnapshot>>;
policy: Readonly<Ref<MotionPolicy>>;
quality: Readonly<Ref<QualityTier>>;
sampleFrame?: ((start: number, end: number) => unknown) | undefined;
}
export function useSceneController(sources: SceneControllerSources): SceneControllerBinding {
@@ -61,14 +62,26 @@ export function useSceneController(sources: SceneControllerSources): SceneContro
if (!mounted) return;
const allowed = sources.policy.value.allowSceneRequest && sources.quality.value !== 'static';
const canvas = sources.canvas.value;
if (!allowed || canvas === null) {
disposeActive(allowed ? (error.value ? 'failed' : 'idle') : 'static');
if (!allowed) {
if (sources.policy.value.reason === 'visitor-pause' && controller !== null) {
controller.pause();
publish();
} else {
disposeActive('static');
}
return;
}
if (canvas === null) {
disposeActive(error.value ? 'failed' : 'idle');
return;
}
if (controller !== null) {
controller.update(sources.journey.value);
await controller.setQuality(sources.quality.value);
if (controller.snapshot().state.kind === 'paused') {
await controller.resume();
}
publish();
return;
}
@@ -94,6 +107,7 @@ export function useSceneController(sources: SceneControllerSources): SceneContro
quality: sources.quality.value,
build: createProceduralSceneGeneration,
motionAllowed: () => sources.policy.value.allowSceneRequest,
onFrameRendered: sources.sampleFrame,
signal: abort.signal,
});
controller = next;

View File

@@ -39,6 +39,7 @@ export function useScrollDrive(): Readonly<Ref<ScrollDriveSnapshot>> {
? controller.reset(input)
: controller.sample(input);
resetOnNextFrame = false;
if (snapshot.value.acceleration > 0) scheduleFrame();
};
const scheduleFrame = (): void => {