openfree commited on
Commit
df6a4c8
Β·
verified Β·
1 Parent(s): 9d4c549

Update index.html

Browse files
Files changed (1) hide show
  1. index.html +106 -87
index.html CHANGED
@@ -1,114 +1,133 @@
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) =&gt; κ°’</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>
 
1
  <!DOCTYPE html>
2
  <html lang="ko">
3
  <head>
4
+ <meta charset="UTF-8" />
 
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
+ <title>Pulsar Mini – Touch Reactive</title>
7
+
8
+ <!-- Tailwind CDN: ν”„λ‘œν† νƒ€μž…μš©, ν•„μš” μ‹œ 둜컬 λΉŒλ“œλ‘œ ꡐ체 -->
9
  <script src="https://cdn.tailwindcss.com"></script>
10
  <style>
11
+ body {
12
+ @apply bg-gray-900 text-gray-100 flex flex-col items-center justify-center min-h-screen gap-6 p-4 select-none;
13
+ }
14
+ canvas {
15
+ image-rendering: pixelated;
16
+ @apply border border-gray-700 rounded shadow-lg;
17
+ }
18
  </style>
19
  </head>
20
  <body>
21
+ <h1 class="text-3xl font-bold mb-2">Pulsar Mini</h1>
22
+ <p class="text-sm text-gray-400 mb-4 text-center">μΊ”λ²„μŠ€λ₯Ό νƒ­ν•˜κ±°λ‚˜ 클릭할 λ•Œλ§ˆλ‹€ μƒˆλ‘œμš΄ λ¬΄μž‘μœ„ νŒ¨ν„΄μ΄ μž¬μƒλ©λ‹ˆλ‹€.</p>
23
 
24
+ <canvas id="canvas"></canvas>
 
 
25
 
26
+ <div class="flex gap-3">
27
+ <button id="play" class="px-4 py-1.5 rounded bg-green-600 text-sm">β–Ά μž¬μƒ</button>
28
+ <button id="pause" class="px-4 py-1.5 rounded bg-red-600 text-sm hidden">❚❚ μΌμ‹œμ •μ§€</button>
29
+ <button id="random" class="px-4 py-1.5 rounded bg-blue-600 text-sm">🎲 랜덀</button>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
30
  </div>
31
 
32
+ <script>
33
+ const DPR = window.devicePixelRatio || 1;
34
+ const canvas = document.getElementById('canvas');
35
+ const ctx = canvas.getContext('2d');
36
+ const playBtn = document.getElementById('play');
37
+ const pauseBtn = document.getElementById('pause');
38
+ const rndBtn = document.getElementById('random');
39
+
40
+ // 10κ°€μ§€ 예제 + λ§€ ν˜ΈμΆœλ§ˆλ‹€ λ§€κ°œλ³€μˆ˜λ₯Ό 랜덀으둜 μ„žμŒ
41
+ const BASE_PATTERNS = [
42
+ '(x,y,t)=>Math.sin((x+y+t)*$FREQ)',
43
+ '(x,y,t)=>Math.cos((x-y+t)*$FREQ)',
44
+ '(x,y,t)=>Math.sin(Math.hypot(x-0.5,y-0.5)*$FREQ - t*3)',
45
+ '(x,y,t)=>Math.sin(x*$FREQ+t)+Math.cos(y*$FREQ+t)',
46
+ '(x,y,t)=>Math.sin((x*$FREQ+y*$FREQ+t*2))*Math.cos((x*$FREQ-y*$FREQ+t))',
47
+ '(x,y,t)=>Math.sin((x+y)*$FREQ + t*5)*0.5+0.5',
48
+ '(x,y,t)=>Math.sin(Math.atan2(y-0.5,x-0.5)*$FREQ + t*2)',
49
+ '(x,y,t)=>((Math.sin(x*$FREQ)+Math.cos(y*$FREQ+t))*0.5)+0.5',
50
+ '(x,y,t)=>Math.sin(((x-0.5)**2+(y-0.5)**2)*$FREQ - t*4)',
51
+ '(x,y,t)=>Math.sin((x*x - y*y)*$FREQ + t*3)'
52
+ ];
53
 
54
+ function pickRandomFormula() {
55
+ const tmpl = BASE_PATTERNS[Math.floor(Math.random()*BASE_PATTERNS.length)];
56
+ const freq = (Math.random()*30 + 10).toFixed(1); // 10~40 사이 주파수
57
+ return tmpl.replaceAll('$FREQ', freq);
58
+ }
59
 
60
+ let formulaSrc = pickRandomFormula();
61
+ let fn = compile(formulaSrc);
62
+ let playing = true;
63
+ let start = performance.now();
64
 
65
+ function resizeCanvas() {
66
+ const size = Math.min(window.innerWidth, window.innerHeight) * 0.8;
67
+ canvas.style.width = size + 'px';
68
+ canvas.style.height = size + 'px';
69
+ canvas.width = size * DPR;
70
+ canvas.height = size * DPR;
71
+ ctx.scale(DPR, DPR);
72
+ }
73
+ resizeCanvas();
74
+ window.addEventListener('resize', resizeCanvas);
75
 
76
+ function compile(src) {
77
+ try {
78
+ return eval(src);
79
+ } catch (e) {
80
+ console.error(e);
81
+ return () => 0;
 
 
 
 
 
 
 
82
  }
83
  }
 
 
 
84
 
85
+ function draw(time) {
86
+ const t = (time - start) / 1000;
87
+ const w = canvas.width / DPR;
88
+ const h = canvas.height / DPR;
89
 
90
+ const img = ctx.createImageData(w, h);
91
+ const data = img.data;
92
+ let i = 0;
93
+ for (let y = 0; y < h; y++) {
94
+ for (let x = 0; x < w; x++) {
95
+ const v = Math.max(0, Math.min(1, fn(x / w, y / h, t, i)));
96
+ const c = v * 255;
97
+ data[i++] = c; // R
98
+ data[i++] = c; // G
99
+ data[i++] = c; // B
100
+ data[i++] = 255; // A
101
+ }
102
+ }
103
+ ctx.putImageData(img, 0, 0);
104
+ if (playing) requestAnimationFrame(draw);
105
+ }
106
  requestAnimationFrame(draw);
 
107
 
108
+ function randomize() {
109
+ formulaSrc = pickRandomFormula();
110
+ fn = compile(formulaSrc);
111
+ start = performance.now();
112
+ }
113
+
114
+ // λ²„νŠΌ 이벀트
115
+ playBtn.addEventListener('click', () => {
116
+ playing = true;
117
+ playBtn.classList.add('hidden');
118
+ pauseBtn.classList.remove('hidden');
119
+ start = performance.now();
120
+ requestAnimationFrame(draw);
121
+ });
122
 
123
+ pauseBtn.addEventListener('click', () => {
124
+ playing = false;
125
+ pauseBtn.classList.add('hidden');
126
+ playBtn.classList.remove('hidden');
127
+ });
128
 
129
+ rndBtn.addEventListener('click', randomize);
130
+ canvas.addEventListener('pointerdown', randomize); // ν„°μΉ˜Β·ν΄λ¦­ λͺ¨λ‘ λŒ€μ‘
131
+ </script>
 
 
132
  </body>
133
  </html>