StrategicCreativeStrategicAuthentic

Creative design that makes brands stand out

Coverflow Gallery — Film Projects
(function() { const SLIDES = [ { image: "https://images.unsplash.com/photo-1485846234645-a62644f84728?w=800&q=80", title: "Proyecto 1" }, { image: "https://images.unsplash.com/photo-1536440136628-849c177e76a1?w=800&q=80", title: "Proyecto 2" }, { image: "https://images.unsplash.com/photo-1478720568477-152d9b164e26?w=800&q=80", title: "Proyecto 3" }, { image: "https://images.unsplash.com/photo-1440404653325-ab127d49abc1?w=800&q=80", title: "Proyecto 4" }, { image: "https://images.unsplash.com/photo-1517604931442-7e0c8ed2963c?w=800&q=80", title: "Proyecto 5" } ]; const CONFIG = { cardWidth: 486, cardHeight: 262, radius: 3, tilt: 12, sideTilt: 8, gap: 8, opacity: 60, autoplay: true, autoplayDirection: "rightToLeft", transition: { duration: 0.6, delay: 3, ease: [0.22, 1, 0.36, 1] }, showTitle: true, titleColor: "#ffffff", titlePosition: { position: "bottomLeft", paddingLeft: 22, paddingRight: 22, paddingTop: 24, paddingBottom: 24 } }; const PERSPECTIVE = 1600; const SCALE_STEP = 0.16; const MAX_VISIBLE = 2; const DEPTH = 240; let active = 0; let lock = false; let autoplayInterval = null; const n = SLIDES.length; const loop = true; const root = document.getElementById('coverflowRoot'); const stage = document.getElementById('coverflowStage'); const dotsWrap = document.getElementById('dotsWrap'); function cssTransition(t) { const dur = t && typeof t.duration === 'number' ? t.duration : 0.6; let ease = 'cubic-bezier(0.22, 1, 0.36, 1)'; const e = t && 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 = { linear: 'linear', easeIn: 'ease-in', easeOut: 'ease-out', easeInOut: 'ease-in-out' }; ease = map[e] || 'ease'; } return { dur, ease }; } const { dur, ease } = cssTransition(CONFIG.transition); const transitionCss = 'transform ' + dur + 's ' + ease + ', opacity ' + dur + 's ' + ease; const effectiveRadius = (Math.max(0, Math.min(20, CONFIG.radius)) / 20) * (Math.min(CONFIG.cardWidth, CONFIG.cardHeight) / 2); const dim = 1 - Math.max(0, Math.min(100, CONFIG.opacity)) / 100; const tp = CONFIG.titlePosition || {}; const corner = tp.position || 'bottomLeft'; const isTop = corner === 'topLeft' || corner === 'topRight'; const isRight = corner === 'topRight' || corner === 'bottomRight'; const padLeft = tp.paddingLeft !== undefined ? tp.paddingLeft : 22; const padRight = tp.paddingRight !== undefined ? tp.paddingRight : 22; const padTop = tp.paddingTop !== undefined ? tp.paddingTop : 24; const padBottom = tp.paddingBottom !== undefined ? tp.paddingBottom : 24; const cards = []; SLIDES.forEach((slide, i) => { const card = document.createElement('div'); card.className = 'coverflow-card'; card.setAttribute('role', 'group'); card.setAttribute('aria-roledescription', 'slide'); card.setAttribute('aria-label', slide.title); if (slide.image) { const img = document.createElement('img'); img.src = slide.image; img.alt = slide.title || ''; img.draggable = false; card.appendChild(img); } if (CONFIG.showTitle) { const gradient = document.createElement('div'); gradient.className = 'gradient-overlay'; gradient.style.background = isTop ? 'linear-gradient(0deg, rgba(0,0,0,0) 35%, rgba(0,0,0,0.7) 100%)' : 'linear-gradient(180deg, rgba(0,0,0,0) 35%, rgba(0,0,0,0.7) 100%)'; card.appendChild(gradient); const titleWrap = document.createElement('div'); titleWrap.className = 'title-wrap'; titleWrap.style.left = padLeft + 'px'; titleWrap.style.right = padRight + 'px'; titleWrap.style[isTop ? 'top' : 'bottom'] = (isTop ? padTop : padBottom) + 'px'; titleWrap.style.textAlign = isRight ? 'right' : 'left'; const span = document.createElement('span'); span.textContent = slide.title; span.style.color = CONFIG.titleColor; titleWrap.appendChild(span); card.appendChild(titleWrap); } const dimOverlay = document.createElement('div'); dimOverlay.className = 'dim-overlay'; dimOverlay.style.transition = 'opacity ' + dur + 's ' + ease; card.appendChild(dimOverlay); card.addEventListener('click', function() { if (lock) return; goTo(i); }); stage.appendChild(card); cards.push({ el: card, dimOverlay: dimOverlay }); }); const dots = []; SLIDES.forEach((_, i) => { const dot = document.createElement('div'); dot.className = 'dot' + (i === 0 ? ' active' : ''); dot.setAttribute('role', 'button'); dot.setAttribute('aria-label', 'Ir a ' + SLIDES[i].title); dot.addEventListener('click', function() { if (lock) return; goTo(i); }); dotsWrap.appendChild(dot); dots.push(dot); }); function update() { cards.forEach((item, 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); const tx = rel * (CONFIG.gap * 30); const tz = -ax * DEPTH; const ry = -rel * CONFIG.tilt; const rz = rel * CONFIG.sideTilt; const transform = 'translate(-50%, -50%) translateX(' + tx + 'px) translateZ(' + tz + 'px) rotateY(' + ry + 'deg) rotateZ(' + rz + 'deg) scale(' + sc + ')'; item.el.style.transform = transform; item.el.style.transition = transitionCss; item.el.style.opacity = visible ? 1 : 0; item.el.style.pointerEvents = visible ? 'auto' : 'none'; item.el.style.cursor = isActive ? 'default' : 'pointer'; item.el.setAttribute('aria-hidden', visible ? 'false' : 'true'); item.dimOverlay.style.opacity = isActive ? 0 : dim; }); dots.forEach((dot, i) => { dot.classList.toggle('active', i === active); }); } function lockInput() { lock = true; setTimeout(function() { lock = false; }, Math.max(50, dur * 1000)); } function step(dir) { if (lock) return; lockInput(); active = (((active + dir) % n) + n) % n; update(); } function goTo(index) { if (lock) return; lockInput(); active = index === active ? (active + 1) % n : index; update(); startAutoplay(); } root.addEventListener('keydown', function(e) { if (e.key === 'ArrowRight') { e.preventDefault(); step(1); } else if (e.key === 'ArrowLeft') { e.preventDefault(); step(-1); } }); function startAutoplay() { if (autoplayInterval) clearInterval(autoplayInterval); if (!CONFIG.autoplay || n < 2) return; const ms = Math.max(0.3, CONFIG.transition.delay || 2.5) * 1000; const dir = CONFIG.autoplayDirection === 'leftToRight' ? -1 : 1; autoplayInterval = setInterval(function() { step(dir); }, ms); } function stopAutoplay() { if (autoplayInterval) { clearInterval(autoplayInterval); autoplayInterval = null; } } root.addEventListener('mousemove', stopAutoplay); root.addEventListener('mouseleave', startAutoplay); update(); startAutoplay(); let touchStartX = 0; let touchEndX = 0; root.addEventListener('touchstart', function(e) { touchStartX = e.changedTouches[0].screenX; }, { passive: true }); root.addEventListener('touchend', function(e) { touchEndX = e.changedTouches[0].screenX; const diff = touchStartX - touchEndX; if (Math.abs(diff) > 50) { if (diff > 0) step(1); else step(-1); } }, { passive: true }); })();

Clients

Logo 1
Logo 2
Logo 3
Logo 4
Logo 5
Logo 6
Logo 7
Logo 8

Aliquam nulla

Sed ipsum dolor

Quis viverra nibh cras pulvinar mattis nunc sed fermentum et orci purus in mollis.

Aliquam nulla

Sed ipsum dolor

Quis viverra nibh cras pulvinar mattis nunc sed fermentum et orci purus in mollis.

Aliquam nulla

Sed ipsum dolor

Quis viverra nibh cras pulvinar mattis nunc sed fermentum et orci purus in mollis.

Aliquam nulla

Sed ipsum dolor

Quis viverra nibh cras pulvinar mattis nunc sed fermentum et orci purus in mollis.

Aliquam nulla

Sed ipsum dolor

Quis viverra nibh cras pulvinar mattis nunc sed fermentum et orci purus in mollis.

Jawa Creations For Carrd logo