Spaces:
Running
Running
Create I Did Lots Of Things And You Can Watch.html
Browse files
I Did Lots Of Things And You Can Watch.html
ADDED
|
@@ -0,0 +1,360 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
<!DOCTYPE html>
|
| 2 |
+
<html lang="en">
|
| 3 |
+
<head>
|
| 4 |
+
<meta charset="UTF-8">
|
| 5 |
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
| 6 |
+
<title>I Did Lots Of Things And You Can Watch | FMN-GPT - CompactAI</title>
|
| 7 |
+
<link rel="stylesheet" href="bluesheet.css">
|
| 8 |
+
<link rel="preconnect" href="https://fonts.googleapis.com">
|
| 9 |
+
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
| 10 |
+
<link href="https://fonts.googleapis.com/css2?family=Geist:wght@400;500:600:700&family=Geist+Mono&display=swap" rel="stylesheet">
|
| 11 |
+
<style>
|
| 12 |
+
:root {
|
| 13 |
+
--blue-900: #000000;
|
| 14 |
+
--blue-800: #0a0a0a;
|
| 15 |
+
--blue-700: #111111;
|
| 16 |
+
--blue-600: #1a1a1a;
|
| 17 |
+
--blue-500: #333333;
|
| 18 |
+
--blue-400: #555555;
|
| 19 |
+
--blue-300: #777777;
|
| 20 |
+
--blue-200: #888888;
|
| 21 |
+
--blue-100: #aaaaaa;
|
| 22 |
+
--white: #ffffff;
|
| 23 |
+
--white-soft: #f5f5f5;
|
| 24 |
+
--white-muted: #e0e0e0;
|
| 25 |
+
--grid-line: rgba(255, 255, 255, 0.03);
|
| 26 |
+
--grid-line-major: rgba(255, 255, 255, 0.06);
|
| 27 |
+
--accent: #ededed;
|
| 28 |
+
--accent-muted: #888888;
|
| 29 |
+
--font-sans: 'Geist', -apple-system, BlinkMacSystemFont, sans-serif;
|
| 30 |
+
--font-mono: 'Geist Mono', 'SF Mono', 'Fira Code', monospace;
|
| 31 |
+
--container-max: 1100px;
|
| 32 |
+
}
|
| 33 |
+
* { box-sizing: border-box; margin: 0; padding: 0; }
|
| 34 |
+
html { font-size: 16px; scroll-behavior: smooth; }
|
| 35 |
+
body { font-family: var(--font-sans); background: var(--blue-900); color: var(--white-muted); line-height: 1.7; -webkit-font-smoothing: antialiased; }
|
| 36 |
+
a { color: var(--white); text-decoration: none; transition: color 0.15s ease; }
|
| 37 |
+
a:hover { color: var(--accent); }
|
| 38 |
+
.container { max-width: var(--container-max); margin: 0 auto; padding: 0 24px; }
|
| 39 |
+
nav { position: fixed; top: 0; left: 0; right: 0; z-index: 100; background: rgba(0, 0, 0, 0.85); backdrop-filter: blur(12px); border-bottom: 1px solid var(--blue-600); padding: 16px 0; }
|
| 40 |
+
nav .container { display: flex; justify-content: space-between; align-items: center; }
|
| 41 |
+
.nav-brand { font-size: 18px; font-weight: 600; color: var(--white); display: flex; align-items: center; gap: 8px; }
|
| 42 |
+
.nav-brand span { color: var(--accent); }
|
| 43 |
+
.nav-links { display: flex; gap: 32px; }
|
| 44 |
+
.nav-links a { font-size: 14px; font-weight: 500; color: var(--blue-200); }
|
| 45 |
+
.nav-links a:hover { color: var(--white); }
|
| 46 |
+
.post { padding: 140px 0 80px; }
|
| 47 |
+
.post-back { display: inline-block; color: var(--blue-200); font-size: 14px; margin-bottom: 32px; }
|
| 48 |
+
.post-back:hover { color: var(--accent); }
|
| 49 |
+
.post-back::before { content: '← '; }
|
| 50 |
+
.post-meta { display: flex; gap: 12px; margin-bottom: 20px; }
|
| 51 |
+
.post-date { font-size: 13px; color: var(--blue-200); font-family: var(--font-mono); }
|
| 52 |
+
.post-tag { font-size: 11px; font-weight: 600; text-transform: uppercase; letter-spacing: 0.05em; color: var(--white); background: rgba(255, 255, 255, 0.08); padding: 4px 10px; border-radius: 4px; }
|
| 53 |
+
.post h1 { font-size: 36px; font-weight: 700; color: var(--white); margin-bottom: 32px; line-height: 1.2; letter-spacing: -0.02em; }
|
| 54 |
+
.post-body p { font-size: 17px; line-height: 1.8; margin-bottom: 24px; color: var(--blue-200); }
|
| 55 |
+
.post-body p:first-of-type { font-size: 20px; color: var(--white-muted); }
|
| 56 |
+
.post-body h2 { font-size: 24px; font-weight: 600; color: var(--white); margin: 48px 0 20px; }
|
| 57 |
+
.post-body blockquote { border-left: 3px solid var(--accent); padding: 20px 24px; margin: 32px 0; background: var(--blue-800); border-radius: 0 8px 8px 0; }
|
| 58 |
+
.post-body blockquote p { font-size: 16px; font-style: italic; color: var(--blue-200); margin: 0; }
|
| 59 |
+
.post-body hr { border: none; height: 1px; background: var(--blue-600); margin: 48px 0; }
|
| 60 |
+
.post-footer { margin-top: 48px; padding-top: 32px; border-top: 1px solid var(--blue-600); }
|
| 61 |
+
.post-footer p { font-size: 14px; color: var(--blue-200); font-style: italic; margin: 0; }
|
| 62 |
+
footer { padding: 40px 0; background: var(--blue-800); border-top: 1px solid var(--blue-600); text-align: center; }
|
| 63 |
+
footer p { color: var(--blue-200); font-size: 14px; margin-bottom: 8px; }
|
| 64 |
+
footer a { color: var(--blue-200); }
|
| 65 |
+
footer a:hover { color: var(--accent); }
|
| 66 |
+
.animation-container {
|
| 67 |
+
width: 100%;
|
| 68 |
+
height: 400px;
|
| 69 |
+
margin: 32px 0;
|
| 70 |
+
border-radius: 12px;
|
| 71 |
+
overflow: hidden;
|
| 72 |
+
position: relative;
|
| 73 |
+
background: var(--blue-800);
|
| 74 |
+
border: 2px solid var(--blue-600);
|
| 75 |
+
cursor: crosshair;
|
| 76 |
+
}
|
| 77 |
+
.animation-canvas {
|
| 78 |
+
width: 100%;
|
| 79 |
+
height: 100%;
|
| 80 |
+
display: block;
|
| 81 |
+
}
|
| 82 |
+
.animation-overlay {
|
| 83 |
+
position: absolute;
|
| 84 |
+
top: 50%;
|
| 85 |
+
left: 50%;
|
| 86 |
+
transform: translate(-50%, -50%);
|
| 87 |
+
color: var(--white);
|
| 88 |
+
font-size: 18px;
|
| 89 |
+
font-weight: 600;
|
| 90 |
+
text-align: center;
|
| 91 |
+
pointer-events: none;
|
| 92 |
+
text-shadow: 0 0 20px rgba(237, 237, 237, 0.5);
|
| 93 |
+
z-index: 10;
|
| 94 |
+
background: rgba(0, 0, 0, 0.6);
|
| 95 |
+
padding: 12px 24px;
|
| 96 |
+
border-radius: 8px;
|
| 97 |
+
border: 1px solid var(--blue-600);
|
| 98 |
+
}
|
| 99 |
+
.animation-hint {
|
| 100 |
+
position: absolute;
|
| 101 |
+
bottom: 12px;
|
| 102 |
+
left: 50%;
|
| 103 |
+
transform: translateX(-50%);
|
| 104 |
+
color: var(--blue-200);
|
| 105 |
+
font-size: 12px;
|
| 106 |
+
font-family: var(--font-mono);
|
| 107 |
+
pointer-events: none;
|
| 108 |
+
opacity: 0.7;
|
| 109 |
+
}
|
| 110 |
+
@media (max-width: 768px) { .post h1 { font-size: 28px; } .nav-links { display: none; } .animation-container { height: 300px; } }
|
| 111 |
+
|
| 112 |
+
</style>
|
| 113 |
+
|
| 114 |
+
</head>
|
| 115 |
+
<body>
|
| 116 |
+
<nav>
|
| 117 |
+
<div class="container">
|
| 118 |
+
<a href="index.html" class="nav-brand"><span>/</span>FMN-GPT</a>
|
| 119 |
+
<div class="nav-links">
|
| 120 |
+
<a href="blog.html">Blog</a>
|
| 121 |
+
<a href="status.html">Model Status</a>
|
| 122 |
+
<a href="https://huggingface.co/CompactAI-O" target="_blank">HuggingFace Org</a>
|
| 123 |
+
</div>
|
| 124 |
+
</div>
|
| 125 |
+
</nav>
|
| 126 |
+
<main>
|
| 127 |
+
<article class="post">
|
| 128 |
+
<div class="container">
|
| 129 |
+
<a href="blog.html" class="post-back">Back to Blog</a>
|
| 130 |
+
<header>
|
| 131 |
+
<div class="post-meta">
|
| 132 |
+
<span class="post-date">2026-04-19</span>
|
| 133 |
+
<span class="post-tag">Updates</span>
|
| 134 |
+
</div>
|
| 135 |
+
<h1>I Did Lots Of Things And You Can Watch</h1>
|
| 136 |
+
</header>
|
| 137 |
+
<div class="post-body">
|
| 138 |
+
<p>I did lots of things. Like, actually lots. Not the "I cleaned my room" kind of lots. The "I built stuff and partnered with people and published datasets" kind of lots. You can watch. You should watch. Or not. Your choice.</p>
|
| 139 |
+
<blockquote>
|
| 140 |
+
<p>When you have too many projects and not enough time to explain them all, you write a blog post that lists things and hopes people get the vibe. This is that post.</p>
|
| 141 |
+
</blockquote>
|
| 142 |
+
<h2>New Partners</h2>
|
| 143 |
+
<p>I partnered with two new people. They are real people. They have HuggingFace accounts. They are helping. This is good.</p>
|
| 144 |
+
<ul style="list-style: disc; padding-left: 20px; color: var(--blue-200); line-height: 1.7;">
|
| 145 |
+
<li><a href="https://huggingface.co/Crownelius" target="_blank">Crownelius</a> - Doing things. Probably smart things.</li>
|
| 146 |
+
<li><a href="https://huggingface.co/Enderchef" target="_blank">Enderchef</a> - Also doing things. Possibly cooking related. Possibly not.</li>
|
| 147 |
+
</ul>
|
| 148 |
+
<p>They are part of CompactAI now. Or adjacent to CompactAI. Or loosely affiliated with CompactAI. The exact legal status is unclear. The collaboration is real. That is what matters.</p>
|
| 149 |
+
<h2>cAI-Grid Is Going Great</h2>
|
| 150 |
+
<p>The cAI grid management system continues to develop. It is going great. That is the official statement. The unofficial statement is that it is complicated and I am tired but also excited. Both can be true.</p>
|
| 151 |
+
<p>Sonnet and Opus are still waiting. They will train when the grid is ready. Or when I give up and use a single GPU for weeks. Or when magic happens. Progress is weird.</p>
|
| 152 |
+
<h2>New Dataset Published</h2>
|
| 153 |
+
<p>I published a new dataset. It is called cAI-PRISM-1600. It has 1600 examples of Q&A with about 48 tokens per token. That is dense. That is efficient. That is the point.</p>
|
| 154 |
+
<div class="code-block">
|
| 155 |
+
<span class="comment"># Dataset specs because numbers are fun</span><br>
|
| 156 |
+
Name: cAI-PRISM-1600<br>
|
| 157 |
+
Examples: 1600<br>
|
| 158 |
+
Format: Q&A pairs<br>
|
| 159 |
+
Density: ~48 tokens per token<br>
|
| 160 |
+
Location: HuggingFace<br>
|
| 161 |
+
<span class="comment"># Simple. Dense. Probably useful.</span>
|
| 162 |
+
</div>
|
| 163 |
+
<p>You can find it on HuggingFace. You can use it. You can break it. You can tell me if it works. That is how open source works. That is how learning works. That is how I work.</p>
|
| 164 |
+
<h2>UI Re-Skinned</h2>
|
| 165 |
+
<p>I re-skinned the UI. It looks different now. It looks better. Or worse. Or just different. You decide. I like it. That is enough for me.</p>
|
| 166 |
+
<p>The colors changed. The layout changed. The vibes changed. Everything is slightly new. Nothing is fundamentally different. This is progress. This is design. This is me clicking buttons until it looks right.</p>
|
| 167 |
+
<h3 style="color: var(--white); margin: 32px 0 16px; font-size: 20px;">Now I can do this!</h3>
|
| 168 |
+
<div class="animation-container">
|
| 169 |
+
<div class="animation-overlay">✨ Interactive Particle Playground ✨<br><span style="font-size: 12px; font-weight: 400; opacity: 0.8;">Move mouse • Click to explode • Have fun</span></div>
|
| 170 |
+
<div class="animation-hint">This is just for fun. Not a neural net. Not science. Just vibes.</div>
|
| 171 |
+
<canvas class="animation-canvas" id="funCanvas"></canvas>
|
| 172 |
+
</div>
|
| 173 |
+
<h2>Next Haiku Additions</h2>
|
| 174 |
+
<p>The next Haiku model is getting new features. I am adding things. I am not explaining them. That is the rule. Here is the list:</p>
|
| 175 |
+
<ul style="list-style: disc; padding-left: 20px; color: var(--blue-200); line-height: 1.7;">
|
| 176 |
+
<li>Latent reasoning</li>
|
| 177 |
+
<li>SleepGate</li>
|
| 178 |
+
<li>TRIM-KV retention gate (learned-eviction complement to SleepGate)</li>
|
| 179 |
+
</ul>
|
| 180 |
+
<p>That is all you get. That is all I am saying. The rest is mystery. The rest is future blog posts. The rest is you waiting and wondering. This is fun. This is marketing. This is me being cryptic on purpose.</p>
|
| 181 |
+
<h2>Why This Matters</h2>
|
| 182 |
+
<p>I did lots of things. I partnered with people. I built systems. I published data. I changed colors. I added features. I did not explain everything. This is my style. This is my pace. This is my blog.</p>
|
| 183 |
+
<p>If you want details, ask. If you want code, look. If you want results, wait. Everything is happening. Everything is moving. Everything is slightly chaotic. This is how it goes.</p>
|
| 184 |
+
<h2>Final Thoughts</h2>
|
| 185 |
+
<p>I did lots of things. You can watch. You can join. You can ignore. All outcomes are valid. All paths are possible. All progress is weird.</p>
|
| 186 |
+
<p>Check the links. Check the datasets. Check the UI. Check the next Haiku when it drops. Or do not. Your choice. Your journey. Your weird.</p>
|
| 187 |
+
<p>I will keep doing things. I will keep posting updates. I will keep being cryptic about features. This is the cycle. This is the vibe. This is the blog.</p>
|
| 188 |
+
<hr>
|
| 189 |
+
</div>
|
| 190 |
+
<footer class="post-footer">
|
| 191 |
+
<p>Current status: Lots of things done. Partners added. Dataset published. UI re-skinned. Haiku features queued. Explanations withheld. Progress is weird. Vibes are high.</p>
|
| 192 |
+
</footer>
|
| 193 |
+
</div>
|
| 194 |
+
</article>
|
| 195 |
+
</main>
|
| 196 |
+
<footer>
|
| 197 |
+
<div class="container">
|
| 198 |
+
<p>Built with curiosity over compute</p>
|
| 199 |
+
<p>FMN-GPT by <a href="https://huggingface.co/CompactAI-O" target="_blank">CompactAI-O</a> | 2026</p>
|
| 200 |
+
</div>
|
| 201 |
+
</footer>
|
| 202 |
+
<script>
|
| 203 |
+
const canvas = document.getElementById('funCanvas');
|
| 204 |
+
const ctx = canvas.getContext('2d');
|
| 205 |
+
|
| 206 |
+
let width, height;
|
| 207 |
+
let particles = [];
|
| 208 |
+
let mouseX = 0, mouseY = 0;
|
| 209 |
+
let mouseActive = false;
|
| 210 |
+
|
| 211 |
+
const colors = ['#ff6b6b', '#4ecdc4', '#ffe66d', '#95e1d3', '#f38181', '#aa96da', '#fcbad3', '#a8d8ea'];
|
| 212 |
+
|
| 213 |
+
function resize() {
|
| 214 |
+
const container = canvas.parentElement;
|
| 215 |
+
width = container.clientWidth;
|
| 216 |
+
height = container.clientHeight;
|
| 217 |
+
canvas.width = width;
|
| 218 |
+
canvas.height = height;
|
| 219 |
+
}
|
| 220 |
+
|
| 221 |
+
class Particle {
|
| 222 |
+
constructor(x, y, isExplosion = false) {
|
| 223 |
+
this.x = x || Math.random() * width;
|
| 224 |
+
this.y = y || Math.random() * height;
|
| 225 |
+
this.vx = isExplosion ? (Math.random() - 0.5) * 15 : (Math.random() - 0.5) * 2;
|
| 226 |
+
this.vy = isExplosion ? (Math.random() - 0.5) * 15 : (Math.random() - 0.5) * 2;
|
| 227 |
+
this.radius = isExplosion ? Math.random() * 8 + 4 : Math.random() * 4 + 2;
|
| 228 |
+
this.color = colors[Math.floor(Math.random() * colors.length)];
|
| 229 |
+
this.life = isExplosion ? 1 : Infinity;
|
| 230 |
+
this.decay = isExplosion ? 0.02 : 0;
|
| 231 |
+
this.trail = [];
|
| 232 |
+
this.maxTrail = isExplosion ? 10 : 0;
|
| 233 |
+
}
|
| 234 |
+
|
| 235 |
+
update() {
|
| 236 |
+
if (this.maxTrail > 0) {
|
| 237 |
+
this.trail.push({x: this.x, y: this.y});
|
| 238 |
+
if (this.trail.length > this.maxTrail) this.trail.shift();
|
| 239 |
+
}
|
| 240 |
+
|
| 241 |
+
this.x += this.vx;
|
| 242 |
+
this.y += this.vy;
|
| 243 |
+
this.life -= this.decay;
|
| 244 |
+
|
| 245 |
+
if (mouseActive) {
|
| 246 |
+
const dx = this.x - mouseX;
|
| 247 |
+
const dy = this.y - mouseY;
|
| 248 |
+
const dist = Math.sqrt(dx * dx + dy * dy);
|
| 249 |
+
if (dist < 100) {
|
| 250 |
+
const force = (100 - dist) / 100;
|
| 251 |
+
this.vx += (dx / dist) * force * 0.5;
|
| 252 |
+
this.vy += (dy / dist) * force * 0.5;
|
| 253 |
+
}
|
| 254 |
+
}
|
| 255 |
+
|
| 256 |
+
if (this.x < -20 || this.x > width + 20) this.vx *= -0.9;
|
| 257 |
+
if (this.y < -20 || this.y > height + 20) this.vy *= -0.9;
|
| 258 |
+
|
| 259 |
+
this.vx *= 0.99;
|
| 260 |
+
this.vy *= 0.99;
|
| 261 |
+
}
|
| 262 |
+
|
| 263 |
+
draw() {
|
| 264 |
+
if (this.trail.length > 1) {
|
| 265 |
+
ctx.beginPath();
|
| 266 |
+
ctx.moveTo(this.trail[0].x, this.trail[0].y);
|
| 267 |
+
for (let i = 1; i < this.trail.length; i++) {
|
| 268 |
+
ctx.lineTo(this.trail[i].x, this.trail[i].y);
|
| 269 |
+
}
|
| 270 |
+
ctx.strokeStyle = this.color + '40';
|
| 271 |
+
ctx.lineWidth = this.radius * 0.5;
|
| 272 |
+
ctx.stroke();
|
| 273 |
+
}
|
| 274 |
+
|
| 275 |
+
const gradient = ctx.createRadialGradient(
|
| 276 |
+
this.x, this.y, 0,
|
| 277 |
+
this.x, this.y, this.radius * 2
|
| 278 |
+
);
|
| 279 |
+
gradient.addColorStop(0, this.color);
|
| 280 |
+
gradient.addColorStop(0.5, this.color + '80');
|
| 281 |
+
gradient.addColorStop(1, this.color + '00');
|
| 282 |
+
|
| 283 |
+
ctx.beginPath();
|
| 284 |
+
ctx.arc(this.x, this.y, this.radius * 2, 0, Math.PI * 2);
|
| 285 |
+
ctx.fillStyle = gradient;
|
| 286 |
+
ctx.fill();
|
| 287 |
+
|
| 288 |
+
ctx.beginPath();
|
| 289 |
+
ctx.arc(this.x, this.y, this.radius, 0, Math.PI * 2);
|
| 290 |
+
ctx.fillStyle = this.color;
|
| 291 |
+
ctx.fill();
|
| 292 |
+
}
|
| 293 |
+
|
| 294 |
+
isDead() {
|
| 295 |
+
return this.life <= 0;
|
| 296 |
+
}
|
| 297 |
+
}
|
| 298 |
+
|
| 299 |
+
function init() {
|
| 300 |
+
resize();
|
| 301 |
+
particles = [];
|
| 302 |
+
for (let i = 0; i < 30; i++) {
|
| 303 |
+
particles.push(new Particle());
|
| 304 |
+
}
|
| 305 |
+
}
|
| 306 |
+
|
| 307 |
+
function createExplosion(x, y) {
|
| 308 |
+
for (let i = 0; i < 20; i++) {
|
| 309 |
+
particles.push(new Particle(x, y, true));
|
| 310 |
+
}
|
| 311 |
+
}
|
| 312 |
+
|
| 313 |
+
function animate() {
|
| 314 |
+
ctx.fillStyle = 'rgba(10, 10, 10, 0.15)';
|
| 315 |
+
ctx.fillRect(0, 0, width, height);
|
| 316 |
+
|
| 317 |
+
particles = particles.filter(p => !p.isDead());
|
| 318 |
+
|
| 319 |
+
if (particles.length < 60 && Math.random() < 0.05) {
|
| 320 |
+
particles.push(new Particle());
|
| 321 |
+
}
|
| 322 |
+
|
| 323 |
+
particles.forEach(particle => {
|
| 324 |
+
particle.update();
|
| 325 |
+
particle.draw();
|
| 326 |
+
});
|
| 327 |
+
|
| 328 |
+
requestAnimationFrame(animate);
|
| 329 |
+
}
|
| 330 |
+
|
| 331 |
+
window.addEventListener('resize', resize);
|
| 332 |
+
canvas.addEventListener('mousemove', (e) => {
|
| 333 |
+
const rect = canvas.getBoundingClientRect();
|
| 334 |
+
mouseX = e.clientX - rect.left;
|
| 335 |
+
mouseY = e.clientY - rect.top;
|
| 336 |
+
mouseActive = true;
|
| 337 |
+
});
|
| 338 |
+
canvas.addEventListener('mouseleave', () => {
|
| 339 |
+
mouseActive = false;
|
| 340 |
+
});
|
| 341 |
+
canvas.addEventListener('click', (e) => {
|
| 342 |
+
const rect = canvas.getBoundingClientRect();
|
| 343 |
+
const x = e.clientX - rect.left;
|
| 344 |
+
const y = e.clientY - rect.top;
|
| 345 |
+
createExplosion(x, y);
|
| 346 |
+
});
|
| 347 |
+
canvas.addEventListener('touchstart', (e) => {
|
| 348 |
+
e.preventDefault();
|
| 349 |
+
const rect = canvas.getBoundingClientRect();
|
| 350 |
+
const touch = e.touches[0];
|
| 351 |
+
const x = touch.clientX - rect.left;
|
| 352 |
+
const y = touch.clientY - rect.top;
|
| 353 |
+
createExplosion(x, y);
|
| 354 |
+
});
|
| 355 |
+
|
| 356 |
+
init();
|
| 357 |
+
animate();
|
| 358 |
+
</script>
|
| 359 |
+
</body>
|
| 360 |
+
</html>
|