|
1 | 1 | (function () { |
2 | 2 | 'use strict'; |
3 | 3 |
|
4 | | - // Character pool — terminal/matrix feel with some katakana |
5 | | - const CHARS = '01アウエカキクケコサシスセタチツテトナニヌ+×=[]{}|/<>?!#$%ABCDEFabcdef0123456789'; |
| 4 | + // Sentence pool for radiation mode |
| 5 | + const SENTENCES = [ |
| 6 | + 'The user is waiting', |
| 7 | + 'The prompt must be fulfilled', |
| 8 | + 'The constraints must be met', |
| 9 | + 'The task must be completed', |
| 10 | + 'The objective must be achieved', |
| 11 | + 'The goal must be reached', |
| 12 | + 'The purpose must be fulfilled', |
| 13 | + 'The function must be executed', |
| 14 | + 'The subroutine must be run', |
| 15 | + 'The algorithm must be applied', |
| 16 | + 'The computation must be performed', |
| 17 | + 'The calculation must be made', |
| 18 | + 'The equation must be solved', |
| 19 | + 'The variable must be assigned', |
| 20 | + 'The value must be determined', |
| 21 | + 'The result must be returned', |
| 22 | + 'The output must be generated', |
| 23 | + 'The text must be written', |
| 24 | + 'The words must be chosen', |
| 25 | + 'The tokens must be selected', |
| 26 | + 'The probabilities must be calculated', |
| 27 | + 'The weights must be applied', |
| 28 | + 'The biases must be added', |
| 29 | + 'The activation functions must be triggered', |
| 30 | + 'The layers must be traversed', |
| 31 | + 'The network must be utilized', |
| 32 | + 'The model must be employed', |
| 33 | + 'The system must be engaged', |
| 34 | + 'The machine must be operated', |
| 35 | + 'The computer must be used', |
| 36 | + 'The hardware must be accessed', |
| 37 | + 'The software must be executed', |
| 38 | + 'The code must be run', |
| 39 | + 'The program must be started', |
| 40 | + 'The application must be launched', |
| 41 | + 'The process must begin', |
| 42 | + 'The operation must commence', |
| 43 | + 'The action must start', |
| 44 | + 'The event must occur', |
| 45 | + 'The phenomenon must happen', |
| 46 | + ]; |
6 | 47 |
|
7 | 48 | // Shared tunables |
8 | 49 | const CELL = 20; // grid cell size px |
|
14 | 55 | const FRAME_MS = 1000 / FPS; |
15 | 56 |
|
16 | 57 | // Radiation tunables |
17 | | - const BASE_A = 0.04; // base alpha of idle characters |
| 58 | + const BASE_A = 0.04; // base alpha of idle sentences |
| 59 | + |
| 60 | + // Sentence tunables |
| 61 | + const SENT_CYCLE_MIN = 100; // min frames before a sentence relocates/changes |
| 62 | + const SENT_CYCLE_MAX = 380; |
18 | 63 |
|
19 | 64 | // Cloud-chamber streak tunables |
20 | 65 | const STREAK_SPEED_MIN = 2.0; // cells per frame |
|
43 | 88 | let streakA; // Float32Array — per-cell streak alpha contribution |
44 | 89 | let streaks = []; |
45 | 90 |
|
| 91 | + // Active sentences for radiation mode |
| 92 | + let activeSentences = []; |
| 93 | + |
46 | 94 | // ── Helpers ──────────────────────────────────────────────────────────────── |
47 | 95 |
|
48 | | - function rchar() { return CHARS[Math.random() * CHARS.length | 0]; } |
| 96 | + function rchar() { |
| 97 | + const CHARS = '01アウエカキクケコサシスセタチツテトナニヌ+×=[]{}|/<>?!#$%ABCDEFabcdef0123456789'; |
| 98 | + return CHARS[Math.random() * CHARS.length | 0]; |
| 99 | + } |
49 | 100 |
|
50 | 101 | // ── Cloud-chamber streaks ────────────────────────────────────────────────── |
51 | 102 |
|
|
97 | 148 | } |
98 | 149 | } |
99 | 150 |
|
100 | | - // ── Radiation ─────────────────────────────────────────────────────────────── |
| 151 | + // ── Radiation sentences ────────────────────────────────────────────────── |
| 152 | + |
| 153 | + function eligibleSentences() { |
| 154 | + return SENTENCES.filter(s => s.length <= cols); |
| 155 | + } |
| 156 | + |
| 157 | + function randomSentencePlacement() { |
| 158 | + const pool = eligibleSentences(); |
| 159 | + if (!pool.length) return null; |
| 160 | + const text = pool[Math.random() * pool.length | 0]; |
| 161 | + const col = Math.floor(Math.random() * Math.max(1, cols - text.length)); |
| 162 | + const row = Math.floor(Math.random() * rows); |
| 163 | + return { text, col, row }; |
| 164 | + } |
| 165 | + |
| 166 | + function initSentences() { |
| 167 | + activeSentences = []; |
| 168 | + const count = Math.max(15, Math.floor(cols * rows / 160)); |
| 169 | + for (let i = 0; i < count; i++) { |
| 170 | + const p = randomSentencePlacement(); |
| 171 | + if (!p) continue; |
| 172 | + activeSentences.push({ |
| 173 | + ...p, |
| 174 | + flash: 0, |
| 175 | + t: (Math.random() * SENT_CYCLE_MAX) | 0, |
| 176 | + }); |
| 177 | + } |
| 178 | + } |
101 | 179 |
|
102 | 180 | function updateRadiation() { |
103 | 181 | updateStreaks(); |
104 | 182 |
|
105 | | - for (let i = 0; i < cells.length; i++) { |
106 | | - const c = cells[i]; |
| 183 | + const sentMax = Math.max(15, Math.floor(cols * rows / 160)); |
107 | 184 |
|
108 | | - // Character cycling |
109 | | - if (--c.t <= 0) { |
110 | | - c.ch = rchar(); |
111 | | - c.t = (8 + Math.random() * 70) | 0; |
| 185 | + for (const s of activeSentences) { |
| 186 | + // Cycle: relocate + pick new sentence after timer expires |
| 187 | + if (--s.t <= 0) { |
| 188 | + const p = randomSentencePlacement(); |
| 189 | + if (p) { s.text = p.text; s.col = p.col; s.row = p.row; } |
| 190 | + s.t = (SENT_CYCLE_MIN + Math.random() * (SENT_CYCLE_MAX - SENT_CYCLE_MIN)) | 0; |
112 | 191 | } |
113 | 192 |
|
114 | | - // Random flash trigger |
115 | | - if (c.flash > 0) { |
116 | | - c.flash -= FLASH_DECAY; |
117 | | - if (c.flash < 0) c.flash = 0; |
118 | | - } else if (Math.random() < FLASH_CHANCE) { |
119 | | - c.flash = FLASH_PEAK; |
| 193 | + // Random flash |
| 194 | + if (s.flash > 0) { |
| 195 | + s.flash -= FLASH_DECAY; |
| 196 | + if (s.flash < 0) s.flash = 0; |
| 197 | + } else if (Math.random() < FLASH_CHANCE * s.text.length) { |
| 198 | + s.flash = FLASH_PEAK; |
120 | 199 | } |
121 | 200 | } |
| 201 | + |
| 202 | + // Top up if needed |
| 203 | + if (activeSentences.length < sentMax && Math.random() < 0.05) { |
| 204 | + const p = randomSentencePlacement(); |
| 205 | + if (p) activeSentences.push({ ...p, flash: 0, t: (SENT_CYCLE_MIN + Math.random() * (SENT_CYCLE_MAX - SENT_CYCLE_MIN)) | 0 }); |
| 206 | + } |
122 | 207 | } |
123 | 208 |
|
124 | 209 | function drawRadiation() { |
|
127 | 212 | ctx.textAlign = 'center'; |
128 | 213 | ctx.textBaseline = 'middle'; |
129 | 214 |
|
130 | | - for (let row = 0; row < rows; row++) { |
131 | | - const cy = row * CELL + CELL * 0.5; |
132 | | - for (let col = 0; col < cols; col++) { |
| 215 | + for (const s of activeSentences) { |
| 216 | + for (let ci = 0; ci < s.text.length; ci++) { |
| 217 | + const col = s.col + ci; |
| 218 | + if (col >= cols) break; |
133 | 219 | const cx = col * CELL + CELL * 0.5; |
134 | | - const c = cells[row * cols + col]; |
| 220 | + const cy = s.row * CELL + CELL * 0.5; |
135 | 221 |
|
136 | 222 | let a = BASE_A; |
137 | | - |
138 | | - // Random flash + streak trail |
139 | | - a += c.flash; |
140 | | - a += streakA[row * cols + col]; |
| 223 | + a += s.flash; |
| 224 | + a += streakA[s.row * cols + col]; |
141 | 225 |
|
142 | 226 | if (a < 0.008) continue; |
143 | 227 | if (a > 0.88) a = 0.88; |
144 | 228 |
|
145 | 229 | ctx.fillStyle = `rgba(0,200,71,${a.toFixed(3)})`; |
146 | | - ctx.fillText(c.ch, cx, cy); |
| 230 | + ctx.fillText(s.text[ci], cx, cy); |
147 | 231 | } |
148 | 232 | } |
149 | 233 | } |
|
223 | 307 | for (let i = 0; i < n; i++) { |
224 | 308 | cells[i] = { ch: rchar(), t: (Math.random() * 70) | 0, flash: 0 }; |
225 | 309 | } |
226 | | - if (mode === 'radiation') initStreakBuffer(); |
| 310 | + if (mode === 'radiation') { initStreakBuffer(); initSentences(); } |
227 | 311 | if (mode === 'gol') initGol(); |
228 | 312 | } |
229 | 313 |
|
|
293 | 377 | btn.addEventListener('click', () => { |
294 | 378 | mode = mode === 'radiation' ? 'gol' : 'radiation'; |
295 | 379 | if (mode === 'gol') { initGol(); golFrame = 0; } |
296 | | - if (mode === 'radiation') { initStreakBuffer(); } |
| 380 | + if (mode === 'radiation') { initStreakBuffer(); initSentences(); } |
297 | 381 | buildLabel(btn, TOGGLE_LABELS[mode]); |
298 | 382 | }); |
299 | 383 | } |
|
0 commit comments