<div class="elastic-container">
<div class="content-overlay">
<h2>Pull The String</h2>
<p>Grab the glowing line below and release it to see the physics engine in action.</p>
</div>
<div class="svg-wrapper" id="string-wrapper">
<svg viewBox="0 0 1000 500" width="100%" height="100%" preserveAspectRatio="none">
<path id="elastic-line" d="M 0 250 Q 500 250 1000 250" fill="none" stroke="#3b82f6" stroke-width="6" stroke-linecap="round"></path>
</svg>
</div>
</div>*, *::before, *::after {
box-sizing: border-box;
}
body {
font-family: system-ui, "Segoe UI", Roboto, Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";
margin: 0;
background: #0f172a;
display: flex;
justify-content: center;
align-items: center;
min-height: 100vh;
overflow: hidden;
}
.elastic-container {
position: relative;
width: 100%;
max-width: 1000px;
height: 500px;
display: flex;
justify-content: center;
align-items: center;
}
.content-overlay {
position: absolute;
top: 60px;
text-align: center;
color: #ffffff;
pointer-events: none;
z-index: 10;
}
.content-overlay h2 {
font-size: 2.5rem;
margin: 0 0 10px 0;
letter-spacing: -1px;
}
.content-overlay p {
color: #94a3b8;
font-size: 1.125rem;
margin: 0;
}
.svg-wrapper {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: 1;
cursor: grab;
}
.svg-wrapper:active {
cursor: grabbing;
}
#elastic-line {
filter: drop-shadow(0 0 15px rgba(59, 130, 246, 0.8));
}const wrapper = document.getElementById("string-wrapper");
const line = document.getElementById("elastic-line");
let isDragging = false;
let mouseX = 500;
let mouseY = 250;
let currentY = 250;
let targetY = 250;
let velocity = 0;
// Physics constants
const tension = 0.05;
const friction = 0.85;
wrapper.addEventListener("pointerdown", function(e) {
isDragging = true;
wrapper.setPointerCapture(e.pointerId);
updateMousePos(e);
});
wrapper.addEventListener("pointermove", function(e) {
if (isDragging) {
updateMousePos(e);
}
});
function endDrag() {
isDragging = false;
targetY = 250;
mouseX = 500;
}
wrapper.addEventListener("pointerup", endDrag);
wrapper.addEventListener("pointercancel", endDrag);
function updateMousePos(e) {
const rect = wrapper.getBoundingClientRect();
// Map mouse position to the 1000x500 SVG viewBox
mouseX = (e.clientX - rect.left) * (1000 / rect.width);
let rawY = (e.clientY - rect.top) * (500 / rect.height);
targetY = rawY;
}
function animate() {
if (!isDragging) {
// Spring physics calculation
const force = (targetY - currentY) * tension;
velocity += force;
velocity *= friction;
currentY += velocity;
} else {
// Follow mouse smoothly when dragging
currentY += (targetY - currentY) * 0.5;
}
// Update the Quadratic Bezier Curve path
line.setAttribute("d", "M 0 250 Q " + mouseX + " " + currentY + " 1000 250");
window.requestAnimationFrame(animate);
}
animate();Nothing to show yetType HTML, CSS or JavaScript and your page appears here.
Click any element to find its code Esc
Check this code before you run it
It came from a shared link. It runs with fewer permissions, so it cannot open pop-ups, submit forms or start downloads.
0.00s / 0.00s
Nothing has animated yet. Hover, click or type in the preview and each CSS animation, transition or
element.animate() call shows up here as it plays.