Springy
A sprigy, bouncy and non-boring way to display images on a webstie.
Try dragging an image around:)
Gist
Images displayed here inlude logos to some of my apps, some medicore 3D concepts of all things Starship and the very first images i created using DALLE-2.
Code
npm i framer-motion @popmotion/popcorn
/components/lab/Springy/spring.js
"use client";import React, { useState,useRef } from "react";import { motion,useMotionValue,useSpring,useTransform, } from "framer-motion";import { distance } from "@popmotion/popcorn";import Image from "next/image";import { springimgs } from "./images";const grid = [[0, 1, 2, 3], [4, 5, 6, 7], [8, 9, 10, 11], [12, 13, 14, 15]];const size = 60;const gap = 10;const Square = ({ active, setActive, colIndex, rowIndex, x, y }) => {const isDragging = colIndex === active.col && rowIndex === active.row;const diagonalIndex = (360 / 6) * (colIndex + rowIndex);const d = distance({ x: active.col, y: active.row },{ x: colIndex, y: rowIndex });const springConfig = {stiffness: Math.max(700 - d * 120, 0),damping: 20 + d * 5};const dx = useSpring(x, springConfig);const dy = useSpring(y, springConfig);return (<motion.divdragdragConstraints={{ left: 0, right: 0, top: 0, bottom: 0 }}dragTransition={{ bounceStiffness: 500, bounceDamping: 20 }}dragElastic={1}onDragStart={() => setActive({ row: rowIndex, col: colIndex })}style={{background: 'hsla(calc(var(--base-hue) + diagonalIndex), 80%, 60%, 1)',width: size,height: size,top: rowIndex * (size + gap),left: colIndex * (size + gap),position: "absolute",// borderRadius: "50%",x: isDragging ? x : dx,y: isDragging ? y : dy,zIndex: isDragging ? 1 : 0}}className="overflow-hidden"><Image src={springimgs[colIndex * 4 + rowIndex]} className="w-full h-auto pointer-events-none"></Image></motion.div>);};const Spring = () => {const [active, setActive] = useState({ row: 0, col: 0 });const x = useMotionValue(0);const y = useMotionValue(0);return (<div className="flex items-center place-content-center place-items-center justify-center text-center"><motion.div transition={{ duration: 10, loop: Infinity, ease: "linear" }} style={{ width: "100%", height: "100%" }}><motion.div style={{display: "flex",width: (size + gap) * 4 - gap,height: (size + gap) * 4 - gap,transform: "translate(0%, 0%)",perspective: 500, position: "relative"}}>{grid.map((row, rowIndex) =>row.map((_item, colIndex) => (<Square x={x} y={y} active={active} setActive={setActive} rowIndex={rowIndex} colIndex={colIndex} key={rowIndex + colIndex}/>)))}</motion.div></motion.div></div>);}export default Spring