// Coverflow Gallery — Originkit
// Originkit — defaults rewritten to match preview.
"use client"
import {
useState,
useEffect,
useCallback,
useRef,
type CSSProperties,
} from "react"
const useIsStaticRenderer = () => false
interface Slide {
image?: { src?: string; srcSet?: string; alt?: string }
title?: string
}
type AutoplayDir = "leftToRight" | "rightToLeft"
type TitleCorner = "topLeft" | "topRight" | "bottomLeft" | "bottomRight"
interface Smooth3DSlideshowProps {
slides?: Slide[]
cardWidth?: number
cardHeight?: number
radius?: number
tilt?: number
sideTilt?: number
gap?: number
opacity?: number
transition?: any
autoplay?: boolean
autoplayDirection?: AutoplayDir
showTitle?: boolean
titleFont?: CSSProperties
titleColor?: string
titlePosition?: {
position?: TitleCorner
paddingLeft?: number
paddingRight?: number
paddingTop?: number
paddingBottom?: number
}
style?: CSSProperties
}
const DEFAULT_SLIDES: Slide[] = [
{
image: {
src: "https://imagedelivery.net/IEUjvl3YUlxY-MrTpOAWDQ/316d1761-fd79-4ca9-b8d4-f2bb20521a00/w=800",
},
title: "For Sitting\nMetal\nMinimal",
},
{
image: {
src: "https://imagedelivery.net/IEUjvl3YUlxY-MrTpOAWDQ/aeaa0756-9647-4f6c-d900-204bd25e4a00/w=800",
},
title: "For Living\nConcrete\nForm",
},
{
image: {
src: "https://imagedelivery.net/IEUjvl3YUlxY-MrTpOAWDQ/34ce1842-4b7a-4d52-0302-38582c341700/w=800",
},
title: "For Working\nSteel\nClean",
},
]
// Fixed internals (no longer exposed as controls).
const PERSPECTIVE = 1600
const SCALE_STEP = 0.16
const MAX_VISIBLE = 2
// In a preserve-3d context paint order follows 3D position, not z-index, so the
// centre is pushed nearest the viewer and neighbours fall back behind it.
const DEPTH = 240
// Derive a CSS transition (duration + easing) from a Framer Transition value.
function cssTransition(t: any): { dur: number; ease: string } {
const dur = t && typeof t.duration === "number" ? t.duration : 0.6
let ease = "cubic-bezier(0.22, 1, 0.36, 1)"
const e = t?.ease
if (Array.isArray(e) && e.length === 4) {
ease = `cubic-bezier(${e[0]}, ${e[1]}, ${e[2]}, ${e[3]})`
} else if (typeof e === "string") {
const map: Record = {
linear: "linear",
easeIn: "ease-in",
easeOut: "ease-out",
easeInOut: "ease-in-out",
}
ease = map[e] || "ease"
}
return { dur, ease }
}
/**
* Smooth 3D Slideshow
*
* A 3D coverflow: the active card sits upright in the spotlight while its
* neighbours tilt back in perspective. Click any card to smoothly bring it to
* centre. Recreated after Tanya Prokofieva's Framer original.
*
* @framerIntrinsicWidth 900
* @framerIntrinsicHeight 560
*
* @framerSupportedLayoutWidth any-prefer-fixed
* @framerSupportedLayoutHeight any-prefer-fixed
*/
export default function Smooth3DSlideshow(props: Smooth3DSlideshowProps) {
props = { ...COMPONENT_DEFAULTS, ...props }
const {
slides = DEFAULT_SLIDES,
cardWidth = 557,
cardHeight = 420,
radius = 0,
tilt = 7,
sideTilt = 7,
gap = 7,
opacity = 65,
transition,
autoplay = false,
autoplayDirection = "rightToLeft",
showTitle = false,
titleFont,
titleColor = "#ffffff",
titlePosition,
style,
} = props
const tp = titlePosition || {}
const corner: TitleCorner = tp.position || "bottomLeft"
const isTop = corner === "topLeft" || corner === "topRight"
const isRight = corner === "topRight" || corner === "bottomRight"
const padLeft = tp.paddingLeft ?? 22
const padRight = tp.paddingRight ?? 22
const padTop = tp.paddingTop ?? 24
const padBottom = tp.paddingBottom ?? 24
const isStatic = useIsStaticRenderer()
const list = slides && slides.length ? slides : DEFAULT_SLIDES
const n = list.length
// Loop is always on.
const loop = true
const [active, setActive] = useState(0)
// Keep active valid if the slide list changes.
useEffect(() => {
setActive((a) => Math.max(0, Math.min(n - 1, a)))
}, [n])
// Lock input while a card is mid-move; release once it settles, so rapid
// clicks/keys don't stack up and look jittery. Duration comes from the
// transition (default 0.6s).
const moveDur =
transition && typeof transition.duration === "number"
? transition.duration
: 0.6
const lockRef = useRef(false)
const lock = useCallback(() => {
lockRef.current = true
window.setTimeout(
() => {
lockRef.current = false
},
Math.max(50, moveDur * 1000)
)
}, [moveDur])
const step = useCallback(
(dir: number) => {
if (lockRef.current) return
lock()
setActive((a) => (((a + dir) % n) + n) % n)
},
[n, lock]
)
const handleCardClick = useCallback(
(i: number) => {
if (isStatic || autoplay || lockRef.current) return
lock()
setActive((a) => (i === a ? (a + 1) % n : i))
},
[isStatic, autoplay, n, lock]
)
// Autoplay — the transition's Delay drives the time each card holds.
const delay =
transition && typeof transition.delay === "number"
? transition.delay
: 2.5
useEffect(() => {
if (isStatic || !autoplay || n < 2) return
const ms = Math.max(0.3, delay) * 1000
const dir = autoplayDirection === "leftToRight" ? -1 : 1
const id = window.setInterval(() => step(dir), ms)
return () => window.clearInterval(id)
}, [isStatic, autoplay, autoplayDirection, delay, n, step])
const onKeyDown = useCallback(
(e: React.KeyboardEvent) => {
if (e.key === "ArrowRight") {
e.preventDefault()
step(1)
} else if (e.key === "ArrowLeft") {
e.preventDefault()
step(-1)
}
},
[step]
)
const { dur, ease } = cssTransition(transition)
const transitionCss = `transform ${dur}s ${ease}, opacity ${dur}s ${ease}`
// Rounded scale 0–20: boxy at 0, fully rounded (pill on the short axis) at 20.
const effectiveRadius =
(Math.max(0, Math.min(20, radius)) / 20) *
(Math.min(cardWidth, cardHeight) / 2)
// Inactive opacity: 100% = fully visible, 0% = hidden. Overlay is the inverse.
const dim = 1 - Math.max(0, Math.min(100, opacity)) / 100
const rootStyle: CSSProperties = {
...(style || {}),
position: "relative",
width: "100%",
height: "100%",
minWidth: 320,
minHeight: 360,
display: "flex",
alignItems: "center",
justifyContent: "center",
perspective: `${PERSPECTIVE}px`,
overflow: "hidden",
outline: "none",
}
return (
{list.map((slide, i) => {
let rel = i - active
if (loop) {
if (rel > n / 2) rel -= n
if (rel < -n / 2) rel += n
}
const ax = Math.abs(rel)
const visible = ax <= MAX_VISIBLE
const isActive = rel === 0
const sc = Math.max(0.4, 1 - ax * SCALE_STEP)
// Gap 0–20 → spacing 0 (stacked) to ~600px (far apart).
const tx = rel * (gap * 30)
const tz = -ax * DEPTH
const ry = -rel * tilt
const rz = rel * sideTilt
const src = slide.image?.src || ""
const cardStyle: CSSProperties = {
position: "absolute",
left: "50%",
top: "50%",
width: cardWidth,
height: cardHeight,
borderRadius: effectiveRadius,
overflow: "hidden",
transformStyle: "preserve-3d",
transformOrigin: "center center",
transform: `translate(-50%, -50%) translateX(${tx}px) translateZ(${tz}px) rotateY(${ry}deg) rotateZ(${rz}deg) scale(${sc})`,
transition: transitionCss,
opacity: visible ? 1 : 0,
cursor: autoplay || isActive ? "default" : "pointer",
pointerEvents:
visible && !isStatic && !autoplay ? "auto" : "none",
backgroundColor: "#1a1a1a",
}
return (
handleCardClick(i)
}
aria-label={slide.title}
aria-hidden={!visible}
>
{src ? (

) : null}
{showTitle && (
<>
{/* Gradient for legibility (matches corner) */}
{/* Title at chosen corner */}
{slide.title}
>
)}
{/* Dim overlay (darkens inactive cards entirely) */}
)
})}
)
}
const COMPONENT_DEFAULTS = {
slides: [
{
image: {
src: "https://imagedelivery.net/IEUjvl3YUlxY-MrTpOAWDQ/7d4d2641-d6a8-4fef-e85c-b12ed100d500/w=800",
},
title: "James Walker",
},
{
image: {
src: "https://imagedelivery.net/IEUjvl3YUlxY-MrTpOAWDQ/933a7615-f4b6-4eae-8ed1-705fa0e24400/w=800",
},
title: "Olivia Carter",
},
{
image: {
src: "https://imagedelivery.net/IEUjvl3YUlxY-MrTpOAWDQ/859c75ea-953e-489e-be61-91a03a35d700/w=800",
},
title: "Amelia Foster",
},
{
image: {
src: "https://imagedelivery.net/IEUjvl3YUlxY-MrTpOAWDQ/31afae9c-5ba3-4ec3-2534-ed8198ed1100/w=800",
},
title: "Benjamin Harris",
},
{
image: {
src: "https://imagedelivery.net/IEUjvl3YUlxY-MrTpOAWDQ/ed7b1c40-3332-43d8-a9eb-4615ef341b00/w=800",
},
title: "Lucas Martin",
},
],
cardWidth: 400,
cardHeight: 400,
radius: 3,
tilt: 12,
sideTilt: 8,
gap: 8,
opacity: 60,
autoplay: false,
autoplayDirection: "rightToLeft",
transition: {
type: "tween",
duration: 0.6,
delay: 2.5,
ease: [0.22, 1, 0.36, 1],
},
showTitle: true,
titleFont: {
fontFamily: "Inter",
variant: "Bold",
fontSize: "28px",
letterSpacing: "-0.02em",
lineHeight: "1.1em",
} as any,
titleColor: "#ffffff",
titlePosition: {
position: "bottomLeft",
paddingLeft: 22,
paddingRight: 22,
paddingTop: 24,
paddingBottom: 24,
},
}
Paso 2 de 2
Realizar Pago
$20.00
Datos Bancarios
Banco: Guayaquil
Tipo: Ahorro
Cuenta: 0023261485
Titular: Karen Mina
CI: 1312458324
Paga de forma rápida y segura a través de PayPhone.
Aceptamos tarjetas
Abrir Link de Pago
¡Gracias, !
Tu pago para el número está en verificación.
Tu Código de Transacción
Cópialo y úsalo en el buscador de la pantalla principal para verificar tu participación.
🎉
¡Felicidades!
es la propietaria del número
y ya está participando en el
💖 GRAN CONCURSO DE BELLEZA del dia de las madres💖
📍 A realizarse en el salón Karen Secret's
🌟 Premio VIP exclusivo incluye:
- 💆♀️ Masaje relajante (1 hora)
- 💐 Hermoso ramo de flores
- ✨ Limpieza facial profesional
- 🧵 Depilación (cejas con hilo o cera + bozo)
- 👁️ Pestañas de punto + maquillaje social
- 💇♀️ Mechas profesionales (marca Lenda)
- 🎨 Cobertura de canas (si aplica)
- ✂️ Corte de puntas o asesorado por estilista
- 💧 Hidratación capilar intensiva con ampollas
- 💅 Manicure + pedicure (técnica a elección: Builder Gel, Soft Gel, etc.)
- 🧴 Kit capilar completo (duración 2 meses):
shampoo, mascarilla, tratamiento, termoprotector, ampollas y aceite hidratante con delicioso aroma 🍪
🔥 ¡Te deseamos mucha suerte!
💖 Este puede ser tu momento… ¡brillar como nunca y con poca inversion!