Spaces:
Running
Running
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) => κ°</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> |