Flexible at Scale Illustration
navdeep-singh/flexible-at-scale-illustrationFreeComponent
An interactive spring-based line field that responds to pointer movement.
Install it
npx shadcn@latest add https://ui.navdeepsingh.dev/r/flexible-at-scale-illustration.jsonSource
1'use client'23import type { PointerEvent } from 'react'4import {5 motion,6 useMotionValue,7 useReducedMotion,8 useSpring,9 useTransform,10 type MotionValue,11} from 'motion/react'1213const clamp = (value: number, min: number, max: number) => Math.min(Math.max(value, min), max)1415const FLEXIBLE_LINE_COUNT = 171617const flexibleLines = Array.from({ length: FLEXIBLE_LINE_COUNT }, (_, index) => {18 const progress = index / (FLEXIBLE_LINE_COUNT - 1)1920 // outer lines away from the illustration edges.21 return 0.04 + progress * 0.9222})2324type FlexibleLineProps = {25 position: number26 pointerX: MotionValue<number>27 interaction: MotionValue<number>28 reduceMotion: boolean29}3031function FlexibleLine({ position, pointerX, interaction, reduceMotion }: FlexibleLineProps) {32 const influence = useTransform(() => {33 if (reduceMotion) return 03435 const distance = pointerX.get() - position36 const influenceRadius = 0.173738 return Math.exp(-Math.pow(distance / influenceRadius, 2))39 })4041 const left = useTransform(() => {42 if (reduceMotion) {43 return `${position * 100}%`44 }4546 const pointer = pointerX.get()47 const amount = interaction.get()48 const distance = pointer - position49 const strength = influence.get()5051 const flexiblePosition = position + distance * strength * amount * 0.885253 return `${clamp(flexiblePosition, 0.02, 0.98) * 100}%`54 })5556 const opacity = useTransform(() => {57 if (reduceMotion) return 0.245859 const amount = interaction.get()60 const strength = influence.get()6162 return 0.2 + amount * (0.08 + strength * 0.72)63 })6465 const scaleY = useTransform(() => {66 if (reduceMotion) return 16768 return 1 + interaction.get() * influence.get() * 0.1669 })7071 const scaleX = useTransform(() => {72 if (reduceMotion) return 17374 return 1 + interaction.get() * influence.get() * 0.6575 })7677 return (78 <motion.span79 className="absolute inset-y-[16%] w-px origin-center bg-foreground"80 style={{81 left,82 x: '-50%',83 opacity,84 scaleX,85 scaleY,86 }}87 />88 )89}9091export function FlexibleAtScaleIllustration() {92 const reduceMotion = useReducedMotion() ?? false9394 const rawPointerX = useMotionValue(0.5)95 const rawInteraction = useMotionValue(0)9697 const pointerX = useSpring(rawPointerX, {98 stiffness: 280,99 damping: 30,100 mass: 0.35,101 })102103 const interaction = useSpring(rawInteraction, {104 stiffness: 220,105 damping: 24,106 mass: 0.4,107 })108109// … truncated
What it pulls in
npm packages
Files it writes
More from navdeep-singh
All 62 items| Component | Registry | Kind | Access | Installs | Command |
|---|---|---|---|---|---|
| Animated Groupanimated-group | navdeep-singh | Components | Free | 1 dep | |
| Animated Numbersanimated-numbers | navdeep-singh | Components | Free | 1 dep | |
| Animated Tabsanimated-tabs | navdeep-singh | Components | Free | 2 deps | |
| Approval Panel Illustrationapproval-panel | navdeep-singh | Components | Free | 2 deps · 2 files | |
| Brand Logobrand-logo | navdeep-singh | Components | Free | 1 dep | |
| Designed for Focus Illustrationdesigned-for-focus-illustration | navdeep-singh | Components | Free | 1 dep | |
| Expandable Cardexpandable-card | navdeep-singh | Components | Free | 4 deps | |
| Fast by Default Illustrationfast-by-default-illustration | navdeep-singh | Components | Free | 1 dep |
