// chrome.jsx — Y2K visual primitives: chrome orbs, iridescent blobs, stars, stickers
const { useRef: __cr, useEffect: __ce, useState: __cs, useMemo: __cm } = React;
/* ════════════════════════════════════════════════════════
CHROME ORB
The signature element: a liquid metal 3D sphere
════════════════════════════════════════════════════════ */
function ChromeOrb({ size = 320, hue = 0, mouse, scrollOffset = 0, style = {}, kind = 'chrome' }) {
const ref = __cr(null);
const [rot, setRot] = __cs({ x: 0, y: 0 });
__ce(() => {
let raf;
let t = 0;
const tick = () => {
t += 0.4;
if (mouse) {
setRot({
x: (mouse.y - 0.5) * -30 + Math.sin(t * 0.01) * 4,
y: (mouse.x - 0.5) * 40 + t * 0.3,
});
} else {
setRot({ x: Math.sin(t * 0.012) * 8, y: t * 0.2 });
}
raf = requestAnimationFrame(tick);
};
raf = requestAnimationFrame(tick);
return () => cancelAnimationFrame(raf);
}, [mouse]);
const surfaces = {
chrome: {
conic: `conic-gradient(from ${rot.y}deg at 50% 50%,
#1a1a24 0deg,
#c8c4d8 25deg,
#f8f4ff 60deg,
#e8e0f0 90deg,
#4a4458 130deg,
#18141e 160deg,
#8a8498 200deg,
#f8f4ff 240deg,
#b8b0c8 280deg,
#2c2638 320deg,
#1a1a24 360deg)`,
glow: 'rgba(200, 200, 220, 0.4)',
},
iridescent: {
conic: `conic-gradient(from ${rot.y}deg at 50% 50%,
#FF3EA5 0deg,
#9D5BFF 45deg,
#4361FF 90deg,
#2DD4FF 135deg,
#C8FF3E 180deg,
#FFD93E 225deg,
#FF6B1A 270deg,
#FF3EA5 315deg,
#FF3EA5 360deg)`,
glow: 'rgba(255, 100, 200, 0.6)',
},
warm: {
conic: `conic-gradient(from ${rot.y}deg at 50% 50%,
#3a2820 0deg,
#d9b8a0 45deg,
#fff5e8 90deg,
#f0d4b8 130deg,
#6b4838 180deg,
#b08568 220deg,
#fff5e8 270deg,
#d9b8a0 315deg,
#3a2820 360deg)`,
glow: 'rgba(255, 180, 130, 0.5)',
},
azure: {
conic: `conic-gradient(from ${rot.y}deg at 50% 50%,
#0a1a3a 0deg,
#4361FF 45deg,
#b8d0ff 90deg,
#f0f8ff 130deg,
#2DD4FF 180deg,
#b8eeff 220deg,
#4361FF 270deg,
#0a1a3a 315deg,
#0a1a3a 360deg)`,
glow: 'rgba(67, 97, 255, 0.5)',
},
lime: {
conic: `conic-gradient(from ${rot.y}deg at 50% 50%,
#1a2a0a 0deg,
#C8FF3E 45deg,
#f0ffb8 90deg,
#fff8b8 130deg,
#88c020 180deg,
#d4f060 220deg,
#C8FF3E 270deg,
#1a2a0a 315deg,
#1a2a0a 360deg)`,
glow: 'rgba(200, 255, 60, 0.5)',
},
};
const s = surfaces[kind] || surfaces.chrome;
return (
{/* Outer glow */}
{/* Main orb */}
{/* Specular highlight 1 */}
{/* Specular highlight 2 — small bright */}
{/* Bottom shadow rim */}
);
}
/* ════════════════════════════════════════════════════════
IRIDESCENT BLOB — organic shape with hue-shift fill
════════════════════════════════════════════════════════ */
function IridescentBlob({ size = 200, style = {}, hue = 0 }) {
// Asymmetric organic borderRadius
const [phase, setPhase] = __cs(0);
__ce(() => {
let raf;
let t = 0;
const tick = () => { t += 0.5; setPhase(t); raf = requestAnimationFrame(tick); };
raf = requestAnimationFrame(tick);
return () => cancelAnimationFrame(raf);
}, []);
const r1 = 50 + Math.sin(phase * 0.02) * 12;
const r2 = 50 - Math.sin(phase * 0.02) * 12;
const r3 = 50 + Math.cos(phase * 0.018) * 14;
const r4 = 50 - Math.cos(phase * 0.018) * 14;
return (
);
}
/* ════════════════════════════════════════════════════════
ROTATING STICKER (Y2K badge)
════════════════════════════════════════════════════════ */
function ChromeSticker({ text, size = 160, color = 'lime' }) {
// Generate text along a circle
const chars = text.split('');
const angleStep = 360 / chars.length;
return (
);
}
/* ════════════════════════════════════════════════════════
STARBURST — classic Y2K star
════════════════════════════════════════════════════════ */
function Star({ size = 40, color, style = {} }) {
return (
);
}
/* ════════════════════════════════════════════════════════
HOLO CARD — iridescent border + glassy fill
════════════════════════════════════════════════════════ */
function HoloCard({ children, style = {}, className = '' }) {
return (
);
}
/* ════════════════════════════════════════════════════════
3D MORPHING SHAPE — different per service
════════════════════════════════════════════════════════ */
function MorphShape({ kind = 'sphere', size = 200, mouse, hue = 0 }) {
const [t, setT] = __cs(0);
__ce(() => {
let raf;
let n = 0;
const tick = () => { n += 0.5; setT(n); raf = requestAnimationFrame(tick); };
raf = requestAnimationFrame(tick);
return () => cancelAnimationFrame(raf);
}, []);
if (kind === 'sphere') {
return ;
}
if (kind === 'torus') {
return (
);
}
if (kind === 'cube') {
return (
{['front', 'back', 'right', 'left', 'top', 'bottom'].map((face, i) => {
const half = size / 2;
const transforms = {
front: `translateZ(${half}px)`,
back: `rotateY(180deg) translateZ(${half}px)`,
right: `rotateY(90deg) translateZ(${half}px)`,
left: `rotateY(-90deg) translateZ(${half}px)`,
top: `rotateX(90deg) translateZ(${half}px)`,
bottom: `rotateX(-90deg) translateZ(${half}px)`,
};
return (
);
})}
);
}
if (kind === 'blob') {
return ;
}
if (kind === 'cylinder') {
return (
);
}
return null;
}
/* ════════════════════════════════════════════════════════
ASTERISK BADGE — logo principal (versión 05)
8 brazos negros con núcleo iridiscente que gira suave.
════════════════════════════════════════════════════════ */
function AsteriskBadge({ size = 320, spin = true, animateCore = true, style = {}, strokeColor }) {
const [phase, setPhase] = __cs(0);
__ce(() => {
if (!animateCore && !spin) return;
let raf;
let t = 0;
const tick = () => { t += 0.4; setPhase(t); raf = requestAnimationFrame(tick); };
raf = requestAnimationFrame(tick);
return () => cancelAnimationFrame(raf);
}, [spin, animateCore]);
const stroke = strokeColor || 'var(--ink)';
const armW = size * 0.085;
const armL = size * 0.42;
const coreR = size * 0.13;
return (
{/* Núcleo iridiscente */}
{/* Brillo especular del núcleo */}
);
}
/* ════════════════════════════════════════════════════════
ASTERISK MARK — versión compacta (nav / favicon / footer)
Gira suave por defecto.
════════════════════════════════════════════════════════ */
function AsteriskMark({ size = 32, strokeColor, spin = true }) {
const stroke = strokeColor || 'var(--ink)';
const sw = size * 0.16;
const uid = __cm(() => Math.random().toString(36).slice(2, 8), []);
return (
);
}
/* ════════════════════════════════════════════════════════
ASTERISK STICKER — asterisco + texto orbitando
Reemplaza al ChromeSticker. Texto gira alrededor, asterisco
independiente en el centro con núcleo iridiscente.
════════════════════════════════════════════════════════ */
/* ════════════════════════════════════════════════════════
Y2K BADGE — sticker circular giratorio (versión canónica 04)
Anillo grueso oscuro, texto blanco orbitando, núcleo iridiscente
════════════════════════════════════════════════════════ */
function Y2KBadge({ text = 'MULTIPLES · MEDIOS · STUDIO · MMXXVI', size = 180, dark = true, className = '' }) {
const uid = __cm(() => 'y2k-' + Math.random().toString(36).slice(2, 8), []);
// Tamaño efectivo según viewport: todo (badge + esfera + halo) escala junto
const [vw, setVw] = __cs(typeof window !== 'undefined' ? window.innerWidth : 1024);
__ce(() => {
const onResize = () => setVw(window.innerWidth);
window.addEventListener('resize', onResize, { passive: true });
return () => window.removeEventListener('resize', onResize);
}, []);
const effSize =
vw <= 360 ? Math.min(size, 84) :
vw <= 480 ? Math.min(size, 100) :
vw <= 720 ? Math.min(size, 124) :
size;
const ring = dark ? '#0E0B14' : '#FFF8EC';
const ink = dark ? '#FFF8EC' : '#0E0B14';
const coreSize = effSize * 0.30; // esfera = 30 % del badge, en todos los tamaños
// Path circumference: 2π · 78 ≈ 490.088 en viewBox 200×200
// textLength=490 + lengthAdjust=spacingAndGlyphs estira el texto para
// cubrir el anillo exactamente UNA vuelta, sin solapado "MULTIPLESMULTIPLES".
return (
{/* Esfera iridiscente al centro */}
);
}
/* Esfera iridiscente compacta para el Y2K badge */
function IridescentSphere({ size = 80 }) {
const [phase, setPhase] = __cs(0);
__ce(() => {
let raf; let t = 0;
const tick = () => { t += 0.6; setPhase(t); raf = requestAnimationFrame(tick); };
raf = requestAnimationFrame(tick);
return () => cancelAnimationFrame(raf);
}, []);
return (
{/* Halo */}
{/* Esfera */}
{/* Brillo especular */}
);
}
function AsteriskSticker({ text = 'MULTIMEDIA · STUDIO · 2026 · ', size = 160, strokeColor }) {
const uid = __cm(() => 'as-' + Math.random().toString(36).slice(2, 8), []);
const stroke = strokeColor || 'var(--ink)';
return (
{/* Anillo + texto orbitando (rota) */}
{/* Asterisco en el centro (gira independiente) */}
);
}
/* ════════════════════════════════════════════════════════
STACKED MASSIVE — wordmark audaz (versión 06)
"MULTIPLES" condensado negro encima de "medios." cursiva
degradado azul→tangerine. Decorativo, no clickable.
════════════════════════════════════════════════════════ */
function StackedMassive({
size = 'clamp(80px, 14vw, 240px)',
align = 'center',
variant = 'light', // 'light' (ink sobre cream) | 'dark' (chrome sobre ink)
animated = true, // anima el fondo iridiscente detrás
style = {}
}) {
const isDark = variant === 'dark';
const topClass = isDark ? 'chrome-text' : '';
return (
{/* Fondo iridiscente animado sutil */}
{animated && (
)}
multiples
medios.
);
}
Object.assign(window, {
ChromeOrb, IridescentBlob, ChromeSticker, Star, HoloCard, MorphShape,
AsteriskBadge, AsteriskMark, AsteriskSticker, StackedMassive,
Y2KBadge, IridescentSphere
});