Spaces:
Running
Running
Update index.html
Browse files- index.html +114 -19
index.html
CHANGED
@@ -1,19 +1,114 @@
|
|
1 |
-
<!
|
2 |
-
<html>
|
3 |
-
|
4 |
-
|
5 |
-
|
6 |
-
|
7 |
-
|
8 |
-
|
9 |
-
|
10 |
-
|
11 |
-
|
12 |
-
|
13 |
-
|
14 |
-
|
15 |
-
|
16 |
-
|
17 |
-
|
18 |
-
|
19 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<!DOCTYPE html>
|
2 |
+
<html lang="ko">
|
3 |
+
<head>
|
4 |
+
<meta charset="UTF-8">
|
5 |
+
<title>Pulsar Mini</title>
|
6 |
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
7 |
+
<!-- Tailwind CDN (λΉ λ₯Έ νλ‘ν νμ΄νμ©) -->
|
8 |
+
<script src="https://cdn.tailwindcss.com"></script>
|
9 |
+
<style>
|
10 |
+
/* custom utility μ‘°ν© */
|
11 |
+
body { @apply bg-gray-900 text-gray-100 flex flex-col items-center py-6 gap-6; }
|
12 |
+
canvas { image-rendering: pixelated; }
|
13 |
+
</style>
|
14 |
+
</head>
|
15 |
+
<body>
|
16 |
+
<h1 class="text-3xl font-bold">Pulsar Mini</h1>
|
17 |
+
|
18 |
+
<div class="flex flex-wrap gap-4 max-w-4xl w-full justify-center">
|
19 |
+
<!-- Canvas μμ -->
|
20 |
+
<canvas id="canvas" width="320" height="320" class="border border-gray-700 rounded"></canvas>
|
21 |
+
|
22 |
+
<!-- 컨νΈλ‘€ -->
|
23 |
+
<div class="flex flex-col gap-3 w-80">
|
24 |
+
<label class="text-sm font-mono">μ½λ:</label>
|
25 |
+
<textarea
|
26 |
+
id="code"
|
27 |
+
rows="4"
|
28 |
+
maxlength="300"
|
29 |
+
class="w-full p-2 rounded bg-gray-800 font-mono text-xs resize-none outline-none"
|
30 |
+
>(x,y,t)=>Math.sin(x*10+t)+Math.cos(y*10+t)</textarea>
|
31 |
+
|
32 |
+
<div class="flex gap-2">
|
33 |
+
<button id="play" class="px-3 py-1 rounded bg-green-600 text-sm">βΆ Play</button>
|
34 |
+
<button id="pause" class="px-3 py-1 rounded bg-red-600 text-sm hidden">ββ Pause</button>
|
35 |
+
<button id="random" class="px-3 py-1 rounded bg-blue-600 text-sm">π² Random</button>
|
36 |
+
</div>
|
37 |
+
|
38 |
+
<p class="text-[11px] text-gray-400 leading-snug">
|
39 |
+
ν¨μλ <code>(x,y,t,i) => κ°</code> νμμ΄μ΄μΌ ν©λλ€.<br>
|
40 |
+
<code>x</code>, <code>y</code> λ 0~1 μ’ν, <code>t</code> λ μ΄, <code>i</code>λ ν½μ
μΈλ±μ€μ
λλ€.<br>
|
41 |
+
λ°νκ°μ 0~1 λ²μλ‘ ν΄λ¨νλμ΄ κ·Έλ μ΄μ€μΌμΌ λ°κΈ°λ‘ ννλ©λλ€.
|
42 |
+
</p>
|
43 |
+
</div>
|
44 |
+
</div>
|
45 |
+
|
46 |
+
<script>
|
47 |
+
const canvas = document.getElementById('canvas');
|
48 |
+
const ctx = canvas.getContext('2d');
|
49 |
+
const codeEl = document.getElementById('code');
|
50 |
+
const playBtn = document.getElementById('play');
|
51 |
+
const pauseBtn= document.getElementById('pause');
|
52 |
+
const rndBtn = document.getElementById('random');
|
53 |
+
|
54 |
+
const EXAMPLES = [
|
55 |
+
'(x,y,t)=>Math.sin((x+y+t)*6)',
|
56 |
+
'(x,y,t)=>Math.sin(x*10+t)+Math.cos(y*10+t)',
|
57 |
+
'(x,y,t)=>Math.sin(Math.hypot(x-0.5,y-0.5)*20-t*2)',
|
58 |
+
];
|
59 |
+
|
60 |
+
let fn = compile(codeEl.value);
|
61 |
+
let playing = false;
|
62 |
+
let start = performance.now();
|
63 |
+
|
64 |
+
function compile(src){
|
65 |
+
try { return eval(src); }
|
66 |
+
catch(e){ console.error(e); return ()=>0; }
|
67 |
+
}
|
68 |
+
|
69 |
+
function draw(time){
|
70 |
+
const t = (time - start) / 1000;
|
71 |
+
const w = canvas.width;
|
72 |
+
const h = canvas.height;
|
73 |
+
const img = ctx.getImageData(0,0,w,h);
|
74 |
+
const data = img.data;
|
75 |
+
for(let y=0; y<h; y++){
|
76 |
+
for(let x=0; x<w; x++){
|
77 |
+
const idx = (y*w + x) * 4;
|
78 |
+
const v = Math.max(0, Math.min(1, fn(x/w, y/h, t, idx)));
|
79 |
+
const c = v * 255;
|
80 |
+
data[idx] = data[idx+1] = data[idx+2] = c;
|
81 |
+
data[idx+3] = 255;
|
82 |
+
}
|
83 |
+
}
|
84 |
+
ctx.putImageData(img,0,0);
|
85 |
+
if(playing) requestAnimationFrame(draw);
|
86 |
+
}
|
87 |
+
|
88 |
+
draw(start);
|
89 |
+
|
90 |
+
// event handlers
|
91 |
+
playBtn.addEventListener('click', () => {
|
92 |
+
playing = true;
|
93 |
+
playBtn.classList.add('hidden');
|
94 |
+
pauseBtn.classList.remove('hidden');
|
95 |
+
requestAnimationFrame(draw);
|
96 |
+
});
|
97 |
+
|
98 |
+
pauseBtn.addEventListener('click', () => {
|
99 |
+
playing = false;
|
100 |
+
pauseBtn.classList.add('hidden');
|
101 |
+
playBtn.classList.remove('hidden');
|
102 |
+
});
|
103 |
+
|
104 |
+
codeEl.addEventListener('input', () => {
|
105 |
+
fn = compile(codeEl.value);
|
106 |
+
});
|
107 |
+
|
108 |
+
rndBtn.addEventListener('click', () => {
|
109 |
+
codeEl.value = EXAMPLES[Math.floor(Math.random()*EXAMPLES.length)];
|
110 |
+
fn = compile(codeEl.value);
|
111 |
+
});
|
112 |
+
</script>
|
113 |
+
</body>
|
114 |
+
</html>
|