Add Creatorlists section: 44 Greats; wire into homepage star map

44greats.html: 44 YouTube creator cards, auto-fill grid, mobile responsive.
index.html: wire Creatorlists star node to Creatorlists/44greats.html.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-04-02 19:49:20 +02:00
parent 334929292e
commit eb1609f652
2 changed files with 688 additions and 1 deletions

687
Creatorlists/44greats.html Normal file
View File

@@ -0,0 +1,687 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>44 GREATS // SINGULAR PARTICULAR</title>
<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=Sixtyfour&family=Share+Tech+Mono&family=Rambla:ital,wght@0,400;0,700;1,400;1,700&family=Noto+Emoji&display=swap" rel="stylesheet">
<style>
:root {
--bg-deep: #030812;
--bg-mid: #060f1a;
--bg-surface: #081524;
--bg-panel: #0d1e32;
--text-main: #c8d8e8;
--text-muted: #3a5570;
--neon-green: #32dc8c;
--neon-green-dim: #229966;
--fire-amber: #e8943a;
--fire-amber-dim: #b06020;
--toucan: #ffcf40;
--fire-coral: #d4654a;
--neon-teal: #2ac4b3;
--border-neon: rgba(50,220,140,0.3);
--border-amber: rgba(232,148,58,0.4);
}
* { margin: 0; padding: 0; box-sizing: border-box; }
body {
background: var(--bg-deep);
color: var(--text-main);
font-family: 'Rambla', sans-serif;
min-height: 100vh;
overflow-x: hidden;
}
body::before {
content: '';
position: fixed;
inset: 0;
background:
radial-gradient(ellipse 60% 50% at 50% 80%, rgba(232,148,58,0.05) 0%, transparent 70%),
radial-gradient(ellipse 100% 60% at 20% 0%, rgba(3,8,18,0.9) 0%, transparent 60%),
radial-gradient(ellipse 100% 60% at 80% 0%, rgba(3,8,18,0.9) 0%, transparent 60%),
repeating-linear-gradient(0deg, transparent, transparent 2px, rgba(0,0,0,0.12) 2px, rgba(0,0,0,0.12) 4px);
pointer-events: none;
z-index: 0;
}
body::after {
content: '';
position: fixed;
inset: 0;
background: repeating-linear-gradient(to bottom, transparent 0px, transparent 3px, rgba(0,0,0,0.15) 3px, rgba(0,0,0,0.15) 4px);
pointer-events: none;
z-index: 1000;
animation: scanline 15s linear infinite;
}
@keyframes scanline { 0% { background-position: 0 0; } 100% { background-position: 0 400px; } }
.noise {
position: fixed; inset: 0; opacity: 0.04;
background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 256 256' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='noise'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='4' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23noise)'/%3E%3C/svg%3E");
pointer-events: none; z-index: 999;
}
.campfire-glow {
position: fixed; bottom: -100px; left: 50%; transform: translateX(-50%);
width: 600px; height: 400px;
background: radial-gradient(ellipse at center bottom, rgba(232,148,58,0.12) 0%, transparent 70%);
pointer-events: none; z-index: 0;
animation: glowPulse 4s ease-in-out infinite;
}
@keyframes glowPulse { 0%,100% { opacity:0.5; } 50% { opacity:0.9; transform:translateX(-50%) scale(1.05); } }
#embers { position: fixed; inset: 0; pointer-events: none; z-index: 3; }
.app {
position: relative; z-index: 1;
max-width: 1100px; margin: 0 auto;
padding: 2rem 1.5rem;
}
.back-link {
display: inline-flex; align-items: center; gap: 0.5rem;
font-family: 'Share Tech Mono', monospace;
color: var(--text-muted); text-decoration: none;
margin-bottom: 1.5rem; transition: color 150ms;
letter-spacing: 0.1em;
}
.back-link:hover { color: var(--neon-green); }
.header {
display: flex; align-items: flex-start; justify-content: space-between;
margin-bottom: 2rem; padding-bottom: 1rem;
border-bottom: 1px solid var(--border-neon);
position: relative;
}
.header::after {
content: ''; position: absolute; bottom: -1px; left: 0;
width: 40%; height: 1px;
background: var(--neon-green); box-shadow: 0 0 10px var(--neon-green);
animation: headerGlow 4s ease-in-out infinite alternate;
}
@keyframes headerGlow { from { opacity:0.4; width:25%; } to { opacity:1; width:55%; } }
.unit-tag {
font-family: 'Share Tech Mono', monospace; font-size: 0.9rem;
color: var(--fire-amber); letter-spacing: 0.25em; text-transform: uppercase;
margin-bottom: 0.4rem;
}
.title {
font-family: 'Sixtyfour', cursive; font-size: 1.8rem; font-weight: 400;
color: var(--neon-green);
text-shadow: 0 0 8px var(--neon-green), 0 0 20px rgba(50,220,140,0.6);
line-height: 1.2; margin-bottom: 0.5rem;
}
.subtitle {
font-family: 'Share Tech Mono', monospace; font-size: 0.9rem;
color: var(--text-muted); letter-spacing: 0.2em; text-transform: uppercase;
}
.header-right {
text-align: right; display: flex; flex-direction: column;
gap: 0.5rem; align-items: flex-end;
}
.status-badge {
font-family: 'Share Tech Mono', monospace; font-size: 1rem;
padding: 0.25rem 0.8rem;
border: 1px solid var(--neon-green); color: var(--neon-green);
letter-spacing: 0.15em; text-shadow: 0 0 8px var(--neon-green);
box-shadow: inset 0 0 10px rgba(50,220,140,0.15);
animation: badgePulse 2.5s ease-in-out infinite;
}
@keyframes badgePulse { 0%,100% { opacity:0.8; } 50% { opacity:1; box-shadow:inset 0 0 16px rgba(50,220,140,0.3), 0 0 12px rgba(50,220,140,0.4); } }
.coord {
font-family: 'Share Tech Mono', monospace; font-size: 0.9rem;
color: var(--text-muted); letter-spacing: 0.1em;
}
.creator-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
gap: 1rem;
}
.creator-card {
background: var(--bg-panel);
border: 1px solid rgba(50,220,140,0.15);
clip-path: polygon(0 0, calc(100% - 10px) 0, 100% 10px, 100% 100%, 10px 100%, 0 calc(100% - 10px));
display: flex; flex-direction: column;
transition: border-color 200ms, background 200ms;
position: relative;
overflow: hidden;
}
.creator-card::before {
content: ''; position: absolute; top: 0; right: 0;
width: 0; height: 0; border-style: solid;
border-width: 0 10px 10px 0;
border-color: transparent var(--bg-deep) transparent transparent;
}
.creator-card:hover {
border-color: rgba(50,220,140,0.5);
background: var(--bg-surface);
}
.card-accent {
height: 3px;
background: linear-gradient(90deg, var(--fire-amber) 0%, var(--fire-amber-dim) 100%);
box-shadow: 0 0 6px rgba(232,148,58,0.4);
}
.card-body {
padding: 1rem; flex: 1; display: flex; flex-direction: column; gap: 0.5rem;
}
.creator-name {
font-family: 'Rambla', sans-serif; font-weight: 700; font-size: 1rem;
color: var(--text-main); line-height: 1.3;
}
.creator-tag {
font-family: 'Share Tech Mono', monospace; font-size: 0.75rem;
color: var(--text-muted); letter-spacing: 0.12em;
margin-top: auto; padding-top: 0.5rem;
}
.visit-btn {
display: block; margin-top: 0.75rem;
font-family: 'Share Tech Mono', monospace; font-size: 0.9rem;
padding: 0.5rem; text-align: center;
background: transparent;
border: 1px solid var(--fire-amber); color: var(--fire-amber);
text-decoration: none; letter-spacing: 0.15em; text-transform: uppercase;
transition: all 150ms;
}
.visit-btn:hover {
background: rgba(232,148,58,0.1);
box-shadow: 0 0 15px rgba(232,148,58,0.3);
text-shadow: 0 0 8px var(--fire-amber);
}
::-webkit-scrollbar { width: 4px; }
::-webkit-scrollbar-track { background: var(--bg-deep); }
::-webkit-scrollbar-thumb { background: var(--text-muted); }
@media (max-width: 680px) {
.header { flex-direction: column; gap: 0.75rem; }
.header-right { align-items: flex-start; text-align: left; }
.creator-grid { grid-template-columns: repeat(2, 1fr); }
}
@media (max-width: 400px) {
.creator-grid { grid-template-columns: 1fr; }
}
</style>
</head>
<body>
<div class="noise"></div>
<div class="campfire-glow"></div>
<canvas id="embers"></canvas>
<div class="app">
<a href="../index.html" class="back-link" target="_top">← SPACE</a>
<header class="header">
<div class="header-left">
<div class="unit-tag">▶ CREATORLISTS // SINGULAR PARTICULAR</div>
<h1 class="title">44 GREATS</h1>
<div class="subtitle">FORTY-FOUR CHANNELS WORTH YOUR TIME</div>
</div>
<div class="header-right">
<div class="status-badge">● 44 CHANNELS</div>
<div class="coord">PLATFORM: YOUTUBE</div>
</div>
</header>
<div class="creator-grid">
<div class="creator-card">
<div class="card-accent"></div>
<div class="card-body">
<div class="creator-name">Hank Green</div>
<div class="creator-tag">▶ YOUTUBE</div>
<a href="https://www.youtube.com/@hankschannel" class="visit-btn" target="_blank" rel="noopener">VISIT ↗</a>
</div>
</div>
<div class="creator-card">
<div class="card-accent"></div>
<div class="card-body">
<div class="creator-name">TeamFourStar</div>
<div class="creator-tag">▶ YOUTUBE</div>
<a href="https://www.youtube.com/@TeamFourStar" class="visit-btn" target="_blank" rel="noopener">VISIT ↗</a>
</div>
</div>
<div class="creator-card">
<div class="card-accent"></div>
<div class="card-body">
<div class="creator-name">Benn Jordan</div>
<div class="creator-tag">▶ YOUTUBE</div>
<a href="https://www.youtube.com/@BennJordan" class="visit-btn" target="_blank" rel="noopener">VISIT ↗</a>
</div>
</div>
<div class="creator-card">
<div class="card-accent"></div>
<div class="card-body">
<div class="creator-name">Kyla Scanlon</div>
<div class="creator-tag">▶ YOUTUBE</div>
<a href="https://www.youtube.com/@KylaScanlon" class="visit-btn" target="_blank" rel="noopener">VISIT ↗</a>
</div>
</div>
<div class="creator-card">
<div class="card-accent"></div>
<div class="card-body">
<div class="creator-name">John Green</div>
<div class="creator-tag">▶ YOUTUBE</div>
<a href="https://www.youtube.com/@johnschannel1007" class="visit-btn" target="_blank" rel="noopener">VISIT ↗</a>
</div>
</div>
<div class="creator-card">
<div class="card-accent"></div>
<div class="card-body">
<div class="creator-name">Dr. Fatima</div>
<div class="creator-tag">▶ YOUTUBE</div>
<a href="https://www.youtube.com/@dr.fatima" class="visit-btn" target="_blank" rel="noopener">VISIT ↗</a>
</div>
</div>
<div class="creator-card">
<div class="card-accent"></div>
<div class="card-body">
<div class="creator-name">Medlife Crisis</div>
<div class="creator-tag">▶ YOUTUBE</div>
<a href="https://www.youtube.com/@MedlifeCrisis" class="visit-btn" target="_blank" rel="noopener">VISIT ↗</a>
</div>
</div>
<div class="creator-card">
<div class="card-accent"></div>
<div class="card-body">
<div class="creator-name">William Spaniel</div>
<div class="creator-tag">▶ YOUTUBE</div>
<a href="https://www.youtube.com/@Gametheory101" class="visit-btn" target="_blank" rel="noopener">VISIT ↗</a>
</div>
</div>
<div class="creator-card">
<div class="card-accent"></div>
<div class="card-body">
<div class="creator-name">Jeremy Fielding</div>
<div class="creator-tag">▶ YOUTUBE</div>
<a href="https://www.youtube.com/@Jeremy_Fielding" class="visit-btn" target="_blank" rel="noopener">VISIT ↗</a>
</div>
</div>
<div class="creator-card">
<div class="card-accent"></div>
<div class="card-body">
<div class="creator-name">Politically Aweh</div>
<div class="creator-tag">▶ YOUTUBE</div>
<a href="https://www.youtube.com/@PoliticallyAweh" class="visit-btn" target="_blank" rel="noopener">VISIT ↗</a>
</div>
</div>
<div class="creator-card">
<div class="card-accent"></div>
<div class="card-body">
<div class="creator-name">Fireship</div>
<div class="creator-tag">▶ YOUTUBE</div>
<a href="https://www.youtube.com/@Fireship" class="visit-btn" target="_blank" rel="noopener">VISIT ↗</a>
</div>
</div>
<div class="creator-card">
<div class="card-accent"></div>
<div class="card-body">
<div class="creator-name">Casual Geographic</div>
<div class="creator-tag">▶ YOUTUBE</div>
<a href="https://www.youtube.com/@mndiaye_97" class="visit-btn" target="_blank" rel="noopener">VISIT ↗</a>
</div>
</div>
<div class="creator-card">
<div class="card-accent"></div>
<div class="card-body">
<div class="creator-name">The Crafsman Steady Craftin</div>
<div class="creator-tag">▶ YOUTUBE</div>
<a href="https://www.youtube.com/@TheCrafsMan" class="visit-btn" target="_blank" rel="noopener">VISIT ↗</a>
</div>
</div>
<div class="creator-card">
<div class="card-accent"></div>
<div class="card-body">
<div class="creator-name">UsefulCharts</div>
<div class="creator-tag">▶ YOUTUBE</div>
<a href="https://www.youtube.com/@UsefulCharts" class="visit-btn" target="_blank" rel="noopener">VISIT ↗</a>
</div>
</div>
<div class="creator-card">
<div class="card-accent"></div>
<div class="card-body">
<div class="creator-name">Xyla Foxlin</div>
<div class="creator-tag">▶ YOUTUBE</div>
<a href="https://www.youtube.com/@xylafoxlin" class="visit-btn" target="_blank" rel="noopener">VISIT ↗</a>
</div>
</div>
<div class="creator-card">
<div class="card-accent"></div>
<div class="card-body">
<div class="creator-name">Tibees</div>
<div class="creator-tag">▶ YOUTUBE</div>
<a href="https://www.youtube.com/@tibees" class="visit-btn" target="_blank" rel="noopener">VISIT ↗</a>
</div>
</div>
<div class="creator-card">
<div class="card-accent"></div>
<div class="card-body">
<div class="creator-name">NotesByNiba</div>
<div class="creator-tag">▶ YOUTUBE</div>
<a href="https://www.youtube.com/@NotesByNiba" class="visit-btn" target="_blank" rel="noopener">VISIT ↗</a>
</div>
</div>
<div class="creator-card">
<div class="card-accent"></div>
<div class="card-body">
<div class="creator-name">Shut Up & Sit Down</div>
<div class="creator-tag">▶ YOUTUBE</div>
<a href="https://www.youtube.com/@shutupandsitdown" class="visit-btn" target="_blank" rel="noopener">VISIT ↗</a>
</div>
</div>
<div class="creator-card">
<div class="card-accent"></div>
<div class="card-body">
<div class="creator-name">People Make Games</div>
<div class="creator-tag">▶ YOUTUBE</div>
<a href="https://www.youtube.com/@PeopleMakeGames" class="visit-btn" target="_blank" rel="noopener">VISIT ↗</a>
</div>
</div>
<div class="creator-card">
<div class="card-accent"></div>
<div class="card-body">
<div class="creator-name">Up and Atom</div>
<div class="creator-tag">▶ YOUTUBE</div>
<a href="https://www.youtube.com/@upandatom" class="visit-btn" target="_blank" rel="noopener">VISIT ↗</a>
</div>
</div>
<div class="creator-card">
<div class="card-accent"></div>
<div class="card-body">
<div class="creator-name">Viva La Dirt League</div>
<div class="creator-tag">▶ YOUTUBE</div>
<a href="https://www.youtube.com/@VivaLaDirtLeague" class="visit-btn" target="_blank" rel="noopener">VISIT ↗</a>
</div>
</div>
<div class="creator-card">
<div class="card-accent"></div>
<div class="card-body">
<div class="creator-name">Ginny Di</div>
<div class="creator-tag">▶ YOUTUBE</div>
<a href="https://www.youtube.com/@GinnyDi" class="visit-btn" target="_blank" rel="noopener">VISIT ↗</a>
</div>
</div>
<div class="creator-card">
<div class="card-accent"></div>
<div class="card-body">
<div class="creator-name">Ze Frank</div>
<div class="creator-tag">▶ YOUTUBE</div>
<a href="https://www.youtube.com/@zefrank" class="visit-btn" target="_blank" rel="noopener">VISIT ↗</a>
</div>
</div>
<div class="creator-card">
<div class="card-accent"></div>
<div class="card-body">
<div class="creator-name">Sanaea Bubber</div>
<div class="creator-tag">▶ YOUTUBE</div>
<a href="https://www.youtube.com/@sanaeabubber69" class="visit-btn" target="_blank" rel="noopener">VISIT ↗</a>
</div>
</div>
<div class="creator-card">
<div class="card-accent"></div>
<div class="card-body">
<div class="creator-name">SmarterEveryDay</div>
<div class="creator-tag">▶ YOUTUBE</div>
<a href="https://www.youtube.com/@smartereveryday" class="visit-btn" target="_blank" rel="noopener">VISIT ↗</a>
</div>
</div>
<div class="creator-card">
<div class="card-accent"></div>
<div class="card-body">
<div class="creator-name">ContraPoints</div>
<div class="creator-tag">▶ YOUTUBE</div>
<a href="https://www.youtube.com/@ContraPoints" class="visit-btn" target="_blank" rel="noopener">VISIT ↗</a>
</div>
</div>
<div class="creator-card">
<div class="card-accent"></div>
<div class="card-body">
<div class="creator-name">Tom Scott</div>
<div class="creator-tag">▶ YOUTUBE</div>
<a href="https://www.youtube.com/@TomScottGo" class="visit-btn" target="_blank" rel="noopener">VISIT ↗</a>
</div>
</div>
<div class="creator-card">
<div class="card-accent"></div>
<div class="card-body">
<div class="creator-name">Dan McClellan</div>
<div class="creator-tag">▶ YOUTUBE</div>
<a href="https://www.youtube.com/@maklelan" class="visit-btn" target="_blank" rel="noopener">VISIT ↗</a>
</div>
</div>
<div class="creator-card">
<div class="card-accent"></div>
<div class="card-body">
<div class="creator-name">Simon Clark</div>
<div class="creator-tag">▶ YOUTUBE</div>
<a href="https://www.youtube.com/@SimonClark" class="visit-btn" target="_blank" rel="noopener">VISIT ↗</a>
</div>
</div>
<div class="creator-card">
<div class="card-accent"></div>
<div class="card-body">
<div class="creator-name">Elephants in Rooms - Ken LaCorte</div>
<div class="creator-tag">▶ YOUTUBE</div>
<a href="https://www.youtube.com/@ElephantsInRooms" class="visit-btn" target="_blank" rel="noopener">VISIT ↗</a>
</div>
</div>
<div class="creator-card">
<div class="card-accent"></div>
<div class="card-body">
<div class="creator-name">Rational Animations</div>
<div class="creator-tag">▶ YOUTUBE</div>
<a href="https://www.youtube.com/@RationalAnimations" class="visit-btn" target="_blank" rel="noopener">VISIT ↗</a>
</div>
</div>
<div class="creator-card">
<div class="card-accent"></div>
<div class="card-body">
<div class="creator-name">Atun-Shei Films</div>
<div class="creator-tag">▶ YOUTUBE</div>
<a href="https://www.youtube.com/@AtunSheiFilms" class="visit-btn" target="_blank" rel="noopener">VISIT ↗</a>
</div>
</div>
<div class="creator-card">
<div class="card-accent"></div>
<div class="card-body">
<div class="creator-name">Simone Giertz</div>
<div class="creator-tag">▶ YOUTUBE</div>
<a href="https://www.youtube.com/@simonegiertz" class="visit-btn" target="_blank" rel="noopener">VISIT ↗</a>
</div>
</div>
<div class="creator-card">
<div class="card-accent"></div>
<div class="card-body">
<div class="creator-name">Howtown</div>
<div class="creator-tag">▶ YOUTUBE</div>
<a href="https://www.youtube.com/@Howtown" class="visit-btn" target="_blank" rel="noopener">VISIT ↗</a>
</div>
</div>
<div class="creator-card">
<div class="card-accent"></div>
<div class="card-body">
<div class="creator-name">Laura Kampf</div>
<div class="creator-tag">▶ YOUTUBE</div>
<a href="https://www.youtube.com/@laurakampf" class="visit-btn" target="_blank" rel="noopener">VISIT ↗</a>
</div>
</div>
<div class="creator-card">
<div class="card-accent"></div>
<div class="card-body">
<div class="creator-name">ESOTERICA</div>
<div class="creator-tag">▶ YOUTUBE</div>
<a href="https://www.youtube.com/@TheEsotericaChannel" class="visit-btn" target="_blank" rel="noopener">VISIT ↗</a>
</div>
</div>
<div class="creator-card">
<div class="card-accent"></div>
<div class="card-body">
<div class="creator-name">Noodle</div>
<div class="creator-tag">▶ YOUTUBE</div>
<a href="https://www.youtube.com/@noodlefunny" class="visit-btn" target="_blank" rel="noopener">VISIT ↗</a>
</div>
</div>
<div class="creator-card">
<div class="card-accent"></div>
<div class="card-body">
<div class="creator-name">J. Draper</div>
<div class="creator-tag">▶ YOUTUBE</div>
<a href="https://www.youtube.com/@JDraper" class="visit-btn" target="_blank" rel="noopener">VISIT ↗</a>
</div>
</div>
<div class="creator-card">
<div class="card-accent"></div>
<div class="card-body">
<div class="creator-name">Stuff Made Here</div>
<div class="creator-tag">▶ YOUTUBE</div>
<a href="https://www.youtube.com/@StuffMadeHere" class="visit-btn" target="_blank" rel="noopener">VISIT ↗</a>
</div>
</div>
<div class="creator-card">
<div class="card-accent"></div>
<div class="card-body">
<div class="creator-name">Aaed Musa</div>
<div class="creator-tag">▶ YOUTUBE</div>
<a href="https://www.youtube.com/@aaedmusa" class="visit-btn" target="_blank" rel="noopener">VISIT ↗</a>
</div>
</div>
<div class="creator-card">
<div class="card-accent"></div>
<div class="card-body">
<div class="creator-name">Heather Cox Richardson</div>
<div class="creator-tag">▶ YOUTUBE</div>
<a href="https://www.youtube.com/@heathercoxrichardson" class="visit-btn" target="_blank" rel="noopener">VISIT ↗</a>
</div>
</div>
<div class="creator-card">
<div class="card-accent"></div>
<div class="card-body">
<div class="creator-name">Steve Mould</div>
<div class="creator-tag">▶ YOUTUBE</div>
<a href="https://www.youtube.com/@SteveMould" class="visit-btn" target="_blank" rel="noopener">VISIT ↗</a>
</div>
</div>
<div class="creator-card">
<div class="card-accent"></div>
<div class="card-body">
<div class="creator-name">Technology Connections</div>
<div class="creator-tag">▶ YOUTUBE</div>
<a href="https://www.youtube.com/@TechnologyConnections" class="visit-btn" target="_blank" rel="noopener">VISIT ↗</a>
</div>
</div>
<div class="creator-card">
<div class="card-accent"></div>
<div class="card-body">
<div class="creator-name">No Boilerplate</div>
<div class="creator-tag">▶ YOUTUBE</div>
<a href="https://www.youtube.com/@NoBoilerplate" class="visit-btn" target="_blank" rel="noopener">VISIT ↗</a>
</div>
</div>
</div>
</div>
<script>
const canvas = document.getElementById('embers');
const ctx = canvas.getContext('2d');
function resize() { canvas.width = window.innerWidth; canvas.height = window.innerHeight; }
resize();
window.addEventListener('resize', resize);
const EMBER_COUNT = 60;
const embers = [];
const mouse = { x: -9999, y: -9999 };
window.addEventListener('mousemove', ev => { mouse.x = ev.clientX; mouse.y = ev.clientY; });
const ZONES = [
{ r: 40, strength: 0.012 },
{ r: 90, strength: 0.004 },
{ r: 130, strength: 0.001 },
];
const COLORS = [
{ r: 232, g: 148, b: 58 },
{ r: 212, g: 101, b: 74 },
{ r: 255, g: 207, b: 64 },
{ r: 197, g: 88, b: 217 },
];
function randomEmber() {
const col = COLORS[Math.floor(Math.random() * COLORS.length)];
return {
x: Math.random() * canvas.width, y: canvas.height + 10,
vx: (Math.random() - 0.5) * 0.8, vy: -(0.4 + Math.random() * 1.2),
life: 0, maxLife: 200 + Math.random() * 300,
size: 1 + Math.random() * 2,
r: col.r, g: col.g, b: col.b,
wobble: Math.random() * Math.PI * 2,
wobbleSpeed: 0.02 + Math.random() * 0.02,
trail: [],
};
}
for (let i = 0; i < EMBER_COUNT; i++) {
const e = randomEmber();
e.y = Math.random() * canvas.height;
e.life = Math.random() * e.maxLife;
embers.push(e);
}
function drawEmber(e) {
const progress = e.life / e.maxLife;
const alpha = progress < 0.1 ? progress / 0.1 : progress > 0.8 ? (1 - progress) / 0.2 : 1;
if (alpha <= 0) return;
const gAlpha = alpha * 0.38;
const glow = ctx.createRadialGradient(e.x, e.y, 0, e.x, e.y, e.size * 5);
glow.addColorStop(0, `rgba(${e.r},${e.g},${e.b},${gAlpha})`);
glow.addColorStop(1, `rgba(${e.r},${e.g},${e.b},0)`);
ctx.beginPath();
ctx.arc(e.x, e.y, e.size * 5, 0, Math.PI * 2);
ctx.fillStyle = glow; ctx.fill();
ctx.fillStyle = `rgba(${e.r},${e.g},${e.b},${Math.min(0.65, gAlpha * 1.4)})`;
const ps = Math.max(1, Math.round(e.size));
ctx.fillRect(Math.round(e.x) - ps, Math.round(e.y) - ps, ps * 2, ps * 2);
for (let t = 0; t < e.trail.length; t++) {
const pt = e.trail[t];
ctx.fillStyle = `rgba(${e.r},${e.g},${e.b},${(t / e.trail.length) * gAlpha * 0.3})`;
ctx.fillRect(Math.round(pt.x), Math.round(pt.y), 2, 2);
}
}
function tick() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
for (const e of embers) {
if (e.life % 6 === 0) { e.trail.push({ x: e.x, y: e.y }); if (e.trail.length > 5) e.trail.shift(); }
const dx = mouse.x - e.x, dy = mouse.y - e.y, d = Math.sqrt(dx*dx+dy*dy);
if (d < ZONES[2].r) {
let s = 0;
for (const z of ZONES) if (d < z.r) { s = z.strength; break; }
e.vx += (dx/d)*s; e.vy += (dy/d)*s;
e.vx *= 0.98; e.vy *= 0.98;
}
e.wobble += e.wobbleSpeed;
e.x += e.vx + Math.sin(e.wobble) * 0.3;
e.y += e.vy;
e.life++;
if (e.life >= e.maxLife || e.y < -20) Object.assign(e, randomEmber());
drawEmber(e);
}
requestAnimationFrame(tick);
}
tick();
</script>
</body>
</html>