3D Marquee — Free HTML CSS JS Perspective Gallery Snippet

3D Marquee · Animations · Plain HTML, CSS & JS · Live preview

Share & Support

What's included

Features

Perspective tilt
rotateX + rotateZ lay the grid into space.
Alternating columns
data-dir scrolls neighbors opposite ways.
Seamless loop
Cloned tile sets and a 50% translate.
cloneNode duplication
Guarantees the two halves match exactly.
Themeable tiles
Random gradients, swappable for images.
Compositor-driven
Pure CSS keyframes, smooth on mobile.
Readable overlay
A radial scrim protects the headline.
Auto-filled columns
JavaScript populates every column.

About this UI Snippet

3D Marquee — Tilted Perspective Wall of Scrolling Tiles

Screenshot of the 3D Marquee snippet rendered live

The 3D marquee is the dramatic hero backdrop where a grid of image tiles is tilted back in perspective like a wall receding into the distance, with its columns endlessly scrolling in alternating directions — a living gallery behind your headline. This snippet builds it with plain HTML, CSS 3D transforms, and a little vanilla JavaScript to populate and loop the tiles.

Tilting the grid into perspective

The scene is a four-column CSS grid that's transformed with rotateX(52deg) rotateZ(-42deg). That combination lays the wall back and rotates it diagonally, so the flat grid reads as a large surface angling away into space — the signature isometric-ish look. It's sized larger than the viewport (1100×1100) and centered with translate(-50%, -50%) so the tilted plane covers the whole hero with no visible edges. No perspective property is needed here because the rotation alone, at this scale, produces the receding-wall illusion.

Columns that scroll in opposite directions

Each column animates vertically, but adjacent columns move opposite ways: columns marked data-dir="1" run the tmUp keyframe (translating to -50%), while data-dir="-1" columns run tmDown (from -50% back to 0). The counter-motion is what gives the wall its dynamic, woven feel — a single direction would look like one flat conveyor. Both keyframes are pure CSS, so the browser's compositor drives the scroll efficiently.

Seamless looping by duplication

To loop endlessly, each column is filled with a set of tiles and then an exact clone of that set, so the column is two identical halves. Animating by 50% (one half's height) means that when a column reaches the end of the first set, the cloned second set sits precisely where the first began — so the keyframe restart is invisible. The tiles are built in JavaScript and cloned with cloneNode(true), which is both concise and guarantees the two halves match exactly.

Image-free, themeable tiles

Each tile is a 4:3 rounded rectangle filled with a random gradient from a palette, with a soft drop shadow so the wall has depth. Using gradients keeps the snippet dependency-free and the wall colorful; swap the --g background for real image URLs to turn it into a portfolio or product wall without changing the layout or loop logic.

Keeping the headline readable

A radial .tm-overlay darkens the scene from a translucent center to near-opaque edges, so the bright tiles don't fight the text. The content sits above at a higher z-index with a soft text-shadow, so the headline stays crisp and centered over the busy, moving backdrop.

Customizing it

Change the rotateX/rotateZ angles to steepen or flatten the wall, adjust the animation duration for a faster or calmer drift, add or remove columns (each picks up its own direction from data-dir), or swap gradients for images. Tune the overlay stops to reveal more or less of the gallery. Pair it with a hero parallax grid elsewhere or a text generate headline for a bold landing page.

Build with AI

Build, Understand, Optimize, and Extend It With AI

You don't have to work through the loop math by hand — paste this snippet's HTML, CSS, and JS into an AI coding assistant like Claude and ask it to explain exactly why each column is filled with its tile set twice via cloneNode and animated by only 50 percent instead of 100, and why that specific combination is what makes the scroll appear seamless. The same assistant is useful for optimizing it — asking whether generating 48 tiles up front is wasteful on a mobile viewport, or whether swapping the gradient tiles for lazy-loaded real images would need an IntersectionObserver to avoid loading offscreen columns. It's just as good for extending the wall: ask it to make tiles clickable and open a lightbox, vary the rotateX/rotateZ tilt responsively so it flattens on narrow screens, or drive the gradient palette from a prop so the wall matches different brand themes. Treat the code less like a finished artifact and more like a starting point for a conversation.

Prompt to recreate it

Copy this into your AI assistant of choice to build the effect from scratch, or as a jumping-off point for your own variant:

text
Build a "3D marquee" hero background in plain HTML, CSS, and vanilla JavaScript — pure CSS keyframe animations for the motion, JS only to populate the tiles, no animation libraries.

Requirements:
- A grid container of four columns tilted into perspective using a combined transform of rotateX (around 52 degrees) and rotateZ (around -42 degrees), sized noticeably larger than the viewport and centered with translate(-50%, -50%) so no edge of the tilted plane is visible within the hero.
- Each column must scroll vertically forever using a CSS @keyframes animation set to linear timing and infinite iteration, and alternating columns (via a data attribute like data-dir) must scroll in opposite directions — one animating toward a negative translateY, the neighboring one animating from a negative translateY back to zero.
- To make each column's scroll loop seamlessly with no visible jump: generate one set of tile elements in JavaScript, clone that exact set with cloneNode(true), and append both the original and the clone to the column (so the column contains two identical halves back to back). The keyframe animation must move by exactly 50% (one half's height), not 100%, so when the loop restarts it lands on a frame identical to the start.
- Fill each tile with a random gradient background (from a small fixed palette) via a CSS custom property, keeping tiles dependency-free and swappable for real background-image URLs later.
- Add a radial-gradient overlay that darkens from a translucent center toward opaque edges, and center a headline and subtext above it at a higher z-index with a text-shadow, so the moving tile wall stays legible as a backdrop rather than fighting the text.

Want to tighten it up first? Run this prompt through the AI Prompt Studio to score it across 8 quality dimensions, catch anti-patterns, and tune the wording for Claude, ChatGPT, or Gemini before you paste it in.

Step by step

How to Use

  1. 1
    Paste HTML, CSS, and JSA tilted wall of colorful tiles fills the hero behind a headline.
  2. 2
    Watch the motionColumns scroll up and down in alternating directions, endlessly.
  3. 3
    Note the perspectiveThe grid angles away like a receding surface.
  4. 4
    Read the headlineA radial overlay keeps the centered text legible.
  5. 5
    Swap in imagesSet each tile's --g to a real image URL.
  6. 6
    Adjust the tiltChange the rotateX and rotateZ angles.

Real-world uses

Common Use Cases

Portfolio walls
Show work behind a portfolio hero.
Agency landing pages
Pair with a hero parallax grid section.
Product galleries
A moving backdrop for a text generate headline.
Event microsites
Set a vivid stage near a lamp header.
Photography sites
Tile real shots into a receding wall.
3D transform demos
A reference for tilted scrolling grids.
Related: AI Code Typing Preview
See the AI Code Typing Preview for a related animations pattern worth pairing with this one.

Got questions?

Frequently Asked Questions

The four-column grid is transformed with rotateX(52deg) and rotateZ(-42deg), which lays it back and rotates it diagonally so the flat grid reads as a surface receding into space. It's sized larger than the viewport and centered so the tilted plane covers the whole hero with no visible edges.

Each column is filled with a set of tiles and an exact clone of that set, making it two identical halves. The columns animate by 50% — one half's height — so when the first set scrolls away, the cloned set sits exactly where it began. The keyframe restart lands on an identical frame, so the loop is seamless.

Columns marked data-dir 1 run an upward keyframe and those marked -1 run a downward one. The counter-motion gives the wall a woven, dynamic feel; if every column scrolled the same way it would look like a single flat conveyor belt. Both keyframes are pure CSS so the compositor handles them efficiently.

Yes. Each tile is a 4:3 rounded box whose background comes from a --g custom property, set to a random gradient by default. Replace --g with a url() image (or swap the div for an img), and the perspective tilt, alternating scroll, and seamless loop all keep working unchanged.

Render the columns and generate the doubled tile lists from a data array in render. The tilt, alternating keyframes, and overlay are pure CSS. If you swap to images, map your URLs into the tiles. In Tailwind, build the grid with grid utilities, apply the rotateX/rotateZ via arbitrary transform values, and define the scroll keyframes in the config.