KINOSHITA STUDIO · RELEASE DOSSIER

BLACK MIRROR BOARD — DEV LOG

VERSION v0.1 → v1.2+ SHIP DATE 2026-04-19 · v1.2 LIVE ROUTE blackmirrorboard.github.io/bmboard AUTHOR Kinoshita Studio STATUS ● LIVE · evolving
 ██████╗ ██╗      █████╗  ██████╗██╗  ██╗    ███╗   ███╗██╗██████╗ ██████╗  ██████╗ ██████╗
 ██╔══██╗██║     ██╔══██╗██╔════╝██║ ██╔╝    ████╗ ████║██║██╔══██╗██╔══██╗██╔═══██╗██╔══██╗
 ██████╔╝██║     ███████║██║     █████╔╝     ██╔████╔██║██║██████╔╝██████╔╝██║   ██║██████╔╝
 ██╔══██╗██║     ██╔══██║██║     ██╔═██╗     ██║╚██╔╝██║██║██╔══██╗██╔══██╗██║   ██║██╔══██╗
 ██████╔╝███████╗██║  ██║╚██████╗██║  ██╗    ██║ ╚═╝ ██║██║██║  ██║██║  ██║╚██████╔╝██║  ██║
 ╚═════╝ ╚══════╝╚═╝  ╚═╝ ╚═════╝╚═╝  ╚═╝    ╚═╝     ╚═╝╚═╝╚═╝  ╚═╝╚═╝  ╚═╝ ╚═════╝ ╚═╝  ╚═╝

Premise

Black Mirror Board は、ターミナル駆動型の無限キャンバス。 マウス/タッチ/ペン入力を1つのモデルに統合し、「図形を描く」と「コマンドを打つ」の境界を溶かすツールとして構築された。

This document catalogs the full development arc from initial sketch (v0.1) through the v1.0 release. Each phase is presented in chronological order with the driving prompt, the resolved challenge, and the resulting capability.

HTML5 Canvas Pointer Events Vanilla JS Zero deps Minimalism Monochrome

Phase Log · v0.1 → v1.0

v0.1 · PROTOTYPE

Terminal + canvas skeleton

2026-04-08 — initial commit
  • Split pane layout: canvas (left) + terminal (right).
  • Basic shapes — circle / square / triangle / arrow / text.
  • Pen tool with freehand stroke capture.
  • ASCII-only UI chrome, no colors beyond greyscale.
v0.3 · INTERACTION

Selection, drag, rotation, zoom

2026-04-10
  • Unified Pointer Event handling for mouse / touch / pen.
  • Space-key pan + pinch-zoom for tablet parity.
  • Rotation handle above the bounding box.
  • Multi-select via marquee drag; group move / resize / rotate.
v0.5 · VECTOR EDIT

Illustrator-style anchor system

2026-04-12
  • Per-vertex anchor handles on pen strokes & triangles.
  • 8-handle bbox resize on squares / images / text.
  • Cardinal handles on circles (single-radius edits).
  • RDP simplification on freehand strokes → editable anchor count.
v0.7 · EXPORT

JSON persistence + transparent PNG

2026-04-13
  • Export entire project (canvas + terminal log) as a single JSON blob.
  • PNG export on offscreen canvas — tight bbox + transparent background.
  • Selection-aware export: exports only selected objects when present.
  • 3× DPR cap to prevent memory spikes on high-resolution exports.
v0.9 · VOID THEME

Dark mode + fill-swatch theming

2026-04-14
  • Terminal command dark mode / light mode engages a glitch-flash mode transition.
  • All object fills invert on mode switch (resolveFill() channel inversion).
  • Swatch SVGs refactored to class-based CSS variables so the toolbar flips in lockstep.
  • Toolbar elevated off pure-black canvas with a subtle shadow for contrast.
v1.0 · STUDIO RELEASE

Gray mode · Hit-test 2.0 · Shift-lock resize

2026-04-16 — ship date
  • Gray mode — pebble ground #DCDBD5 / cobalt ink #1600A2. Dedicated CSS-variable theme alongside light/dark, triggered by gray command.
  • Hit-test 2.0 — segment-distance hit testing on strokes; 8px invisible padding; hover glow + directional cursors.
  • Shift-lock resize — aspect-ratio preserved on corner handles; Alt anchors to center; images lock by default.
  • Snap scale — ×0.5 / ×1 / ×1.5 / ×2 magnet windows during Shift-resize.
  • Theme-aware selection — selection box and marquee auto-invert for max contrast in each mode.
v1.1 · INTERIM POLISH

Modifier reliability · Cursor language · Escape routes

2026-04-17 → 2026-04-18
  • Modifier pipeline — Shift / Alt read from a window-level S.modifiers ledger so holding a key mid-drag updates geometry instantly; window blur resets the ledger to defeat the classic "stuck Shift after tab-swap" bug.
  • Directional cursors — corner / edge / rotate handles expose OS cursors matching their drag axis; dashed directional glyphs on hover.
  • Escape routesEsc abandons any in-flight gesture (drag, marquee, rotate, resize, text edit) back to neutral; double-click exits text mode cleanly.
  • Text editing rigour — commit on blur or Enter, cancel on Esc; click outside drops focus without losing the object.
v1.2 · SPELLBOOK RELEASE

SVG export · camera wipe · share URL · custom spells

2026-04-19 — ship date
  • SVG export — typing svg in the terminal writes a native SVG of the current selection (or the whole canvas). Every primitive translates: circle→<ellipse>, square→<rect>, triangle→<polygon>, arrow→<line>+<polygon>, text→<text dominant-baseline="hanging">, pen stroke→<path M…Q…>, image→<image>. Rotation wraps as <g transform="rotate()">. Colors resolved via resolveFill(). Opens in Figma / Illustrator / Inkscape editable.
  • Black Mirror camera wipe — the phrase Black Mirror flips on getUserMedia and docks a 220×165 PIP in the top-right (128×170 on mobile). Red REC dot, ◼ BLACK MIRROR label in mix-blend-mode: difference, selfie-mirrored with a faint grayscale + contrast filter for the CRT look. Hover exposes an × close; Black Mirror off also releases all tracks. The wipe is draggable — place it anywhere on screen.
  • Share URLshare with no args gzips the canvas + terminal state via native CompressionStream, base64-urls it, and copies a self-contained link. Opening the URL on any device restores the full board. share vs share url selects between file download and clipboard.
  • Custom spells — pasting a JSON payload into the terminal runs a schema check, binds it to IndexedDB, and exposes it as a named command. Features travel as text, one line at a time. BM API + natural language prompts to Claude / ChatGPT produce runnable spells.
  • Preset libraryscatter, grid-3x3, biwako-blue, fetch-img, monoclo, svg ship with the app, each as JSON-portable spells that can be dumped, remixed, and re-shared.
  • Image brainstormfetch-img <keyword> pulls public images for the word, scatters them on the canvas with rotation + margin, turning the board into a self-writing mood-board.
  • Del / Backspace fix — the delete key was swallowed by inputs outside text-edit mode; now correctly removes the selection, with the text-edit exception restored.
  • FEEDBACK modal — tap the logo → prefilled feedback form with subject auto-stamped per version; studio email + Instagram + X links consolidated.
  • Manual split — v1.2 manual authored in Obsidian (JP + EN), exported as markdown files under v1.2_manual_ja/ and v1.2_manual_en/.
v1.2+ · POST-RELEASE EVOLUTION

Brand routing · capabilities grid · responsive chrome · OGP

2026-04-20 → 2026-04-22 (ongoing)
  • URL migration — moved from 99letters.github.io/projects/black_mirror/ to the canonical blackmirrorboard.github.io/bmboard/. All ../../md.html / ../../history.html references absolutized to https://99letters.github.io/… so the new origin still reaches the dev log.
  • Rebrand — studio name corrected everywhere: "99letters studio" → "kinoshita studio" across 22 manual files, README.md, usage docs, app.html footer, terminal ghost lines (Playing: kinoshita studio / Black Mirror Board), and INDEX frontmatter tags. The 99letters domain remains as the GitHub identity only.
  • ASCII-art render fix — the BM pixel logo in README/overview collapsed because Courier New / SF Mono render (U+2588) shorter than the cell, leaving vertical gaps. Loaded JetBrains Mono via Google Fonts and force-applied font-size: 14px; line-height: 1; letter-spacing: 0; word-spacing: 0 to the logo <pre> with !important.
  • index.html — CAPABILITIES section — six new feature cards ship below the Dual Perspective section, each with a 16:9 demo-frame SVG illustration: SVG Export / Transparent PNG / Image Brainstorm / Custom Spells / SNS Share / Camera + YouTube Live. Monochrome 1-bit aesthetic preserved.
  • index.html — light / dark theme — a 1-bit inversion toggle (● · ○) next to the EN/JA switch. All colors run through CSS variables (--ink / --void / --scan-color / --glow-halo / --checker-fill / --header-bg); hard-coded whites and blacks were removed. prefers-color-scheme is honored on first visit; choice persists via bmboard.theme in localStorage. An inline head script applies the saved theme before paint to defeat flash-of-wrong-theme. Dark-ink logo.png is inverted via CSS filter: invert(1) in dark mode only, left as-is in light mode.
  • app.html — theme extensiondark and gray commands now also theme the header (background, border, .hbtn, .hlink, .zoom-label, .logo*). All colors read from the existing --bm-tb-* / --bm-fg / --bm-fg-dim tokens. Logo PNG inverted only in dark mode.
  • app.html — mobile header — logo pinned to the left, right-side chrome optimized for narrow viewports: FLUSH + CLEAR hidden (still reachable via terminal), icon+label stacked vertically inside each .hbtn (36px square), OVERVIEW split across two lines as OVER / VIEW with the arrow removed. All buttons' icons centered in their box via inline-flex; justify-content: center.
  • app.html — header grid — replaced the old margin-left: auto trick with an explicit 2-column grid (grid-template-columns: auto 1fr), logo in column 1, right buttons in column 2 with justify-self: end. Predictable on every viewport.
  • OGP imageog-image.svg (1200×630) authored for both index.html and app.html: black ground with scanline texture, corner brackets, top-right ● REC ON AIR, 400-px logo (base64-embedded, SVG feColorMatrix inverted to white), title stack BLACK MIRROR / BOARD, subtitle DRAW · SPEAK · CAST, version strip.
  • Overview README tab — BM pixel ASCII now renders crisply in Courier-deprived browsers via the JetBrains Mono fix + font-feature-settings: "liga" 0, "calt" 0.

Driving Prompts

The core prompts that shaped v1.0 — quoted verbatim from Kinoshita Studio, paraphrased where long.

Dark Mode 時の図形・塗りの視認性改善。背景は反転するが、図形の「塗り(Fill)」や一部のスタイルが以前の黒(または濃い色)のまま残っているため、視認性が著しく低下している。
第3のモードとして、ユーザーが最も頻繁に使用する "gray" モードを追加してください。 背景 #DCDBD5 / アクセント #1600A2。最高にクールな青のコントラストを実現して。
PCでの操作時、特に細い鉛筆やパスツールで描いたオブジェクトを選択・移動する際、正確に線の上をクリックしないと掴めない。判定領域を「見た目の線+左右に 5〜8px」に拡張し、「直感的に掴める」プロの道具としての精度を完成させて。
Shiftキー連動のアスペクト比固定。角のハンドルをドラッグしてリサイズする際、Shiftキーが押されている間は、オブジェクトの元のアスペクト比を完全に維持して拡大縮小するようにしてください。画像のリサイズで比率が崩れるのは致命的。

Resolved Technical Challenges

500 ERR
Local server 500 error — PermissionError 初期に python -m http.server~/ から起動した際、OS のアクセス制限でサブディレクトリの HTML が 500 を返した。 プロジェクトローカルの server.pyprojects/black_mirror/ 直下で立ち上げるフローに変更して解決。
RESIZE
5箇所に重複していた 8-handle bbox スイッチ circle / triangle / square+image / arrow / text / stroke の各 applyAnchor ブロックに同一の switch が copy-paste されていた。 resizeBoxWithMods(anchorId, ob, nx, ny, shift, alt) に一本化し、Shift/Alt の挙動を一点で管理できるようにした。
HIT-TEST
Sparse stroke vertices created unclickable gaps RDP simplification 後の折線は頂点間に最大 20–30px の空間ができ、「線の上を狙ってクリックしないと掴めない」問題が発生していた。 pointToSegDist() によるセグメント距離判定 + 閉パスの ray-cast fill check に切替えて解決。
THEME
ハードコードされた fill swatch SVG popover 内のスウォッチが fill="#111" / fill="#FAFAF8" 直書きで、dark/gray モードで溶けていた。 .sw-black / .sw-grey / .sw-white / .sw-ind クラスに置換し、var(--bm-swatch-*) で自動反転させる設計に。
MODIFIER
ドラッグ途中で Shift を押しても制約が効かない PointerEvent の shiftKey をその都度読んでいたため、マウスが停止した状態で Shift を押しても再評価されなかった。 window keydown/keyupS.modifiers を更新し、S.lastAnchorPt を保持して即座に applyAnchor() を再実行することで解決。
BLUR
Stuck Shift after tab-switch window blur で S.modifiers を強制リセット。タブを戻したときに「Shift が押されっぱなし扱い」になる問題を根絶。

v1.0 Ship Manifest

What's In

What's Out (intentionally)

Architecture Notes

State model

Single S object holds all mutable canvas state; VIEW holds pan/zoom; MODE holds theme. No framework, no reactive glue — changes call redrawAll() explicitly.

Theme tokens

Per-mode CSS custom properties (--bm-canvas-bg, --bm-fg, --bm-tb-bg, --bm-accent, --bm-swatch-*) toggled via body.bm-dark / body.bm-gray. Single class swap cascades the entire UI.

Fill resolution

Objects store canonical light-mode fills. resolveFill() translates at render time: dark → channel-inverted, gray → cobalt family. No mutation of stored data — mode switch is pure view.

Resize modifier pipeline

One helper (resizeBoxWithMods) normalizes 8-handle bbox math + shift/alt constraints. Single source of truth for single-object anchors and multi-select group resize alike.


·