魔法の書式Spell format
1行のJSONで、ボードの上で動くものを作れる。作ったものは書き出して人に配れる。
AIに書かせるためのプロンプトも用意してある。A spell is one line of JSON that makes something happen on the board — and it travels as text, so you can hand it to someone. A ready-made prompt for AI is included.
JSON · one line · no build step
まず動く例を1つ0. Lead with a working example
中央から🔥を15個ばらまいて、外へ飛ばしながら小さくして、最後に自分で片づける魔法。これをコピーして、形を真似るのが一番早い。A spell that scatters 15 🔥 from view center, animates them outward while shrinking, then cleans up after itself. Copy this and match its shape.
{"command":"fire","action":"const N=15,vc=BM.viewCenter();const sparks=[];for(let i=0;i<N;i++){const s=BM.create('text',{x:vc.x,y:vc.y,text:'🔥',fontSize:20+Math.random()*20});sparks.push({o:s,vx:(Math.random()-0.5)*15,vy:(Math.random()-0.5)*15});}let f=0;const id=setInterval(()=>{if(f++>40){clearInterval(id);for(const s of sparks){const i=BM.all().indexOf(s.o);if(i>=0)BM.all().splice(i,1);}BM.redraw();BM.log('fire: extinguished.');return;}for(const s of sparks){s.o.data.x+=s.vx;s.o.data.y+=s.vy;s.o.data.fontSize*=0.92;}BM.redraw();},30);BM.log('fire: burst of 15 sparks.');"}
ここから読み取れること:What this teaches you:
- 魔法は「command」と「action」の2つだけを持つ1行のJSON。それ以外の項目は無い。A spell is one line of JSON with exactly two keys:
commandandaction. Nothing else. actionは JavaScript を文字列にしたもの。new Function("BM","args",action)で実行される。actionis a string of raw JS, executed vianew Function("BM","args",action).- よくある形=
BM.create()で置く →setIntervalで動かす → 片づける → 毎回BM.redraw()→BM.log()で結果を出す。Typical pattern:BM.create()→setInterval→ clean up →BM.redraw()after each change →BM.log()for status.
魔法には2種類あるTwo kinds of spell
この頁が説明しているのはコードで書く魔法(action型)。もう1つ、図形を置くだけの魔法(ops型)がある。ops型は置ける形が決まっていて(square / sticky / text / circle / triangle / arrow)、コードは一切実行されない。STOREでは「図形を置くだけ」と「コードで動く」を分けて表示していて、コード型は掲載前に審査を通している。This page describes the code kind (action). There is also a shapes-only kind (ops), limited to a fixed set of shapes (square / sticky / text / circle / triangle / arrow) with no code execution at all. The STORE labels the two separately, and code spells are reviewed before they are listed.
選んだものを spell 名前 で保存すると ops 型になる。動きを付けたいときだけ action 型を書く。Saving a selection with spell name produces an ops spell. Write an action spell only when you want motion.
書式1. The format
{"command":"NAME","action":"JAVASCRIPT_CODE_AS_A_STRING"}
"command"— 呼び出す名前。小文字・数字・ハイフン・アンダースコアで1〜31文字。登録すると、ターミナルや ⌘K からその名前で呼べる。"command"— the invocation name. Lowercase letters, digits, hyphens, underscores. 1–31 chars."action"— JavaScript を文字列にしたもの。中身がそのまま関数の本体になる(構造化されたオブジェクトではない)。"action"— raw JavaScript as a string. The string IS the function body; it is NOT a structured object.
他の項目は無い。1行で出力する(Markdownの囲みや前置きの文章は付けない)。There are no other fields. Output a single line — no Markdown fences, no leading prose.
使ってはいけない言葉2. Forbidden / hallucinated terms
⚠️次の語は他のシステム(ゲームのプラグイン等)のもので、BM BOARD では意味を持たない。AIがよく混ぜてくるので、出てきたら書式から外れている合図。⚠️These belong to other systems (game plugins, RPG engines) and have no meaning in BM BOARD. If you find yourself reaching for any of them, you are off-spec.
internalName, displayName, description, icon, category, cost, mp, cooldown, actions (as array), PROJECTILE, particle, onHit, effect, range, power, type (top-level), magic create, /bmboard, /reload, plugins/, skills/, give, server-side, mod, plugin, manifest
action の中で使える BM.*3. The BM.* API
⚠️ここに無いものは使えない。AIに書かせるときは、この表をそのまま渡すのが確実。⚠️Nothing outside this table is available. When prompting an AI, hand it this table verbatim.
| Symbol | Meaning |
|---|---|
BM.log(msg, cls?) | Print to terminal. cls is 't-ok' / 't-err' / 't-dim' / undefined. |
BM.viewCenter() | Returns {x, y} — current canvas view center in world coordinates. |
BM.create(type, props) | Adds a new canvas object. Returns the object. |
BM.translate(obj, dx, dy) | Move obj by delta. |
BM.update(idOrObj, patch) | Patch obj's data with given properties. |
BM.remove(obj) | Remove obj from canvas. |
BM.setStroke(obj, color) | Set stroke color. |
BM.setFill(obj, color) | Set fill color. |
BM.all() | Array of all canvas objects (mutable — use .splice to remove). |
BM.getSelected() | Array of currently-selected objects. |
BM.clear() | Wipe all canvas objects. |
BM.redraw() | Force a repaint. Call after every mutation. |
BM.save() | Push a history snapshot for undo. |
BM.rand(min, max) | Random number in [min, max]. |
args | String passed at invocation. $name foo bar → args === 'foo bar'. |
置けるものと、その設定4. Object types and props
| type | 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} or {pts:[{x,y},{x,y},{x,y}], rotation, fill} |
arrow | {x1, y1, x2, y2, rotation} |
text | {x, y, text, fontSize, rotation} |
sticky | {x, y, w, h, text, color, rotation} (default color: '#FFE873') |
もう少し例5. More working examples
いちばん短いもの — 中央に黄色い付箋を置く5.1 Minimal — drop a yellow sticky at view center
{"command":"hi","action":"const c=BM.viewCenter();BM.create('sticky',{x:c.x-100,y:c.y-100,w:200,h:200,text:'hello'});BM.redraw();BM.log('placed.');"}
同じ名前で始めて止める(トグル)5.2 Toggle pattern (start / stop on the same command)
{"command":"snowy","action":"if(window._snowyId){clearInterval(window._snowyId);window._snowyId=null;BM.log('stopped.');return;}let i=0;const c=BM.viewCenter();const items=[];for(let k=0;k<40;k++){const o=BM.create('text',{x:c.x+Math.random()*1200-600,y:c.y-400-Math.random()*200,text:'❄',fontSize:14+Math.random()*10});items.push({o,vy:0.5+Math.random()*1.2});}window._snowyId=setInterval(()=>{if(i++>10000){clearInterval(window._snowyId);window._snowyId=null;return;}for(const it of items){it.o.data.y+=it.vy;if(it.o.data.y>c.y+400){it.o.data.y=c.y-400;it.o.data.x=c.x+Math.random()*1200-600;}}BM.redraw();},30);BM.log('snowy: running. $snowy again to stop.');"}
選択中のものを使う — 選んだ全部の色を変える5.3 Use selection — recolor every selected object
{"command":"red","action":"const sel=BM.getSelected();if(!sel.length){BM.log('select first','t-err');return;}for(const o of sel){BM.setStroke(o,'#FF0000');}BM.redraw();BM.log('recolored '+sel.length);"}
登録のしかた6. How a spell is registered
- JSONをターミナルに貼る — 自動で検出して登録される(Enterも要らない)。Paste the JSON into the terminal — auto-detected and registered, no Enter needed.
.jsonファイルをボードにドラッグ&ドロップ — 自動で取り込む。Drop a.jsonfile onto the canvas — auto-imported.register 名前 JS— 名前とコードを1行で書いて登録する。register <name> <js>— name and raw JS on one line.- 設定 → 魔法の ✨「コードから作る」 — AI用のプロンプトをコピーして、返ってきたJSONを貼る。Settings → Spells → ✨ "create from code" — copy the AI prompt, paste the JSON that comes back.
登録すると、⌘K に名前で並ぶ。forget 名前 で消せる。Once registered it appears in ⌘K by name. Remove it with forget <name>.
AIに書かせるためのプロンプト(英語のまま使う)7. AI agent system prompt
⚠️これは訳さずそのまま貼る。API名や禁止語は英語が正なので、日本語に直すと精度が落ちる。最後の行だけ、作りたいものを日本語で書いてよい。⚠️Paste this as-is. The API names and banned terms are canonical in English. Describe what you want on the last line.
You are creating a "spell" for BMBoard, a single-page canvas web app.
OUTPUT FORMAT (mandatory, no exceptions):
{"command":"NAME","action":"JAVASCRIPT_CODE_AS_STRING"}
Output 1 line, no Markdown, no explanation, no code fences.
Reference example (study this shape — yours should look the same):
{"command":"fire","action":"const N=15,vc=BM.viewCenter();const sparks=[];for(let i=0;i<N;i++){const s=BM.create('text',{x:vc.x,y:vc.y,text:'🔥',fontSize:20+Math.random()*20});sparks.push({o:s,vx:(Math.random()-0.5)*15,vy:(Math.random()-0.5)*15});}let f=0;const id=setInterval(()=>{if(f++>40){clearInterval(id);for(const s of sparks){const i=BM.all().indexOf(s.o);if(i>=0)BM.all().splice(i,1);}BM.redraw();return;}for(const s of sparks){s.o.data.x+=s.vx;s.o.data.y+=s.vy;s.o.data.fontSize*=0.92;}BM.redraw();},30);"}
The action is RAW JS executed via `new Function('BM','args',action)`.
Available API:
- BM.log(msg, cls?)
- BM.viewCenter() → {x, y}
- BM.create(type, props) // type: 'circle'|'square'|'triangle'|'arrow'|'text'|'sticky'
- BM.translate / update / remove
- BM.setStroke(obj, color), BM.setFill(obj, color)
- BM.all() / BM.getSelected() / BM.clear() / BM.redraw() / BM.save()
- BM.rand(min, max)
- args // string passed at call time
Object props:
- circle: {cx, cy, rx, ry, rotation, fill}
- square: {x, y, w, h, rotation, fill}
- triangle: {x, y, w, h, rotation, fill}
- arrow: {x1, y1, x2, y2, rotation}
- text: {x, y, text, fontSize, rotation}
- sticky: {x, y, w, h, text, color, rotation}
NEVER use: internalName, displayName, description, icon, category, cost, cooldown,
mp, projectile, particle, onHit, range, power, type-as-top-level-field,
plugins, skills, magic create, /bmboard, /reload.
Those are not BMBoard.
Now create a spell: <DESCRIBE WHAT YOU WANT>
配るSharing
作った魔法は1つのJSONとして書き出して人に渡せる。設定 → 魔法の 📤 から提出すると、自動の一次審査(禁止API・BM APIが実在するか・構文・名前の重複)を通って STORE の一覧に載る。サーバーは無く、費用もかからない。A spell exports as a single JSON you can hand to someone. Submitting it from Settings → Spells (📤) runs an automatic first review — banned APIs, whether each BM API actually exists, syntax, name collisions — and then it lands in the STORE list. No server, no cost.
この頁の機械可読な写し8. Reference
spell-spec.md— Markdown版Markdown mirrorllms.txt— AI向けの索引LLM index