From 8fc4cadd196a95acabcc40e23bc32ff1791a1d19 Mon Sep 17 00:00:00 2001 From: Marc Mintel Date: Mon, 11 May 2026 10:49:56 +0200 Subject: [PATCH] feat: replace technical drawings with premium animated design elements (DrillOrbit + StratumLines) Former-commit-id: f56a9d40b6b4068691b1d8851da455da6514fa3c --- components/blocks/CompetenceBentoGrid.tsx | 4 + components/blocks/HeroSection.tsx | 3 + components/blocks/ReferencesSlider.tsx | 3 + components/blocks/SubCompanyTiles.tsx | 5 +- components/layout/Footer.tsx | 3 + .../providers/PageTransitionShutter.tsx | 32 +++++ components/ui/decorations/DrillOrbit.tsx | 131 ++++++++++++++++++ components/ui/decorations/StratumLines.tsx | 130 +++++++++++++++++ 8 files changed, 310 insertions(+), 1 deletion(-) create mode 100644 components/ui/decorations/DrillOrbit.tsx create mode 100644 components/ui/decorations/StratumLines.tsx diff --git a/components/blocks/CompetenceBentoGrid.tsx b/components/blocks/CompetenceBentoGrid.tsx index c1c41718c..a8aae7282 100644 --- a/components/blocks/CompetenceBentoGrid.tsx +++ b/components/blocks/CompetenceBentoGrid.tsx @@ -6,6 +6,7 @@ import { motion } from 'framer-motion'; import { useState, useEffect } from 'react'; import { Button } from '@/components/ui/Button'; import { HoverShineOverlay } from '@/components/ui/HoverShineOverlay'; +import { StratumLines } from '@/components/ui/decorations/StratumLines'; interface CompetenceBentoGridProps { badge?: string; @@ -167,6 +168,9 @@ export function CompetenceBentoGrid(props: CompetenceBentoGridProps) { })} + {/* Decorative: abstract earth strata / excavation layers */} + + ); } diff --git a/components/blocks/HeroSection.tsx b/components/blocks/HeroSection.tsx index 1fa034444..445d202a3 100644 --- a/components/blocks/HeroSection.tsx +++ b/components/blocks/HeroSection.tsx @@ -3,6 +3,7 @@ import Image from 'next/image'; import Reveal from '@/components/Reveal'; import { Badge, Container, Heading } from '@/components/ui'; import { Button } from '@/components/ui/Button'; +import { DrillOrbit } from '@/components/ui/decorations/DrillOrbit'; export interface HeroSectionProps { title: string; @@ -70,6 +71,8 @@ export const HeroSection: React.FC = (props) => { )} + {/* Decorative: abstract HDD bore trajectory */} + ); diff --git a/components/blocks/ReferencesSlider.tsx b/components/blocks/ReferencesSlider.tsx index 3f95e0dad..93aca8cef 100644 --- a/components/blocks/ReferencesSlider.tsx +++ b/components/blocks/ReferencesSlider.tsx @@ -5,6 +5,7 @@ import { motion } from 'framer-motion'; import Link from 'next/link'; import Image from 'next/image'; import { HoverShineOverlay } from '@/components/ui/HoverShineOverlay'; +import { DrillOrbit } from '@/components/ui/decorations/DrillOrbit'; export interface Reference { id: string; @@ -151,6 +152,8 @@ export function ReferencesSlider(props: ReferencesSliderProps) { + {/* Decorative: abstract HDD bore trajectory */} + ); } diff --git a/components/blocks/SubCompanyTiles.tsx b/components/blocks/SubCompanyTiles.tsx index ea79ba7bd..416086502 100644 --- a/components/blocks/SubCompanyTiles.tsx +++ b/components/blocks/SubCompanyTiles.tsx @@ -4,6 +4,7 @@ import * as React from 'react'; import { motion, Variants } from 'framer-motion'; import Image from 'next/image'; import { HoverShineOverlay } from '@/components/ui/HoverShineOverlay'; +import { DrillOrbit } from '@/components/ui/decorations/DrillOrbit'; interface SubCompanyTilesProps { badge?: string; @@ -65,7 +66,7 @@ export function SubCompanyTiles(props: SubCompanyTilesProps) { })) || defaultCompanies; return ( -
+
{(badge || title) && ( @@ -197,6 +198,8 @@ export function SubCompanyTiles(props: SubCompanyTilesProps) { })}
+ {/* Decorative: abstract HDD bore trajectory */} +
); } diff --git a/components/layout/Footer.tsx b/components/layout/Footer.tsx index f776e373a..8a722ad5d 100644 --- a/components/layout/Footer.tsx +++ b/components/layout/Footer.tsx @@ -3,6 +3,7 @@ import Image from 'next/image'; import { useLocale } from 'next-intl'; import { ShieldCheck, Leaf, Lock, Accessibility, Zap } from 'lucide-react'; import { LanguageSwitcher } from './LanguageSwitcher'; +import { StratumLines } from '@/components/ui/decorations/StratumLines'; interface CompanyInfo { contactEmail: string; @@ -150,6 +151,8 @@ export function Footer({ companyInfo }: FooterProps) {
High Performance
+ {/* Decorative: abstract earth strata */} + ); } diff --git a/components/providers/PageTransitionShutter.tsx b/components/providers/PageTransitionShutter.tsx index 06e59b0b1..84c1d5bdc 100644 --- a/components/providers/PageTransitionShutter.tsx +++ b/components/providers/PageTransitionShutter.tsx @@ -166,6 +166,38 @@ export function PageTransitionShutter() { /> ))} + + {/* Abstract HDD bore arc — decorative element during page transitions */} + + + + + )} diff --git a/components/ui/decorations/DrillOrbit.tsx b/components/ui/decorations/DrillOrbit.tsx new file mode 100644 index 000000000..2816271de --- /dev/null +++ b/components/ui/decorations/DrillOrbit.tsx @@ -0,0 +1,131 @@ +'use client'; + +import { motion, useInView } from 'framer-motion'; +import { useRef } from 'react'; + +/** + * DrillOrbit + * + * A glowing point continuously looping along a parabolic arc — + * evoking the trajectory of a horizontal directional drill bit. + * + * The arc is drawn once on scroll-entry. The dot then loops forever. + * Place inside any `relative overflow-hidden` section. Zero layout impact. + */ + +type Side = 'left' | 'right'; + +interface DrillOrbitProps { + /** Which side of the section to anchor to */ + side?: Side; + /** Invert colors for light backgrounds */ + invert?: boolean; + className?: string; +} + +// The parabolic bore path (left-to-right across a 800×200 canvas) +const PATH = 'M -20 80 C 150 80 200 340 400 340 C 600 340 650 80 820 80'; + +export function DrillOrbit({ + side = 'right', + invert = false, + className = '', +}: DrillOrbitProps) { + const ref = useRef(null); + const isInView = useInView(ref, { once: true, margin: '0px 0px -10% 0px' }); + + const color = invert ? '#084c39' : '#0e7a5c'; + const glowColor = invert ? 'rgba(8,76,57,0.35)' : 'rgba(14,122,92,0.45)'; + + return ( + + ); +} diff --git a/components/ui/decorations/StratumLines.tsx b/components/ui/decorations/StratumLines.tsx new file mode 100644 index 000000000..9db5ea406 --- /dev/null +++ b/components/ui/decorations/StratumLines.tsx @@ -0,0 +1,130 @@ +'use client'; + +import { motion, useInView } from 'framer-motion'; +import { useRef } from 'react'; + +/** + * StratumLines + * + * Abstract horizontal "earth stratum" lines that slide in from opposite sides + * and form a downward-tapered open shape — evoking excavated earth layers. + * + * - On scroll entry: lines slide in with staggered delay, longest at top + * - After entry: each line gently breathes (oscillates horizontally) forever + * + * Place inside any `relative overflow-hidden` section. Zero layout impact. + */ + +interface StratumLinesProps { + /** Which corner to anchor to */ + placement?: 'bottom-left' | 'bottom-right' | 'top-left' | 'top-right'; + /** Invert colors for light backgrounds */ + invert?: boolean; + className?: string; +} + +type StratumLine = { + width: number; // % of container width + fromRight: boolean; // which side it slides in from + delay: number; + breatheAmp: number; // px oscillation + breatheDur: number; +}; + +// The stratum lines — longest at top, tapering like an open excavation +const LINES: StratumLine[] = [ + { width: 100, fromRight: false, delay: 0.0, breatheAmp: 4, breatheDur: 5.2 }, + { width: 88, fromRight: true, delay: 0.1, breatheAmp: 5, breatheDur: 4.7 }, + { width: 74, fromRight: false, delay: 0.2, breatheAmp: 6, breatheDur: 5.8 }, + { width: 60, fromRight: true, delay: 0.3, breatheAmp: 5, breatheDur: 4.3 }, + { width: 46, fromRight: false, delay: 0.4, breatheAmp: 4, breatheDur: 6.1 }, + { width: 32, fromRight: true, delay: 0.5, breatheAmp: 3, breatheDur: 5.5 }, + { width: 18, fromRight: false, delay: 0.6, breatheAmp: 2, breatheDur: 4.9 }, +]; + +const PLACEMENT_CLASSES: Record, string> = { + 'bottom-left': 'bottom-0 left-0', + 'bottom-right': 'bottom-0 right-0', + 'top-left': 'top-0 left-0', + 'top-right': 'top-0 right-0', +}; + +export function StratumLines({ + placement = 'bottom-left', + invert = false, + className = '', +}: StratumLinesProps) { + const ref = useRef(null); + const isInView = useInView(ref, { once: true, margin: '0px 0px -8% 0px' }); + + const color = invert ? '#084c39' : '#0e7a5c'; + + return ( + + ); +}