Film Strip Carousel
A film strip with orange sprocket holes top and bottom, carrying 16:9 launch cards that advance on their own. Each frame has a slanted headline; on hover the card gets an orange ring, the title changes color and playback pauses. Arrows hide at either end.
Taken from the page template Ranzhen AI Video Studio Home. Use it on its own, or combine it with the other components from the same template to rebuild the full page.
Plain HTML, CSS and a little vanilla JS, with no framework dependency. Copy the prompt into Claude Code, Cursor, Trae or Codex and the model adds Film Strip Carousel to your project in your colors.
Where to use it
Image comparisons, video showcases, galleries, carousels and media cards.
Install
With Builder, install it with the 8pt CLI or call it directly from an editor connected to 8pt MCP.
Code
Source for Film Strip Carousel. Motion uses only transform and opacity and respects the Reduce motion setting.
<div class="x-rzf"><div class="x-rzf__in" style="width:900px;height:300px"> <button class="x-rzf__a p" type="button" aria-label="Previous"><svg viewBox="0 0 24 24"><path d="M15 6l-6 6 6 6"/></svg></button> <div class="x-rzf__t"><a class="x-rzf__c" href="#"><span class="x-rzf__im" style="background-image:url(https://8pt.dev/assets/tpl/ranzhen/c3.webp)"><em>Dreamdraw 5.5</em></span><b>Dreamdraw 5.5</b><small>100 rounds of edits, and the look never drifts</small></a><a class="x-rzf__c" href="#"><span class="x-rzf__im" style="background-image:url(https://8pt.dev/assets/tpl/ranzhen/s3.webp)"><em>Story short</em></span><b>Story short</b><small>High-converting story videos for any platform</small></a><a class="x-rzf__c" href="#"><span class="x-rzf__im" style="background-image:url(https://8pt.dev/assets/tpl/ranzhen/c7.webp)"><em>Cinematic shots</em></span><b>Cinematic shots</b><small>Director-level control with built-in pro color grading</small></a><a class="x-rzf__c" href="#"><span class="x-rzf__im" style="background-image:url(https://8pt.dev/assets/tpl/ranzhen/p6.webp)"><em>Motion design</em></span><b>Motion design</b><small>Bring every frame to life</small></a><a class="x-rzf__c" href="#"><span class="x-rzf__im" style="background-image:url(https://8pt.dev/assets/tpl/ranzhen/h6.webp)"><em>AI Digital twin</em></span><b>AI Digital twin</b><small>Create an avatar, then ride the trends</small></a><a class="x-rzf__c" href="#"><span class="x-rzf__im" style="background-image:url(https://8pt.dev/assets/tpl/ranzhen/c1.webp)"><em>Recast challenge</em></span><b>Recast challenge</b><small>Make it go viral, see the winners</small></a></div> <button class="x-rzf__a n" type="button" aria-label="Next"><svg viewBox="0 0 24 24"><path d="M9 6l6 6-6 6"/></svg></button> </div></div>
.x-rzf{position:relative;flex:none}
.x-rzf__in{position:absolute;left:0;top:0;transform-origin:0 0;display:flex;align-items:center;padding:22px 0;border-radius:18px;overflow:hidden;background:linear-gradient(180deg,#1a0904,#3b1306 50%,#1d0904);font-family:var(--d-font,system-ui,sans-serif);color:#fff;box-sizing:border-box}
.x-rzf__in::before,.x-rzf__in::after{content:"";position:absolute;left:0;right:0;height:9px;background:repeating-linear-gradient(90deg,rgba(255,90,31,.6) 0 13px,transparent 13px 27px)}
.x-rzf__in::before{top:6px}.x-rzf__in::after{bottom:6px}
.x-rzf__t{display:flex;gap:16px;width:100%;overflow-x:auto;scroll-snap-type:x mandatory;scrollbar-width:none;padding:4px 20px;scroll-padding:0 20px}
.x-rzf__t::-webkit-scrollbar{display:none}
.x-rzf__c{flex:none;width:250px;scroll-snap-align:start;border-radius:14px;overflow:hidden;background:linear-gradient(180deg,#1d0c07,#2b1008);box-shadow:0 0 0 1px rgba(255,120,60,.2);color:inherit;text-decoration:none;transition:box-shadow .3s}
.x-rzf__im{position:relative;display:block;aspect-ratio:16/9;background:center/cover no-repeat}
.x-rzf__im em{position:absolute;left:0;right:0;bottom:8px;text-align:center;font:italic 900 26px/1 Impact,"Arial Narrow",var(--d-font,sans-serif);color:#FF5A1F;text-shadow:0 2px 0 #4a1102,0 0 18px rgba(0,0,0,.6)}
.x-rzf__c b{display:block;padding:12px 14px 0;font-size:14.5px;font-weight:600;transition:color .25s}
.x-rzf__c small{display:block;padding:2px 14px 14px;font-size:12px;color:#a9948c;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.x-rzf__c:hover,.x-rzf__c:focus-visible{outline:0;box-shadow:0 0 0 2px #FF5A1F,0 0 26px rgba(255,90,31,.4)}.x-rzf__c:hover b,.x-rzf__c:focus-visible b{color:#FF8A3D}
…const init = (root) => {
const fit = (box, W, H) => {
const inner = box.firstElementChild;
const run = () => {
const cs = getComputedStyle(root);
const aw = root.clientWidth - parseFloat(cs.paddingLeft) - parseFloat(cs.paddingRight);
const ah = root.clientHeight - parseFloat(cs.paddingTop) - parseFloat(cs.paddingBottom);
if (aw <= 0 || ah <= 0) return;
const s = Math.max(0.2, Math.min(aw / W, ah / H, 1));
box.style.width = W * s + 'px'; box.style.height = H * s + 'px'; inner.style.transform = `scale(${s})`;
};
const ro = new ResizeObserver(run); ro.observe(root); run();
…