diff --git a/src/App.vue b/src/App.vue index eeb7cd5..8914b64 100644 --- a/src/App.vue +++ b/src/App.vue @@ -10,7 +10,7 @@ import './styles/evolution.css'; import './styles/chromatic.css'; import './styles/refinements.css'; import './styles/title-navigation.css'; -import './styles/nightshift.css'; +import './styles/wayfinding.css'; import './styles/print.css'; defineProps<{ inputs: Readonly }>(); diff --git a/src/components/AppShell.vue b/src/components/AppShell.vue index 024f596..7496192 100644 --- a/src/components/AppShell.vue +++ b/src/components/AppShell.vue @@ -2,12 +2,10 @@ import { computed, onMounted, onUnmounted, shallowRef, watch } from 'vue'; import ContactDestination from './ContactDestination.vue'; import DriveControls from './DriveControls.vue'; -import BootSequence from './BootSequence.vue'; import ExperienceTimeline from './ExperienceTimeline.vue'; import HeroJourney from './HeroJourney.vue'; import InfrastructureDiagram from './InfrastructureDiagram.vue'; import JourneyHud from './JourneyHud.vue'; -import OperationsStrip from './OperationsStrip.vue'; import PortfolioSection from './PortfolioSection.vue'; import ProjectCard from './ProjectCard.vue'; import ProjectCaseStudy from './ProjectCaseStudy.vue'; @@ -18,10 +16,10 @@ import { useAdaptiveQuality } from '@/composables/useAdaptiveQuality'; import { useAudioEngine } from '@/composables/useAudioEngine'; import { useAudioIntent } from '@/composables/useAudioIntent'; import { useJourneySections } from '@/composables/useJourneySections'; -import { useHeadlight } from '@/composables/useHeadlight'; import { useKeyboardNavigation } from '@/composables/useKeyboardNavigation'; import { useMotionPreferences } from '@/composables/useMotionPreferences'; import { assetUrl } from '@/content/asset-url'; +import { signRouteFor } from '@/journey/sign-routes'; import type { PortfolioContent, PublicAssetManifest, SectionId, SectionLayout } from '@/content/types'; import type { SceneHostState } from '@/composables/useSceneController'; import type { MotionPolicy } from '@/journey/motion-policy'; @@ -60,9 +58,16 @@ const sectionLabel = (id: SectionId): string => { return item.label; }; +/** One wayfinding vocabulary: chapter plates reuse the roadside sign markers. */ +const exitFor = (id: SectionId): string => signRouteFor(id).marker; +const nextLabelFor = (id: SectionId): string | undefined => { + const index = canonicalSectionIds.indexOf(id); + const next = canonicalSectionIds[index + 1]; + return next === undefined ? undefined : sectionLabel(next); +}; + const canonicalNavigation = computed(() => canonicalSectionIds.map((id) => ({ id, label: sectionLabel(id) }))); const motion = useMotionPreferences(); -useHeadlight(computed(() => motion.policy.value.allowSceneRequest)); const navigation = useKeyboardNavigation(canonicalSectionIds); const journeyBinding = useJourneySections( canonicalSectionIds, @@ -139,6 +144,18 @@ watch( (id) => navigation.notePassiveSection(id), ); +// Light the current chapter's plate once per arrival (attribute only, no per-frame work). +watch( + () => [journey.value.activeSectionId, controlsReady.value] as const, + ([id, ready]) => { + if (!ready) return; + for (const section of document.querySelectorAll('#portfolio-content > section[id]')) { + section.toggleAttribute('data-current', section.id === id); + } + }, + { flush: 'post' }, +); + watch( () => motion.policy.value.maximumTier, (tier, previous) => { @@ -215,11 +232,10 @@ onUnmounted(() => removePageListeners()); :sample-frame="sampleSceneFrame" @state-change="updateSceneState" /> - -