Arduino 에뮬레이터: OLED 2x 렌더링으로 교체 — CSS 스케일링 의존 제거

aspect-ratio:2/1 미지원 브라우저에서 캔버스가 64px 자연 높이로
렌더링되어 가로로만 늘어나 '줄만 몇 개'로 보이는 버그 수정.

- canvas 128×64 → 256×128 (물리 픽셀 2배)
- JS 렌더러: 논리 픽셀 1개 → 2×2 물리 픽셀로 직접 기록
- CSS: image-rendering:pixelated + aspect-ratio 제거
  → max-width:100%; height:auto 로 브라우저 자연 스케일링

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
kim
2026-06-11 17:45:11 +09:00
co-authored by Claude Fable 5
parent cd269f017e
commit a12e671e80
+20 -12
View File
@@ -58,7 +58,7 @@
.oled-dot { width:6px; height:6px; border-radius:50%; background:#333; flex-shrink:0; }
.oled-dot.on { background:#60a5fa; box-shadow:0 0 4px #60a5fa; }
.oled-wrap { background:#000; border:2px solid #222; border-radius:4px; padding:4px; position:relative; }
#oled-canvas { display:block; image-rendering:pixelated; width:100%; aspect-ratio:2/1; }
#oled-canvas { display:block; max-width:100%; height:auto; }
.oled-placeholder { position:absolute; inset:4px; display:flex; flex-direction:column; align-items:center; justify-content:center; gap:4px; pointer-events:none; }
.oled-placeholder span { font-size:10px; color:#333; letter-spacing:.05em; }
.oled-placeholder .oled-ph-grid { width:100%; height:2px; background:repeating-linear-gradient(90deg,#1a1a1a 0,#1a1a1a 4px,transparent 4px,transparent 8px); }
@@ -179,7 +179,7 @@
SSD1306 OLED 128×64
</div>
<div class="oled-wrap">
<canvas id="oled-canvas" width="128" height="64"></canvas>
<canvas id="oled-canvas" width="256" height="128"></canvas>
<div class="oled-placeholder" id="oled-placeholder">
<div class="oled-ph-grid"></div>
<span>OLED 연결 대기</span>
@@ -455,20 +455,26 @@ function oledReset() {
function oledFlushCanvas() {
if (!oledCtx || !oledDirty) return;
oledDirty = false;
const img = oledCtx.createImageData(128, 64);
const fg = oled.inverse ? 0 : 255;
const bg = oled.inverse ? 255 : 0;
// 2x 렌더링: 캔버스 256×128, 논리 픽셀 1개 = 2×2 물리 픽셀
const img = oledCtx.createImageData(256, 128);
for (let page = 0; page < 8; page++) {
for (let col = 0; col < 128; col++) {
const byte = oled.gddram[page * 128 + col];
for (let bit = 0; bit < 8; bit++) {
const row = page * 8 + bit;
const idx = (row * 128 + col) * 4;
const on = (byte >> bit) & 1;
img.data[idx] = on ? fg : bg;
img.data[idx + 1] = on ? (oled.inverse ? 0 : 0x62) : bg; // slight blue tint when on
img.data[idx + 2] = on ? (oled.inverse ? 0 : 0xff) : bg;
img.data[idx + 3] = 255;
const row = page * 8 + bit;
const pr = on ? (oled.inverse ? 0 : 0xff) : 0;
const pg = on ? (oled.inverse ? 0 : 0x5a) : 0;
const pb = on ? 0xff : 0;
for (let dy = 0; dy < 2; dy++) {
for (let dx = 0; dx < 2; dx++) {
const idx = ((row * 2 + dy) * 256 + (col * 2 + dx)) * 4;
img.data[idx] = pr;
img.data[idx + 1] = pg;
img.data[idx + 2] = pb;
img.data[idx + 3] = 255;
}
}
}
}
}
@@ -726,7 +732,9 @@ function initEmulator(hex) {
totalCycles = 0;
lcdReset();
oledReset();
oledCtx = document.getElementById('oled-canvas').getContext('2d');
const oledCanvas = document.getElementById('oled-canvas');
oledCtx = oledCanvas.getContext('2d');
oledCtx.clearRect(0, 0, 256, 128);
buildPinUI();
let lastD13 = -1;