99LETTERS STUDIO · USER MANUAL

BLACK MIRROR BOARD — USAGE

VERSION v1.2 LANGUAGES 日本語 × English UPDATED 2026-04-19 STATUS ● LIVE
 ██╗   ██╗███████╗ █████╗  ██████╗ ███████╗
 ██║   ██║██╔════╝██╔══██╗██╔════╝ ██╔════╝
 ██║   ██║███████╗███████║██║  ███╗█████╗
 ██║   ██║╚════██║██╔══██║██║   ██║██╔══╝
 ╚██████╔╝███████║██║  ██║╚██████╔╝███████╗
  ╚═════╝ ╚══════╝╚═╝  ╚═╝ ╚═════╝ ╚══════╝

§1Welcome to Black Mirror Board

Black Mirror Board is an infinite canvas that amplifies a designer's intuition with an engineer's command layer.

コードを書かない美学と、コマンドを打つ快感が交わる場所。それが 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.
フリーハンド / FreehandP で Pen。始点近くでリリース → 自動クローズ / P for Pen; release near start to auto-close.
テキスト / TextT → click → type → Enter

Zoom / ズーム   ·   Pan / パン

ActionDesktopMobile / Trackpad
Zoom in / outScroll wheelPinch
Reset viewDouble-clickDouble-tap
Pan canvasHold Space + drag2-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 / ターミナル

The 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 / 履歴の呼び出し

KeyAction
EnterExecute current input. / 現在の入力を実行。
Recall the previous command. / 直前のコマンドを呼び戻す。
Move forward through history back toward the draft. / 履歴を前進し、元の下書きに戻る。
EscIf 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 / カスタムコマンドの魔法

The 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>
Copies 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:

MethodWhat 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
Duplicates an existing spell under a new name. Brand the magic with your own naming.

4.5 Import collision behavior / 取り込み時の衝突回避

When 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 / 画像の召喚とモノクロ化

Screenshot → paste / drop — クリップボードから直接

Screenshot any region of your screen, then paste or drop it onto the board. Both routes flow through the same image placement pipeline (centered, scaled to fit, undo-safe).
OSクリップボードに撮る (paste with ⌘/Ctrl+V)ファイルに撮る (drag onto canvas)
macOS +Shift+Ctrl+4 +Shift+4 → デスクトップから D&D
Windows PrtScn(通常キー) / Win+Shift+S Win+PrtScn → ピクチャ > スクリーンショット から D&D
// Pipeline
clipboard image  →  paste handler  →  placeImageOnCanvas('paste')
file drop        →  drop handler   →  placeImageOnCanvas('drop')
file picker (I)  →  change handler →  placeImageOnCanvas('upload')

// All three routes share the same scaling, centering, undo, and terminal log.

$ fetch-img — keyword-based image summoning

Summons photos from Lorem Flickr by keyword. No API key required. Multiple images auto-arrange into a grid.
CommandBehavior
fetch-imgdefault keyword "biwako", 1 image
fetch-img mountain"mountain" keyword, 1 image
fetch-img mountain 66 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

Grayscales 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

⚠ Image Persistence — 画像の保存について

Images are NOT included in autosave (localStorage).
Shapes, text, and strokes save automatically, but image pixel data is too large for the localStorage quota.

To save a board that contains images:
Use the SAVE button or export data command to write a .json file.
The .json fully embeds all image data — OPEN restores everything exactly.

Cloud storage (iCloud, Dropbox, etc.):
Saving your .json to iCloud Drive lets you share boards across Mac, iPhone, and iPad. Avoid editing the same file on two devices simultaneously — the last save wins and conflicts may occur.
データオートセーブ.json 保存
テキスト・付箋・図形・線✅ 自動保存✅ 含まれる
画像(写真・スクショ等)❌ 保存されない✅ 含まれる
カスタムコマンド(Spells)✅ 自動保存✅ 含まれる

§5AI-Assisted Spells / AI に魔法を作らせる

Non-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.

完全な機械可読仕様: spell-spec.md · LLM index: llms.txtFull machine-readable spec: spell-spec.md · LLM index: llms.txt

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.clear()
BM.create(type, props)   // type ∈ {circle, square, triangle, arrow, text, sticky}
BM.update(idOrObj, patch) / BM.translate(obj, dx, dy)
BM.setStroke(obj, color) / BM.setFill(obj, color)
BM.remove(obj)
BM.viewCenter()  // {x, y}
BM.rand(min, max)
BM.redraw()      // call after any mutation
BM.save()        // commits to undo history
BM.log(msg, cls?) // cls ∈ {t-ok, t-err, t-dim}
args             // string passed at invocation: "$name foo bar" → args === "foo bar"

── Object types and props ──
circle:   {cx, cy, rx, ry, rotation, fill, strokeOff}
square:   {x, y, w, h, rotation, fill, strokeOff}
triangle: {x, y, w, h, rotation, fill, strokeOff}
arrow:    {x1, y1, x2, y2, rotation}
text:     {x, y, text, fontSize, rotation}
sticky:   {x, y, w, h, text, color, rotation}  // default color '#FFE873'

── 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; }

── FORBIDDEN — these are NOT BMBoard ──
internalName, displayName, description, icon, category, cost, mp, cooldown,
PROJECTILE, particle, onHit, effect, magic create, /bmboard, /reload,
plugins/, skills/, give, server-side, mod, plugin, manifest.
If you reach for any of these, you are off-spec — start over.

── 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. Output 1 line of JSON, no Markdown:
{"command":"NAME","action":"JS"}

BM API (only): getSelected(), all(), clear(), create(type, props),
update(o,patch), translate(o,dx,dy), setStroke/setFill(o,c), remove(o),
viewCenter(), rand(min,max), log(msg,cls), redraw(), save(). args = string.

Types: circle | square | triangle | arrow | text | sticky  (NO rect).
NEVER: internalName, displayName, cooldown, magic create, /bmboard,
plugins/, skills/. Those are not BMBoard.
No async/await. 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. 最初は最小の魔法を頼む(動作1つ)Start with the smallest version that works.
  2. 取り込んで実行確認Register it and verify it runs.
  3. 「次は選択が無いときの分岐を追加して」Then ask: "add a guard for empty selection."
  4. 「次はランダム色を追加して」Then: "add random color."
  5. 動く状態を保ちながら機能追加。一気に複雑化しないのがコツ。Keep it working at every step — avoid big-bang complexity.

§6Tutorial — Your First Command / 最初の一手

Let'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 ターミナルに打ち込んで EnterType 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 / 次の一歩

§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 / 書き出しと取り込み

v1.2 overhauls the export and import story — modal pickers, drag-and-drop, and collision-safe auto-rename.

8.1 Export — 書き出し

CommandOutputFlow
exporttransparent PNGSelection (or all) · Save-As dialog
$ svgBM_CANVAS_*.svgSelection (or all) · editable vector · Illustrator / Figma / Inkscape
shareURL in modalCanvas state → gzip-encoded URL · paste to SNS · recipient opens, board restores
export magic*_SPELLS.jsonModal · checkbox picker · pick any combination
export data*_BUNDLE.json or *_SPELLS.jsonModal · toggle canvas / user / preset
share <name>clipboard JSONOne spell · post to SNS directly
export-all*_BUNDLE.jsonNon-interactive · full bundle
export-spells [names]*_SPELLS.jsonNon-interactive · named or all user

8.1c URL share — share でキャンバス丸ごと送る

Type 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 — ベクター書き出しの詳細

Select 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 — 取り込み

Paste 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

Drag 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 / 衝突時の自動リネーム

SituationResult
Name not takenRegister as-is
User spell exists · identical actionSKIP — already there
User spell exists · different actionRename to <name>_2026-04-19
Rename target also existsAppend _2, _3, …
Collides with presetAlways renamed — preset never overwritten

§9Capabilities & Limits / できること・できないこと

Knowing 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)

TypeRequired 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 は未対応。squarecircle(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

FeatureStatus
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

If 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

リロードしてもタブを閉じても残ります。ブラウザのデータを消すと消えるので、重要なワークは 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
TypeBM.createReadMoveColorRemove
circle / square / triangle
arrow / text
stroke (pen)❌ user-only✅ (v1.2)
image❌ via fetch-img / I

9.7 Use-case feasibility / ユースケース別の可否

Want to doPossibleNote
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 exportPNG 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 / トラブルシューティング

Common 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 applyv1.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 / ターミナル

SymptomFix
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 truncatedv1.2 以前の表示バグ。最新版で解消済みPre-v1.2 cosmetic bug — fixed in the current release.

10.3 Spells / 魔法

SymptomFix
unknown type "rect"BM.create('square', ...) に書き換えReplace with 'square'.
Cannot read property 'x' of undefinedBM.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-19Collision-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-imguser 版が 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

SymptomFix
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 importOVERWRITE を選んだため。Cmd+Z で戻せる場合あり。または最後の saveload で復元You picked OVERWRITE. Try Cmd+Z, or load your last save.

10.5 Performance / パフォーマンス

SymptomFix
動作が重いSluggishobjects で数を確認、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 / カメラワイプ

SymptomFix
Black Mirror と打ってもカメラが出ないCamera doesn't openfile:// だと secure-context 制約で動かない。HTTPS または localhostfile:// blocks getUserMedia. Serve via python -m http.server or HTTPS.
許可したのに画面が真っ黒Allowed but video is black他のアプリがカメラ占有中(Zoom 等)。Black Mirror offBlack Mirror で再試行Another app (Zoom etc.) holds the device. Cycle off/on.

10.5c Share URL

SymptomFix
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 canvasCmd+Z で戻せる場合あり。事前に save <名前> 推奨Cmd+Z may help; pre-save with save <name>.

10.6 Mobile / モバイル

SymptomFix
iPhone で入力するとズームされるiPhone auto-zooms on input2026-04-18 修正済み(font-size 16px 以上に調整)Fixed on 2026-04-18 — use the latest build.
長押しペーストで魔法が登録されないLong-press paste doesn't register2026-04-18 修正済みFixed on 2026-04-18.
タッチで描画できないTouch drawing doesn't workSafari の JS が無効の可能性。Chrome for iOS でも試すCheck that JavaScript is enabled; try Chrome for iOS as fallback.

10.7 Still stuck? / それでも解決しない

  1. DevTools (F12) の Console でエラーログを取得Open DevTools (F12) → Console to capture the real error.
  2. 再現手順を添えて SNS (#blackmirror) または GitHub Issues に報告Report to SNS (#blackmirror) or GitHub Issues with the steps.
  3. 「こういう魔法が作れない」系は §9 をまず確認For "spell X won't work" questions, check §9 first.

JP · EN
·