CSS
/* ─── 02 Neon Lattice — 5×5 spinning cube matrix ──────────── */
.cd-nln {
--cd-nln-bg: #010208;
position: relative;
width: 100%;
height: 560px;
background: var(--cd-nln-bg);
overflow: hidden;
perspective: 1200px;
box-sizing: border-box;
}
.cd-nln *,
.cd-nln *::before,
.cd-nln *::after { box-sizing: border-box; margin: 0; padding: 0; }
.cd-nln .card {
position: absolute;
inset: 0;
display: flex;
align-items: center;
justify-content: center;
}
.cd-nln .cd-nln-grid {
position: absolute;
inset: 0;
background-image:
linear-gradient(rgba(0,220,255,0.035) 1px, transparent 1px),
linear-gradient(90deg, rgba(0,220,255,0.035) 1px, transparent 1px);
background-size: 42px 42px;
animation: cd-nln-grid-shift 30s linear infinite;
pointer-events: none;
}
@keyframes cd-nln-grid-shift {
from { background-position: 0 0; }
to { background-position: 42px 42px; }
}
.cd-nln .cd-nln-vignette {
position: absolute;
inset: 0;
background: radial-gradient(ellipse 75% 75% at 50% 50%, transparent 35%, rgba(1,2,8,0.94) 100%);
pointer-events: none;
}
.cd-nln .cd-nln-scanline {
position: absolute;
left: 0; right: 0;
height: 2px;
background: rgba(0, 220, 255, 0.06);
animation: cd-nln-scan 6s linear infinite;
pointer-events: none;
}
@keyframes cd-nln-scan {
from { top: -2px; }
to { top: 100%; }
}
/* Matrix */
.cd-nln .matrix {
display: grid;
grid-template-columns: repeat(5, 72px);
grid-template-rows: repeat(5, 72px);
gap: 22px;
transform-style: preserve-3d;
transform: rotateX(22deg) rotateY(-18deg);
transition: transform 0.5s cubic-bezier(0.23, 1, 0.32, 1);
position: relative;
z-index: 1;
}
.cd-nln .cube-wrap {
width: 72px;
height: 72px;
perspective: 600px;
display: flex;
align-items: center;
justify-content: center;
animation: cd-nln-glow-pulse var(--gp, 3s) ease-in-out infinite var(--gpd, 0s);
}
@keyframes cd-nln-glow-pulse {
0%,100% { opacity: 0.85; }
50% { opacity: 1; }
}
.cd-nln .cube {
width: 52px;
height: 52px;
position: relative;
transform-style: preserve-3d;
animation: cd-nln-spin var(--sd) linear infinite var(--dl);
}
.cd-nln .f {
position: absolute;
width: 52px;
height: 52px;
border: 1px solid rgba(255,255,255,0.04);
backface-visibility: visible;
}
.cd-nln .f-front { transform: translateZ(26px); }
.cd-nln .f-back { transform: translateZ(-26px) rotateY(180deg); }
.cd-nln .f-left { transform: translateX(-26px) rotateY(-90deg); }
.cd-nln .f-right { transform: translateX(26px) rotateY(90deg); }
.cd-nln .f-top { transform: translateY(-26px) rotateX(90deg); }
.cd-nln .f-bottom { transform: translateY(26px) rotateX(-90deg); }
/* Row 1 — Cyan */
.cd-nln .cube-wrap:nth-child(-n+5) .f-front { background: rgba(0,18,38,0.95); }
.cd-nln .cube-wrap:nth-child(-n+5) .f-back { background: rgba(0,12,28,0.95); }
.cd-nln .cube-wrap:nth-child(-n+5) .f-left { background: rgba(0,10,24,0.92); }
.cd-nln .cube-wrap:nth-child(-n+5) .f-right { background: rgba(0,14,30,0.92); }
.cd-nln .cube-wrap:nth-child(-n+5) .f-bottom { background: rgba(0,8,20,0.95); }
.cd-nln .cube-wrap:nth-child(-n+5) .f-top { background: #00e8ff; box-shadow: 0 0 18px #00e8ff, 0 0 40px rgba(0,232,255,0.5); }
.cd-nln .cube-wrap:nth-child(-n+5) { filter: drop-shadow(0 0 8px rgba(0,232,255,0.35)); }
/* Row 2 — Magenta */
.cd-nln .cube-wrap:nth-child(n+6):nth-child(-n+10) .f-front { background: rgba(28,0,38,0.95); }
.cd-nln .cube-wrap:nth-child(n+6):nth-child(-n+10) .f-back { background: rgba(20,0,28,0.95); }
.cd-nln .cube-wrap:nth-child(n+6):nth-child(-n+10) .f-left { background: rgba(16,0,24,0.92); }
.cd-nln .cube-wrap:nth-child(n+6):nth-child(-n+10) .f-right { background: rgba(22,0,32,0.92); }
.cd-nln .cube-wrap:nth-child(n+6):nth-child(-n+10) .f-bottom { background: rgba(12,0,18,0.95); }
.cd-nln .cube-wrap:nth-child(n+6):nth-child(-n+10) .f-top { background: #ff00ff; box-shadow: 0 0 18px #ff00ff, 0 0 40px rgba(255,0,255,0.5); }
.cd-nln .cube-wrap:nth-child(n+6):nth-child(-n+10) { filter: drop-shadow(0 0 8px rgba(255,0,255,0.35)); }
/* Row 3 — Lime */
.cd-nln .cube-wrap:nth-child(n+11):nth-child(-n+15) .f-front { background: rgba(0,22,8,0.95); }
.cd-nln .cube-wrap:nth-child(n+11):nth-child(-n+15) .f-back { background: rgba(0,15,5,0.95); }
.cd-nln .cube-wrap:nth-child(n+11):nth-child(-n+15) .f-left { background: rgba(0,12,4,0.92); }
.cd-nln .cube-wrap:nth-child(n+11):nth-child(-n+15) .f-right { background: rgba(0,18,6,0.92); }
.cd-nln .cube-wrap:nth-child(n+11):nth-child(-n+15) .f-bottom { background: rgba(0,10,3,0.95); }
.cd-nln .cube-wrap:nth-child(n+11):nth-child(-n+15) .f-top { background: #00ff66; box-shadow: 0 0 18px #00ff66, 0 0 40px rgba(0,255,102,0.5); }
.cd-nln .cube-wrap:nth-child(n+11):nth-child(-n+15) { filter: drop-shadow(0 0 8px rgba(0,255,102,0.35)); }
/* Row 4 — Amber */
.cd-nln .cube-wrap:nth-child(n+16):nth-child(-n+20) .f-front { background: rgba(30,14,0,0.95); }
.cd-nln .cube-wrap:nth-child(n+16):nth-child(-n+20) .f-back { background: rgba(22,10,0,0.95); }
.cd-nln .cube-wrap:nth-child(n+16):nth-child(-n+20) .f-left { background: rgba(18,8,0,0.92); }
.cd-nln .cube-wrap:nth-child(n+16):nth-child(-n+20) .f-right { background: rgba(24,12,0,0.92); }
.cd-nln .cube-wrap:nth-child(n+16):nth-child(-n+20) .f-bottom { background: rgba(14,6,0,0.95); }
.cd-nln .cube-wrap:nth-child(n+16):nth-child(-n+20) .f-top { background: #ffcc00; box-shadow: 0 0 18px #ffcc00, 0 0 40px rgba(255,204,0,0.5); }
.cd-nln .cube-wrap:nth-child(n+16):nth-child(-n+20) { filter: drop-shadow(0 0 8px rgba(255,204,0,0.35)); }
/* Row 5 — Rose */
.cd-nln .cube-wrap:nth-child(n+21) .f-front { background: rgba(32,0,12,0.95); }
.cd-nln .cube-wrap:nth-child(n+21) .f-back { background: rgba(22,0,8,0.95); }
.cd-nln .cube-wrap:nth-child(n+21) .f-left { background: rgba(18,0,6,0.92); }
.cd-nln .cube-wrap:nth-child(n+21) .f-right { background: rgba(26,0,10,0.92); }
.cd-nln .cube-wrap:nth-child(n+21) .f-bottom { background: rgba(12,0,4,0.95); }
.cd-nln .cube-wrap:nth-child(n+21) .f-top { background: #ff3080; box-shadow: 0 0 18px #ff3080, 0 0 40px rgba(255,48,128,0.5); }
.cd-nln .cube-wrap:nth-child(n+21) { filter: drop-shadow(0 0 8px rgba(255,48,128,0.35)); }
@keyframes cd-nln-spin {
from { transform: rotateX(var(--rx-start,0deg)) rotateY(var(--ry-start,0deg)) rotateZ(0deg); }
to { transform: rotateX(var(--rx-end,360deg)) rotateY(var(--ry-end,360deg)) rotateZ(var(--rz-end,0deg)); }
}
@media (max-width: 720px) {
.cd-nln .matrix {
grid-template-columns: repeat(5, 52px);
grid-template-rows: repeat(5, 52px);
gap: 16px;
}
.cd-nln .cube-wrap { width: 52px; height: 52px; }
.cd-nln .cube, .cd-nln .f { width: 40px; height: 40px; }
.cd-nln .f-front { transform: translateZ(20px); }
.cd-nln .f-back { transform: translateZ(-20px) rotateY(180deg); }
.cd-nln .f-left { transform: translateX(-20px) rotateY(-90deg); }
.cd-nln .f-right { transform: translateX(20px) rotateY(90deg); }
.cd-nln .f-top { transform: translateY(-20px) rotateX(90deg); }
.cd-nln .f-bottom { transform: translateY(20px) rotateX(-90deg); }
}
@media (prefers-reduced-motion: reduce) {
.cd-nln .cd-nln-grid,
.cd-nln .cd-nln-scanline,
.cd-nln .cube-wrap,
.cd-nln .cube { animation: none !important; }
} JS
(() => {
const root = document.querySelector('.cd-nln');
if (!root) return;
const matrix = root.querySelector('[data-cd-nln-matrix]');
if (!matrix) return;
// Build cubes
const axes = [
[360, 360, 0], [360, 0, 0], [0, 360, 0],
[0, 0, 360], [360, 360, 360], [-360, 360, 0], [360, -360, 0],
];
for (let i = 0; i < 25; i++) {
const ax = axes[Math.floor(Math.random() * axes.length)];
const sd = (Math.random() * 8 + 3).toFixed(1) + 's';
const dl = (-Math.random() * 12).toFixed(2) + 's';
const gp = (Math.random() * 3 + 2).toFixed(1) + 's';
const gpd = (-Math.random() * 5).toFixed(2) + 's';
const rxStart = Math.random() * 360;
const ryStart = Math.random() * 360;
const wrap = document.createElement('div');
wrap.className = 'cube-wrap';
wrap.style.cssText = `--gp:${gp}; --gpd:${gpd};`;
const cube = document.createElement('div');
cube.className = 'cube';
cube.style.cssText = `
--sd:${sd}; --dl:${dl};
--rx-start:${rxStart}deg; --ry-start:${ryStart}deg;
--rx-end:${rxStart + ax[0]}deg; --ry-end:${ryStart + ax[1]}deg; --rz-end:${ax[2]}deg;
`;
cube.innerHTML = '<div class="f f-front"></div><div class="f f-back"></div><div class="f f-left"></div><div class="f f-right"></div><div class="f f-top"></div><div class="f f-bottom"></div>';
wrap.appendChild(cube);
matrix.appendChild(wrap);
}
// Mouse parallax scoped to wrapper
const prefersReduced = window.matchMedia('(prefers-reduced-motion: reduce)').matches;
if (prefersReduced) return;
let tx = 22, ty = -18, cx = 22, cy = -18, rafId = null;
root.addEventListener('mousemove', e => {
const rect = root.getBoundingClientRect();
tx = 22 + ((e.clientY - rect.top) / rect.height - 0.5) * 25;
ty = -18 + ((e.clientX - rect.left) / rect.width - 0.5) * 30;
if (!rafId) rafId = requestAnimationFrame(animate);
});
root.addEventListener('mouseleave', () => { tx = 22; ty = -18; });
function animate() {
cx += (tx - cx) * 0.055;
cy += (ty - cy) * 0.055;
matrix.style.transform = `rotateX(${cx}deg) rotateY(${cy}deg)`;
if (Math.abs(tx - cx) > 0.05 || Math.abs(ty - cy) > 0.05) {
rafId = requestAnimationFrame(animate);
} else {
rafId = null;
}
}
})();