<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
<title>AI Grid - Geist Color Lab</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/geist@1.3.0/dist/fonts/geist.css">
<style>
:root {
--bg-dark: #070707;
--corner-radius: 45px;
--grid-gap: 12px;
}
html, body {
margin: 0;
padding: 0;
width: 100%;
height: 100%;
overflow: hidden;
background-color: var(--bg-dark);
display: flex;
justify-content: center;
align-items: center;
font-family: 'Geist Sans', -apple-system, sans-serif;
touch-action: none;
}
.grid-wrapper {
display: grid;
grid-template-columns: repeat(3, 340px);
grid-template-rows: repeat(3, 340px);
gap: var(--grid-gap);
padding: 20px;
transform-origin: center center;
}
.tile {
position: relative;
background-size: cover;
background-position: center;
padding: 45px;
display: flex;
flex-direction: column;
mask-image: radial-gradient(circle at var(--corner-radius) var(--corner-radius), black 100%, transparent 0);
mask-position: calc(var(--corner-radius) * -1) calc(var(--corner-radius) * -1);
border-radius: var(--corner-radius);
overflow: hidden;
transition: color 0.4s ease;
}
/* Color Tiles */
.black-tile { background-color: #0b0b0a; grid-column: 1; grid-row: 1; color: #fff; }
.purple-tile { background-color: #afa1ea; color: #000; grid-column: 3; grid-row: 1; }
.blue-tile { background-color: #0404e9; grid-column: 1; grid-row: 2 / 4; color: #fff; }
.white-tile { background-color: #ffffff; color: #000; grid-column: 2; grid-row: 2; }
.lime-tile { background-color: #c0bf34; color: #000; grid-column: 3; grid-row: 3; }
/* People Images */
.person-1 { grid-column: 2; grid-row: 1; background-image: url('https://images.unsplash.com/photo-1507003211169-0a1dd7228f2d?auto=format&fit=crop&q=80&w=800'); }
.person-2 { grid-column: 3; grid-row: 2; background-image: url('https://images.unsplash.com/photo-1494790108377-be9c29b29330?auto=format&fit=crop&q=80&w=800'); }
.person-3 { grid-column: 2; grid-row: 3; background-image: url('https://images.unsplash.com/photo-1539571696357-5a69c17a67c6?auto=format&fit=crop&q=80&w=800'); }
.title-input {
font-size: 32px;
font-weight: 900;
margin-bottom: 24px;
background: transparent;
border: none;
color: inherit;
font-family: 'Geist Sans', sans-serif;
outline: none;
width: 100%;
cursor: text;
letter-spacing: -0.04em;
text-transform: capitalize;
}
.title-input::placeholder {
color: inherit;
opacity: 0.2;
}
.stats {
font-family: 'Geist Mono', monospace;
font-size: 14px;
font-weight: 500;
line-height: 2;
text-transform: uppercase;
pointer-events: none;
letter-spacing: 0.02em;
}
</style>
</head>
<body>
<div class="grid-wrapper" id="mainGrid">
<div class="tile color-tile black-tile">
<input type="text" class="title-input" value="Black" spellcheck="false">
<div class="stats">
<div class="hex-val">HEX : #0b0b0a</div>
<div class="rgb-val">RGB : 11, 10, 11</div>
</div>
</div>
<div class="tile person-1"></div>
<div class="tile color-tile purple-tile">
<input type="text" class="title-input" value="Cold Purple" spellcheck="false">
<div class="stats">
<div class="hex-val">HEX : #afa1ea</div>
<div class="rgb-val">RGB : 175, 234, 161</div>
</div>
</div>
<div class="tile color-tile blue-tile">
<input type="text" class="title-input" value="Medium Blue" spellcheck="false">
<div class="stats">
<div class="hex-val">HEX : #0404e9</div>
<div class="rgb-val">RGB : 4, 233, 4</div>
</div>
</div>
<div class="tile color-tile white-tile">
<input type="text" class="title-input" value="White" spellcheck="false">
<div class="stats">
<div class="hex-val">HEX : #ffffff</div>
<div class="rgb-val">RGB : 255, 255, 255</div>
</div>
</div>
<div class="tile person-2"></div>
<div class="tile person-3"></div>
<div class="tile color-tile lime-tile">
<input type="text" class="title-input" value="Key Lime" spellcheck="false">
<div class="stats">
<div class="hex-val">HEX : #c0bf34</div>
<div class="rgb-val">RGB : 192, 52, 191</div>
</div>
</div>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.12.2/gsap.min.js"></script>
<script>
const grid = document.getElementById('mainGrid');
function scaleToFit() {
const padding = 60;
const size = 1020 + 24;
const scale = Math.min((window.innerWidth - padding) / size, (window.innerHeight - padding) / size, 1);
gsap.to(grid, { scale: scale, duration: 0.3 });
}
window.addEventListener('resize', scaleToFit);
scaleToFit();
const hexToRgb = (hex) => {
if(!/^#([A-Fa-f0-9]{3}){1,2}$/.test(hex)) return null;
let c = hex.substring(1).split('');
if(c.length == 3) c = [c[0], c[0], c[1], c[1], c[2], c[2]];
c = '0x' + c.join('');
return [(c>>16)&255, (c>>8)&255, c&255].join(', ');
};
const getBrightness = (rgbStr) => {
const [r, g, b] = rgbStr.split(',').map(Number);
return (r * 299 + g * 587 + b * 114) / 1000;
};
const generateRandomHex = () => '#' + Math.floor(Math.random()*16777215).toString(16).padStart(6, '0');
async function fetchColorName(hex) {
try {
const cleanHex = hex.replace('#', '');
const response = await fetch(`https://api.color.pizza/v1/${cleanHex}`);
const data = await response.json();
return data.colors[0].name;
} catch (e) { return "Custom Color"; }
}
// Spacebar Logic
window.addEventListener('keydown', (e) => {
if (e.code === 'Space') {
e.preventDefault();
if (document.activeElement.tagName === 'INPUT') return;
document.querySelectorAll('.color-tile').forEach((tile, index) => {
const newHex = generateRandomHex();
setTimeout(async () => {
const rgb = hexToRgb(newHex);
const brightness = getBrightness(rgb);
gsap.to(tile, {
backgroundColor: newHex,
color: brightness > 125 ? "#000" : "#fff",
duration: 0.8,
ease: "expo.out"
});
tile.querySelector('.hex-val').textContent = `HEX : ${newHex}`;
tile.querySelector('.rgb-val').textContent = `RGB : ${rgb}`;
const name = await fetchColorName(newHex);
tile.querySelector('.title-input').value = name;
}, index * 60);
});
}
});
// Input Logic
document.querySelectorAll('.title-input').forEach(input => {
let originalName = "";
input.addEventListener('focus', function() {
originalName = this.value;
this.value = '';
const currentHex = this.closest('.tile').querySelector('.hex-val').textContent.split(': ')[1];
this.placeholder = currentHex;
});
input.addEventListener('keydown', (e) => {
if (e.key === 'Enter') input.blur();
});
input.addEventListener('blur', async function() {
const tile = this.closest('.tile');
const currentHex = tile.querySelector('.hex-val').textContent.split(': ')[1];
// If the user cleared it or didn't type a valid hex, revert to the name before focus
// Otherwise, get the name for the current hex in the tile
if (this.value.trim() === "") {
this.value = originalName;
} else {
const name = await fetchColorName(currentHex);
this.value = name;
}
});
input.addEventListener('input', function() {
let val = this.value;
if (val && !val.startsWith('#')) val = '#' + val;
const rgb = hexToRgb(val);
// Update visuals only if hex is valid 3 or 6 chars
if (rgb && (val.length === 7 || val.length === 4)) {
const tile = this.closest('.tile');
const brightness = getBrightness(rgb);
gsap.to(tile, {
backgroundColor: val,
color: brightness > 125 ? "#000" : "#fff",
duration: 0.5,
ease: "power2.out"
});
tile.querySelector('.hex-val').textContent = `HEX : ${val}`;
tile.querySelector('.rgb-val').textContent = `RGB : ${rgb}`;
}
});
});
// Initial Entry Animation
gsap.from(".tile", {
duration: 1.4,
scale: 0.7,
opacity: 0,
stagger: { grid: [3, 3], from: "center", amount: 0.6 },
ease: "expo.out"
});
</script>
</body>
</html>“Create a "AI Grid - Geist Color Lab" component. Use GSAP for advanced animations. Apply gradients. Color palette: #070707. Layout: CSS Grid, Flexbox. Interactivity: responsive resize handling. Includes form input fields.”