idiotik.js 1.0.0
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/README.md +196 -0
- package/package.json +16 -0
- package/src/idiot.js +546 -0
package/README.md
ADDED
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
# idiot.js
|
|
2
|
+
|
|
3
|
+
youareanidiot-style chaos toolkit for the browser. recursive by default. you were warned.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## install
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
npm install idiot.js
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
or just drop `src/idiot.js` into your page:
|
|
14
|
+
|
|
15
|
+
```html
|
|
16
|
+
<script src="idiot.js"></script>
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
---
|
|
20
|
+
|
|
21
|
+
## api
|
|
22
|
+
|
|
23
|
+
### global toggles
|
|
24
|
+
|
|
25
|
+
```js
|
|
26
|
+
idiot.recursive(yes/no) // default: yes — everything spawns itself
|
|
27
|
+
idiot.volume(0-5000) // 101-200: loud | 201-449: + bass boost | 450+: full EQ destruction
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
---
|
|
31
|
+
|
|
32
|
+
### script context
|
|
33
|
+
|
|
34
|
+
group and tag sequences so you can kill them later.
|
|
35
|
+
|
|
36
|
+
```js
|
|
37
|
+
idiot.script()
|
|
38
|
+
idiot.id("myscript") // name it so idiot.halt() can kill it
|
|
39
|
+
idiot.html("<b>chaos</b>") // inject html — ONLY works inside script()
|
|
40
|
+
idiot.start(idiot.html)
|
|
41
|
+
idiot.repeat(inf)
|
|
42
|
+
idiot.continue // keep running, move on
|
|
43
|
+
idiot.end()
|
|
44
|
+
|
|
45
|
+
idiot.halt("myscript") // kills everything under that id
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
- `idiot.html()` **must** be inside `idiot.script()` — throws if used outside
|
|
49
|
+
- `idiot.id()` **must** be inside `idiot.script()`
|
|
50
|
+
- everything else works inside or outside
|
|
51
|
+
|
|
52
|
+
---
|
|
53
|
+
|
|
54
|
+
### flow control
|
|
55
|
+
|
|
56
|
+
```js
|
|
57
|
+
idiot.start(ref) // fire a method
|
|
58
|
+
idiot.repeat(n / inf) // repeat last start n times or forever
|
|
59
|
+
idiot.continue // don't block, keep going (async)
|
|
60
|
+
idiot.wait(ms) // delay (returns promise)
|
|
61
|
+
idiot.halt("id") // force stop a named script
|
|
62
|
+
idiot.random(a, b, c) // picks one randomly and fires it
|
|
63
|
+
idiot.if(condition).then(fn).else(fn2)
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
---
|
|
67
|
+
|
|
68
|
+
### chaos methods
|
|
69
|
+
|
|
70
|
+
```js
|
|
71
|
+
idiot.say("msg") // alert loop
|
|
72
|
+
idiot.scream() // audio blast via oscillator
|
|
73
|
+
idiot.jumpscare(imgUrl, sfxUrl) // fullscreen image + sound
|
|
74
|
+
idiot.redirect(url) // sends em somewhere else
|
|
75
|
+
idiot.freeze() // disables all user input
|
|
76
|
+
idiot.fullscreen() // forces fullscreen, fights exit
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
---
|
|
80
|
+
|
|
81
|
+
### audio
|
|
82
|
+
|
|
83
|
+
```js
|
|
84
|
+
idiot.audio("https://example.com/sound.mp3") // from url
|
|
85
|
+
idiot.audio("file://mysound.mp3") // local file (strips file://)
|
|
86
|
+
idiot.volume(150) // loud
|
|
87
|
+
idiot.volume(300) // loud + bass boosted
|
|
88
|
+
idiot.volume(500) // loud + bass boost + every EQ band maxed 💀
|
|
89
|
+
idiot.volume(5000) // sonic weapon
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
---
|
|
93
|
+
|
|
94
|
+
### effects (stackable)
|
|
95
|
+
|
|
96
|
+
```js
|
|
97
|
+
idiot.start(idiot.effect("shake"))() // seizure mode
|
|
98
|
+
idiot.start(idiot.effect("spin"))() // rotating hell
|
|
99
|
+
idiot.start(idiot.effect("glitch"))() // css glitch
|
|
100
|
+
idiot.start(idiot.effect("rainbow"))() // color flash
|
|
101
|
+
idiot.start(idiot.effect("invert"))() // inverts page
|
|
102
|
+
idiot.start(idiot.effect("matrix"))() // you already know
|
|
103
|
+
idiot.start(idiot.effect("melt"))() // page droops
|
|
104
|
+
|
|
105
|
+
idiot.cleareffects() // wipe all active effects
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
effects stack — calling multiple adds them all simultaneously.
|
|
109
|
+
|
|
110
|
+
---
|
|
111
|
+
|
|
112
|
+
### cursor
|
|
113
|
+
|
|
114
|
+
```js
|
|
115
|
+
idiot.start(idiot.cursor("hand")) // pointer everywhere
|
|
116
|
+
idiot.start(idiot.cursor("none")) // cursor gone
|
|
117
|
+
idiot.start(idiot.cursor("rainbow")) // color trail
|
|
118
|
+
idiot.start(idiot.cursor("wiggle")) // cursor fights you
|
|
119
|
+
idiot.start(idiot.cursor("explode")) // particles on click
|
|
120
|
+
idiot.start(idiot.cursor("crosshair")) // crosshair
|
|
121
|
+
idiot.start(idiot.cursor("https://example.com/cur.png")) // custom url
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
---
|
|
125
|
+
|
|
126
|
+
### presets
|
|
127
|
+
|
|
128
|
+
```js
|
|
129
|
+
idiot.start(idiot.classic())() // the full youareanidiot experience
|
|
130
|
+
idiot.start(idiot.mild())() // annoying but survivable
|
|
131
|
+
idiot.start(idiot.nuclear())() // god help them
|
|
132
|
+
idiot.start(idiot.rickroll())() // you know what this does
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
---
|
|
136
|
+
|
|
137
|
+
## examples
|
|
138
|
+
|
|
139
|
+
### basic alert spam
|
|
140
|
+
|
|
141
|
+
```js
|
|
142
|
+
idiot.start(idiot.say("FREE ROBUX AT PORNHUB.COM!!!"))
|
|
143
|
+
idiot.repeat(inf)
|
|
144
|
+
idiot.continue
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
### named script you can kill
|
|
148
|
+
|
|
149
|
+
```js
|
|
150
|
+
idiot.script()
|
|
151
|
+
idiot.id("chaos")
|
|
152
|
+
idiot.say("YOU ARE AN IDIOT")
|
|
153
|
+
idiot.start(idiot.say)
|
|
154
|
+
idiot.repeat(inf)
|
|
155
|
+
idiot.continue
|
|
156
|
+
idiot.end()
|
|
157
|
+
|
|
158
|
+
// somewhere else:
|
|
159
|
+
idiot.halt("chaos")
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
### stacked effects
|
|
163
|
+
|
|
164
|
+
```js
|
|
165
|
+
idiot.recursive("yes")
|
|
166
|
+
idiot.volume(5000)
|
|
167
|
+
idiot.start(idiot.effect("shake"))()
|
|
168
|
+
idiot.start(idiot.effect("rainbow"))()
|
|
169
|
+
idiot.start(idiot.effect("glitch"))()
|
|
170
|
+
idiot.start(idiot.scream())()
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
### conditional chaos
|
|
174
|
+
|
|
175
|
+
```js
|
|
176
|
+
idiot.if(userIsAnnoying).then(() => {
|
|
177
|
+
idiot.start(idiot.nuclear())()
|
|
178
|
+
}).else(() => {
|
|
179
|
+
idiot.start(idiot.mild())()
|
|
180
|
+
})
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
---
|
|
184
|
+
|
|
185
|
+
## volume breakdown
|
|
186
|
+
|
|
187
|
+
| range | behavior |
|
|
188
|
+
|-------|----------|
|
|
189
|
+
| 0–100 | normal |
|
|
190
|
+
| 101–200 | just loud |
|
|
191
|
+
| 201–449 | loud + bass boost (scales with value) |
|
|
192
|
+
| 450–5000 | loud + bass boost + every EQ band maxed |
|
|
193
|
+
|
|
194
|
+
---
|
|
195
|
+
|
|
196
|
+
built different. use responsibly. (don't.)
|
package/package.json
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "idiotik.js",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "youareanidiot-style chaos toolkit for the browser",
|
|
5
|
+
"main": "src/idiot.js",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"build": "node build.js"
|
|
8
|
+
},
|
|
9
|
+
"keywords": ["chaos", "prank", "browser", "youareanidiot"],
|
|
10
|
+
"license": "MIT",
|
|
11
|
+
"files": [
|
|
12
|
+
"src/",
|
|
13
|
+
"presets/",
|
|
14
|
+
"README.md"
|
|
15
|
+
]
|
|
16
|
+
}
|
package/src/idiot.js
ADDED
|
@@ -0,0 +1,546 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* idiot.js — youareanidiot-style chaos toolkit
|
|
3
|
+
* recursive by default. you were warned.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
(function (global) {
|
|
7
|
+
|
|
8
|
+
// ─── GLOBAL STATE ───────────────────────────────────────────────────────────
|
|
9
|
+
let _recursive = true;
|
|
10
|
+
let _volume = 100;
|
|
11
|
+
let _activeScripts = {}; // id -> { intervals, timeouts, audioNodes }
|
|
12
|
+
let _activeEffects = new Set();
|
|
13
|
+
let _audioCtx = null;
|
|
14
|
+
let _lastStarted = null; // last method ref passed to idiot.start()
|
|
15
|
+
let _scriptStack = []; // current script context stack
|
|
16
|
+
|
|
17
|
+
// ─── HELPERS ────────────────────────────────────────────────────────────────
|
|
18
|
+
function _getAudioCtx() {
|
|
19
|
+
if (!_audioCtx) _audioCtx = new (window.AudioContext || window.webkitAudioContext)();
|
|
20
|
+
return _audioCtx;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function _currentScript() {
|
|
24
|
+
return _scriptStack.length ? _scriptStack[_scriptStack.length - 1] : null;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function _requireScript(name) {
|
|
28
|
+
if (!_currentScript()) throw new Error(`idiot.${name}() must be inside idiot.script()`);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function _track(thing, type) {
|
|
32
|
+
const ctx = _currentScript();
|
|
33
|
+
if (!ctx) return;
|
|
34
|
+
ctx[type] = ctx[type] || [];
|
|
35
|
+
ctx[type].push(thing);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function _buildAudioChain(buffer) {
|
|
39
|
+
const ctx = _getAudioCtx();
|
|
40
|
+
const source = ctx.createBufferSource();
|
|
41
|
+
source.buffer = buffer;
|
|
42
|
+
source.loop = true;
|
|
43
|
+
|
|
44
|
+
const gainNode = ctx.createGain();
|
|
45
|
+
const rawVol = _volume;
|
|
46
|
+
|
|
47
|
+
// volume scaling
|
|
48
|
+
if (rawVol <= 100) {
|
|
49
|
+
gainNode.gain.value = rawVol / 100;
|
|
50
|
+
} else if (rawVol <= 200) {
|
|
51
|
+
gainNode.gain.value = rawVol / 100;
|
|
52
|
+
} else {
|
|
53
|
+
gainNode.gain.value = Math.min(rawVol / 100, 50);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
let lastNode = source;
|
|
57
|
+
|
|
58
|
+
// bass boost kicks in at 201
|
|
59
|
+
if (rawVol > 200) {
|
|
60
|
+
const bassBoost = ctx.createBiquadFilter();
|
|
61
|
+
bassBoost.type = "lowshelf";
|
|
62
|
+
bassBoost.frequency.value = 200;
|
|
63
|
+
const boostAmount = Math.min(((rawVol - 200) / 4800) * 40, 40);
|
|
64
|
+
bassBoost.gain.value = boostAmount;
|
|
65
|
+
lastNode.connect(bassBoost);
|
|
66
|
+
lastNode = bassBoost;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// full EQ rape kicks in at 450
|
|
70
|
+
if (rawVol >= 450) {
|
|
71
|
+
const bands = [
|
|
72
|
+
{ type: "lowshelf", freq: 60, gain: 40 },
|
|
73
|
+
{ type: "peaking", freq: 250, gain: 40 },
|
|
74
|
+
{ type: "peaking", freq: 500, gain: 40 },
|
|
75
|
+
{ type: "peaking", freq: 1500, gain: 40 },
|
|
76
|
+
{ type: "peaking", freq: 4000, gain: 40 },
|
|
77
|
+
{ type: "peaking", freq: 8000, gain: 40 },
|
|
78
|
+
{ type: "highshelf", freq: 16000, gain: 40 },
|
|
79
|
+
];
|
|
80
|
+
for (const b of bands) {
|
|
81
|
+
const f = ctx.createBiquadFilter();
|
|
82
|
+
f.type = b.type;
|
|
83
|
+
f.frequency.value = b.freq;
|
|
84
|
+
f.gain.value = b.gain;
|
|
85
|
+
lastNode.connect(f);
|
|
86
|
+
lastNode = f;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
lastNode.connect(gainNode);
|
|
91
|
+
gainNode.connect(ctx.destination);
|
|
92
|
+
return source;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
async function _loadAndPlay(url) {
|
|
96
|
+
const ctx = _getAudioCtx();
|
|
97
|
+
const resp = await fetch(url);
|
|
98
|
+
const arrayBuf = await resp.arrayBuffer();
|
|
99
|
+
const audioBuf = await ctx.decodeAudioData(arrayBuf);
|
|
100
|
+
const source = _buildAudioChain(audioBuf);
|
|
101
|
+
source.start(0);
|
|
102
|
+
return source;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// ─── CURSOR PRESETS ─────────────────────────────────────────────────────────
|
|
106
|
+
const _cursorPresets = {
|
|
107
|
+
hand: "pointer",
|
|
108
|
+
none: "none",
|
|
109
|
+
crosshair: "crosshair",
|
|
110
|
+
wait: "wait",
|
|
111
|
+
// animated ones inject a style tag
|
|
112
|
+
rainbow: "__rainbow__",
|
|
113
|
+
wiggle: "__wiggle__",
|
|
114
|
+
explode: "__explode__",
|
|
115
|
+
};
|
|
116
|
+
|
|
117
|
+
// ─── EFFECT IMPLEMENTATIONS ─────────────────────────────────────────────────
|
|
118
|
+
const _effectImpls = {
|
|
119
|
+
shake() {
|
|
120
|
+
const styleId = "__idiot_shake__";
|
|
121
|
+
if (document.getElementById(styleId)) return;
|
|
122
|
+
const s = document.createElement("style");
|
|
123
|
+
s.id = styleId;
|
|
124
|
+
s.textContent = `
|
|
125
|
+
@keyframes __idiot_shake { 0%,100%{transform:translate(0,0)} 10%{transform:translate(-8px,8px)} 20%{transform:translate(8px,-8px)} 30%{transform:translate(-8px,0)} 40%{transform:translate(8px,8px)} 50%{transform:translate(-4px,-4px)} 60%{transform:translate(4px,4px)} 70%{transform:translate(-8px,8px)} 80%{transform:translate(8px,-8px)} 90%{transform:translate(-4px,4px)} }
|
|
126
|
+
body { animation: __idiot_shake 0.3s infinite; }
|
|
127
|
+
`;
|
|
128
|
+
document.head.appendChild(s);
|
|
129
|
+
},
|
|
130
|
+
spin() {
|
|
131
|
+
const styleId = "__idiot_spin__";
|
|
132
|
+
if (document.getElementById(styleId)) return;
|
|
133
|
+
const s = document.createElement("style");
|
|
134
|
+
s.id = styleId;
|
|
135
|
+
s.textContent = `
|
|
136
|
+
@keyframes __idiot_spin { from{transform:rotate(0deg)} to{transform:rotate(360deg)} }
|
|
137
|
+
body { animation: __idiot_spin 2s linear infinite; transform-origin: center center; }
|
|
138
|
+
`;
|
|
139
|
+
document.head.appendChild(s);
|
|
140
|
+
},
|
|
141
|
+
glitch() {
|
|
142
|
+
const styleId = "__idiot_glitch__";
|
|
143
|
+
if (document.getElementById(styleId)) return;
|
|
144
|
+
const s = document.createElement("style");
|
|
145
|
+
s.id = styleId;
|
|
146
|
+
s.textContent = `
|
|
147
|
+
@keyframes __idiot_glitch1 { 0%,100%{clip-path:inset(0 0 95% 0)} 25%{clip-path:inset(30% 0 50% 0)} 50%{clip-path:inset(60% 0 20% 0)} 75%{clip-path:inset(10% 0 80% 0)} }
|
|
148
|
+
@keyframes __idiot_glitch2 { 0%,100%{clip-path:inset(80% 0 5% 0);transform:translate(-5px,0)} 25%{clip-path:inset(20% 0 70% 0);transform:translate(5px,0)} 50%{clip-path:inset(50% 0 30% 0);transform:translate(-3px,0)} 75%{clip-path:inset(5% 0 90% 0);transform:translate(3px,0)} }
|
|
149
|
+
body::before, body::after { content:''; position:fixed; top:0;left:0;width:100%;height:100%; background:inherit; pointer-events:none; z-index:9999; }
|
|
150
|
+
body::before { animation: __idiot_glitch1 0.4s infinite; color:red; text-shadow:2px 0 red; }
|
|
151
|
+
body::after { animation: __idiot_glitch2 0.4s infinite; color:blue; text-shadow:-2px 0 blue; }
|
|
152
|
+
`;
|
|
153
|
+
document.head.appendChild(s);
|
|
154
|
+
},
|
|
155
|
+
rainbow() {
|
|
156
|
+
const styleId = "__idiot_rainbow__";
|
|
157
|
+
if (document.getElementById(styleId)) return;
|
|
158
|
+
const s = document.createElement("style");
|
|
159
|
+
s.id = styleId;
|
|
160
|
+
s.textContent = `
|
|
161
|
+
@keyframes __idiot_rainbow { 0%{background:#ff0000} 15%{background:#ff8800} 30%{background:#ffff00} 45%{background:#00ff00} 60%{background:#0000ff} 75%{background:#8800ff} 90%{background:#ff00ff} 100%{background:#ff0000} }
|
|
162
|
+
body { animation: __idiot_rainbow 0.5s infinite; }
|
|
163
|
+
`;
|
|
164
|
+
document.head.appendChild(s);
|
|
165
|
+
},
|
|
166
|
+
invert() {
|
|
167
|
+
const styleId = "__idiot_invert__";
|
|
168
|
+
if (document.getElementById(styleId)) return;
|
|
169
|
+
const s = document.createElement("style");
|
|
170
|
+
s.id = styleId;
|
|
171
|
+
s.textContent = `body { filter: invert(1); }`;
|
|
172
|
+
document.head.appendChild(s);
|
|
173
|
+
},
|
|
174
|
+
matrix() {
|
|
175
|
+
const canvasId = "__idiot_matrix__";
|
|
176
|
+
if (document.getElementById(canvasId)) return;
|
|
177
|
+
const canvas = document.createElement("canvas");
|
|
178
|
+
canvas.id = canvasId;
|
|
179
|
+
canvas.style.cssText = "position:fixed;top:0;left:0;z-index:9998;pointer-events:none;width:100vw;height:100vh;opacity:0.7;";
|
|
180
|
+
document.body.appendChild(canvas);
|
|
181
|
+
const ctx = canvas.getContext("2d");
|
|
182
|
+
canvas.width = window.innerWidth;
|
|
183
|
+
canvas.height = window.innerHeight;
|
|
184
|
+
const cols = Math.floor(canvas.width / 16);
|
|
185
|
+
const drops = Array(cols).fill(1);
|
|
186
|
+
const chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789@#$%^&*()";
|
|
187
|
+
const id = setInterval(() => {
|
|
188
|
+
ctx.fillStyle = "rgba(0,0,0,0.05)";
|
|
189
|
+
ctx.fillRect(0, 0, canvas.width, canvas.height);
|
|
190
|
+
ctx.fillStyle = "#0f0";
|
|
191
|
+
ctx.font = "16px monospace";
|
|
192
|
+
drops.forEach((y, i) => {
|
|
193
|
+
const ch = chars[Math.floor(Math.random() * chars.length)];
|
|
194
|
+
ctx.fillText(ch, i * 16, y * 16);
|
|
195
|
+
if (y * 16 > canvas.height && Math.random() > 0.975) drops[i] = 0;
|
|
196
|
+
drops[i]++;
|
|
197
|
+
});
|
|
198
|
+
}, 50);
|
|
199
|
+
_track(id, "intervals");
|
|
200
|
+
},
|
|
201
|
+
melt() {
|
|
202
|
+
const styleId = "__idiot_melt__";
|
|
203
|
+
if (document.getElementById(styleId)) return;
|
|
204
|
+
const s = document.createElement("style");
|
|
205
|
+
s.id = styleId;
|
|
206
|
+
s.textContent = `
|
|
207
|
+
@keyframes __idiot_melt { 0%{transform:skewY(0deg) scaleY(1)} 50%{transform:skewY(5deg) scaleY(1.1)} 100%{transform:skewY(-3deg) scaleY(0.9)} }
|
|
208
|
+
body { animation: __idiot_melt 1s ease-in-out infinite alternate; transform-origin: bottom; }
|
|
209
|
+
`;
|
|
210
|
+
document.head.appendChild(s);
|
|
211
|
+
},
|
|
212
|
+
};
|
|
213
|
+
|
|
214
|
+
// ─── CORE idiot OBJECT ───────────────────────────────────────────────────────
|
|
215
|
+
const idiot = {
|
|
216
|
+
|
|
217
|
+
// ── GLOBAL TOGGLES ─────────────────────────────────────────────────────────
|
|
218
|
+
|
|
219
|
+
recursive(val) {
|
|
220
|
+
_recursive = (val === true || val === "yes" || val === 1);
|
|
221
|
+
return idiot;
|
|
222
|
+
},
|
|
223
|
+
|
|
224
|
+
volume(n) {
|
|
225
|
+
_volume = Math.max(0, Math.min(5000, Number(n)));
|
|
226
|
+
return idiot;
|
|
227
|
+
},
|
|
228
|
+
|
|
229
|
+
// ── SCRIPT CONTEXT ─────────────────────────────────────────────────────────
|
|
230
|
+
|
|
231
|
+
script() {
|
|
232
|
+
const ctx = {
|
|
233
|
+
id: null,
|
|
234
|
+
intervals: [],
|
|
235
|
+
timeouts: [],
|
|
236
|
+
audioSources: [],
|
|
237
|
+
htmlNodes: [],
|
|
238
|
+
_html: null,
|
|
239
|
+
};
|
|
240
|
+
_scriptStack.push(ctx);
|
|
241
|
+
return idiot;
|
|
242
|
+
},
|
|
243
|
+
|
|
244
|
+
id(name) {
|
|
245
|
+
_requireScript("id");
|
|
246
|
+
const ctx = _currentScript();
|
|
247
|
+
ctx.id = name;
|
|
248
|
+
_activeScripts[name] = ctx;
|
|
249
|
+
return idiot;
|
|
250
|
+
},
|
|
251
|
+
|
|
252
|
+
html(code) {
|
|
253
|
+
_requireScript("html");
|
|
254
|
+
const ctx = _currentScript();
|
|
255
|
+
ctx._html = code;
|
|
256
|
+
return idiot;
|
|
257
|
+
},
|
|
258
|
+
|
|
259
|
+
end() {
|
|
260
|
+
if (!_currentScript()) throw new Error("idiot.end() called outside a script");
|
|
261
|
+
_scriptStack.pop();
|
|
262
|
+
return idiot;
|
|
263
|
+
},
|
|
264
|
+
|
|
265
|
+
// ── FLOW CONTROL ───────────────────────────────────────────────────────────
|
|
266
|
+
|
|
267
|
+
start(ref) {
|
|
268
|
+
_lastStarted = ref;
|
|
269
|
+
if (typeof ref === "function") {
|
|
270
|
+
ref();
|
|
271
|
+
}
|
|
272
|
+
return idiot;
|
|
273
|
+
},
|
|
274
|
+
|
|
275
|
+
repeat(n) {
|
|
276
|
+
if (!_lastStarted) return idiot;
|
|
277
|
+
const fn = _lastStarted;
|
|
278
|
+
const infinite = (n === Infinity || n === "inf" || n === "Infinity");
|
|
279
|
+
if (infinite) {
|
|
280
|
+
const id = setInterval(() => fn(), 100);
|
|
281
|
+
_track(id, "intervals");
|
|
282
|
+
} else {
|
|
283
|
+
let count = 0;
|
|
284
|
+
const id = setInterval(() => {
|
|
285
|
+
fn();
|
|
286
|
+
count++;
|
|
287
|
+
if (count >= n) clearInterval(id);
|
|
288
|
+
}, 100);
|
|
289
|
+
_track(id, "intervals");
|
|
290
|
+
}
|
|
291
|
+
return idiot;
|
|
292
|
+
},
|
|
293
|
+
|
|
294
|
+
get continue() {
|
|
295
|
+
// no-op — execution continues naturally (async stuff already running)
|
|
296
|
+
return idiot;
|
|
297
|
+
},
|
|
298
|
+
|
|
299
|
+
wait(ms) {
|
|
300
|
+
return new Promise(resolve => {
|
|
301
|
+
const id = setTimeout(resolve, ms);
|
|
302
|
+
_track(id, "timeouts");
|
|
303
|
+
});
|
|
304
|
+
},
|
|
305
|
+
|
|
306
|
+
halt(name) {
|
|
307
|
+
const ctx = _activeScripts[name];
|
|
308
|
+
if (!ctx) return idiot;
|
|
309
|
+
(ctx.intervals || []).forEach(id => clearInterval(id));
|
|
310
|
+
(ctx.timeouts || []).forEach(id => clearTimeout(id));
|
|
311
|
+
(ctx.audioSources || []).forEach(s => { try { s.stop(); } catch(e){} });
|
|
312
|
+
(ctx.htmlNodes || []).forEach(n => { try { n.remove(); } catch(e){} });
|
|
313
|
+
delete _activeScripts[name];
|
|
314
|
+
return idiot;
|
|
315
|
+
},
|
|
316
|
+
|
|
317
|
+
// ── CONDITIONAL ────────────────────────────────────────────────────────────
|
|
318
|
+
|
|
319
|
+
_ifResult: null,
|
|
320
|
+
|
|
321
|
+
if(condition) {
|
|
322
|
+
idiot._ifResult = !!condition;
|
|
323
|
+
return {
|
|
324
|
+
then(fn) {
|
|
325
|
+
if (idiot._ifResult) fn();
|
|
326
|
+
return {
|
|
327
|
+
else(fn2) { if (!idiot._ifResult) fn2(); return idiot; }
|
|
328
|
+
};
|
|
329
|
+
}
|
|
330
|
+
};
|
|
331
|
+
},
|
|
332
|
+
|
|
333
|
+
else(fn) {
|
|
334
|
+
if (!idiot._ifResult) fn();
|
|
335
|
+
return idiot;
|
|
336
|
+
},
|
|
337
|
+
|
|
338
|
+
random(...methods) {
|
|
339
|
+
const pick = methods[Math.floor(Math.random() * methods.length)];
|
|
340
|
+
if (typeof pick === "function") pick();
|
|
341
|
+
return idiot;
|
|
342
|
+
},
|
|
343
|
+
|
|
344
|
+
// ── CHAOS METHODS ──────────────────────────────────────────────────────────
|
|
345
|
+
|
|
346
|
+
say(msg) {
|
|
347
|
+
return function _say() {
|
|
348
|
+
alert(msg);
|
|
349
|
+
if (_recursive) setTimeout(() => _say(), 0);
|
|
350
|
+
};
|
|
351
|
+
},
|
|
352
|
+
|
|
353
|
+
redirect(url) {
|
|
354
|
+
return function() {
|
|
355
|
+
window.location.href = url;
|
|
356
|
+
};
|
|
357
|
+
},
|
|
358
|
+
|
|
359
|
+
freeze() {
|
|
360
|
+
return function() {
|
|
361
|
+
document.addEventListener("keydown", e => e.preventDefault(), true);
|
|
362
|
+
document.addEventListener("mousedown", e => e.preventDefault(), true);
|
|
363
|
+
document.addEventListener("contextmenu", e => e.preventDefault(), true);
|
|
364
|
+
};
|
|
365
|
+
},
|
|
366
|
+
|
|
367
|
+
fullscreen() {
|
|
368
|
+
return function _fs() {
|
|
369
|
+
const el = document.documentElement;
|
|
370
|
+
if (el.requestFullscreen) el.requestFullscreen();
|
|
371
|
+
else if (el.webkitRequestFullscreen) el.webkitRequestFullscreen();
|
|
372
|
+
document.addEventListener("fullscreenchange", () => {
|
|
373
|
+
if (!document.fullscreenElement && _recursive) setTimeout(_fs, 100);
|
|
374
|
+
});
|
|
375
|
+
};
|
|
376
|
+
},
|
|
377
|
+
|
|
378
|
+
jumpscare(imgUrl, sfxUrl) {
|
|
379
|
+
return function _js() {
|
|
380
|
+
const div = document.createElement("div");
|
|
381
|
+
div.style.cssText = "position:fixed;top:0;left:0;width:100vw;height:100vh;z-index:99999;background:#000;display:flex;align-items:center;justify-content:center;";
|
|
382
|
+
const img = document.createElement("img");
|
|
383
|
+
img.src = imgUrl;
|
|
384
|
+
img.style.cssText = "max-width:100%;max-height:100%;object-fit:contain;";
|
|
385
|
+
div.appendChild(img);
|
|
386
|
+
document.body.appendChild(div);
|
|
387
|
+
if (sfxUrl) {
|
|
388
|
+
const parsed = _parseAudioUrl(sfxUrl);
|
|
389
|
+
_loadAndPlay(parsed);
|
|
390
|
+
}
|
|
391
|
+
const ctx = _currentScript();
|
|
392
|
+
if (ctx) ctx.htmlNodes.push(div);
|
|
393
|
+
if (_recursive) setTimeout(() => { div.remove(); _js(); }, 1000);
|
|
394
|
+
};
|
|
395
|
+
},
|
|
396
|
+
|
|
397
|
+
scream() {
|
|
398
|
+
return function() {
|
|
399
|
+
const ctx = _getAudioCtx();
|
|
400
|
+
const osc = ctx.createOscillator();
|
|
401
|
+
const gain = ctx.createGain();
|
|
402
|
+
osc.type = "sawtooth";
|
|
403
|
+
osc.frequency.value = 880;
|
|
404
|
+
gain.gain.value = Math.min(_volume / 100, 10);
|
|
405
|
+
osc.connect(gain);
|
|
406
|
+
gain.connect(ctx.destination);
|
|
407
|
+
osc.start();
|
|
408
|
+
setTimeout(() => osc.stop(), 2000);
|
|
409
|
+
if (_recursive) setTimeout(idiot.scream()(), 2100);
|
|
410
|
+
};
|
|
411
|
+
},
|
|
412
|
+
|
|
413
|
+
// ── AUDIO ──────────────────────────────────────────────────────────────────
|
|
414
|
+
|
|
415
|
+
audio(urlOrFile) {
|
|
416
|
+
const parsed = _parseAudioUrl(urlOrFile);
|
|
417
|
+
return async function _audio() {
|
|
418
|
+
const source = await _loadAndPlay(parsed);
|
|
419
|
+
const ctx = _currentScript();
|
|
420
|
+
if (ctx) ctx.audioSources.push(source);
|
|
421
|
+
if (_recursive) source.addEventListener?.("ended", _audio);
|
|
422
|
+
};
|
|
423
|
+
},
|
|
424
|
+
|
|
425
|
+
// ── EFFECT ─────────────────────────────────────────────────────────────────
|
|
426
|
+
|
|
427
|
+
effect(name) {
|
|
428
|
+
return function() {
|
|
429
|
+
if (_effectImpls[name]) {
|
|
430
|
+
_activeEffects.add(name);
|
|
431
|
+
_effectImpls[name]();
|
|
432
|
+
} else {
|
|
433
|
+
console.warn(`idiot.effect: unknown preset "${name}"`);
|
|
434
|
+
}
|
|
435
|
+
};
|
|
436
|
+
},
|
|
437
|
+
|
|
438
|
+
cleareffects() {
|
|
439
|
+
_activeEffects.clear();
|
|
440
|
+
document.querySelectorAll("[id^='__idiot_']").forEach(el => el.remove());
|
|
441
|
+
},
|
|
442
|
+
|
|
443
|
+
// ── CURSOR ─────────────────────────────────────────────────────────────────
|
|
444
|
+
|
|
445
|
+
cursor(preset) {
|
|
446
|
+
return function() {
|
|
447
|
+
const val = _cursorPresets[preset];
|
|
448
|
+
if (!val) {
|
|
449
|
+
// treat as URL
|
|
450
|
+
document.body.style.cursor = `url(${preset}), auto`;
|
|
451
|
+
return;
|
|
452
|
+
}
|
|
453
|
+
if (val === "__rainbow__") {
|
|
454
|
+
let h = 0;
|
|
455
|
+
setInterval(() => {
|
|
456
|
+
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>`;
|
|
457
|
+
const url = `url("data:image/svg+xml,${encodeURIComponent(svg)}")`;
|
|
458
|
+
document.body.style.cursor = `${url}, auto`;
|
|
459
|
+
h = (h + 10) % 360;
|
|
460
|
+
}, 50);
|
|
461
|
+
} else if (val === "__wiggle__") {
|
|
462
|
+
document.addEventListener("mousemove", e => {
|
|
463
|
+
const offset = Math.sin(Date.now() / 100) * 10;
|
|
464
|
+
document.body.style.cursor = `url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' width='20' height='20'><text y='16' font-size='16'>👆</text></svg>") ${offset} 0, auto`;
|
|
465
|
+
});
|
|
466
|
+
} else if (val === "__explode__") {
|
|
467
|
+
document.addEventListener("click", e => {
|
|
468
|
+
for (let i = 0; i < 12; i++) {
|
|
469
|
+
const p = document.createElement("div");
|
|
470
|
+
p.textContent = ["💥","✨","⭐","🔥"][i % 4];
|
|
471
|
+
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;`;
|
|
472
|
+
document.body.appendChild(p);
|
|
473
|
+
const angle = (i / 12) * 2 * Math.PI;
|
|
474
|
+
setTimeout(() => {
|
|
475
|
+
p.style.transform = `translate(${Math.cos(angle)*60}px,${Math.sin(angle)*60}px)`;
|
|
476
|
+
p.style.opacity = "0";
|
|
477
|
+
}, 10);
|
|
478
|
+
setTimeout(() => p.remove(), 700);
|
|
479
|
+
}
|
|
480
|
+
});
|
|
481
|
+
} else {
|
|
482
|
+
document.body.style.cursor = val;
|
|
483
|
+
}
|
|
484
|
+
};
|
|
485
|
+
},
|
|
486
|
+
|
|
487
|
+
// ── PRESETS ────────────────────────────────────────────────────────────────
|
|
488
|
+
|
|
489
|
+
classic() {
|
|
490
|
+
return function() {
|
|
491
|
+
idiot.recursive("yes");
|
|
492
|
+
idiot.start(idiot.say("YOU ARE AN IDIOT HA HA HA HA HA HA"));
|
|
493
|
+
idiot.start(idiot.effect("rainbow"))();
|
|
494
|
+
idiot.start(idiot.effect("shake"))();
|
|
495
|
+
idiot.start(idiot.scream())();
|
|
496
|
+
};
|
|
497
|
+
},
|
|
498
|
+
|
|
499
|
+
mild() {
|
|
500
|
+
return function() {
|
|
501
|
+
idiot.recursive("no");
|
|
502
|
+
idiot.start(idiot.say("gotcha lol"));
|
|
503
|
+
idiot.start(idiot.effect("shake"))();
|
|
504
|
+
};
|
|
505
|
+
},
|
|
506
|
+
|
|
507
|
+
nuclear() {
|
|
508
|
+
return function() {
|
|
509
|
+
idiot.recursive("yes");
|
|
510
|
+
idiot.volume(5000);
|
|
511
|
+
idiot.start(idiot.effect("shake"))();
|
|
512
|
+
idiot.start(idiot.effect("rainbow"))();
|
|
513
|
+
idiot.start(idiot.effect("glitch"))();
|
|
514
|
+
idiot.start(idiot.effect("spin"))();
|
|
515
|
+
idiot.start(idiot.scream())();
|
|
516
|
+
idiot.start(idiot.fullscreen())();
|
|
517
|
+
idiot.start(idiot.freeze())();
|
|
518
|
+
idiot.start(idiot.say("💀💀💀 YOU ARE SO COOKED 💀💀💀"));
|
|
519
|
+
};
|
|
520
|
+
},
|
|
521
|
+
|
|
522
|
+
rickroll() {
|
|
523
|
+
return function() {
|
|
524
|
+
idiot.recursive("no");
|
|
525
|
+
idiot.start(idiot.redirect("https://www.youtube.com/watch?v=dQw4w9WgXcQ"))();
|
|
526
|
+
};
|
|
527
|
+
},
|
|
528
|
+
|
|
529
|
+
};
|
|
530
|
+
|
|
531
|
+
// ─── INTERNAL UTILS ─────────────────────────────────────────────────────────
|
|
532
|
+
function _parseAudioUrl(urlOrFile) {
|
|
533
|
+
if (typeof urlOrFile === "string" && urlOrFile.startsWith("file://")) {
|
|
534
|
+
return urlOrFile.replace("file://", "");
|
|
535
|
+
}
|
|
536
|
+
return urlOrFile;
|
|
537
|
+
}
|
|
538
|
+
|
|
539
|
+
// ─── EXPORT ─────────────────────────────────────────────────────────────────
|
|
540
|
+
if (typeof module !== "undefined" && module.exports) {
|
|
541
|
+
module.exports = idiot;
|
|
542
|
+
} else {
|
|
543
|
+
global.idiot = idiot;
|
|
544
|
+
}
|
|
545
|
+
|
|
546
|
+
})(typeof window !== "undefined" ? window : global);
|