/* eslint-disable */ // Section 07 — Project Lifecycle. Dark. 6-column timeline. // Scroll-tied domino flip: section is a 200vh scroll track; the content // sticks for one viewport while progress runs 0→1, then releases. Each card // owns a 1/6 slice of that progress and flips on its left edge in sequence. // Hovering a card zooms the photo in. const STAGES = [ { n: '01', title: 'Project planning', tone: 'detail', src: 'assets/uc-plans-bw.jpeg', items: [ 'Project briefing & scope review', 'Procurement scheduling', 'Project timeline scheduling', 'Approval of materials & finishes', ], }, { n: '02', title: 'Engineering & production', tone: 'workshop', src: 'assets/uc-planer.jpeg', items: [ 'Detailed shop drawings & material optimisation', 'Job orders & cutting lists issued', 'Mock-ups & prototype approvals prior to production', ], }, { n: '03', title: 'QA / QC', tone: 'grain', src: 'assets/uc-finishing-grain.jpeg', items: [ 'In-process inspections during fabrication', 'Quality checks on dimensions, joinery, finish', 'Assembly & high-precision finishing in controlled environment', 'Corrective actions & stage approvals', 'Final inspection before packaging', ], }, { n: '04', title: 'Packaging & logistics', tone: 'ash', src: 'assets/uc-sanding-round.jpeg', items: [ 'Custom crating & protective wrapping for all units', 'Labelling by zone & project reference', 'Coordination of transport, delivery schedules, storage', ], }, { n: '05', title: 'Installation', tone: 'raking', src: 'assets/uc-heritage-table.jpeg', items: [ 'Site delivery & unloading supervision', 'Installation by certified carpentry team', 'Alignment, fixing, finishing on site', 'Inspection with consultant & client representatives', ], }, { n: '06', title: 'Handover', tone: 'detail', src: 'assets/uc-interior-armchair.jpeg', items: [ 'Final snagging & rectifications', 'As-built drawings & maintenance manual', 'Warranty issuance & project close-out documentation', ], }, ]; // eased clamp helper const clamp01 = (v) => Math.max(0, Math.min(1, v)); const easeOutCubic = (t) => 1 - Math.pow(1 - t, 3); const Lifecycle = () => { const sectionRef = React.useRef(null); const [progress, setProgress] = React.useState(0); React.useEffect(() => { const el = sectionRef.current; if (!el) return; let raf = 0; const update = () => { raf = 0; const rect = el.getBoundingClientRect(); const vh = window.innerHeight; // total scrollable range inside this section while it is pinned const range = rect.height - vh; if (range <= 0) { setProgress(1); return; } // -rect.top is how far the section's top has scrolled past the viewport top const p = clamp01(-rect.top / range); setProgress(p); }; const onScroll = () => { if (raf) return; raf = requestAnimationFrame(update); }; update(); window.addEventListener('scroll', onScroll, { passive: true }); window.addEventListener('resize', onScroll); return () => { window.removeEventListener('scroll', onScroll); window.removeEventListener('resize', onScroll); if (raf) cancelAnimationFrame(raf); }; }, []); // Each card owns a slot in the [0,1] progress. We give each slot some // overlap with the next so the domino keeps cascading without dead air. const N = STAGES.length; const slot = 1 / (N + 1); // each card gets ~14% of the track const overlap = slot * 0.45; // the next card starts a bit early return (
How the work is made
06 stages

The Unicraft project life cycle.

{STAGES.map((s, i) => { // local progress for this card within its slot const start = i * slot; const end = start + slot + overlap; const local = clamp01((progress - start) / (end - start)); const eased = easeOutCubic(local); // domino: from edge-on (folded back-left, invisible) to flat const angle = -95 * (1 - eased); const opacity = 0.05 + 0.95 * eased; return (
{/* connector line + node */}
{s.n}

{s.title}

    {s.items.map((it) => (
  • {it}
  • ))}
); })}
); }; Object.assign(window, { Lifecycle });