---
name: holographic-ui
description: Use when you want "Futuristic, premium, exotic" - Uses iridescent gradients, glow, and transparency to simulate holographic surfaces.
---

# Holographic UI

> **Category:** Premium / Futuristic  -  **Personality:** Futuristic, premium, exotic
>
> **Best use:** AI, Web3, advanced product sites
>
> **Ratings:** Professional 3/5 - Casual 3/5 - Exotic 5/5 - Visual impact 5/5 - Difficulty 4/5 - Performance cost 4/5

## What it is

Holographic UI simulates the iridescent, oil-slick foil of a physical holographic trading card or security hologram. A stack of wide rainbow gradients is blended over a dark surface with `mix-blend-mode: color-dodge` / `soft-light`, and the pointer drives the gradient offset, a specular glare and a subtle 3D tilt — so the colours shift and bloom as you move, exactly like tilting real foil under a light. It reads as exotic and premium, which is why AI, Web3 and high-end product sites use it for hero cards, passes and credentials.

## Dependencies / CDN

None - pure CSS for the effect (a few blended gradient layers) and None - vanilla JS for the pointer tracking. The demo only loads display/body fonts — optional:

```html
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Tektur:wght@700;800;900&family=Sora:wght@400;500;600;700&display=swap" rel="stylesheet">
```

## HTML

The card is the effect — four stacked layers (foil / grain / glare + a CSS `::before` wash) under the real content. The dark stage and aurora backdrop are optional dressing:

```html
<div class="hu-stage">
  <!-- ambient backdrop (optional) -->
  <div class="hu-bg" aria-hidden="true">
    <span class="hu-aurora hu-a1"></span>
    <span class="hu-aurora hu-a2"></span>
    <span class="hu-grid"></span>
  </div>

  <!-- THE HOLOGRAPHIC CARD -->
  <div class="hu-cardwrap">
    <article class="hu-card" id="huCard">
      <div class="hu-foil"  aria-hidden="true"></div>  <!-- oil-slick rainbow bands -->
      <div class="hu-grain" aria-hidden="true"></div>  <!-- micro sparkle near pointer -->
      <div class="hu-glare" aria-hidden="true"></div>  <!-- specular highlight -->
      <div class="hu-card-inner">
        <header class="hu-card-top">
          <span class="hu-card-kicker">Genesis Pass</span>
          <span class="hu-seal">&#9672; Verified</span>
        </header>
        <div class="hu-card-id">#0427</div>
        <div class="hu-tier">Tier &middot; <b>Iridescent</b></div>
        <div class="hu-foilchip" aria-hidden="true"></div>
        <div class="hu-stats">
          <div class="hu-stat"><span>Staked</span><b>12,400 PRISM</b></div>
          <div class="hu-stat"><span>Yield</span><b>18.6% APR</b></div>
        </div>
      </div>
    </article>
    <span class="hu-badge" aria-hidden="true">&#11042; Genesis</span>
  </div>
</div>
```

## CSS

```css
/* contained dark stage — the foil needs a dark base to read as metal */
.hu-stage{position:relative;border-radius:26px;overflow:hidden;isolation:isolate;
  min-height:620px;display:flex;align-items:center;justify-content:center;padding:54px 34px;
  background:radial-gradient(120% 120% at 12% 6%,#1b0a36 0,transparent 46%),#05050d;color:#eef0ff}

.hu-cardwrap{position:relative;perspective:1200px;display:flex;justify-content:center}

/* the card holds every pointer-driven custom property */
.hu-card{--mx:50%;--my:42%;--rx:0deg;--ry:0deg;--fx:36%;--fy:40%;--glow:0;
  position:relative;width:100%;max-width:392px;min-height:332px;border-radius:22px;overflow:hidden;
  transform:rotateX(var(--rx)) rotateY(var(--ry));
  transition:transform .3s cubic-bezier(.2,.7,.2,1),box-shadow .3s;
  background:linear-gradient(165deg,#12122c,#0a0a18 58%,#140a26);
  border:1px solid rgba(170,190,255,.18);
  box-shadow:0 30px 70px -24px rgba(0,0,0,.85);cursor:crosshair}

/* ambient iridescent wash — visible even at rest */
.hu-card::before{content:"";position:absolute;inset:0;z-index:1;pointer-events:none;
  background:conic-gradient(from 210deg at 30% 22%,#ff4ecd,#ffe267,#5dffba,#38e8ff,#6a7bff,#c46bff,#ff4ecd);
  mix-blend-mode:soft-light;opacity:.5}

/* oil-slick foil bands — THE signature layer */
.hu-foil{position:absolute;inset:0;z-index:2;pointer-events:none;
  background:repeating-linear-gradient(105deg,
    #ff4ecd 0%,#ff8a4c 7%,#ffe267 14%,#5dffba 21%,#38e8ff 28%,#6aa8ff 35%,#b07bff 42%,#ff4ecd 49%);
  background-size:300% 300%;background-position:var(--fx) var(--fy);
  mix-blend-mode:color-dodge;opacity:.4;filter:saturate(1.4) contrast(1.05);
  transition:background-position .25s ease,opacity .3s;animation:hu-slide 8s linear infinite}

/* micro sparkle, masked to a radius around the pointer */
.hu-grain{position:absolute;inset:0;z-index:3;pointer-events:none;
  background:repeating-linear-gradient(62deg,rgba(255,255,255,.08) 0 1px,transparent 1px 4px);
  mix-blend-mode:overlay;opacity:.55;
  -webkit-mask-image:radial-gradient(42% 42% at var(--mx) var(--my),#000,transparent 72%);
          mask-image:radial-gradient(42% 42% at var(--mx) var(--my),#000,transparent 72%)}

/* pointer specular glare — opacity tied to --glow */
.hu-glare{position:absolute;inset:0;z-index:4;pointer-events:none;
  background:radial-gradient(34% 34% at var(--mx) var(--my),rgba(255,255,255,.78),rgba(180,220,255,.22) 40%,transparent 66%);
  mix-blend-mode:overlay;opacity:calc(var(--glow) * .9);transition:opacity .3s}

/* while tracking: freeze the auto-slide so the pointer alone drives the foil */
.hu-card.is-live .hu-foil{animation:none;background-position:var(--fx) var(--fy);opacity:.58}
.hu-card.is-live{box-shadow:0 36px 84px -22px rgba(120,90,200,.6),0 0 44px -10px rgba(120,200,255,.4)}

/* real content sits ABOVE every foil layer */
.hu-card-inner{position:relative;z-index:5;height:100%;padding:22px 24px;display:flex;flex-direction:column}

@keyframes hu-slide{0%{background-position:0% 0%}100%{background-position:300% 0%}}

/* reduced motion → static iridescent sheen, no tracking, no tilt */
@media(prefers-reduced-motion:reduce){
  .hu-foil{animation:none;background-position:34% 36%;opacity:.48}
  .hu-glare{opacity:.42}
  .hu-card{transform:none}
}
```

## JavaScript

Pointer position is normalised to 0–1 and written as CSS custom properties; writes are coalesced into one `requestAnimationFrame`. Reduced-motion users bail before any listener is attached:

```js
(function(){
  var card=document.getElementById('huCard');
  if(!card)return;
  if(window.matchMedia&&matchMedia('(prefers-reduced-motion: reduce)').matches)return;

  var raf=null,pend=null;
  function apply(){
    raf=null;if(!pend)return;var p=pend;
    var s=card.style;
    s.setProperty('--mx',p.mx+'%');s.setProperty('--my',p.my+'%');
    s.setProperty('--fx',p.fx+'%');s.setProperty('--fy',p.fy+'%');
    s.setProperty('--rx',p.rx+'deg');s.setProperty('--ry',p.ry+'deg');
    s.setProperty('--glow','1');
  }
  card.addEventListener('pointermove',function(e){
    var r=card.getBoundingClientRect();
    var px=(e.clientX-r.left)/r.width, py=(e.clientY-r.top)/r.height;
    pend={
      mx:(px*100).toFixed(1), my:(py*100).toFixed(1),
      fx:(18+px*64).toFixed(1), fy:(18+py*64).toFixed(1),
      rx:(-(py-0.5)*16).toFixed(2), ry:((px-0.5)*18).toFixed(2)
    };
    card.classList.add('is-live');
    if(!raf)raf=requestAnimationFrame(apply);
  });
  card.addEventListener('pointerleave',function(){
    card.classList.remove('is-live');
    var s=card.style;
    s.setProperty('--rx','0deg');s.setProperty('--ry','0deg');
    s.setProperty('--mx','50%');s.setProperty('--my','42%');
    s.setProperty('--glow','0');
    s.removeProperty('--fx');s.removeProperty('--fy');
  });
})();
```

## How it works

- **Oversized rainbow gradients.** Each layer is a wide rainbow (`repeating-linear-gradient` for the foil bands, `conic-gradient` for the ambient wash) sized far larger than the card (`background-size:300%`), so only a thin slice is visible at any moment.
- **Blend modes do the metal.** `mix-blend-mode: color-dodge` (foil) and `soft-light` (wash) make those rainbows *interact* with the dark base instead of sitting on top — dark pixels stay dark, bright ones bloom into neon. That selective bloom is what sells "metallic foil"; a normal-blended rainbow just looks like a printed sticker.
- **The pointer writes CSS variables.** The handler sets `--fx/--fy` (foil `background-position`), `--mx/--my` (glare + sparkle-mask centre) and `--rx/--ry` (tilt). CSS `transition`s interpolate them, so moving the mouse re-slices the gradient and slides the highlight smoothly.
- **Glare + grain add specular detail.** `.hu-glare` is a radial white highlight in `overlay` blend whose opacity rides `--glow` (0 at rest → 1 while live); `.hu-grain` is a fine line pattern masked to a radius around the pointer for micro-sparkle.
- **Rest vs. live.** At rest the foil auto-animates via `hu-slide`; adding `.is-live` on `pointermove` freezes that keyframe so the pointer alone drives the foil, and `pointerleave` resets every variable to its centred default.

## Customization

- **Palette:** change the colour stops in `.hu-foil`, `.hu-card::before` and `.hu-foilchip`. Keep them saturated — pastels wash out to grey under `color-dodge`.
- **Intensity:** foil `opacity` (.4–.6), the `filter:saturate()/contrast()`, and the glare alpha control how "loud" the foil reads.
- **Tilt range:** the `*16` / `*18` multipliers in the JS set max rotation; `perspective` on `.hu-cardwrap` sets how dramatic the 3D feels.
- **Band texture:** `background-size` (bigger = wider, slower bands) plus the `repeating-linear-gradient` angle and percentage stops reshape the foil striping.
- **Base depth:** a darker `.hu-card` base gives the dodge more contrast to bloom against; the conic `::before` sets the resting rainbow at 50% opacity.

## Accessibility & performance

- **GPU-bound layers.** Several full-size blended gradients (plus blurred auroras) composite on the GPU. Animate only `background-position` / `transform` / `opacity` (the demo does); never animate `filter` blur radius or the gradient stops.
- **Stacking-context cost.** `mix-blend-mode` forces offscreen compositing — fine for one card, expensive if you tile dozens. Keep the effect to a hero element.
- **Text contrast.** Put real copy on `.hu-card-inner` (z-index above every foil layer) so the blended rainbow never sits over body text; the foil stays purely decorative and `aria-hidden`.
- **Reduced motion.** The `@media (prefers-reduced-motion: reduce)` block kills all keyframes and the tilt, leaving a static iridescent sheen, and the JS returns early via `matchMedia` so no pointer loop ever attaches.

## Gotchas

- **Needs a dark base.** `color-dodge` / `soft-light` only look metallic over a dark surface; over a light background they blow out to flat white.
- **Clip + isolate the card.** Without `overflow:hidden` + `isolation:isolate`, the blended layers composite against the whole page instead of just the card, and the rainbows leak.
- **Default the variables.** Custom properties need sane defaults (`--glow:0`, `--mx:50%`, …) or the first paint (before any `pointermove`) shows an off-centre glare; `pointerleave` must reset them.
- **Coalesce pointer writes.** `pointermove` fires very fast — buffer into a single `requestAnimationFrame` (the demo stores `pend` and rAF-flushes) or you thrash style recalc and stutter.
- **Tilt creates a containing block.** A 3D `rotate` on `.hu-card` establishes a new containing block; keep the foil/grain/glare as z-indexed children so they tilt *with* the card, and keep real content on the top layer.
