File size: 3,542 Bytes
9d4c549
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
<!DOCTYPE html>
<html lang="ko">
<head>
  <meta charset="UTF-8">
  <title>Pulsar Mini</title>
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <!-- Tailwind CDN (λΉ λ₯Έ ν”„λ‘œν† νƒ€μ΄ν•‘μš©) -->
  <script src="https://cdn.tailwindcss.com"></script>
  <style>
    /* custom utility μ‘°ν•© */
    body { @apply bg-gray-900 text-gray-100 flex flex-col items-center py-6 gap-6; }
    canvas { image-rendering: pixelated; }
  </style>
</head>
<body>
  <h1 class="text-3xl font-bold">Pulsar Mini</h1>

  <div class="flex flex-wrap gap-4 max-w-4xl w-full justify-center">
    <!-- Canvas μ˜μ—­ -->
    <canvas id="canvas" width="320" height="320" class="border border-gray-700 rounded"></canvas>

    <!-- 컨트둀 -->
    <div class="flex flex-col gap-3 w-80">
      <label class="text-sm font-mono">μ½”λ“œ:</label>
      <textarea
        id="code"
        rows="4"
        maxlength="300"
        class="w-full p-2 rounded bg-gray-800 font-mono text-xs resize-none outline-none"
      >(x,y,t)=>Math.sin(x*10+t)+Math.cos(y*10+t)</textarea>

      <div class="flex gap-2">
        <button id="play"  class="px-3 py-1 rounded bg-green-600 text-sm">β–Ά Play</button>
        <button id="pause" class="px-3 py-1 rounded bg-red-600 text-sm hidden">❚❚ Pause</button>
        <button id="random" class="px-3 py-1 rounded bg-blue-600 text-sm">🎲 Random</button>
      </div>

      <p class="text-[11px] text-gray-400 leading-snug">
        ν•¨μˆ˜λŠ” <code>(x,y,t,i) =&gt; κ°’</code> ν˜•μ‹μ΄μ–΄μ•Ό ν•©λ‹ˆλ‹€.<br>
        <code>x</code>, <code>y</code> λŠ” 0~1 μ’Œν‘œ, <code>t</code> λŠ” 초, <code>i</code>λŠ” ν”½μ…€ μΈλ±μŠ€μž…λ‹ˆλ‹€.<br>
        λ°˜ν™˜κ°’μ€ 0~1 λ²”μœ„λ‘œ ν΄λž¨ν”„λ˜μ–΄ κ·Έλ ˆμ΄μŠ€μΌ€μΌ 밝기둜 ν‘œν˜„λ©λ‹ˆλ‹€.
      </p>
    </div>
  </div>

<script>
const canvas = document.getElementById('canvas');
const ctx     = canvas.getContext('2d');
const codeEl  = document.getElementById('code');
const playBtn = document.getElementById('play');
const pauseBtn= document.getElementById('pause');
const rndBtn  = document.getElementById('random');

const EXAMPLES = [
  '(x,y,t)=>Math.sin((x+y+t)*6)',
  '(x,y,t)=>Math.sin(x*10+t)+Math.cos(y*10+t)',
  '(x,y,t)=>Math.sin(Math.hypot(x-0.5,y-0.5)*20-t*2)',
];

let fn = compile(codeEl.value);
let playing = false;
let start  = performance.now();

function compile(src){
  try { return eval(src); }
  catch(e){ console.error(e); return ()=>0; }
}

function draw(time){
  const t = (time - start) / 1000;
  const w = canvas.width;
  const h = canvas.height;
  const img = ctx.getImageData(0,0,w,h);
  const data = img.data;
  for(let y=0; y<h; y++){
    for(let x=0; x<w; x++){
      const idx = (y*w + x) * 4;
      const v = Math.max(0, Math.min(1, fn(x/w, y/h, t, idx)));
      const c = v * 255;
      data[idx] = data[idx+1] = data[idx+2] = c;
      data[idx+3] = 255;
    }
  }
  ctx.putImageData(img,0,0);
  if(playing) requestAnimationFrame(draw);
}

draw(start);

// event handlers
playBtn.addEventListener('click', () => {
  playing = true;
  playBtn.classList.add('hidden');
  pauseBtn.classList.remove('hidden');
  requestAnimationFrame(draw);
});

pauseBtn.addEventListener('click', () => {
  playing = false;
  pauseBtn.classList.add('hidden');
  playBtn.classList.remove('hidden');
});

codeEl.addEventListener('input', () => {
  fn = compile(codeEl.value);
});

rndBtn.addEventListener('click', () => {
  codeEl.value = EXAMPLES[Math.floor(Math.random()*EXAMPLES.length)];
  fn = compile(codeEl.value);
});
</script>
</body>
</html>