feat: dashcam photo mode with telemetry frame, lens drift and postcard capture

This commit is contained in:
2026-10-11 07:49:56 +03:00
parent d71b0ecfd4
commit 568b0802b4
29 changed files with 1472 additions and 7 deletions

View File

@@ -24,6 +24,7 @@ import { useMotionPreferences } from '@/composables/useMotionPreferences';
import { useRouteMemory } from '@/composables/useRouteMemory';
import { useRouteLog } from '@/composables/useRouteLog';
import { useBillboard } from '@/composables/useBillboard';
import { useDashcam } from '@/composables/useDashcam';
import { assetUrl } from '@/content/asset-url';
import { signRouteFor } from '@/journey/sign-routes';
import { END_OF_SHIFT_SUBLINE } from '@/journey/dawn';
@@ -160,6 +161,16 @@ const headlight = useHeadlightBeam({
quality: actualQuality,
activeSectionId: () => journey.value.activeSectionId,
});
/* DASHCAM: a full-screen photo mode over the live scene (lazy frame). */
const dashcam = useDashcam({
allowed: computed(() => controlsReady.value
&& motion.policy.value.reason === 'full'
&& motion.policy.value.allowSceneRequest
&& actualQuality.value !== 'static'
&& pageLifecycle.value === 'active'),
sceneRunning: computed(() => sceneState.value === 'running'),
drift: () => actualQuality.value !== 'low' && matchMedia('(pointer: fine)').matches,
});
const activeSectionLabel = computed(() => sectionLabel(journey.value.activeSectionId));
const serverDefaultPolicy: MotionPolicy = {
allowSceneRequest: false,
@@ -376,6 +387,7 @@ onUnmounted(() => removePageListeners());
:audio-state="audio.state.value"
:audio-muted="audio.muted.value"
:audio-volume="controlsReady ? motion.volume.value : 0.4"
:dashcam="dashcam.available.value"
@pause="pauseMotion"
@resume="resumeMotion"
@enable="enableMotion"
@@ -384,5 +396,17 @@ onUnmounted(() => removePageListeners());
@audio-resume="audio.resumeFromGesture"
@audio-mute-toggle="toggleAudioMuted"
@audio-volume-change="updateAudioVolume"
@dashcam="dashcam.show"
@dashcam-prefetch="dashcam.prefetch"
/>
<component
:is="dashcam.frame.value"
v-if="dashcam.open.value && dashcam.frame.value"
:journey="journey"
:section-label="activeSectionLabel"
:name="content.identity.name"
:city="content.identity.location.city"
:scene-ready="sceneState === 'running'"
@close="dashcam.close"
/>
</template>