@ssgoi/core
Version:
Core animation engine for SSGOI - Native app-like page transitions with spring physics
1,502 lines (1,501 loc) • 49 kB
JavaScript
const g = (t, i) => {
var r;
t.style.position = "absolute", t.style.width = "100%", t.style.top = `${-1 * (((r = i == null ? void 0 : i.scrollOffset) == null ? void 0 : r.y) ?? 0)}px`, t.style.left = "0";
}, _ = (t) => new Promise((i) => setTimeout(i, t));
function x(t, i) {
function r(s) {
let e = 0, a = 0;
const l = s.offsetWidth, y = s.offsetHeight;
let o = s;
for (; o; )
e += o.offsetTop, a += o.offsetLeft, o = o.offsetParent;
return e -= window.scrollY, a -= window.scrollX, { top: e, left: a, width: l, height: y };
}
const c = r(t), n = r(i);
return new DOMRect(
n.left - c.left,
n.top - c.top,
n.width,
n.height
);
}
function E() {
let t, i;
return { promise: new Promise((c, n) => {
t = c, i = n;
}), resolve: t, reject: i };
}
const H = {
spring: { stiffness: 200, damping: 22 }
}, X = {
spring: { stiffness: 200, damping: 22 }
}, z = 300, W = 10, M = "horizontal", B = "#000000", Mt = (t = {}) => {
const {
transitionDelay: i = z,
blindCount: r = W,
direction: c = M,
blindColor: n = B
} = t, s = t.physics ?? X, e = t.physics ?? H;
let a, l = null;
const y = (o, h, d = "left") => {
window.getComputedStyle(o).position === "static" && (o.style.position = "relative");
const f = document.createElement("div");
f.className = "blind-container", f.style.cssText = `
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
pointer-events: none;
z-index: 9999;
overflow: hidden;
`;
const p = [];
for (let $ = 0; $ < r; $++) {
const w = document.createElement("div");
if (c === "horizontal") {
const b = 100 / r, C = `calc(${b}% + 1px)`;
w.style.cssText = `
position: absolute;
top: ${b * $}%;
left: 0;
width: 100%;
height: ${C};
background: ${n};
transform: scaleX(${h === "hidden" ? 0 : 1});
transform-origin: ${d} center;
will-change: transform;
`;
} else {
const b = 100 / r, C = `calc(${b}% + 1px)`;
w.style.cssText = `
position: absolute;
top: 0;
left: ${b * $}%;
width: ${C};
height: 100%;
background: ${n};
transform: scaleY(${h === "hidden" ? 0 : 1});
transform-origin: ${d === "left" ? "top" : "bottom"} center;
will-change: transform;
`;
}
p.push(w), f.appendChild(w);
}
return o.appendChild(f), { container: f, blinds: p };
};
return {
out: (o) => {
let h = null;
a = new Promise((f) => {
l = f;
});
const d = (f) => {
const p = 1 - f;
return {
transform: c === "horizontal" ? `scaleX(${p})` : `scaleY(${p})`
};
};
return {
items: Array.from({ length: r }, (f, p) => ({
physics: e,
offset: 0.2,
css: {
// Use getter for lazy element access (evaluated after prepare)
get element() {
return h == null ? void 0 : h.blinds[p];
},
style: d
}
})),
schedule: "stagger",
prepare: () => {
g(o), o.style.zIndex = "1000", h = y(o, "hidden", "left");
},
onStart: () => {
},
onEnd: () => {
l && l();
}
};
},
in: (o) => {
let h = null;
const d = (f) => {
const p = 1 - f;
return {
transform: c === "horizontal" ? `scaleX(${p})` : `scaleY(${p})`
};
};
return {
items: Array.from({ length: r }, (f, p) => ({
physics: s,
offset: 0.2,
css: {
// Use getter for lazy element access (evaluated after prepare)
get element() {
return h == null ? void 0 : h.blinds[p];
},
style: d
}
})),
schedule: "stagger",
prepare: () => {
o.style.position = "relative", o.style.zIndex = "0", h = y(o, "closed", "right");
},
onStart: () => {
},
wait: async () => {
a && await a, await _(i);
},
onEnd: () => {
h && h.container && h.container.remove();
}
};
}
};
}, q = {
spring: { stiffness: 1, damping: 1 }
}, j = {
spring: { stiffness: 20, damping: 25 }
}, N = "#000000", G = "circle", k = "CURTAIN_REVEAL_OVERLAY_ID", Z = {
position: "fixed",
inset: "0",
width: "100vw",
height: "100%",
zIndex: "9999",
display: "flex",
alignItems: "center",
justifyContent: "center",
overflow: "hidden"
}, J = {
position: "relative",
display: "inline-block",
height: "5.5rem",
overflow: "hidden"
}, K = {
display: "flex",
height: "100%",
willChange: "transform",
transition: "transform 0.3s ease"
}, Q = {
display: "inline-flex",
alignItems: "center",
justifyContent: "center",
whiteSpace: "nowrap",
fontSize: "5.5rem",
fontWeight: "900",
letterSpacing: "0.02em",
color: "#FFFFFF"
}, R = 0.4, S = 0.5, tt = 0.2;
function st(t, i) {
switch (t) {
case "circle":
return `circle(${i * 100}% at 50% 50%)`;
case "square":
return `inset(${(1 - i) * 50}% round ${10 * i}%)`;
case "triangle": {
const r = i * 100;
return `polygon(50% ${50 - r}%, ${50 - r}% ${50 + r}%, ${50 + r}% ${50 + r}%)`;
}
}
}
const it = (t) => t.reduce((i, r) => i + r, 0), Bt = (t = {}) => {
const {
background: i = N,
texts: r = [],
shape: c = G,
textStyle: n = {}
} = t, s = t.physics ?? j, e = t.physics ?? q;
return {
out: (a, l) => {
const y = a.style.opacity;
return {
physics: e,
from: 1,
to: 0,
prepare: () => {
g(a, l), a.style.opacity = "1";
},
tick: (o) => {
const h = Math.max(0, o - R);
a.style.opacity = String(h);
},
onEnd: () => {
a.style.opacity = y;
}
};
},
in: (a) => {
let l = null, y = null, o = null;
const h = document.body.style.overflow, d = document.getElementById(
k
);
let u = [];
const f = () => {
l = document.createElement("div"), l.id = k, Object.assign(l.style, Z, { background: i }), document.body.appendChild(l), y = document.createElement("div"), Object.assign(y.style, J), l.appendChild(y), o = document.createElement("div"), Object.assign(o.style, K), y.appendChild(o), r.forEach((p) => {
const $ = document.createElement("div");
$.textContent = p, Object.assign($.style, Q, n), o.appendChild($);
}), u = Array.from(o.children).map(
(p) => p.getBoundingClientRect().width
);
};
return {
physics: s,
from: 0,
to: 1,
prepare: () => {
document.body.style.overflow = "hidden", a.style.opacity = "1", d == null || d.remove(), f(), l && y && (l.style.clipPath = "none", y.style.transform = "scale(1)");
},
tick: (p) => {
if (!(!l || !y || !o)) {
if (p <= S && r.length > 0) {
const $ = p / S, w = Math.min(
Math.floor($ * r.length),
r.length - 1
), b = u[w] ?? 0, C = it(u.slice(0, w));
y.style.width = `${b}px`, o.style.transform = `translateX(-${C}px)`;
}
if (p > S) {
const w = 1 - Math.max(
0,
Math.min(1, (p - S) / tt)
);
l.style.clipPath = st(c, w), y.style.transform = `scale(${w})`;
}
}
},
onEnd: () => {
l == null || l.remove(), l = y = o = null, document.body.style.overflow = h;
}
};
}
};
}, nt = {
spring: {
stiffness: 600,
damping: 40,
restDelta: 0.1,
restSpeed: 1e14
}
}, et = {
spring: {
stiffness: 600,
damping: 40,
restDelta: 0.1,
restSpeed: 1e14
}
}, at = 0.05;
function A(t) {
const i = x(document.body, t.positionedParent), r = t.scroll.y, c = window.innerHeight - i.top;
return {
top: r,
left: 0,
width: i.width,
height: c
};
}
const qt = (t = {}) => {
const { direction: i = "enter" } = t, r = t.physics ?? (i === "enter" ? nt : et), c = t.scaleOffset ?? at;
let { promise: n, resolve: s } = E();
return i === "enter" ? {
// Entering page: scales up from small (0.8 → 1) with fade in
in: (e, a) => {
const l = A(a), y = l.left + l.width / 2, o = l.top + l.height / 2;
return {
physics: r,
prepare: () => {
e.style.opacity = "0", e.style.willChange = "transform, opacity", e.style.backfaceVisibility = "hidden", e.style.contain = "layout paint", e.style.transformOrigin = `${y}px ${o}px`;
},
wait: async () => {
if (n) {
await n;
const h = E();
n = h.promise, s = h.resolve;
}
},
css: (h) => ({
transform: `scale(${1 - c + h * c})`,
opacity: h
}),
onEnd: () => {
e.style.opacity = "1", e.style.willChange = "auto", e.style.backfaceVisibility = "", e.style.contain = "", e.style.transformOrigin = "";
}
};
},
// Exiting page: scales up (1 → 1.2) with fade out, goes to back
out: (e, a) => {
const l = A(a), y = l.left + l.width / 2, o = l.top + l.height / 2 + a.scrollOffset.y;
return {
physics: r,
prepare: () => {
g(e, a), e.style.zIndex = "-1", e.style.willChange = "transform, opacity", e.style.backfaceVisibility = "hidden", e.style.contain = "layout paint", e.style.pointerEvents = "none", e.style.transformOrigin = `${y}px ${o}px`;
},
css: (h) => ({
transform: `scale(${1 + (1 - h) * c})`,
opacity: h
}),
onEnd: () => {
s && s();
}
};
}
} : {
// Entering page: scales down from large (1.2 → 1) with fade in
in: (e, a) => {
const l = A(a), y = l.left + l.width / 2, o = l.top + l.height / 2;
return {
physics: r,
prepare: () => {
e.style.opacity = "0", e.style.willChange = "transform, opacity", e.style.backfaceVisibility = "hidden", e.style.contain = "layout paint", e.style.transformOrigin = `${y}px ${o}px`;
},
wait: async () => {
if (n) {
await n;
const h = E();
n = h.promise, s = h.resolve;
}
},
css: (h) => ({
transform: `scale(${1 + c - h * c})`,
opacity: h
}),
onEnd: () => {
e.style.opacity = "1", e.style.willChange = "auto", e.style.backfaceVisibility = "", e.style.contain = "", e.style.transformOrigin = "";
}
};
},
// Exiting page: scales down to small (1 → 0.8) with fade out
out: (e, a) => {
const l = A(a), y = l.left + l.width / 2, o = l.top + l.height / 2 + a.scrollOffset.y;
return {
physics: r,
prepare: () => {
g(e, a), e.style.zIndex = "100", e.style.willChange = "transform, opacity", e.style.backfaceVisibility = "hidden", e.style.contain = "layout paint", e.style.pointerEvents = "none", e.style.transformOrigin = `${y}px ${o}px`;
},
css: (h) => ({
transform: `scale(${1 - (1 - h) * c})`,
opacity: h
}),
onEnd: () => {
s && s();
}
};
}
};
}, rt = {
spring: {
stiffness: 170,
damping: 22
}
}, ot = {
spring: {
stiffness: 170,
damping: 22
}
}, jt = (t = {}) => {
const { opacity: i = !1, direction: r = "enter" } = t, c = t.physics ?? (r === "enter" ? rt : ot);
return r === "enter" ? {
in: (n) => ({
physics: c,
prepare: () => {
n.style.willChange = i ? "transform, opacity" : "transform", n.style.backfaceVisibility = "hidden", n.style.contain = "layout paint";
},
css: (s) => {
const e = {
transform: `translate3d(${(1 - s) * 100}%, 0, 0)`
};
return i && (e.opacity = s), e;
},
onEnd: () => {
n.style.willChange = "auto", n.style.backfaceVisibility = "", n.style.contain = "";
}
}),
out: (n, s) => ({
physics: c,
prepare: () => {
g(n, s), n.style.zIndex = "-1", n.style.willChange = i ? "transform, opacity" : "transform", n.style.backfaceVisibility = "hidden", n.style.contain = "layout paint", n.style.pointerEvents = "none";
},
css: (e) => {
const a = {
transform: `translate3d(${-(1 - e) * 20}%, 0, 0)`
};
return i && (a.opacity = e), a;
}
})
} : {
in: (n) => ({
physics: c,
prepare: () => {
n.style.willChange = i ? "transform, opacity" : "transform", n.style.backfaceVisibility = "hidden", n.style.contain = "layout paint";
},
css: (s) => {
const e = {
transform: `translate3d(${-(1 - s) * 20}%, 0, 0)`
};
return i && (e.opacity = s), e;
},
onEnd: () => {
n.style.willChange = "auto", n.style.backfaceVisibility = "", n.style.contain = "";
}
}),
out: (n, s) => ({
physics: c,
prepare: () => {
g(n, s), n.style.zIndex = "100", n.style.willChange = i ? "transform, opacity" : "transform", n.style.backfaceVisibility = "hidden", n.style.contain = "layout paint", n.style.pointerEvents = "none";
},
css: (e) => {
const a = {
transform: `translate3d(${(1 - e) * 100}%, 0, 0)`
};
return i && (a.opacity = e), a;
}
})
};
}, lt = {
spring: { stiffness: 180, damping: 20, doubleSpring: !0 }
}, ct = {
spring: { stiffness: 170, damping: 20, doubleSpring: !0 }
}, yt = 0, Nt = (t = {}) => {
const { transitionDelay: i = yt } = t, r = t.physics ?? ct, c = t.physics ?? lt;
let { promise: n, resolve: s } = E();
return {
in: (e) => ({
physics: r,
prepare: () => {
e.style.opacity = "0", e.style.willChange = "opacity";
},
wait: async () => {
if (n) {
await n;
const a = E();
n = a.promise, s = a.resolve, await _(i);
}
},
css: (a) => ({
opacity: a
}),
onEnd: () => {
e.style.willChange = "auto", e.style.opacity = "1";
}
}),
out: (e, a) => ({
physics: c,
css: (l) => ({
opacity: l
}),
prepare: () => {
g(e, a), e.style.willChange = "opacity";
},
onEnd: () => {
s && s(), e.style.willChange = "auto";
}
})
};
}, ht = {
scaleDown: { stiffness: 20, damping: 7 },
// Soft start for cinematic scale
translate: { stiffness: 15, damping: 7 },
// Medium for movement
scaleUp: { stiffness: 20, damping: 7 }
// Crisp return to full size
}, O = {
scaleDown: 0,
// Start immediately
translate: 0.2,
// Start when scaleDown is 25% complete
scaleUp: 0.8
// Start when translate is 70% complete
}, pt = 0.8, dt = "white", Gt = (t) => {
var n;
const i = ht, r = pt, c = ((n = t == null ? void 0 : t.border) == null ? void 0 : n.color) ?? dt;
return {
out: async (s, e) => {
const a = v(e), l = x(document.body, e.positionedParent), y = ft(c, {
...a,
top: l.top
}), o = {
scale: 1,
translateY: -a.top
}, h = () => {
s.style.transform = `translateY(${o.translateY}px) scale(${o.scale})`;
const d = (a.width - a.width * o.scale) / 2, u = (a.height - a.height * o.scale) / 2;
ut(y, d, u);
};
return {
items: [
// Spring 1: Scale Down (1 → scale)
{
physics: (t == null ? void 0 : t.physics) ?? { spring: i.scaleDown },
offset: O.scaleDown,
tick: (d) => {
const u = 1 - d;
o.scale = 1 - (1 - r) * u, h();
}
},
// Spring 2: Translate (vertical movement)
{
physics: (t == null ? void 0 : t.physics) ?? { spring: i.translate },
offset: O.translate,
tick: (d) => {
const u = 1 - d;
o.translateY = -a.top - a.height * u, h();
}
},
// Spring 3: Scale Up (scale → 1)
{
physics: (t == null ? void 0 : t.physics) ?? { spring: i.scaleUp },
offset: O.scaleUp,
tick: (d) => {
const u = 1 - d;
o.scale = r + (1 - r) * u, h();
}
}
],
schedule: "stagger",
prepare: () => {
g(s), m(s, a), I(s, a), gt(s, a);
for (const d of y)
e.positionedParent.appendChild(d);
},
onEnd: () => {
s.style.clipPath = "", s.style.transformOrigin = "", setTimeout(() => {
for (const d of y)
e.positionedParent.removeChild(d);
}, 1e3);
}
};
},
in: async (s, e) => {
const a = v(e), l = {
scale: r,
translateY: -a.top + a.height
}, y = () => {
s.style.transform = `translateY(${l.translateY}px) scale(${l.scale})`;
};
return {
items: [
// Spring 1: Scale Down (1 → scale) - element starts scaled, shrinks further
{
physics: (t == null ? void 0 : t.physics) ?? { spring: i.scaleDown },
offset: O.scaleDown,
tick: (o) => {
l.scale = 1 - (1 - r) * o, y();
}
},
// Spring 2: Translate (vertical movement from bottom to top)
{
physics: (t == null ? void 0 : t.physics) ?? { spring: i.translate },
offset: O.translate,
tick: (o) => {
l.translateY = -a.top + a.height * (1 - o), y();
}
},
// Spring 3: Scale Up (scale → 1) - element returns to full size
{
physics: (t == null ? void 0 : t.physics) ?? { spring: i.scaleUp },
offset: O.scaleUp,
tick: (o) => {
l.scale = r + (1 - r) * o, y();
}
}
],
schedule: "stagger",
prepare: () => {
m(s, a), I(s, a), s.style.transform = `translateY(${-a.top + a.height}px) scale(${r})`;
},
onEnd: () => {
s.style.clipPath = "", s.style.transformOrigin = "", s.style.transform = "";
}
};
}
};
};
function ut(t, i, r) {
const c = i * 0.7, n = r * 0.7;
t.topLeft.style.transform = `translate(${c}px, ${n}px)`, t.topRight.style.transform = `translate(${-c}px, ${n}px)`, t.bottomLeft.style.transform = `translate(${c}px, ${-n}px)`, t.bottomRight.style.transform = `translate(${-c}px, ${-n}px)`;
}
function ft(t = "white", i) {
const n = document.createElement("div");
n.style.position = "fixed", n.style.pointerEvents = "none", n.style.zIndex = "9999", n.style.top = `${i.top - 1}px`, n.style.left = `${i.left - 1}px`, n.style.width = "15px", n.style.height = "15px";
const s = document.createElement("div");
s.style.position = "absolute", s.style.width = "15px", s.style.height = "1px", s.style.backgroundColor = t, s.style.top = "0", s.style.left = "0";
const e = document.createElement("div");
e.style.position = "absolute", e.style.width = "1px", e.style.height = "15px", e.style.backgroundColor = t, e.style.top = "0", e.style.left = "0", n.appendChild(s), n.appendChild(e);
const a = document.createElement("div");
a.style.position = "fixed", a.style.pointerEvents = "none", a.style.zIndex = "9999", a.style.top = `${i.top - 1}px`, a.style.left = `${i.left + i.width - 15 + 1}px`, a.style.width = "15px", a.style.height = "15px";
const l = document.createElement("div");
l.style.position = "absolute", l.style.width = "15px", l.style.height = "1px", l.style.backgroundColor = t, l.style.top = "0", l.style.right = "0";
const y = document.createElement("div");
y.style.position = "absolute", y.style.width = "1px", y.style.height = "15px", y.style.backgroundColor = t, y.style.top = "0", y.style.right = "0", a.appendChild(l), a.appendChild(y);
const o = document.createElement("div");
o.style.position = "fixed", o.style.pointerEvents = "none", o.style.zIndex = "9999", o.style.top = `${i.top + i.height - 15 + 1}px`, o.style.left = `${i.left - 1}px`, o.style.width = "15px", o.style.height = "15px";
const h = document.createElement("div");
h.style.position = "absolute", h.style.width = "15px", h.style.height = "1px", h.style.backgroundColor = t, h.style.bottom = "0", h.style.left = "0";
const d = document.createElement("div");
d.style.position = "absolute", d.style.width = "1px", d.style.height = "15px", d.style.backgroundColor = t, d.style.bottom = "0", d.style.left = "0", o.appendChild(h), o.appendChild(d);
const u = document.createElement("div");
u.style.position = "fixed", u.style.pointerEvents = "none", u.style.zIndex = "9999", u.style.top = `${i.top + i.height - 15 + 1}px`, u.style.left = `${i.left + i.width - 15 + 1}px`, u.style.width = "15px", u.style.height = "15px";
const f = document.createElement("div");
f.style.position = "absolute", f.style.width = "15px", f.style.height = "1px", f.style.backgroundColor = t, f.style.bottom = "0", f.style.right = "0";
const p = document.createElement("div");
return p.style.position = "absolute", p.style.width = "1px", p.style.height = "15px", p.style.backgroundColor = t, p.style.bottom = "0", p.style.right = "0", u.appendChild(f), u.appendChild(p), {
topLeft: n,
topRight: a,
bottomLeft: o,
bottomRight: u,
*[Symbol.iterator]() {
yield n, yield a, yield o, yield u;
}
};
}
function v(t) {
const i = x(document.body, t.positionedParent);
return {
top: t.scroll.y,
left: 0,
width: i.width,
height: window.innerHeight - i.top
};
}
function m(t, i) {
const r = i.left + i.width / 2, c = i.top + i.height / 2;
t.style.transformOrigin = `${r}px ${c}px`;
}
function I(t, i) {
t.style.clipPath = `polygon(
${i.left}px ${i.top}px,
${i.left + i.width}px ${i.top}px,
${i.left + i.width}px ${i.top + i.height}px,
${i.left}px ${i.top + i.height}px
)`;
}
function gt(t, i) {
t.style.transform = `translateY(${-i.top}px)`;
}
const wt = {
spring: { stiffness: 300, damping: 30 }
};
function $t(t, i) {
return t.querySelector(`[data-hero-key="${i}"]`);
}
const Zt = (t = {}) => {
const i = t.physics ?? wt, r = t.maxDistance ?? 700;
let c = null, n = E();
return {
in: async (s, e) => {
const a = s, l = Array.from(a.querySelectorAll("[data-hero-key]"));
await n.promise;
const y = l.map((o) => {
const h = o.getAttribute("data-hero-key");
if (!h) return null;
const d = $t(c, h);
if (!d) return null;
const u = o, f = x(c, d), p = x(a, u), $ = f.left - p.left - e.scrollOffset.x, w = f.top - p.top - e.scrollOffset.y, b = f.width / p.width, C = f.height / p.height, D = u.style.transform, Y = u.style.position, F = u.style.transformOrigin, U = u.style.zIndex, V = u.style.willChange;
return {
toEl: u,
dx: $,
dy: w,
dw: b,
dh: C,
originalTransform: D,
originalPosition: Y,
originalTransformOrigin: F,
originalZIndex: U,
originalWillChange: V
};
}).filter(
(o) => o !== null && Math.abs(o.dy) <= r
);
return c = null, n = E(), y.length === 0 ? {
physics: i,
tick: () => {
}
// No matching hero elements
} : {
items: y.map(({ toEl: o, dx: h, dy: d, dw: u, dh: f }) => ({
physics: i,
tick: (p) => {
o.style.transform = `translate(${(1 - p) * h}px, ${(1 - p) * d}px) scale(${p + (1 - p) * u}, ${p + (1 - p) * f})`;
}
})),
schedule: "parallel",
prepare: () => {
y.forEach(({ toEl: o }) => {
o.style.position = "relative", o.style.transformOrigin = "top left", o.style.zIndex = "1000", o.style.willChange = "transform";
});
},
onEnd: () => {
y.forEach(
({
toEl: o,
originalTransform: h,
originalPosition: d,
originalTransformOrigin: u,
originalZIndex: f,
originalWillChange: p
}) => {
o.style.transform = h, o.style.position = d, o.style.transformOrigin = u, o.style.zIndex = f, o.style.willChange = p;
}
);
}
};
},
out: async (s) => ({
physics: i,
tick: () => {
},
prepare: () => {
c = s, n.resolve(), g(s), s.style.opacity = "0";
}
})
};
}, bt = {
spring: { stiffness: 180, damping: 22, doubleSpring: 1 }
};
function xt({
detailRect: t,
galleryRect: i,
pageRect: r,
scrollOffset: c
}) {
const n = i.left - t.left + (i.width - t.width) / 2 - c.x, s = i.top - t.top + (i.height - t.height) / 2 - c.y, e = i.width / t.width, a = i.height / t.height, l = Math.max(e, a), y = t.top / r.height * 100, o = (r.width - (t.left + t.width)) / r.width * 100, h = (r.height - (t.top + t.height)) / r.height * 100, d = t.left / r.width * 100;
return {
transformOrigin: `${t.left + t.width / 2}px ${t.top + t.height / 2}px`,
animate: (f) => {
const p = 1 - f;
return {
clipPath: `inset(${y * p}% ${o * p}% ${h * p}% ${d * p}%)`,
transform: `translate(${n * p}px, ${s * p}px) scale(${1 + (l - 1) * p})`
};
}
};
}
function Et({
detailRect: t,
galleryRect: i,
pageRect: r,
scrollOffset: c
}) {
const n = i.left - t.left + (i.width - t.width) / 2 + c.x, s = i.top - t.top + (i.height - t.height) / 2 + c.y, e = i.width / t.width, a = i.height / t.height, l = Math.min(e, a), y = t.top / r.height * 100, o = (r.width - (t.left + t.width)) / r.width * 100, h = (r.height - (t.top + t.height)) / r.height * 100, d = t.left / r.width * 100;
return {
transformOrigin: `${t.left + t.width / 2}px ${t.top + t.height / 2}px`,
animate: (f) => {
const p = 1 - f;
return {
clipPath: `inset(${y * p}% ${o * p}% ${h * p}% ${d * p}%)`,
transform: `translate(${n * p - c.x}px, ${s * p - c.y}px) scale(${1 + (l - 1) * p})`
};
}
};
}
function Ct(t, i, r) {
const c = t.querySelector(
"[data-instagram-detail-key]"
), n = i.querySelector(
"[data-instagram-detail-key]"
);
if (t.querySelectorAll("[data-instagram-detail-key]").length > 1 || i.querySelectorAll("[data-instagram-detail-key]").length > 1)
return null;
let s = null, e = null, a = !1;
if (!c && n) {
e = n;
const o = e.getAttribute("data-instagram-detail-key");
if (!o) return null;
s = t.querySelector(
`[data-instagram-gallery-key="${o}"]`
), s && (a = !0);
} else if (c && !n) {
e = c;
const o = e.getAttribute("data-instagram-detail-key");
if (!o) return null;
s = i.querySelector(
`[data-instagram-gallery-key="${o}"]`
), s && (a = !1);
}
if (!s || !e)
return null;
const l = x(a ? t : i, s), y = x(a ? i : t, e);
if (a) {
const o = xt({
detailRect: y,
galleryRect: l,
pageRect: i.getBoundingClientRect(),
scrollOffset: r
});
return i.style.transformOrigin = o.transformOrigin, {
isEnterMode: !0,
inAnimation: o.animate
// No outAnimation - gallery stays visible
};
} else {
const o = Et({
detailRect: y,
galleryRect: l,
pageRect: t.getBoundingClientRect(),
scrollOffset: r
});
return t.style.transformOrigin = o.transformOrigin, {
isEnterMode: !1,
outAnimation: o.animate
// No inAnimation - gallery stays visible
};
}
}
const Jt = (t = {}) => {
const i = t.physics ?? bt, r = t.timeout ?? 300;
let c = null, n = null, s = null, e = null;
return {
in: async (a, { scrollOffset: l }) => {
const y = a;
return !await new Promise((h) => {
c ? h(!0) : (n = h, setTimeout(() => {
n = null, h(!1);
}, r));
}) || !c ? (e == null || e(), e = null, c = null, {
physics: i,
css: () => ({})
}) : (s = Ct(c, y, l), e == null || e(), e = null, s ? (c = null, {
physics: i,
css: (h) => s != null && s.inAnimation ? s.inAnimation(h) : {}
}) : (c = null, {
physics: i,
css: () => ({})
}));
},
out: async (a, l) => {
const y = new Promise((o) => {
e = o;
});
return {
physics: i,
prepare: () => {
s != null && s.isEnterMode ? g(a) : (g(a, l), a.style.zIndex = "-1");
},
wait: async () => {
c = a, n && (n(!0), n = null), await y;
},
css: (o) => s != null && s.outAnimation ? s.outAnimation(o) : {}
};
}
};
}, Ot = {
spring: { stiffness: 50, damping: 30 }
};
function St(t) {
const i = x(document.body, t.positionedParent);
return {
top: t.scroll.y,
left: 0,
width: i.width,
height: window.innerHeight - i.top
};
}
const Kt = (t = {}) => {
const i = t.physics ?? Ot, r = t.initialRotation ?? 45, c = t.initialScale ?? 0.01, n = t.rotationTriggerPoint ?? 0.8;
return {
out: async (s, e) => {
const a = s.style.opacity;
return {
physics: {
spring: {
stiffness: 80,
damping: 25
}
},
from: 1,
to: 0,
prepare: () => {
g(s, e), s.style.opacity = "1";
},
tick: (l) => {
s.style.opacity = String(l);
},
onEnd: () => {
s.style.opacity = a;
}
};
},
in: async (s, e) => {
const a = St(e), l = s.style.transform, y = s.style.transformOrigin, o = s.style.position, h = s.style.zIndex;
return {
physics: i,
from: 0,
to: 1,
prepare: () => {
const d = Math.min(a.width, a.height) * 0.4;
s.style.setProperty(
"--max-border-radius",
`${d}px`
), s.style.setProperty("--border-radius-scale", "1"), s.style.willChange = "transform", s.style.backfaceVisibility = "hidden";
const u = a.left + a.width / 2, f = a.top + a.height / 2;
s.style.transformOrigin = `${u}px ${f}px`, s.style.position = "fixed", s.style.top = `${a.top}px`, s.style.left = `${a.left}px`, s.style.width = `${a.width}px`, s.style.height = `${a.height}px`, s.style.zIndex = "1000", s.style.overflow = "hidden", s.style.transform = `rotate(${r}deg) scale(${c}) translateZ(0)`, s.style.borderRadius = "calc(var(--max-border-radius) * var(--border-radius-scale))", s.style.opacity = "1";
},
tick: (d) => {
let u;
if (d <= 0.05)
u = c;
else if (d <= n) {
const w = (d - 0.05) / (n - 0.05), b = Math.pow(w, 9);
u = c + (0.8 - c) * b;
} else {
const w = (d - n) / (1 - n);
u = 0.8 + 0.2 * (1 - Math.pow(1 - w, 3));
}
let f;
const p = 0.7;
if (d <= p)
f = r;
else {
const w = (d - p) / (1 - p), b = 1 - Math.pow(1 - w, 2);
f = r * (1 - b);
}
let $;
if (d <= p)
$ = 1;
else {
const w = (d - p) / (1 - p);
$ = 1 - Math.pow(w, 0.5);
}
s.style.transform = `rotate(${f.toFixed(2)}deg) scale(${u.toFixed(4)}) translateZ(0)`, s.style.setProperty(
"--border-radius-scale",
$.toFixed(4)
);
},
onEnd: () => {
s.style.willChange = "", s.style.backfaceVisibility = "", s.style.removeProperty("--max-border-radius"), s.style.removeProperty("--border-radius-scale"), s.style.transform = l, s.style.transformOrigin = y, s.style.position = o, s.style.zIndex = h, s.style.top = "", s.style.left = "", s.style.width = "", s.style.height = "", s.style.overflow = "", s.style.borderRadius = "";
}
};
}
};
}, At = {
spring: { stiffness: 200, damping: 23, doubleSpring: 1 }
};
function Tt({
detailRect: t,
galleryRect: i,
pageRect: r,
scrollOffset: c
}) {
const n = i.left - t.left + (i.width - t.width) / 2 - c.x, s = i.top - t.top + (i.height - t.height) / 2 - c.y, e = i.width / t.width, a = i.height / t.height, l = Math.max(e, a), y = t.top / r.height * 100, o = (r.width - (t.left + t.width)) / r.width * 100, h = (r.height - (t.top + t.height)) / r.height * 100, d = t.left / r.width * 100;
return {
transformOrigin: `${t.left + t.width / 2}px ${t.top + t.height / 2}px`,
animate: (f) => {
const p = 1 - f;
return {
clipPath: `inset(${y * p}% ${o * p}% ${h * p}% ${d * p}%)`,
transform: `translate(${n * p}px, ${s * p}px) scale(${1 + (l - 1) * p})`
};
}
};
}
function Lt({
galleryRect: t,
detailRect: i,
scrollOffset: r
}) {
const c = i.left - t.left + (i.width - t.width) / 2 + r.x, n = i.top - t.top + (i.height - t.height) / 2 + r.y, s = i.width / t.width, e = i.height / t.height, a = Math.max(s, e);
return {
transformOrigin: `${t.left + t.width / 2}px ${t.top + t.height / 2}px`,
animate: (y) => {
const o = 1 - y;
return {
transform: `translate(${c * o - r.x}px, ${n * o - r.y}px) scale(${1 + (a - 1) * o})`,
opacity: `${1 - o}`
};
}
};
}
function Pt({
galleryRect: t,
detailRect: i,
scrollOffset: r
}) {
const c = i.left - t.left + (i.width - t.width) / 2 - r.x, n = i.top - t.top + (i.height - t.height) / 2 - r.y, s = i.width / t.width, e = i.height / t.height, a = Math.max(s, e);
return {
transformOrigin: `${t.left + t.width / 2}px ${t.top + t.height / 2}px`,
animate: (y) => {
const o = 1 - y, h = y;
return {
transform: `translate(${c * o}px, ${n * o}px) scale(${1 + (a - 1) * o})`,
opacity: `${h}`
};
}
};
}
function kt({
detailRect: t,
galleryRect: i,
pageRect: r,
scrollOffset: c
}) {
const n = i.left - t.left + (i.width - t.width) / 2 + c.x, s = i.top - t.top + (i.height - t.height) / 2 + c.y, e = i.width / t.width, a = i.height / t.height, l = Math.min(e, a), y = t.top / r.height * 100, o = (r.width - (t.left + t.width)) / r.width * 100, h = (r.height - (t.top + t.height)) / r.height * 100, d = t.left / r.width * 100;
return {
transformOrigin: `${t.left + t.width / 2}px ${t.top + t.height / 2}px`,
animate: (f) => {
const p = 1 - f;
return {
clipPath: `inset(${y * p}% ${o * p}% ${h * p}% ${d * p}%)`,
transform: `translate(${n * p - c.x}px, ${s * p - c.y}px) scale(${1 + (l - 1) * p})`
};
}
};
}
function vt(t, i, r) {
const c = t.querySelector(
"[data-pinterest-detail-key]"
), n = i.querySelector(
"[data-pinterest-detail-key]"
);
if (t.querySelectorAll("[data-pinterest-detail-key]").length > 1 || i.querySelectorAll("[data-pinterest-detail-key]").length > 1)
return null;
let s = null, e = null, a = !1;
if (!c && n) {
e = n;
const o = e.getAttribute("data-pinterest-detail-key");
if (!o) return null;
s = t.querySelector(
`[data-pinterest-gallery-key="${o}"]`
), s && (a = !0);
} else if (c && !n) {
e = c;
const o = e.getAttribute("data-pinterest-detail-key");
if (!o) return null;
s = i.querySelector(
`[data-pinterest-gallery-key="${o}"]`
), s && (a = !1);
}
if (!s || !e)
return null;
const l = x(a ? t : i, s), y = x(a ? i : t, e);
if (a) {
const o = Tt({
detailRect: y,
galleryRect: l,
pageRect: i.getBoundingClientRect(),
scrollOffset: r
}), h = Lt({
galleryRect: l,
detailRect: y,
scrollOffset: r
});
return i.style.transformOrigin = o.transformOrigin, t.style.transformOrigin = h.transformOrigin, {
inAnimation: o.animate,
outAnimation: h.animate
};
} else {
const o = Pt({
galleryRect: l,
detailRect: y,
scrollOffset: r
}), h = kt({
detailRect: y,
galleryRect: l,
pageRect: t.getBoundingClientRect(),
scrollOffset: r
});
return i.style.transformOrigin = o.transformOrigin, t.style.transformOrigin = h.transformOrigin, {
inAnimation: o.animate,
outAnimation: h.animate
};
}
}
const Qt = (t = {}) => {
const i = t.physics ?? At, r = t.timeout ?? 300;
let c = null, n = null, s = null, e = null;
return {
in: async (a, { scrollOffset: l }) => {
const y = a;
return !await new Promise((h) => {
c ? h(!0) : (n = h, setTimeout(() => {
n = null, h(!1);
}, r));
}) || !c ? (e == null || e(), e = null, c = null, {
physics: i,
css: () => ({})
}) : (s = vt(c, y, l), e == null || e(), e = null, s ? (c = null, {
physics: i,
css: (h) => s ? s.inAnimation(h) : {}
}) : (c = null, {
physics: i,
css: () => ({})
}));
},
out: async (a) => {
const l = new Promise((y) => {
e = y;
});
return {
physics: i,
prepare: () => {
g(a), a.style.zIndex = "-1", c = a, n && (n(!0), n = null);
},
wait: async () => {
await l;
},
css: (y) => s ? s.outAnimation(y) : {}
};
}
};
}, mt = {
spring: { stiffness: 100, damping: 30 }
}, Rt = (t = {}) => {
const i = t.physics ?? mt;
return {
in: (r) => ({
physics: i,
prepare: () => {
r.style.opacity = "0", r.style.transform = "rotate(-180deg)", r.style.transformOrigin = "center center", r.style.willChange = "transform, opacity";
},
css: (c) => ({
// -180deg → 0deg, show after 90deg (progress > 0.5)
transform: `rotate(${(c - 1) * 180}deg)`,
opacity: c > 0.5 ? 1 : 0
}),
onEnd: () => {
r.style.willChange = "auto", r.style.transform = "", r.style.transformOrigin = "", r.style.opacity = "";
}
}),
out: (r, c) => ({
physics: i,
prepare: () => {
g(r, c), r.style.transformOrigin = "center center", r.style.willChange = "transform, opacity";
},
css: (n) => ({
// 0deg → 180deg, hide after 90deg (progress < 0.5)
transform: `rotate(${(1 - n) * 180}deg)`,
opacity: n > 0.5 ? 1 : 0
}),
onEnd: () => {
r.style.willChange = "auto";
}
})
};
}, It = {
spring: { stiffness: 5, damping: 4 }
}, ts = (t = {}) => {
const i = t.direction ?? "up", r = t.physics ?? It, c = i === "up";
let n = null, s = null, e = null;
const a = () => {
if (n === null || s === null)
return null;
const l = Math.min(n, s), y = window.innerHeight;
return Math.max(l, y);
};
return {
in: (l) => (s = l.offsetHeight, n !== null && (e = a()), {
physics: r,
prepare: () => {
l.style.willChange = "transform", l.style.backfaceVisibility = "hidden", l.style.contain = "layout paint";
},
tick: (y) => {
e === null && (e = a());
const o = e ?? window.innerHeight, h = c ? (1 - y) * o : (1 - y) * -o;
l.style.transform = `translate3d(0, ${h}px, 0)`;
},
onEnd: () => {
l.style.willChange = "auto", l.style.backfaceVisibility = "", l.style.contain = "";
}
}),
out: (l, y) => ({
physics: r,
tick: (o) => {
e === null && (e = a());
const h = e ?? window.innerHeight, d = c ? (1 - o) * -h : (1 - o) * h;
l.style.transform = `translate3d(0, ${d}px, 0)`;
},
prepare: () => {
n = l.offsetHeight, s !== null && (e = a()), g(l, y), l.style.zIndex = c ? "-1" : "1", l.style.willChange = "transform", l.style.backfaceVisibility = "hidden", l.style.contain = "layout paint", l.style.pointerEvents = "none";
}
})
};
}, _t = {
inertia: {
acceleration: 20,
resistance: 1.5
}
}, Dt = {
inertia: {
acceleration: 20,
resistance: 1
}
}, Yt = 0.2;
function T(t) {
const i = x(document.body, t.positionedParent), r = t.scroll.y, c = window.innerHeight - i.top;
return {
top: r,
left: 0,
width: i.width,
height: c
};
}
const ss = (t = {}) => {
const { direction: i = "enter" } = t, r = t.physics ?? (i === "enter" ? _t : Dt), c = t.scaleOffset ?? Yt;
return i === "enter" ? {
// Entering sheet: slides up from bottom
in: (n, s) => {
const a = T(s).height;
return {
physics: r,
prepare: () => {
n.style.willChange = "transform", n.style.backfaceVisibility = "hidden", n.style.contain = "layout paint";
},
css: (l) => ({
transform: `translate3d(0, ${(1 - l) * a}px, 0)`
}),
onEnd: () => {
n.style.willChange = "auto", n.style.backfaceVisibility = "", n.style.contain = "";
}
};
},
// Exiting background: scales down with fade
out: (n, s) => {
const e = T(s), a = e.left + e.width / 2, l = e.top + e.height / 2 + s.scrollOffset.y;
return {
physics: r,
prepare: () => {
g(n, s), n.style.zIndex = "-1", n.style.willChange = "transform, opacity", n.style.backfaceVisibility = "hidden", n.style.contain = "layout paint", n.style.pointerEvents = "none", n.style.transformOrigin = `${a}px ${l}px`;
},
css: (y) => ({
transform: `scale(${1 - c + y * c})`,
opacity: y
})
};
}
} : {
// Entering background: scales up with fade
in: (n, s) => {
const e = T(s), a = e.left + e.width / 2, l = e.top + e.height / 2;
return {
physics: r,
prepare: () => {
n.style.willChange = "transform, opacity", n.style.backfaceVisibility = "hidden", n.style.contain = "layout paint", n.style.transformOrigin = `${a}px ${l}px`;
},
css: (y) => ({
transform: `scale(${1 - c + y * c})`,
opacity: y
}),
onEnd: () => {
n.style.willChange = "auto", n.style.backfaceVisibility = "", n.style.contain = "", n.style.transformOrigin = "";
}
};
},
// Exiting sheet: slides down with high z-index
out: (n, s) => {
const a = T(s).height;
return {
physics: r,
prepare: () => {
g(n, s), n.style.zIndex = "100", n.style.willChange = "transform", n.style.backfaceVisibility = "hidden", n.style.contain = "layout paint", n.style.pointerEvents = "none";
},
css: (l) => ({
transform: `translate3d(0, ${(1 - l) * a}px, 0)`
})
};
}
};
}, Ft = {
spring: {
stiffness: 140,
damping: 19,
doubleSpring: 0.8
}
}, is = (t = {}) => {
const i = t.direction ?? "left", r = t.physics ?? Ft, c = i === "left";
return {
in: (n) => ({
physics: r,
prepare: () => {
n.style.willChange = "transform", n.style.backfaceVisibility = "hidden", n.style.contain = "layout paint";
},
css: (s) => ({
transform: `translate3d(${c ? (1 - s) * 100 : (1 - s) * -100}%, 0, 0)`
}),
onEnd: () => {
n.style.willChange = "auto", n.style.backfaceVisibility = "", n.style.contain = "";
}
}),
out: (n, s) => ({
physics: r,
css: (e) => ({
transform: `translate3d(${c ? (1 - e) * -100 : (1 - e) * 100}%, 0, 0)`
}),
prepare: () => {
g(n, s), n.style.willChange = "transform", n.style.backfaceVisibility = "hidden", n.style.contain = "layout paint", n.style.pointerEvents = "none";
}
})
};
}, Ut = 8, Vt = {
spring: {
stiffness: 600,
damping: 40,
restDelta: 0.1,
restSpeed: 1e14
}
}, ns = (t = {}) => {
const i = t.direction ?? "left", r = t.physics ?? Vt, c = t.translateOffset ?? Ut, n = i === "left";
let { promise: s, resolve: e } = E();
return {
// Entering page: fades in + slides from opposite direction
in: (a) => ({
physics: r,
prepare: () => {
a.style.opacity = "0", a.style.willChange = "transform, opacity", a.style.backfaceVisibility = "hidden", a.style.contain = "layout paint";
},
wait: async () => {
if (s) {
await s;
const l = E();
s = l.promise, e = l.resolve;
}
},
css: (l) => {
const y = n ? (1 - l) * c : (1 - l) * -c, o = `${l}`;
return {
transform: `translate3d(${y}px, 0, 0)`,
opacity: o
};
},
onEnd: () => {
a.style.opacity = "1", a.style.willChange = "auto", a.style.backfaceVisibility = "", a.style.contain = "";
}
}),
// Exiting page: fade out + slide in same direction as navigation
out: (a, l) => ({
physics: r,
prepare: () => {
g(a, l), a.style.willChange = "transform, opacity", a.style.backfaceVisibility = "hidden", a.style.contain = "layout paint", a.style.pointerEvents = "none";
},
css: (y) => {
const o = n ? (1 - y) * -c : (1 - y) * c, h = `${y}`;
return {
transform: `translate3d(${o}px, 0, 0)`,
opacity: h
};
},
onEnd: () => {
e && e(), a.style.willChange = "auto", a.style.backfaceVisibility = "", a.style.contain = "";
}
})
};
}, Ht = {
spring: { stiffness: 17, damping: 6 }
}, P = 20, L = 800, es = (t = {}) => {
const i = t.physics ?? Ht;
let r, c = null;
return {
in: (n) => ({
physics: i,
prepare: () => {
n.style.willChange = "transform", n.style.backfaceVisibility = "hidden", n.style.contain = "layout paint", n.style.transform = `perspective(${L}px) rotateY(${P}deg) translate3d(-100%, 0, 0)`;
},
wait: async () => {
r && await r;
},
css: (s) => {
const e = (1 - s) * P, a = -(1 - s) * 100;
return {
transform: `perspective(${L}px) rotateY(${e}deg) translate3d(${a}%, 0, 0)`
};
},
onEnd: () => {
n.style.transform = "", n.style.willChange = "auto", n.style.backfaceVisibility = "", n.style.contain = "";
}
}),
out: (n, s) => (r = new Promise((e) => {
c = e;
}), {
physics: i,
prepare: () => {
g(n, s), n.style.willChange = "transform", n.style.backfaceVisibility = "hidden", n.style.contain = "layout paint", n.style.pointerEvents = "none", n.style.transform = `perspective(${L}px) rotateY(0deg) translate3d(0%, 0, 0)`;
},
css: (e) => {
const a = 1 - e, l = a * P, y = a * 100;
return {
transform: `perspective(${L}px) rotateY(${-l}deg) translate3d(${y}%, 0, 0)`
};
},
onEnd: () => {
c && c(), n.style.transform = "";
}
})
};
}, Xt = {
spring: {
stiffness: 600,
damping: 40,
restDelta: 0.1,
restSpeed: 1e14
}
}, zt = 0.05;
function Wt(t) {
const i = x(document.body, t.positionedParent), r = t.scroll.y, c = window.innerHeight - i.top;
return {
top: r,
left: 0,
width: i.width,
height: c
};
}
const as = (t = {}) => {
const i = t.physics ?? Xt, r = t.scaleOffset ?? zt;
let { promise: c, resolve: n } = E();
return {
// Entering page: scales up from small (0.95 → 1) with fade in
in: (s, e) => {
const a = Wt(e), l = a.left + a.width / 2, y = a.top + a.height / 2;
return {
physics: i,
prepare: () => {
s.style.opacity = "0", s.style.willChange = "transform, opacity", s.style.backfaceVisibility = "hidden", s.style.contain = "layout paint", s.style.transformOrigin = `${l}px ${y}px`;
},
wait: async () => {
if (c) {
await c;
const o = E();
c = o.promise, n = o.resolve;
}
},
css: (o) => ({
transform: `scale(${1 - r + o * r})`,
opacity: o
}),
onEnd: () => {
s.style.opacity = "1", s.style.willChange = "auto", s.style.backfaceVisibility = "", s.style.contain = "", s.style.transformOrigin = "";
}
};
},
// Exiting page: fade out only (no scale)
out: (s, e) => ({
physics: i,
prepare: () => {
g(s, e), s.style.willChange = "opacity", s.style.backfaceVisibility = "hidden", s.style.contain = "layout paint", s.style.pointerEvents = "none";
},
css: (a) => ({
opacity: a
}),
onEnd: () => {
n && n();
}
})
};
};
export {
Mt as blind,
Bt as curtainReveal,
qt as depth,
jt as drill,
Nt as fade,
Gt as film,
Zt as hero,
Jt as instagram,
Kt as jaemin,
Qt as pinterest,
Rt as rotate,
ts as scroll,
ss as sheet,
is as slide,
ns as snap,
es as strip,
as as swap
};