§1Welcome to Black Mirror Board
JPBlack Mirror Board は、デザイナーの「直感」を、エンジニアの「コマンド」で増幅するための無限キャンバスです。
ENBlack Mirror Board is an infinite canvas that amplifies a designer's intuition with an engineer's command layer.
- 🇯🇵 図形を描けば、ターミナルがそれに応えて言葉を返す。 / 🇬🇧 Draw a shape — the terminal answers in words.
- 🇯🇵 打鍵ではなく描画で、世界を構築していく。 / 🇬🇧 Build the world by gesture, not just by keystroke.
- 🇯🇵 個人の小さな呪文(コマンド)を SNS で共有し合い、他人の魔法を自分の道具にできる。 / 🇬🇧 Share tiny spells on SNS — someone else's magic becomes your tool.
🇯🇵 コードを書かない美学と、コマンドを打つ快感が交わる場所。それが Black Mirror です。
🇬🇧 It's where the aesthetic of "I don't write code" meets the thrill of "I speak to the machine."
Infinite canvas
Interactive terminal
Custom spells (localStorage)
SNS-portable JSON
3 themes
Zero deps
§2Basic Controls / 基本操作
Drawing / 描画
| Action / 動作 | How / やり方 |
| 図形を描く / Draw a shape | ツールバーから形を選び、キャンバスをドラッグ / Pick a tool, drag on canvas. |
| フリーハンド / Freehand | P で Pen。始点近くでリリース → 自動クローズ / P for Pen; release near start to auto-close. |
| テキスト / Text | T → click → type → Enter |
Zoom / ズーム · Pan / パン
| Action | Desktop | Mobile / Trackpad |
| Zoom in / out | Scroll wheel | Pinch |
| Reset view | Double-click | Double-tap |
| Pan canvas | Hold Space + drag | 2-finger drag |
Move · Rotate · Resize / 移動・回転・リサイズ
S → Select tool
· Click an object (or within 8px of its outline) to grab it.
· Drag to move.
· Drag the ○ handle above the bbox to rotate.
· Drag any of the 8 □ anchors to resize.
Modifier keys while resizing:
Shift Lock aspect ratio (corner handles).
Alt / Option Anchor to the center (symmetric scale).
Shift + Alt Both at once.
Images are aspect-locked on corners by DEFAULT —
Shift releases the lock, so photos never warp accidentally.
Marquee Selection / 範囲選択
Drag on empty canvas → dashed selection rectangle.
Any object that the marquee grazes (AABB intersection) → selected.
Then drag any selected object to move the whole group.
The group rotates + resizes like a single object.
Del / Backspace → delete all selected.
Esc → deselect all.
§3The Terminal Interface / ターミナル
JPBlack Mirror のターミナルは「環境音としてのログ」と「入力受付の対話型プロンプト」の二重構造です。入力欄は常に右下にあり、キーボードに触れればいつでもコマンドが打てます。
ENThe terminal is two things at once: an ambient log that hums with system activity, and an interactive prompt that accepts commands. The input is always pinned bottom-right.
History & Recall / 履歴の呼び出し
| Key | Action |
Enter | Execute current input. / 現在の入力を実行。 |
↑ | Recall the previous command. / 直前のコマンドを呼び戻す。 |
↓ | Move forward through history back toward the draft. / 履歴を前進し、元の下書きに戻る。 |
Esc | If USAGE overlay is open, close it first. / オーバーレイを優先して閉じる。 |
🇯🇵 履歴は最大 80 件まで localStorage に保存 — リロードしても残る。 / 🇬🇧 History persists (up to 80 entries) in localStorage — survives reload.
Built-in Commands / 組込みコマンド
── navigation ──
help / ? → in-terminal cheat sheet
usage / man / docs → summon the USAGE overlay
clear / flush → wipe terminal output
objects → dump every object on the board (debug)
── theme ──
light / dark / gray → switch canvas theme
── project (IndexedDB) ──
save <name> → snapshot canvas to local DB
ls → list saved snapshots
load <name> → restore snapshot
── spell management ──
list → list every registered command (preset / user flagged)
register <n> <js> → create a new spell
alias <new>=<old> → duplicate a spell under a new name
share <name> → copy spell JSON to clipboard
forget <name> → remove a user spell (presets protected)
── preset spells ──
$ scatter → scatter selected objects randomly
$ grid-3x3 → place a 3×3 grid at view center
$ biwako-blue → retint all strokes to #0044CC
$ fetch-img <kw> <n> → summon n images (Lorem Flickr, no key)
$ monoclo → grayscale the selected image(s)
$ svg → selection → editable vector SVG
── camera & sharing (v1.2) ──
Black Mirror → selfie camera wipe, top-right PIP
Black Mirror off → dismiss the camera wipe
share → canvas → shareable URL (modal, no args)
── export ──
export → selection as transparent PNG
export magic → spell picker modal
export data → bundle export modal (canvas / spells)
export-all → one-shot: project + all spells
export-spells [names] → one-shot: spells as a package
── easter egg ──
youtube → (try it)
§4Custom Commands / カスタムコマンドの魔法
JPBlack Mirror の最大の遊びは、「誰かが作ったコマンドを、SNS 経由で手に入れて、自分のボードで使える」ことです。
ENThe single most interesting thing about Black Mirror is that commands travel. Someone writes a spell, posts it on SNS, and with a single paste your board inherits it.
4.1 Importing a spell / 魔法を拾う
STEP · 01
🇯🇵 X / Discord / Slack などで以下のような JSON を見つける。
🇬🇧 Spot a JSON payload like this on social media.
{
"command": "scatter",
"action": "const sel = BM.getSelected(); for (const o of sel) BM.translate(o, BM.rand(-400,400), BM.rand(-300,300)); BM.log('scattered ' + sel.length);"
}
STEP · 02
🇯🇵 ターミナル入力欄にペーストする。
🇬🇧 Paste it directly into the terminal input.
STEP · 03
🇯🇵 自動で
$<name> として登録される。リロードしても残る。
🇬🇧 Auto-registered as
$<name>. Persists across reload.
paste > [JSON payload intercepted]
→ schema check... { command, action } ✓
→ binding $scatter → sandboxed function...
→ persisting to local storage...
[OK] spell acquired — run: $scatter
4.2 Exporting a spell / 魔法を放つ
share <name>
JPコマンドの JSON 定義をクリップボードにコピー。そのまま SNS に貼れば、誰でも拾える呪文として世界に放流できます。
ENCopies the spell's JSON to your clipboard. Paste it on SNS and you've just released a spell into the wild.
[CLIPBOARD] Copied to clipboard. Paste this on SNS!
───────────────────────────────────────────
{
"command": "scatter",
"action": "..."
}
───────────────────────────────────────────
4.3 Writing your own / 自作する
register <name> <javascript action>
Inside the action, the BM global is your interface:
| Method | What it does |
BM.getSelected() | selected object(s) as an array / 選択中のオブジェクト配列 |
BM.all() | every object on the board / 全オブジェクト |
BM.getById(id) | lookup a single object by id / ID検索 |
BM.find(fn) | filter objects by predicate / 条件検索 |
BM.create(type, props?) | spawn circle/square/triangle/arrow/text |
BM.update(obj|id, patch) | bulk-update data attributes / 属性一括更新 |
BM.translate(obj, dx, dy) | nudge an object / 移動 |
BM.setStroke(obj, color) | per-object line color / 個別線色 |
BM.setFill(obj, color) | per-object fill / 個別塗り |
BM.remove(obj) | delete an object / 削除 |
BM.clear() | wipe the canvas / 全削除 |
BM.viewCenter() | { x, y } current view center (world coords) |
BM.rand(min, max) | uniform random number / 一様乱数 |
BM.getMode() | current theme name / 現テーマ |
BM.setMode('dark') | switch theme programmatically |
BM.redraw() | repaint after mutations / 変更後の再描画(必須) |
BM.save() | commit state to undo history / Undo履歴に保存 |
BM.log(msg, cls?) | print to terminal ('t-ok' / 't-err' / 't-dim') |
🇯🇵 重要: BM.create('rect', ...) は使えません。四角は 'square' を使ってください。対応タイプは circle / square / triangle / arrow / text の5種のみです。
🇬🇧 Important: BM.create('rect', ...) is not supported. Use 'square' instead. The five valid types are circle / square / triangle / arrow / text.
4.4 Aliasing / 別名
alias ripple = scatter
JP既存コマンドを別の名前で複製します。呪文に自分の名前をつけたい時に。
ENDuplicates an existing spell under a new name. Brand the magic with your own naming.
4.5 Import collision behavior / 取り込み時の衝突回避
JPペーストや D&D で同名の魔法が送られてきた場合、既存の魔法は上書きされず、取り込んだ方が <name>_2026-04-19 のように日付サフィックス付きにリネームされます。action が完全一致の場合はスキップ。preset(組み込み魔法)は絶対に上書き不可。
ENWhen a spell with the same name arrives via paste or drop, existing spells are never overwritten. The incoming spell is renamed to <name>_2026-04-19. Identical payloads are skipped. Presets are always protected.
§4.5Images / 画像の召喚とモノクロ化
$ fetch-img — keyword-based image summoning
JPキーワードで画像を取得してキャンバスに配置します。API キー不要(Lorem Flickr 使用)。枚数指定で自動グリッド配置。
ENSummons photos from Lorem Flickr by keyword. No API key required. Multiple images auto-arrange into a grid.
| Command | Behavior |
fetch-img | default keyword "biwako", 1 image |
fetch-img mountain | "mountain" keyword, 1 image |
fetch-img mountain 6 | 6 images · auto 3×2 grid |
fetch-img tokyo night 9 | "tokyo night" · 9 images · 3×3 grid |
// Technical spec
endpoint : https://loremflickr.com/<w>/<h>/<keyword>?lock=<seed>
size : 240 × 180 per tile
gap : 20px
max : 25 images per invocation
output : color (use $ monoclo to grayscale after)
grid : cols = ceil(√n) · rows = ceil(n / cols)
cors : falls back to URL ref if dataURL conversion fails
$ monoclo — grayscale selected images
JP選択中の画像をグレースケール化します。カラーで fetch-img した画像を後からモノクロ統一したい時に。シェイプやペン線には効きません(エラー表示)。
ENGrayscales selected image objects. Pair with fetch-img to retroactively monochrome a mood board. Shapes and pen strokes are ignored (explicit error).
// Filter applied
grayscale(100%) contrast(110%) brightness(95%)
// Behavior
· selection required · multi-select supported
· updates obj.data.src to a new dataURL → persisted
· Cmd+Z reverts to the original color image
§5AI-Assisted Spells / AI に魔法を作らせる
JPJavaScript が書けなくても、Claude / ChatGPT に BM API を教え込めば、動く魔法 JSON を生成してくれます。このセクションはそのまま AI に渡せるテンプレートとして設計されています。
ENNon-coders can still author spells — hand Claude or ChatGPT the BM API spec and it returns working JSON. This section is designed to be copy-pasted directly into an AI chat.
5.1 Prompt template / プロンプト雛形
🇯🇵 以下のブロックを AI に貼って、最後の「リクエスト」部分だけ書き換えてください。 / 🇬🇧 Paste the block below into your AI chat and fill in the request at the bottom.
You are a Black Mirror Board spell author.
Return exactly one JSON object in this shape — nothing else:
{
"command": "name-of-spell (a-z 0-9 _ -, max 30 chars)",
"action": "javascript source as a string"
}
── BM API (the only functions available inside action) ──
BM.getSelected() / BM.all() / BM.getById(id) / BM.find(fn)
BM.create(type, props?) // type ∈ {circle, square, triangle, arrow, text}
BM.update(obj|id, patch) / BM.translate(obj, dx, dy)
BM.setStroke(obj, color) / BM.setFill(obj, color)
BM.remove(obj) / BM.clear()
BM.viewCenter() // {x, y}
BM.rand(min, max) / BM.getMode() / BM.setMode(mode)
BM.redraw() // call after any mutation
BM.save() // commits to undo history
BM.log(msg, cls?) // cls ∈ {t-ok, t-err, t-dim}
── Hard rules ──
1. Rect does not exist. Use 'square', not 'rect'.
2. No async/await at the top level — action runs synchronously.
Use .then() chains if you need Promises.
3. No import / require / external libraries.
4. Always call BM.redraw() after mutations.
5. For meaningful changes, call BM.save() so Cmd+Z works.
6. If the spell requires a selection, guard it:
if (!sel.length) { BM.log('select first', 't-err'); return; }
── Request ──
(write what you want in one or two sentences)
5.2 Short form / 超短縮版
🇯🇵 上のテンプレが長すぎる場合に。 / 🇬🇧 When the full template is overkill:
Make a Black Mirror Board spell as JSON: {"command":"NAME","action":"JS"}.
BM API: getSelected(), all(), create(type, props), translate(o,dx,dy),
setStroke/setFill(o, c), remove(o), viewCenter(), rand(min,max),
log(msg,cls), redraw(), save().
BM.create types: circle | square | triangle | arrow | text (NO rect).
No async/await. Always end with BM.redraw().
Request: (what you want)
5.3 Example round-trip / 応答例
YOU ↘
Request: 選択中の図形を画面中央に集めて、選択が無ければエラーにする
AI ↘
{
"command": "center-all",
"action": "const sel=BM.getSelected();if(!sel.length){BM.log('select first','t-err');return}const vc=BM.viewCenter();for(const o of sel){if(o.data.cx!==undefined){o.data.cx=vc.x;o.data.cy=vc.y}else if(o.data.x!==undefined){o.data.x=vc.x-(o.data.w||0)/2;o.data.y=vc.y-(o.data.h||0)/2}}BM.redraw();BM.save();BM.log('centered '+sel.length+' object(s)')"
}
YOU ↘
🇯🇵 JSON をコピー → ターミナルにペースト → 自動登録 → $ center-all で実行。
🇬🇧 Copy the JSON, paste into the terminal, auto-registers, run with $ center-all.
5.4 Common AI pitfalls / よくある失敗と対処
| Pitfall / 失敗 | Fix / 対処 |
AI が BM.create('rect', ...) を書く | "rect doesn't exist — use 'square'" と指摘して再生成 |
BM.redraw() 呼び忘れで画面が更新されない | 「変更後は必ず BM.redraw()」と強調 |
action の先頭で async を使う | 「action is synchronous — use .then()」と伝える |
外部ライブラリ (lodash 等) を使おうとする | 「BM API only, no external libs」と制約を明示 |
| エラーが出るが原因不明 | エラー文をそのまま AI にコピペで返す |
5.5 Growing a spell incrementally / 段階的に育てる
- 🇯🇵 最初は最小の魔法を頼む(動作1つ) / 🇬🇧 Start with the smallest version that works.
- 🇯🇵 取り込んで実行確認 / 🇬🇧 Register it and verify it runs.
- 🇯🇵 「次は選択が無いときの分岐を追加して」 / 🇬🇧 Then ask: "add a guard for empty selection."
- 🇯🇵 「次はランダム色を追加して」 / 🇬🇧 Then: "add random color."
- 🇯🇵 動く状態を保ちながら機能追加。一気に複雑化しないのがコツ。 / 🇬🇧 Keep it working at every step — avoid big-bang complexity.
§6Tutorial — Your First Command / 最初の一手
JPまずは呪文を撃ってみよう。
ENLet's cast your first spell.
STEP · 01
🇯🇵 画面上に適当な図形を 3〜5 個描いてください(鉛筆でも矩形でも OK)。
🇬🇧 Draw 3–5 objects anywhere on the canvas (pen strokes or squares, both work).
STEP · 02
🇯🇵 ターミナルに打ち込んで
Enter:
🇬🇧 Type into the terminal and hit
Enter:
biwako-blue
🇯🇵 → 全ての線が
#0044CC(琵琶湖の静寂を思わせる青)に変わる。
🇬🇧 → Every stroke turns to
#0044CC — the blue of Lake Biwa's silence.
STEP · 03
🇯🇵 Select ツールで全部まとめて範囲選択。
🇬🇧 With Select, marquee-drag to grab all objects.
STEP · 04
scatter
🇯🇵 → 選択したオブジェクトがランダムに散らばります。
🇬🇧 → The selected objects fling themselves into random positions.
STEP · 05
grid-3x3
🇯🇵 → ビュー中心に 3×3 のマスが整列配置されます。
🇬🇧 → A crisp 3×3 grid snaps into existence at the view center.
STEP · 06
fetch-img ocean 4
🇯🇵 → 「ocean」で検索した4枚の画像が 2×2 グリッドで配置されます。
🇬🇧 → 4 "ocean" images appear in a 2×2 grid · Lorem Flickr · no API key.
STEP · 07
🇯🇵 画像をマーキーで全選択してから:
🇬🇧 Marquee-select all the images, then:
monoclo
🇯🇵 → 画像が一括でモノクロ化されます。
Cmd+Z で戻せます。
🇬🇧 → All selected images grayscale in one pass.
Cmd+Z reverts.
🇯🇵 これで、あなたは5つの呪文を既に使ったことになります。
🇬🇧 You've just cast five spells. Now make your own.
Next Steps / 次の一歩
- Type
$ usage to summon the overlay manual from within the app.
- Type
$ help for a terminal-native cheat sheet.
- Write your own:
register <name> <js> → share <name> → paste to SNS.
- Try
export magic to bundle several spells as a shareable .json.
§7Keyboard Reference / キーボード完全版
TOOLS THEMES
──────────────────────────────── ────────────────────────────────
S Select dark Void theme
P Pen light Surface theme
N Path (anchor-by-click) gray Studio theme (cobalt)
E Eraser
C Circle COMMANDS
G Triangle ────────────────────────────────
Q Square help terminal cheat sheet
A Arrow usage overlay manual
T Text list list registered spells
I Upload image register create a new spell
X Export transparent PNG share copy spell JSON
alias duplicate as new name
WIDTH forget remove a user spell
──────────────────────────────── clear flush terminal
1 Thin ↑ / ↓ command history
2 Medium
3 Thick RESIZE MODIFIERS
────────────────────────────────
GLOBAL Shift lock aspect ratio
──────────────────────────────── Alt/Opt scale from center
Space Hold to pan Shift+Alt both at once
Ctrl+Z Undo
Ctrl+Y Redo
Del Delete selected
Esc Dismiss / deselect
§8Export & Import / 書き出しと取り込み
JPv1.2 で書き出し・取り込みが刷新されました。対話モーダル・D&D・衝突自動回避まで揃っています。
ENv1.2 overhauls the export and import story — modal pickers, drag-and-drop, and collision-safe auto-rename.
8.1 Export — 書き出し
| Command | Output | Flow |
export | transparent PNG | Selection (or all) · Save-As dialog |
$ svg | BM_CANVAS_*.svg | Selection (or all) · editable vector · Illustrator / Figma / Inkscape |
share | URL in modal | Canvas state → gzip-encoded URL · paste to SNS · recipient opens, board restores |
export magic | *_SPELLS.json | Modal · checkbox picker · pick any combination |
export data | *_BUNDLE.json or *_SPELLS.json | Modal · toggle canvas / user / preset |
share <name> | clipboard JSON | One spell · post to SNS directly |
export-all | *_BUNDLE.json | Non-interactive · full bundle |
export-spells [names] | *_SPELLS.json | Non-interactive · named or all user |
8.1c URL share — share でキャンバス丸ごと送る
JPshare を引数なしで打つと、現在のキャンバス状態が**gzip 圧縮 + base64url** でエンコードされ、URL hash に埋め込まれます。モーダルが開いて URL を表示、COPY URL でクリップボードへ。受信側が URL を開くと、自動で同じキャンバスが復元されます。
ENType share with no arguments and the current canvas gets gzip-compressed, base64url-encoded, and attached to the URL as a #s=... hash. A modal opens with the URL and a copy button. Whoever opens that URL reconstructs your board automatically.
// Typical size
10 shapes → ~1 KB
50 shapes → ~3 KB
200 shapes → ~8 KB (warning threshold)
500+ shapes → 10 KB+ (may break SNS link previews)
// Stripped to keep URL short
· image objects (dataURLs too heavy) → use export data for full fidelity
// Browser requirement
CompressionStream API — Chrome 80+ · Safari 16.4+ · Firefox 113+
// Receiver behavior
open URL → board loads with #s=... → decodes → replaces canvas
terminal logs "[SYSTEM] shared-state detected"
URL hash is cleared after load (reload is idempotent)
8.1b SVG export — ベクター書き出しの詳細
JP鉛筆ストローク・テキスト・シェイプ・画像を選択して svg と打つと、選択範囲だけを標準 SVG として保存します。選択が空ならキャンバス全体を出力。書き出した .svg は Illustrator / Figma / Inkscape で直接開いて、各オブジェクトをレイヤーとして編集できます。
ENSelect pen strokes, text, shapes, or images, type svg. The selection (or all objects, if selection is empty) is serialized as standard SVG. The resulting file opens in Illustrator / Figma / Inkscape as editable layered vectors.
// Mapping
circle → <ellipse> rotation → <g transform="rotate(...)">
square → <rect> color → obj.data.stroke / resolveFill(theme)
triangle → <polygon> fill → fill attribute (or none)
arrow → <line> + <polygon head> stroke → stroke attribute + stroke-width
text → <text dominant-baseline="hanging">
pen → <path d="M ... Q ..."> (closed strokes carry a final Z + fill)
image → <image href="dataURL"> (URL-only images: linked, may not load offline)
// Filename
BM_CANVAS_YYYYMMDD_HHMM.svg
// Background note
· Colors come from the current theme. Exporting from DARK mode
produces light strokes — view on a dark background, or switch
to LIGHT / GRAY mode first for print-friendly output.
8.2 Import — 取り込み
JPターミナルへのペースト、または画面への .json ファイル D&D で自動取り込みされます。形式は4種類を自動判別:
ENPaste into the terminal, or drop a .json file anywhere on the board. Four payload shapes are auto-detected:
1. single spell
{"command":"grain", "action":"..."}
2. array of spells
[{"command":"a", "action":"..."}, {"command":"b", "action":"..."}]
3. spells package
{"format":"blackmirror.spells", "version":"1.2", "commands":[...]}
4. full bundle (canvas + spells)
{"format":"blackmirror.bundle", "version":"1.2", "project":{...}, "commands":[...]}
8.3 Drop zone
JP.json ファイルをデスクトップからボードにドラッグすると、「◼ DROP JSON HERE」と点線枠が画面全体に現れます。ドロップすれば自動判別されて登録。
ENDrag a .json file onto the board and the whole screen shows a dashed overlay: "◼ DROP JSON HERE". Drop to auto-detect and register.
8.4 Bundle confirmation dialog
◼ BUNDLE DETECTED
incoming: 12 object(s), 3 spell(s)
current canvas: 5 object(s)
[O] OVERWRITE — replace current canvas with the bundle
[A] ADD — merge bundle into current canvas (re-IDs incoming)
[C] CANCEL — do nothing
🇯🇵 完全バンドル(キャンバス込み)を取り込む時だけ、3択の確認ダイアログが出ます。
🇬🇧 The confirmation dialog appears only for full bundles that include canvas objects.
8.5 Collision-safe rename / 衝突時の自動リネーム
| Situation | Result |
| Name not taken | Register as-is |
| User spell exists · identical action | SKIP — already there |
| User spell exists · different action | Rename to <name>_2026-04-19 |
| Rename target also exists | Append _2, _3, … |
| Collides with preset | Always renamed — preset never overwritten |
§9Capabilities & Limits / できること・できないこと
JP自作やAI生成で魔法を書く際、「できる・できない」の境界を先に知るとストレスが減ります。
ENKnowing the edges of what's possible up-front — especially when asking an AI to write spells for you — saves a lot of friction.
9.1 BM.create types (the only 5 valid)
| Type | Required props |
circle | { cx, cy, rx, ry } |
square | { x, y, w, h } ⚠ not rect |
triangle | { x, y, w, h } |
arrow | { x1, y1, x2, y2 } |
text | { x, y, text, fontSize } |
🇯🇵 rect / ellipse / polygon / path / line は未対応。square・circle(rx≠ry で楕円)・arrow 等で代用してください。
🇬🇧 rect / ellipse / polygon / path / line are not valid. Use square / circle (with different rx/ry) / arrow etc.
9.2 JS features available in actions
| Feature | Status |
async / await at top-level | ❌ action runs synchronously — use .then() chains |
import / require | ❌ no module system |
| External libraries (jQuery, Lodash, …) | ❌ not loaded |
setTimeout / setInterval | ✅ works (build your own stop condition) |
fetch() / new Image() | ✅ subject to CORS |
document.* / window.* | ⚠ accessible, but not recommended |
9.3 Canvas limits
~500 objects comfortable
~1000 still smooth
~10000+ likely to stall the browser
Tip: call BM.redraw() once after a bulk loop, not on every iteration.
9.4 External APIs via CORS
JP画像やAPIを外部から取得する魔法を書くなら、Access-Control-Allow-Origin: * を返すサーバーでないとブラウザがブロックします。Lorem Flickr・Picsum Photos・JSONPlaceholder 等は OK。
ENIf your spell fetches external data, the server must return Access-Control-Allow-Origin: *. Lorem Flickr, Picsum Photos, JSONPlaceholder all work; many others won't.
9.5 Persistence layout
- Spells (preset + user) → IndexedDB
blackmirror/commands + localStorage shadow
- Named projects (
save / load) → IndexedDB blackmirror/projects
- Terminal history →
localStorage key bm.termHistory.v1
- Everything is local-only. Nothing is uploaded.
🇯🇵 リロードしてもタブを閉じても残ります。ブラウザのデータを消すと消えるので、重要なワークは export data でファイル書き出し推奨。 / 🇬🇧 Survives reloads and tab-close. Lost if you clear browser data — use export data for hard backups.
9.6 Object data properties / オブジェクト型ごとのプロパティ
🇯🇵 BM.all() で返ってくる各オブジェクトの obj.data で読み書きできる属性。 / 🇬🇧 Attributes available on each object's obj.data, returned by BM.all().
circle { cx, cy, rx, ry, rotation, fill, stroke, strokeOff }
square { x, y, w, h, rotation, fill, stroke, strokeOff }
triangle { x, y, w, h, rotation, fill, stroke, strokeOff }
arrow { x1, y1, x2, y2, rotation }
text { x, y, text, fontSize, rotation, fill, stroke }
stroke { pts: [{x,y}, ...], lw, closed, fill, stroke, strokeOff } // pen drawing — read-only to BM.create
image { x, y, w, h, src (dataURL or URL) } // via fetch-img or I key
| Type | BM.create | Read | Move | Color | Remove |
circle / square / triangle | ✅ | ✅ | ✅ | ✅ | ✅ |
arrow / text | ✅ | ✅ | ✅ | ✅ | ✅ |
stroke (pen) | ❌ user-only | ✅ | ✅ | ✅ (v1.2) | ✅ |
image | ❌ via fetch-img / I | ✅ | ✅ | — | ✅ |
9.7 Use-case feasibility / ユースケース別の可否
| Want to do | Possible | Note |
| Clone selected objects / 選択を複製 | ✅ | Re-create with same props |
| Grid / lattice layouts / グリッド配置 | ✅ | Loop BM.create |
| Randomize colors / 色ランダム化 | ✅ | BM.setStroke + random hex |
| Rotate an object / 回転 | ✅ | Set obj.data.rotation in radians |
| Keyword image search / 画像検索 | ✅ | Lorem Flickr (CORS OK) |
| Film-grain texture / フィルムグレイン | ✅ | Scatter tiny squares |
| Play a sound / 音を鳴らす | ⚠ | new Audio().play() — user-gesture required |
| Animate objects / アニメーション | ⚠ | setInterval OK, set a stop condition yourself |
| PDF / SVG / GIF export | ❌ | PNG only |
| Embed video / 動画埋込 | ❌ | No video support in image type |
| Realtime multi-user edit / 共同編集 | ❌ | No server — local-only design |
| Cloud sync / クラウド同期 | ❌ | Manual bundle export/import only |
§10FAQ / トラブルシューティング
JPよくある問題と対処。ここを先に見るのが一番早い。
ENCommon problems and their fixes — check here first.
10.1 Drawing / 描画
| Symptom / 症状 | Fix / 対処 |
| 🇯🇵 絵が描けない / 🇬🇧 Can't draw | 🇯🇵 セレクトツール (S) になっている → P でペンに切替 / 🇬🇧 You're in Select — press P for Pen. |
| 🇯🇵 選択しているのに色が変わらない / 🇬🇧 Color change won't apply | 🇯🇵 v1.2 以前のペン線色バグ。最新 app.html を使う / 🇬🇧 Pre-v1.2 pen-stroke color bug. Reload with the latest app.html. |
| 🇯🇵 描いた絵が全部消えた / 🇬🇧 All my work disappeared | 🇯🇵 シークレットモードでは保存されない。重要なら save <name> と export data を併用 / 🇬🇧 Private/incognito tabs don't persist. Combine save <name> with export data for safety. |
10.2 Terminal / ターミナル
| Symptom | Fix |
command not found | 🇯🇵 スペルミス・$ の重複・list で登録名を確認 / 🇬🇧 Typo, duplicated $, or run list to verify the name. |
| 🇯🇵 実行ログは出るが何も起きない / 🇬🇧 Log prints but nothing visible | 🇯🇵 対象オブジェクトが 0 個、または画面外にいる。objects で確認 / 🇬🇧 Zero targets, or off-screen. Check with objects. |
| 🇯🇵 引数が表示から消える / 🇬🇧 Arguments look truncated | 🇯🇵 v1.2 以前の表示バグ。最新版で解消済み / 🇬🇧 Pre-v1.2 cosmetic bug — fixed in the current release. |
10.3 Spells / 魔法
| Symptom | Fix |
unknown type "rect" | 🇯🇵 BM.create('square', ...) に書き換え / 🇬🇧 Replace with 'square'. |
Cannot read property 'x' of undefined | 🇯🇵 BM.getById の戻り値 null チェックを入れる / 🇬🇧 Null-check the result of BM.getById. |
🇯🇵 取り込んだら $grain_2026-04-19 になった / 🇬🇧 Imported spell got a date suffix | 🇯🇵 既存名を保護する仕様。元を削るなら forget grain、別名にするなら alias grain=grain_2026-04-19 / 🇬🇧 Collision-safe rename. Remove original with forget, or re-point via alias. |
| 🇯🇵 preset を削除したい / 🇬🇧 Want to delete a preset | 🇯🇵 不可。preset は上書き・削除禁止 / 🇬🇧 Not possible — presets are immutable by design. |
🇯🇵 $ fetch-img で画像が出ない / 🇬🇧 No images from fetch-img | 🇯🇵 user 版が preset を上書きしている可能性 → forget fetch-img → リロード。あるいはオフライン / 🇬🇧 A user spell may be shadowing the preset — forget fetch-img and reload. Or you're offline. |
10.4 Export / Import
| Symptom | Fix |
🇯🇵 export しても PNG が落ちない / 🇬🇧 PNG doesn't download | 🇯🇵 キャンバスが空・モバイル Safari は共有シート / 🇬🇧 Canvas might be empty; on iOS the share sheet opens instead of a download. |
| 🇯🇵 D&D しても無反応 / 🇬🇧 Drop does nothing | 🇯🇵 拡張子が .json でない、JSON が壊れている、または複数ファイル(先頭のみ処理) / 🇬🇧 Wrong extension, invalid JSON, or multiple files dropped (only the first is processed). |
| 🇯🇵 バンドル取り込みで絵が消えた / 🇬🇧 Canvas wiped after bundle import | 🇯🇵 OVERWRITE を選んだため。Cmd+Z で戻せる場合あり。または最後の save を load で復元 / 🇬🇧 You picked OVERWRITE. Try Cmd+Z, or load your last save. |
10.5 Performance / パフォーマンス
| Symptom | Fix |
| 🇯🇵 動作が重い / 🇬🇧 Sluggish | 🇯🇵 objects で数を確認、1000 超なら分割推奨。画像が多いとメモリを食う / 🇬🇧 Run objects. Split if >1000. Many inline images eat memory. |
fetch-img 20枚以上で固まる | 🇯🇵 Lorem Flickr のレート制限。10枚ずつ取得を推奨 / 🇬🇧 Rate limit — fetch 10 at a time. |
10.5b Camera wipe / カメラワイプ
| Symptom | Fix |
🇯🇵 Black Mirror と打ってもカメラが出ない / 🇬🇧 Camera doesn't open | 🇯🇵 file:// だと secure-context 制約で動かない。HTTPS または localhost に / 🇬🇧 file:// blocks getUserMedia. Serve via python -m http.server or HTTPS. |
| 🇯🇵 許可したのに画面が真っ黒 / 🇬🇧 Allowed but video is black | 🇯🇵 他のアプリがカメラ占有中(Zoom 等)。Black Mirror off → Black Mirror で再試行 / 🇬🇧 Another app (Zoom etc.) holds the device. Cycle off/on. |
10.5c Share URL
| Symptom | Fix |
🇯🇵 share でモーダルが出ない / 🇬🇧 share does nothing | 🇯🇵 キャンバスが空 or Safari 16.3 以下(CompressionStream 未対応) / 🇬🇧 Empty canvas or Safari ≤16.3 (no CompressionStream). |
| 🇯🇵 URL が長すぎて SNS で壊れる / 🇬🇧 URL is too long for SNS | 🇯🇵 オブジェクト数を減らすか export data でファイル共有 / 🇬🇧 Reduce object count or use export data for a file bundle. |
| 🇯🇵 共有 URL を開いたらキャンバスが消えた / 🇬🇧 Receiving a share URL wiped my canvas | 🇯🇵 Cmd+Z で戻せる場合あり。事前に save <名前> 推奨 / 🇬🇧 Cmd+Z may help; pre-save with save <name>. |
10.6 Mobile / モバイル
| Symptom | Fix |
| 🇯🇵 iPhone で入力するとズームされる / 🇬🇧 iPhone auto-zooms on input | 🇯🇵 2026-04-18 修正済み(font-size 16px 以上に調整) / 🇬🇧 Fixed on 2026-04-18 — use the latest build. |
| 🇯🇵 長押しペーストで魔法が登録されない / 🇬🇧 Long-press paste doesn't register | 🇯🇵 2026-04-18 修正済み / 🇬🇧 Fixed on 2026-04-18. |
| 🇯🇵 タッチで描画できない / 🇬🇧 Touch drawing doesn't work | 🇯🇵 Safari の JS が無効の可能性。Chrome for iOS でも試す / 🇬🇧 Check that JavaScript is enabled; try Chrome for iOS as fallback. |
10.7 Still stuck? / それでも解決しない
- 🇯🇵 DevTools (F12) の Console でエラーログを取得 / 🇬🇧 Open DevTools (F12) → Console to capture the real error.
- 🇯🇵 再現手順を添えて SNS (#blackmirror) または GitHub Issues に報告 / 🇬🇧 Report to SNS (
#blackmirror) or GitHub Issues with the steps.
- 🇯🇵 「こういう魔法が作れない」系は §9 をまず確認 / 🇬🇧 For "spell X won't work" questions, check §9 first.