Imported library

← Imported library
Free sampleMIT licence

Curved gallery

carousel

Carousel from davidjerleke/embla-carousel.

From prompt to live site

  1. 01

    Copy the code

    Grab every file as one text, each carrying its licence notice.

  2. 02

    Paste into your AI

    Drop it into Claude, Cursor or v0 — or straight into your own project.

  3. 03

    Launch it live

    Adapt the copy, wire your data, and ship — with the notice kept alongside.

Read the full code
Curved gallery
davidjerleke/embla-carousel@85a5e3cdb697 · 4 code file(s)

Licence notice — required by the licence; keep it with this code:

MIT License

Copyright (c) David Jerleke.

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

Modifications (CreativePower): converted on 2026-09-30 from davidjerleke/embla-carousel@85a5e3cdb697 (website/src/content/v9/sandboxes/Vanilla/SandboxFilesSrc/Predefined/Scale/EmblaCarouselTweenScale.ts, website/src/content/v9/examples/Predefined/Tween/Scale.ts, packages/embla-carousel/src/components/ScrollBody.ts) into CreativePower's native pattern format — rewritten as plain HTML, CSS and JavaScript on design tokens, with the source's demo imagery, fonts and copy replaced by slots and token-driven defaults.

--- pattern.html ---
<!DOCTYPE html>
<!--
MIT License

Copyright (c) David Jerleke.

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

Modifications (CreativePower): converted on 2026-09-30 from davidjerleke/embla-carousel@85a5e3cdb697 (website/src/content/v9/sandboxes/Vanilla/SandboxFilesSrc/Predefined/Scale/EmblaCarouselTweenScale.ts, website/src/content/v9/examples/Predefined/Tween/Scale.ts, packages/embla-carousel/src/components/ScrollBody.ts) into CreativePower's native pattern format — rewritten as plain HTML, CSS and JavaScript on design tokens, with the source's demo imagery, fonts and copy replaced by slots and token-driven defaults.
-->
<html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1"><title>Curved gallery</title>
<style>html,body{margin:0;min-height:100%;background:#07070c}body{-webkit-font-smoothing:antialiased}</style>
<style>/* Curved gallery — CreativePower showpiece, converted from davidjerleke/embla-carousel@85a5e3cdb697 (website/src/content/v9/sandboxes/Vanilla/SandboxFilesSrc/Predefined/Scale/EmblaCarouselTweenScale.ts, website/src/content/v9/examples/Predefined/Tween/Scale.ts, packages/embla-carousel/src/components/ScrollBody.ts), by David Jerleke., under the MIT licence. The full licence notice travels with this pattern (its library item's NOTICE.txt). */
[data-sp="curved-gallery"]{
  --sp-a: var(--color-primary, #7c5cff);
  --sp-b: var(--color-secondary, #ff5c8a);
  --sp-ground: #07070c;
  --sp-ink: #f4f4f8;
  --sp-dim: color-mix(in oklab, var(--sp-ink) 62%, transparent);
  --sp-line: color-mix(in oklab, var(--sp-ink) 14%, transparent);
  --sp-radius: var(--ds-radius, 14px);
  --sp-radius-lg: var(--ds-radius-lg, 24px);
  --sp-font-display: var(--ds-font-display, "Inter", system-ui, sans-serif);
  --sp-font-body: var(--ds-font-body, "Inter", system-ui, sans-serif);
  --sp-font-mono: var(--ds-font-mono, ui-monospace, "SFMono-Regular", monospace);
  position: relative; isolation: isolate; overflow: hidden;
  min-height: 100vh; width: 100%;
  background: radial-gradient(120% 80% at 50% -10%, color-mix(in oklab, var(--sp-a) 22%, transparent), transparent 60%),
    radial-gradient(90% 70% at 100% 110%, color-mix(in oklab, var(--sp-b) 18%, transparent), transparent 60%), var(--sp-ground);
  color: var(--sp-ink); font-family: var(--sp-font-body);
}
@supports (color: oklch(from red l c h)) {
  [data-sp="curved-gallery"]{
    --sp-ground: oklch(from var(--color-on-surface, #0b0b12) min(l, 0.15) min(c, 0.04) h);
    --sp-ink: oklch(from var(--color-surface, #ffffff) max(l, 0.96) min(c, 0.02) h);
  }
}
[data-sp="curved-gallery"] *, [data-sp="curved-gallery"] *::before, [data-sp="curved-gallery"] *::after { box-sizing: border-box; }
[data-sp="curved-gallery"] :focus-visible { outline: 2px solid var(--sp-ink); outline-offset: 3px; }
[data-sp="curved-gallery"] .sp-art { position: relative; margin: 0; overflow: hidden; background-color: var(--sp-ground); }
[data-sp="curved-gallery"] .sp-art > img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; display: block; }
[data-sp="curved-gallery"] .sp-art::after { content: ""; position: absolute; inset: 0; pointer-events: none; opacity: .22; mix-blend-mode: overlay;
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='160' height='160'><filter id='n'><feTurbulence type='fractalNoise' baseFrequency='.9' numOctaves='2' stitchTiles='stitch'/></filter><rect width='100%' height='100%' filter='url(%23n)'/></svg>"); }
[data-sp="curved-gallery"] .sp-art:has(> img)::after { display: none; }
[data-sp="curved-gallery"] .sp-art[data-art="1"] { background-image: radial-gradient(120% 90% at 18% 12%, color-mix(in oklab, var(--sp-a) 92%, white 8%), transparent 58%), radial-gradient(90% 80% at 88% 92%, var(--sp-b), transparent 62%), linear-gradient(160deg, color-mix(in oklab, var(--sp-a) 40%, var(--sp-ground)), var(--sp-ground)); }
[data-sp="curved-gallery"] .sp-art[data-art="2"] { background-image: conic-gradient(from 210deg at 70% 30%, var(--sp-b), color-mix(in oklab, var(--sp-a) 70%, var(--sp-b)), var(--sp-a), var(--sp-b)); }
[data-sp="curved-gallery"] .sp-art[data-art="3"] { background-image: radial-gradient(60% 60% at 50% 40%, color-mix(in oklab, var(--sp-ink) 55%, var(--sp-a)), transparent 62%), linear-gradient(200deg, var(--sp-a), color-mix(in oklab, var(--sp-a) 30%, var(--sp-ground)) 70%); }
[data-sp="curved-gallery"] .sp-art[data-art="4"] { background-image: radial-gradient(80% 70% at 30% 80%, var(--sp-b), transparent 60%), radial-gradient(70% 60% at 75% 20%, color-mix(in oklab, var(--sp-b) 40%, var(--sp-ink)), transparent 55%), linear-gradient(20deg, color-mix(in oklab, var(--sp-b) 35%, var(--sp-ground)), var(--sp-ground)); }
[data-sp="curved-gallery"] .sp-art[data-art="5"] { background-image: repeating-linear-gradient(115deg, color-mix(in oklab, var(--sp-a) 85%, transparent) 0 14%, color-mix(in oklab, var(--sp-b) 80%, transparent) 14% 26%, transparent 26% 34%), linear-gradient(180deg, color-mix(in oklab, var(--sp-a) 30%, var(--sp-ground)), var(--sp-ground)); }
[data-sp="curved-gallery"] .sp-art[data-art="6"] { background-image: radial-gradient(40% 40% at 50% 55%, color-mix(in oklab, var(--sp-b) 85%, white 15%), transparent 70%), radial-gradient(100% 100% at 50% 100%, var(--sp-a), transparent 70%), linear-gradient(0deg, color-mix(in oklab, var(--sp-a) 30%, var(--sp-ground)), var(--sp-ground)); }
[data-sp="curved-gallery"] .sp-art[data-art="7"] { background-image: linear-gradient(135deg, var(--sp-a) 0%, color-mix(in oklab, var(--sp-a) 50%, var(--sp-b)) 45%, var(--sp-b) 100%); }
[data-sp="curved-gallery"] .sp-art[data-art="8"] { background-image: radial-gradient(90% 60% at 50% 0%, color-mix(in oklab, var(--sp-ink) 35%, var(--sp-b)), transparent 60%), radial-gradient(120% 90% at 0% 100%, var(--sp-a), transparent 60%), linear-gradient(90deg, color-mix(in oklab, var(--sp-b) 40%, var(--sp-ground)), var(--sp-ground)); }
@media (prefers-reduced-motion: reduce) {
  [data-sp="curved-gallery"] *, [data-sp="curved-gallery"] *::before, [data-sp="curved-gallery"] *::after { animation-duration: .001ms !important; animation-iteration-count: 1 !important; transition-duration: .001ms !important; scroll-behavior: auto !important; }
}
.cg-head{position:absolute;top:6.5vh;left:0;right:0;z-index:5;text-align:center;padding:0 24px;pointer-events:none}
.cg-eyebrow{font:500 12px/1 var(--sp-font-mono);letter-spacing:.3em;text-transform:uppercase;color:var(--sp-dim);margin:0 0 14px}
.cg-title{font:var(--ds-display-weight,600) clamp(28px,4.2vw,58px)/1 var(--sp-font-display);letter-spacing:var(--ds-display-tracking,-.025em);margin:0;
  background:linear-gradient(180deg,var(--sp-ink),color-mix(in oklab,var(--sp-ink) 50%,var(--sp-b)));-webkit-background-clip:text;background-clip:text;color:transparent}
.cg{position:absolute;inset:0}
.cg-glow{position:absolute;left:50%;top:52%;width:70vw;height:60vh;transform:translate(-50%,-50%);pointer-events:none;
  background:radial-gradient(50% 50% at 50% 50%,color-mix(in oklab,var(--sp-a) 26%,transparent),transparent 70%);filter:blur(20px)}
.cg-viewport{position:absolute;inset:0;perspective:1100px;perspective-origin:50% 52%;cursor:grab;touch-action:pan-y;outline:none;overflow:hidden}
.cg-viewport:focus-visible{outline:2px solid var(--sp-ink);outline-offset:-12px;border-radius:var(--sp-radius-lg)}
.cg.is-dragging .cg-viewport{cursor:grabbing}
.cg-row{position:absolute;left:50%;top:53%;width:0;height:0;transform-style:preserve-3d}
.cg-slide{position:absolute;left:0;top:0;width:var(--cg-w,300px);aspect-ratio:4/5;margin:0;transform-style:preserve-3d;will-change:transform,opacity;backface-visibility:hidden}
.cg-inner{position:absolute;inset:0;border-radius:var(--sp-radius-lg);overflow:hidden;will-change:transform;backface-visibility:hidden;
  box-shadow:0 40px 80px -36px rgb(0 0 0/.85),inset 0 0 0 1px var(--sp-line)}
.cg-inner .sp-art{position:absolute;inset:0}
.cg-veil{position:absolute;inset:0;background:var(--sp-ground);pointer-events:none}
.cg-cap{position:absolute;left:0;right:0;bottom:0;padding:18px 20px;display:grid;gap:7px;background:linear-gradient(180deg,transparent,rgb(0 0 0/.62))}
.cg-cap span{font:500 11px/1 var(--sp-font-mono);letter-spacing:.22em;text-transform:uppercase;color:var(--sp-dim)}
.cg-cap strong{font:600 clamp(16px,1.6vw,22px)/1.1 var(--sp-font-display);color:var(--sp-ink)}
.cg-ui{position:absolute;bottom:5vh;left:50%;transform:translateX(-50%);display:flex;align-items:center;gap:18px;z-index:5}
.cg-btn{width:46px;height:46px;border-radius:999px;border:1px solid var(--sp-line);background:color-mix(in oklab,var(--sp-ink) 8%,transparent);
  color:var(--sp-ink);display:grid;place-items:center;cursor:pointer;-webkit-backdrop-filter:blur(8px);backdrop-filter:blur(8px);transition:background .2s}
.cg-btn:hover{background:color-mix(in oklab,var(--sp-ink) 18%,transparent)}
.cg-btn svg{width:18px;height:18px}
.cg-progress{width:min(220px,40vw);height:3px;border-radius:99px;background:var(--sp-line);overflow:hidden;position:relative}
.cg-progress i{position:absolute;top:0;bottom:0;left:0;width:calc(100% / var(--cg-n,9));border-radius:inherit;background:linear-gradient(90deg,var(--sp-a),var(--sp-b))}
.sr-only{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap}</style>
</head><body>
<main class="sp-stage" data-sp="curved-gallery">
<header class="cg-head">
  <p class="cg-eyebrow" data-slot="eyebrow">Exhibition · Room two</p>
  <h2 class="cg-title" data-slot="title">A wall that bends toward you</h2>
</header>
<section class="cg" aria-roledescription="carousel" aria-label="Curved gallery">
  <div class="cg-glow"></div>
  <div class="cg-viewport" tabindex="0" aria-label="Plates — drag, scroll or use the arrow keys">
    <div class="cg-row">
      <article class="cg-slide" aria-roledescription="slide" aria-label="1 of 9">
        <div class="cg-inner">
          <figure class="sp-art" data-slot="image" data-art="1"></figure>
          <div class="cg-cap"><span data-slot="label">Plate I</span><strong data-slot="title">Morning glass</strong></div>
          <i class="cg-veil"></i>
        </div>
      </article>
      <article class="cg-slide" aria-roledescription="slide" aria-label="2 of 9">
        <div class="cg-inner">
          <figure class="sp-art" data-slot="image" data-art="2"></figure>
          <div class="cg-cap"><span data-slot="label">Plate II</span><strong data-slot="title">The quiet coast</strong></div>
          <i class="cg-veil"></i>
        </div>
      </article>
      <article class="cg-slide" aria-roledescription="slide" aria-label="3 of 9">
        <div class="cg-inner">
          <figure class="sp-art" data-slot="image" data-art="3"></figure>
          <div class="cg-cap"><span data-slot="label">Plate III</span><strong data-slot="title">Warm static</strong></div>
          <i class="cg-veil"></i>
        </div>
      </article>
      <article class="cg-slide" aria-roledescription="slide" aria-label="4 of 9">
        <div class="cg-inner">
          <figure class="sp-art" data-slot="image" data-art="4"></figure>
          <div class="cg-cap"><span data-slot="label">Plate IV</span><strong data-slot="title">Field notes</strong></div>
          <i class="cg-veil"></i>
        </div>
      </article>
      <article class="cg-slide" aria-roledescription="slide" aria-label="5 of 9">
        <div class="cg-inner">
          <figure class="sp-art" data-slot="image" data-art="5"></figure>
          <div class="cg-cap"><span data-slot="label">Plate V</span><strong data-slot="title">Slow orbit</strong></div>
          <i class="cg-veil"></i>
        </div>
      </article>
      <article class="cg-slide" aria-roledescription="slide" aria-label="6 of 9">
        <div class="cg-inner">
          <figure class="sp-art" data-slot="image" data-art="6"></figure>
          <div class="cg-cap"><span data-slot="label">Plate VI</span><strong data-slot="title">Afterglow</strong></div>
          <i class="cg-veil"></i>
        </div>
      </article>
      <article class="cg-slide" aria-roledescription="slide" aria-label="7 of 9">
        <div class="cg-inner">
          <figure class="sp-art" data-slot="image" data-art="7"></figure>
          <div class="cg-cap"><span data-slot="label">Plate VII</span><strong data-slot="title">Open water</strong></div>
          <i class="cg-veil"></i>
        </div>
      </article>
      <article class="cg-slide" aria-roledescription="slide" aria-label="8 of 9">
        <div class="cg-inner">
          <figure class="sp-art" data-slot="image" data-art="8"></figure>
          <div class="cg-cap"><span data-slot="label">Plate VIII</span><strong data-slot="title">Soft machines</strong></div>
          <i class="cg-veil"></i>
        </div>
      </article>
      <article class="cg-slide" aria-roledescription="slide" aria-label="9 of 9">
        <div class="cg-inner">
          <figure class="sp-art" data-slot="image" data-art="1"></figure>
          <div class="cg-cap"><span data-slot="label">Plate IX</span><strong data-slot="title">Last light</strong></div>
          <i class="cg-veil"></i>
        </div>
      </article>
    </div>
  </div>
  <p class="sr-only" aria-live="polite"></p>
  <div class="cg-ui">
    <button class="cg-btn" type="button" data-dir="-1" aria-label="Previous plate"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M15 18l-6-6 6-6"/></svg></button>
    <div class="cg-progress" aria-hidden="true"><i></i></div>
    <button class="cg-btn" type="button" data-dir="1" aria-label="Next plate"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M9 18l6-6-6-6"/></svg></button>
  </div>
</section>
</main>

<script>// Curved gallery — CreativePower showpiece, converted from davidjerleke/embla-carousel@85a5e3cdb697 (website/src/content/v9/sandboxes/Vanilla/SandboxFilesSrc/Predefined/Scale/EmblaCarouselTweenScale.ts, website/src/content/v9/examples/Predefined/Tween/Scale.ts, packages/embla-carousel/src/components/ScrollBody.ts), by David Jerleke., under the MIT licence. The full licence notice travels with this pattern (its library item's NOTICE.txt).
(function(){
  var root = document.querySelector('[data-sp="curved-gallery"]');
  if (!root) return;
  var reduced = window.matchMedia('(prefers-reduced-motion: reduce)').matches;
  // Embla's ScrollBody: velocity += displacement / duration; velocity *= friction (base 25 / 0.68).
  // Duration 0 is Embla's instant scroll, used under reduced motion.
  var DURATION = reduced ? 0 : 25, FRICTION = 0.68;
  // Embla's scale tween: tweenFactor = TWEEN_FACTOR_BASE * snapCount, tween = 1 - |diffToTarget * tweenFactor|.
  // With equal slides in a loop, diffToTarget is the slide offset / snapCount, so tween = 1 - 0.52 * |offset|.
  var TWEEN_FACTOR_BASE = 0.52;
  var ARC = 24; // degrees of cylinder per slide
  var wrapEl = root.querySelector('.cg');
  var vp = root.querySelector('.cg-viewport');
  var slides = [].slice.call(root.querySelectorAll('.cg-slide'));
  var inners = slides.map(function (s) { return s.querySelector('.cg-inner'); });
  var veils = slides.map(function (s) { return s.querySelector('.cg-veil'); });
  var bar = root.querySelector('.cg-progress i');
  var live = root.querySelector('[aria-live]');
  var n = slides.length, loc = 0, target = 0, vel = 0, raf = 0, w = 300, R = 1000;
  var startX = null, startLoc = 0, lastX = 0, dragVel = 0, wheelTimer = 0;
  root.style.setProperty('--cg-n', n);
  
  function clamp(v, a, b) { return Math.min(Math.max(v, a), b); }
  function wrap(d) { return ((d % n) + n + n / 2) % n - n / 2; }
  
  function measure() {
    w = clamp(Math.min(window.innerWidth * 0.23, window.innerHeight * 0.48), 180, 360);
    root.style.setProperty('--cg-w', w + 'px');
    R = (w * 0.9) / Math.sin(ARC * Math.PI / 180);
  }
  
  function render() {
    slides.forEach(function (el, i) {
      var d = wrap(i - loc);
      var phi = d * ARC * Math.PI / 180;
      var x = R * Math.sin(phi), z = R * (1 - Math.cos(phi));
      var tween = clamp(1 - Math.abs(d * TWEEN_FACTOR_BASE), 0, 1);
      el.style.transform = 'translate3d(' + (x - w / 2).toFixed(1) + 'px,' + (-w * 0.625).toFixed(1) + 'px,' + z.toFixed(1) + 'px) rotateY(' + (-d * ARC).toFixed(2) + 'deg)';
      el.style.opacity = String(clamp(3.3 - Math.abs(d), 0, 1));
      el.style.zIndex = String(100 - Math.round(Math.abs(d) * 10));
      inners[i].style.transform = 'scale(' + (0.66 + 0.34 * tween).toFixed(4) + ')';
      veils[i].style.opacity = ((1 - tween) * 0.55).toFixed(3);
    });
    var p = ((loc % n) + n) % n / n;
    bar.style.transform = 'translateX(' + (p * n * 100).toFixed(2) + '%)';
  }
  
  function seek() {
    if (!DURATION) { loc = target; vel = 0; return; }
    vel += (target - loc) / DURATION;
    vel *= FRICTION;
    loc += vel;
  }
  function tick() {
    seek();
    if (Math.abs(target - loc) < 0.001 && Math.abs(vel) < 0.001) { loc = target; vel = 0; raf = 0; render(); return; }
    render();
    raf = requestAnimationFrame(tick);
  }
  function run() {
    if (!DURATION) { loc = target; render(); return; }
    if (!raf) raf = requestAnimationFrame(tick);
  }
  function selected() { return ((Math.round(target) % n) + n) % n; }
  function announce() {
    var i = selected();
    slides.forEach(function (s, k) { s.setAttribute('aria-hidden', k === i ? 'false' : 'true'); });
    var t = slides[i].querySelector('strong');
    live.textContent = 'Plate ' + (i + 1) + ' of ' + n + (t ? ': ' + t.textContent : '');
  }
  function goTo(k) { target = k; announce(); run(); }
  
  root.querySelectorAll('[data-dir]').forEach(function (b) {
    b.addEventListener('click', function () { goTo(Math.round(target) + Number(b.getAttribute('data-dir'))); });
  });
  vp.addEventListener('keydown', function (e) {
    var k = Math.round(target), base = k - selected();
    if (e.key === 'ArrowRight') { goTo(k + 1); e.preventDefault(); }
    else if (e.key === 'ArrowLeft') { goTo(k - 1); e.preventDefault(); }
    else if (e.key === 'Home') { goTo(base); e.preventDefault(); }
    else if (e.key === 'End') { goTo(base + n - 1); e.preventDefault(); }
  });
  vp.addEventListener('pointerdown', function (e) {
    startX = lastX = e.clientX; startLoc = loc; dragVel = 0; vel = 0;
    wrapEl.classList.add('is-dragging'); vp.setPointerCapture(e.pointerId);
  });
  vp.addEventListener('pointermove', function (e) {
    if (startX === null) return;
    dragVel = (e.clientX - lastX) / w; lastX = e.clientX;
    loc = target = startLoc - (e.clientX - startX) / (w * 0.9);
    render();
  });
  function endDrag() {
    if (startX === null) return;
    startX = null; wrapEl.classList.remove('is-dragging');
    goTo(Math.round(loc - dragVel * 6));
  }
  vp.addEventListener('pointerup', endDrag);
  vp.addEventListener('pointercancel', endDrag);
  if (!reduced) {
    vp.addEventListener('wheel', function (e) {
      e.preventDefault();
      target += (Math.abs(e.deltaX) > Math.abs(e.deltaY) ? e.deltaX : e.deltaY) / (w * 2.2);
      run();
      clearTimeout(wheelTimer);
      wheelTimer = setTimeout(function () { goTo(Math.round(target)); }, 160);
    }, { passive: false });
  }
  window.addEventListener('resize', function () { measure(); render(); });
  measure();
  render();
  announce();
})();</script>
</body></html>

--- pattern.css ---
/*!
MIT License

Copyright (c) David Jerleke.

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

Modifications (CreativePower): converted on 2026-09-30 from davidjerleke/embla-carousel@85a5e3cdb697 (website/src/content/v9/sandboxes/Vanilla/SandboxFilesSrc/Predefined/Scale/EmblaCarouselTweenScale.ts, website/src/content/v9/examples/Predefined/Tween/Scale.ts, packages/embla-carousel/src/components/ScrollBody.ts) into CreativePower's native pattern format — rewritten as plain HTML, CSS and JavaScript on design tokens, with the source's demo imagery, fonts and copy replaced by slots and token-driven defaults.
*/
/* Curved gallery — CreativePower showpiece, converted from davidjerleke/embla-carousel@85a5e3cdb697 (website/src/content/v9/sandboxes/Vanilla/SandboxFilesSrc/Predefined/Scale/EmblaCarouselTweenScale.ts, website/src/content/v9/examples/Predefined/Tween/Scale.ts, packages/embla-carousel/src/components/ScrollBody.ts), by David Jerleke., under the MIT licence. The full licence notice travels with this pattern (its library item's NOTICE.txt). */
[data-sp="curved-gallery"]{
  --sp-a: var(--color-primary, #7c5cff);
  --sp-b: var(--color-secondary, #ff5c8a);
  --sp-ground: #07070c;
  --sp-ink: #f4f4f8;
  --sp-dim: color-mix(in oklab, var(--sp-ink) 62%, transparent);
  --sp-line: color-mix(in oklab, var(--sp-ink) 14%, transparent);
  --sp-radius: var(--ds-radius, 14px);
  --sp-radius-lg: var(--ds-radius-lg, 24px);
  --sp-font-display: var(--ds-font-display, "Inter", system-ui, sans-serif);
  --sp-font-body: var(--ds-font-body, "Inter", system-ui, sans-serif);
  --sp-font-mono: var(--ds-font-mono, ui-monospace, "SFMono-Regular", monospace);
  position: relative; isolation: isolate; overflow: hidden;
  min-height: 100vh; width: 100%;
  background: radial-gradient(120% 80% at 50% -10%, color-mix(in oklab, var(--sp-a) 22%, transparent), transparent 60%),
    radial-gradient(90% 70% at 100% 110%, color-mix(in oklab, var(--sp-b) 18%, transparent), transparent 60%), var(--sp-ground);
  color: var(--sp-ink); font-family: var(--sp-font-body);
}
@supports (color: oklch(from red l c h)) {
  [data-sp="curved-gallery"]{
    --sp-ground: oklch(from var(--color-on-surface, #0b0b12) min(l, 0.15) min(c, 0.04) h);
    --sp-ink: oklch(from var(--color-surface, #ffffff) max(l, 0.96) min(c, 0.02) h);
  }
}
[data-sp="curved-gallery"] *, [data-sp="curved-gallery"] *::before, [data-sp="curved-gallery"] *::after { box-sizing: border-box; }
[data-sp="curved-gallery"] :focus-visible { outline: 2px solid var(--sp-ink); outline-offset: 3px; }
[data-sp="curved-gallery"] .sp-art { position: relative; margin: 0; overflow: hidden; background-color: var(--sp-ground); }
[data-sp="curved-gallery"] .sp-art > img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; display: block; }
[data-sp="curved-gallery"] .sp-art::after { content: ""; position: absolute; inset: 0; pointer-events: none; opacity: .22; mix-blend-mode: overlay;
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='160' height='160'><filter id='n'><feTurbulence type='fractalNoise' baseFrequency='.9' numOctaves='2' stitchTiles='stitch'/></filter><rect width='100%' height='100%' filter='url(%23n)'/></svg>"); }
[data-sp="curved-gallery"] .sp-art:has(> img)::after { display: none; }
[data-sp="curved-gallery"] .sp-art[data-art="1"] { background-image: radial-gradient(120% 90% at 18% 12%, color-mix(in oklab, var(--sp-a) 92%, white 8%), transparent 58%), radial-gradient(90% 80% at 88% 92%, var(--sp-b), transparent 62%), linear-gradient(160deg, color-mix(in oklab, var(--sp-a) 40%, var(--sp-ground)), var(--sp-ground)); }
[data-sp="curved-gallery"] .sp-art[data-art="2"] { background-image: conic-gradient(from 210deg at 70% 30%, var(--sp-b), color-mix(in oklab, var(--sp-a) 70%, var(--sp-b)), var(--sp-a), var(--sp-b)); }
[data-sp="curved-gallery"] .sp-art[data-art="3"] { background-image: radial-gradient(60% 60% at 50% 40%, color-mix(in oklab, var(--sp-ink) 55%, var(--sp-a)), transparent 62%), linear-gradient(200deg, var(--sp-a), color-mix(in oklab, var(--sp-a) 30%, var(--sp-ground)) 70%); }
[data-sp="curved-gallery"] .sp-art[data-art="4"] { background-image: radial-gradient(80% 70% at 30% 80%, var(--sp-b), transparent 60%), radial-gradient(70% 60% at 75% 20%, color-mix(in oklab, var(--sp-b) 40%, var(--sp-ink)), transparent 55%), linear-gradient(20deg, color-mix(in oklab, var(--sp-b) 35%, var(--sp-ground)), var(--sp-ground)); }
[data-sp="curved-gallery"] .sp-art[data-art="5"] { background-image: repeating-linear-gradient(115deg, color-mix(in oklab, var(--sp-a) 85%, transparent) 0 14%, color-mix(in oklab, var(--sp-b) 80%, transparent) 14% 26%, transparent 26% 34%), linear-gradient(180deg, color-mix(in oklab, var(--sp-a) 30%, var(--sp-ground)), var(--sp-ground)); }
[data-sp="curved-gallery"] .sp-art[data-art="6"] { background-image: radial-gradient(40% 40% at 50% 55%, color-mix(in oklab, var(--sp-b) 85%, white 15%), transparent 70%), radial-gradient(100% 100% at 50% 100%, var(--sp-a), transparent 70%), linear-gradient(0deg, color-mix(in oklab, var(--sp-a) 30%, var(--sp-ground)), var(--sp-ground)); }
[data-sp="curved-gallery"] .sp-art[data-art="7"] { background-image: linear-gradient(135deg, var(--sp-a) 0%, color-mix(in oklab, var(--sp-a) 50%, var(--sp-b)) 45%, var(--sp-b) 100%); }
[data-sp="curved-gallery"] .sp-art[data-art="8"] { background-image: radial-gradient(90% 60% at 50% 0%, color-mix(in oklab, var(--sp-ink) 35%, var(--sp-b)), transparent 60%), radial-gradient(120% 90% at 0% 100%, var(--sp-a), transparent 60%), linear-gradient(90deg, color-mix(in oklab, var(--sp-b) 40%, var(--sp-ground)), var(--sp-ground)); }
@media (prefers-reduced-motion: reduce) {
  [data-sp="curved-gallery"] *, [data-sp="curved-gallery"] *::before, [data-sp="curved-gallery"] *::after { animation-duration: .001ms !important; animation-iteration-count: 1 !important; transition-duration: .001ms !important; scroll-behavior: auto !important; }
}
.cg-head{position:absolute;top:6.5vh;left:0;right:0;z-index:5;text-align:center;padding:0 24px;pointer-events:none}
.cg-eyebrow{font:500 12px/1 var(--sp-font-mono);letter-spacing:.3em;text-transform:uppercase;color:var(--sp-dim);margin:0 0 14px}
.cg-title{font:var(--ds-display-weight,600) clamp(28px,4.2vw,58px)/1 var(--sp-font-display);letter-spacing:var(--ds-display-tracking,-.025em);margin:0;
  background:linear-gradient(180deg,var(--sp-ink),color-mix(in oklab,var(--sp-ink) 50%,var(--sp-b)));-webkit-background-clip:text;background-clip:text;color:transparent}
.cg{position:absolute;inset:0}
.cg-glow{position:absolute;left:50%;top:52%;width:70vw;height:60vh;transform:translate(-50%,-50%);pointer-events:none;
  background:radial-gradient(50% 50% at 50% 50%,color-mix(in oklab,var(--sp-a) 26%,transparent),transparent 70%);filter:blur(20px)}
.cg-viewport{position:absolute;inset:0;perspective:1100px;perspective-origin:50% 52%;cursor:grab;touch-action:pan-y;outline:none;overflow:hidden}
.cg-viewport:focus-visible{outline:2px solid var(--sp-ink);outline-offset:-12px;border-radius:var(--sp-radius-lg)}
.cg.is-dragging .cg-viewport{cursor:grabbing}
.cg-row{position:absolute;left:50%;top:53%;width:0;height:0;transform-style:preserve-3d}
.cg-slide{position:absolute;left:0;top:0;width:var(--cg-w,300px);aspect-ratio:4/5;margin:0;transform-style:preserve-3d;will-change:transform,opacity;backface-visibility:hidden}
.cg-inner{position:absolute;inset:0;border-radius:var(--sp-radius-lg);overflow:hidden;will-change:transform;backface-visibility:hidden;
  box-shadow:0 40px 80px -36px rgb(0 0 0/.85),inset 0 0 0 1px var(--sp-line)}
.cg-inner .sp-art{position:absolute;inset:0}
.cg-veil{position:absolute;inset:0;background:var(--sp-ground);pointer-events:none}
.cg-cap{position:absolute;left:0;right:0;bottom:0;padding:18px 20px;display:grid;gap:7px;background:linear-gradient(180deg,transparent,rgb(0 0 0/.62))}
.cg-cap span{font:500 11px/1 var(--sp-font-mono);letter-spacing:.22em;text-transform:uppercase;color:var(--sp-dim)}
.cg-cap strong{font:600 clamp(16px,1.6vw,22px)/1.1 var(--sp-font-display);color:var(--sp-ink)}
.cg-ui{position:absolute;bottom:5vh;left:50%;transform:translateX(-50%);display:flex;align-items:center;gap:18px;z-index:5}
.cg-btn{width:46px;height:46px;border-radius:999px;border:1px solid var(--sp-line);background:color-mix(in oklab,var(--sp-ink) 8%,transparent);
  color:var(--sp-ink);display:grid;place-items:center;cursor:pointer;-webkit-backdrop-filter:blur(8px);backdrop-filter:blur(8px);transition:background .2s}
.cg-btn:hover{background:color-mix(in oklab,var(--sp-ink) 18%,transparent)}
.cg-btn svg{width:18px;height:18px}
.cg-progress{width:min(220px,40vw);height:3px;border-radius:99px;background:var(--sp-line);overflow:hidden;position:relative}
.cg-progress i{position:absolute;top:0;bottom:0;left:0;width:calc(100% / var(--cg-n,9));border-radius:inherit;background:linear-gradient(90deg,var(--sp-a),var(--sp-b))}
.sr-only{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap}

--- pattern.js ---
/*!
MIT License

Copyright (c) David Jerleke.

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

Modifications (CreativePower): converted on 2026-09-30 from davidjerleke/embla-carousel@85a5e3cdb697 (website/src/content/v9/sandboxes/Vanilla/SandboxFilesSrc/Predefined/Scale/EmblaCarouselTweenScale.ts, website/src/content/v9/examples/Predefined/Tween/Scale.ts, packages/embla-carousel/src/components/ScrollBody.ts) into CreativePower's native pattern format — rewritten as plain HTML, CSS and JavaScript on design tokens, with the source's demo imagery, fonts and copy replaced by slots and token-driven defaults.
*/
// Curved gallery — CreativePower showpiece, converted from davidjerleke/embla-carousel@85a5e3cdb697 (website/src/content/v9/sandboxes/Vanilla/SandboxFilesSrc/Predefined/Scale/EmblaCarouselTweenScale.ts, website/src/content/v9/examples/Predefined/Tween/Scale.ts, packages/embla-carousel/src/components/ScrollBody.ts), by David Jerleke., under the MIT licence. The full licence notice travels with this pattern (its library item's NOTICE.txt).
(function(){
  var root = document.querySelector('[data-sp="curved-gallery"]');
  if (!root) return;
  var reduced = window.matchMedia('(prefers-reduced-motion: reduce)').matches;
  // Embla's ScrollBody: velocity += displacement / duration; velocity *= friction (base 25 / 0.68).
  // Duration 0 is Embla's instant scroll, used under reduced motion.
  var DURATION = reduced ? 0 : 25, FRICTION = 0.68;
  // Embla's scale tween: tweenFactor = TWEEN_FACTOR_BASE * snapCount, tween = 1 - |diffToTarget * tweenFactor|.
  // With equal slides in a loop, diffToTarget is the slide offset / snapCount, so tween = 1 - 0.52 * |offset|.
  var TWEEN_FACTOR_BASE = 0.52;
  var ARC = 24; // degrees of cylinder per slide
  var wrapEl = root.querySelector('.cg');
  var vp = root.querySelector('.cg-viewport');
  var slides = [].slice.call(root.querySelectorAll('.cg-slide'));
  var inners = slides.map(function (s) { return s.querySelector('.cg-inner'); });
  var veils = slides.map(function (s) { return s.querySelector('.cg-veil'); });
  var bar = root.querySelector('.cg-progress i');
  var live = root.querySelector('[aria-live]');
  var n = slides.length, loc = 0, target = 0, vel = 0, raf = 0, w = 300, R = 1000;
  var startX = null, startLoc = 0, lastX = 0, dragVel = 0, wheelTimer = 0;
  root.style.setProperty('--cg-n', n);
  
  function clamp(v, a, b) { return Math.min(Math.max(v, a), b); }
  function wrap(d) { return ((d % n) + n + n / 2) % n - n / 2; }
  
  function measure() {
    w = clamp(Math.min(window.innerWidth * 0.23, window.innerHeight * 0.48), 180, 360);
    root.style.setProperty('--cg-w', w + 'px');
    R = (w * 0.9) / Math.sin(ARC * Math.PI / 180);
  }
  
  function render() {
    slides.forEach(function (el, i) {
      var d = wrap(i - loc);
      var phi = d * ARC * Math.PI / 180;
      var x = R * Math.sin(phi), z = R * (1 - Math.cos(phi));
      var tween = clamp(1 - Math.abs(d * TWEEN_FACTOR_BASE), 0, 1);
      el.style.transform = 'translate3d(' + (x - w / 2).toFixed(1) + 'px,' + (-w * 0.625).toFixed(1) + 'px,' + z.toFixed(1) + 'px) rotateY(' + (-d * ARC).toFixed(2) + 'deg)';
      el.style.opacity = String(clamp(3.3 - Math.abs(d), 0, 1));
      el.style.zIndex = String(100 - Math.round(Math.abs(d) * 10));
      inners[i].style.transform = 'scale(' + (0.66 + 0.34 * tween).toFixed(4) + ')';
      veils[i].style.opacity = ((1 - tween) * 0.55).toFixed(3);
    });
    var p = ((loc % n) + n) % n / n;
    bar.style.transform = 'translateX(' + (p * n * 100).toFixed(2) + '%)';
  }
  
  function seek() {
    if (!DURATION) { loc = target; vel = 0; return; }
    vel += (target - loc) / DURATION;
    vel *= FRICTION;
    loc += vel;
  }
  function tick() {
    seek();
    if (Math.abs(target - loc) < 0.001 && Math.abs(vel) < 0.001) { loc = target; vel = 0; raf = 0; render(); return; }
    render();
    raf = requestAnimationFrame(tick);
  }
  function run() {
    if (!DURATION) { loc = target; render(); return; }
    if (!raf) raf = requestAnimationFrame(tick);
  }
  function selected() { return ((Math.round(target) % n) + n) % n; }
  function announce() {
    var i = selected();
    slides.forEach(function (s, k) { s.setAttribute('aria-hidden', k === i ? 'false' : 'true'); });
    var t = slides[i].querySelector('strong');
    live.textContent = 'Plate ' + (i + 1) + ' of ' + n + (t ? ': ' + t.textContent : '');
  }
  function goTo(k) { target = k; announce(); run(); }
  
  root.querySelectorAll('[data-dir]').forEach(function (b) {
    b.addEventListener('click', function () { goTo(Math.round(target) + Number(b.getAttribute('data-dir'))); });
  });
  vp.addEventListener('keydown', function (e) {
    var k = Math.round(target), base = k - selected();
    if (e.key === 'ArrowRight') { goTo(k + 1); e.preventDefault(); }
    else if (e.key === 'ArrowLeft') { goTo(k - 1); e.preventDefault(); }
    else if (e.key === 'Home') { goTo(base); e.preventDefault(); }
    else if (e.key === 'End') { goTo(base + n - 1); e.preventDefault(); }
  });
  vp.addEventListener('pointerdown', function (e) {
    startX = lastX = e.clientX; startLoc = loc; dragVel = 0; vel = 0;
    wrapEl.classList.add('is-dragging'); vp.setPointerCapture(e.pointerId);
  });
  vp.addEventListener('pointermove', function (e) {
    if (startX === null) return;
    dragVel = (e.clientX - lastX) / w; lastX = e.clientX;
    loc = target = startLoc - (e.clientX - startX) / (w * 0.9);
    render();
  });
  function endDrag() {
    if (startX === null) return;
    startX = null; wrapEl.classList.remove('is-dragging');
    goTo(Math.round(loc - dragVel * 6));
  }
  vp.addEventListener('pointerup', endDrag);
  vp.addEventListener('pointercancel', endDrag);
  if (!reduced) {
    vp.addEventListener('wheel', function (e) {
      e.preventDefault();
      target += (Math.abs(e.deltaX) > Math.abs(e.deltaY) ? e.deltaX : e.deltaY) / (w * 2.2);
      run();
      clearTimeout(wheelTimer);
      wheelTimer = setTimeout(function () { goTo(Math.round(target)); }, 160);
    }, { passive: false });
  }
  window.addEventListener('resize', function () { measure(); render(); });
  measure();
  render();
  announce();
})();

--- markup.html ---
<!--
MIT License

Copyright (c) David Jerleke.

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

Modifications (CreativePower): converted on 2026-09-30 from davidjerleke/embla-carousel@85a5e3cdb697 (website/src/content/v9/sandboxes/Vanilla/SandboxFilesSrc/Predefined/Scale/EmblaCarouselTweenScale.ts, website/src/content/v9/examples/Predefined/Tween/Scale.ts, packages/embla-carousel/src/components/ScrollBody.ts) into CreativePower's native pattern format — rewritten as plain HTML, CSS and JavaScript on design tokens, with the source's demo imagery, fonts and copy replaced by slots and token-driven defaults.
-->
<main class="sp-stage" data-sp="curved-gallery">
<header class="cg-head">
  <p class="cg-eyebrow" data-slot="eyebrow">Exhibition · Room two</p>
  <h2 class="cg-title" data-slot="title">A wall that bends toward you</h2>
</header>
<section class="cg" aria-roledescription="carousel" aria-label="Curved gallery">
  <div class="cg-glow"></div>
  <div class="cg-viewport" tabindex="0" aria-label="Plates — drag, scroll or use the arrow keys">
    <div class="cg-row">
      <article class="cg-slide" aria-roledescription="slide" aria-label="1 of 9">
        <div class="cg-inner">
          <figure class="sp-art" data-slot="image" data-art="1"></figure>
          <div class="cg-cap"><span data-slot="label">Plate I</span><strong data-slot="title">Morning glass</strong></div>
          <i class="cg-veil"></i>
        </div>
      </article>
      <article class="cg-slide" aria-roledescription="slide" aria-label="2 of 9">
        <div class="cg-inner">
          <figure class="sp-art" data-slot="image" data-art="2"></figure>
          <div class="cg-cap"><span data-slot="label">Plate II</span><strong data-slot="title">The quiet coast</strong></div>
          <i class="cg-veil"></i>
        </div>
      </article>
      <article class="cg-slide" aria-roledescription="slide" aria-label="3 of 9">
        <div class="cg-inner">
          <figure class="sp-art" data-slot="image" data-art="3"></figure>
          <div class="cg-cap"><span data-slot="label">Plate III</span><strong data-slot="title">Warm static</strong></div>
          <i class="cg-veil"></i>
        </div>
      </article>
      <article class="cg-slide" aria-roledescription="slide" aria-label="4 of 9">
        <div class="cg-inner">
          <figure class="sp-art" data-slot="image" data-art="4"></figure>
          <div class="cg-cap"><span data-slot="label">Plate IV</span><strong data-slot="title">Field notes</strong></div>
          <i class="cg-veil"></i>
        </div>
      </article>
      <article class="cg-slide" aria-roledescription="slide" aria-label="5 of 9">
        <div class="cg-inner">
          <figure class="sp-art" data-slot="image" data-art="5"></figure>
          <div class="cg-cap"><span data-slot="label">Plate V</span><strong data-slot="title">Slow orbit</strong></div>
          <i class="cg-veil"></i>
        </div>
      </article>
      <article class="cg-slide" aria-roledescription="slide" aria-label="6 of 9">
        <div class="cg-inner">
          <figure class="sp-art" data-slot="image" data-art="6"></figure>
          <div class="cg-cap"><span data-slot="label">Plate VI</span><strong data-slot="title">Afterglow</strong></div>
          <i class="cg-veil"></i>
        </div>
      </article>
      <article class="cg-slide" aria-roledescription="slide" aria-label="7 of 9">
        <div class="cg-inner">
          <figure class="sp-art" data-slot="image" data-art="7"></figure>
          <div class="cg-cap"><span data-slot="label">Plate VII</span><strong data-slot="title">Open water</strong></div>
          <i class="cg-veil"></i>
        </div>
      </article>
      <article class="cg-slide" aria-roledescription="slide" aria-label="8 of 9">
        <div class="cg-inner">
          <figure class="sp-art" data-slot="image" data-art="8"></figure>
          <div class="cg-cap"><span data-slot="label">Plate VIII</span><strong data-slot="title">Soft machines</strong></div>
          <i class="cg-veil"></i>
        </div>
      </article>
      <article class="cg-slide" aria-roledescription="slide" aria-label="9 of 9">
        <div class="cg-inner">
          <figure class="sp-art" data-slot="image" data-art="1"></figure>
          <div class="cg-cap"><span data-slot="label">Plate IX</span><strong data-slot="title">Last light</strong></div>
          <i class="cg-veil"></i>
        </div>
      </article>
    </div>
  </div>
  <p class="sr-only" aria-live="polite"></p>
  <div class="cg-ui">
    <button class="cg-btn" type="button" data-dir="-1" aria-label="Previous plate"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M15 18l-6-6 6-6"/></svg></button>
    <div class="cg-progress" aria-hidden="true"><i></i></div>
    <button class="cg-btn" type="button" data-dir="1" aria-label="Next plate"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M9 18l6-6-6-6"/></svg></button>
  </div>
</section>
</main>
Source and licence

Source: davidjerleke/embla-carousel@85a5e3cdb697

Author: David Jerleke.

Entry: website/src/content/v9/sandboxes/Vanilla/SandboxFilesSrc/Predefined/Scale/EmblaCarouselTweenScale.ts

  • Converted into the native showpiece "curved-gallery" (lib/motion-patterns/showpiece/curved-gallery.ts): plain HTML/CSS/JS on the design tokens, with slots for imagery and text. The shipped files are the conversion; the source files it was converted from (source.paths, at source.commit) are not shipped.
  • Passed step 7 on 2026-09-30: render, reduced, keyboard, noTrap, tokens, slots, notice, engines (scripts/ui-blocks/check-showpiece.ts).
MIT License

Copyright (c) David Jerleke.

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

Modifications (CreativePower): converted on 2026-09-30 from davidjerleke/embla-carousel@85a5e3cdb697 (website/src/content/v9/sandboxes/Vanilla/SandboxFilesSrc/Predefined/Scale/EmblaCarouselTweenScale.ts, website/src/content/v9/examples/Predefined/Tween/Scale.ts, packages/embla-carousel/src/components/ScrollBody.ts) into CreativePower's native pattern format — rewritten as plain HTML, CSS and JavaScript on design tokens, with the source's demo imagery, fonts and copy replaced by slots and token-driven defaults.
Files (4)
  • pattern.html (18,792 bytes)
  • pattern.css (8,457 bytes)
  • pattern.js (5,584 bytes)
  • markup.html (4,419 bytes)

Want the whole library?

Every item's prompt, code and instructions, with a CreativePower subscription.

See plans

More carousel templates