DOCS

書き方

ポートを宣言して、つなぐ。それだけです。下の図はすべて、左のソースを公開済みパッケージでビルド時にコンパイルした結果で、描き直したものではありません。

01入れる

コマンドラインで使う場合は CLI を入れます。

shell
pnpm add @love-rox/kumihimo-cli

kumihimo build studio.khm -o studio.svg   # 描く
kumihimo check studio.khm                 # 検証だけ
kumihimo build studio.khm --watch         # 保存で描き直す
kumihimo export studio.khm drawio         # 編集できる draw.io ファイル
kumihimo export studio.khm cable --stdout # ケーブル表を TSV で

kumihimokhm の両方の名前で入ります。警告は既定ではビルドを失敗させません。失敗させたいときは --strict を付けます。

VS Code で書くなら拡張があります。書きながら診断が出て、隣に図が出ます。 判定は下の「信号と互換判定」と同じもので、コンパイラがそのまま動いています。

shell
code --install-extension love-rox.kumihimo-vscode

プレビューは ⌘K V(Windows / Linux は Ctrl+K V)、またはタイトルバーのボタンです。エディタの配色に追随し、図・ケーブル表・機器表・変換部材をタブで切り替えられます。補完はコンパイラの一覧そのものから出ます。文言も診断も VS Code の表示言語に追従します。詳しくは[トップページの VS Code の節](/ja#vscode)。

02最初の一枚

機材を宣言して、ポートどうしをつなぎます。拡張子は .khm です。

first.khmclean
device pc  "ノートPC"  as computer { out HDMI : hdmi }
device mon "モニター" as display  { in  HDMI : hdmi }

pc.HDMI -> mon.HDMI : hdmi 5m "V-01"
output
V-01 5mノートPCHDMIモニターHDMI

device <id> "<ラベル>" as <種別><id> は接続を書くときの名前で、図には出ません。図に出るのは "<ラベル>" の方です。

03機材とポート

構文
device <id> "<ラベル>" as <種別> {
  in   <ポート指定> : <信号>   # 入力
  out  <ポート指定> : <信号>   # 出力
  io   <ポート指定> : <信号>   # 双方向(Dante, Ethernet …)
  @model "HyperDeck Studio HD Mini"
}

ポート指定には4つの書き方があります。16ch の卓を16行書く必要はありません。

書き方展開
単体SDISDI
並べるL, RL, R
数の範囲1..41, 2, 3, 4
接頭辞つき範囲CH[1..16]CH1CH16
ports.khmclean
device mixer "Yamaha DM3" as mixer {
  in  CH[1..16] : xlr
  out L, R      : xlr
  io  DANTE     : dante
}
device amp "アンプ" as amplifier { in IN_L, IN_R : trs }

mixer.(L, R) -> amp.(IN_L, IN_R) : trs 3m "A-10"
output
A-10 3mA-10 3mYamaha DM3CH1CH2CH3CH4CH5CH6CH7CH8CH9CH10CH11CH12CH13CH14CH15CH16LRDANTEアンプIN_LIN_R

宣言した順序がそのまま描かれます。IN 1IN 2 の下に来ることはありません。機材の中での位置は意味を持つ情報なので、並べ替えません。

端子が等間隔で16個並ぶと、16個の同じものにしか見えません。実機はそうではなく、HDMI が4つ、SDI が4つ、アナログが2つ、と面板が余白で区切っています。gap の行を置くと、その次に宣言されるものの上に余白が入ります。

gap.khmclean
device sw "ATEM Mini Extreme" as switcher {
  in  1..4 : hdmi
  gap
  in  5..8 : sdi
  gap 2
  in  AUDIO_L, AUDIO_R : trs
  out PGM    : sdi
  gap
  out STREAM : lan
}
output
ATEM Mini Extreme12345678AUDIO_LAUDIO_RPGMSTREAM

gap ひとつがポート間隔の半分、gap 2 で1ポート分です。連続して書けば加算されます。複数のポートに展開される宣言でも、余白が入るのは最初の1つの前だけです。in CH[1..16] の上の gapCH1 の前の1箇所であって、16箇所ではありません。

これは見た目だけの指定です。ポートも結線も一覧表も変わりません。すべての gap を消した図は、同じ系統を表します。

種別は形を決めます。camera switcher mixer recorder player display projector speaker microphone amplifier computer converter matrix patchbay router interface generic から選びます。省略すると generic です。

@ で始まる行は任意のメタデータです。図には出ませんが、機材表と各種エクスポートに載ります。

04つなぐ

構文
<機材>.<ポート> <矢印> <機材>.<ポート> : <信号> <修飾子>*
矢印意味
->一方向。信号が流れる向き
<->双方向(Dante, Ethernet, 制御 …)
--向きなし(電源 …)

修飾子は順不同で、どれも省略できます。

書き方意味
<長さ>ケーブル長10m 30cm 2.5m 3ft
"<ラベル>"ケーブル番号や名前"V-01"
via "<部品>"変換ケーブルやアダプタvia "HDMI-DVI変換"
[k=v, …]任意の属性[connector=BNC, color=青]
connect.khmclean
device mixer "卓"       as mixer     { out L, R : xlr  io DANTE : dante }
device amp   "アンプ"   as amplifier { in  IN_L, IN_R : trs  in AC : ac }
device netsw "スイッチ" as router    { io  1 : dante }
device pdu   "電源"     as generic   { out 1 : ac }

mixer.(L, R) -> amp.(IN_L, IN_R) : trs   3m  "A-10" [color=青]
mixer.DANTE <-> netsw.1          : dante 10m "N-01"
pdu.1        -- amp.AC           : ac    2m
output
A-10 3mA-10 3mN-01 10m2mLRDANTEアンプIN_LIN_RACスイッチ1電源1

両端が同じ数のポートを並べると、順に対応します。mixer.(L, R) -> amp.(IN_L, IN_R) は2行書くのと同じです。

[color=…] はケーブルの被覆の色です。信号種別の既定色を上書きします。これは装飾ではなく、現場で線を特定する手段(「青いのを1番へ」)なので、色はケーブル表にも持ち越されます。日本語名(赤・青・緑・黄・橙・桃・紫・黒・白・灰・茶)と英語名、#0af のような16進が使えます。解釈できない値は診断になり、図には届きません。

長さは数と単位だけの裸のトークンです。# は行コメント専用なので、長さの前に付くことはありません。

05まとめる

場所・ラック・サブシステムを枠で囲みます。

group.khmclean
diagram "会場" { direction: LR }

group stage "ステージ" {
  device cam1 "FX3"  as camera     { out SDI : sdi }
  device mic1 "SM58" as microphone { out OUT : xlr }
}

group rack "ラック" {
  device sw    "ATEM" as switcher { in 1..2      : sdi  out PGM  : sdi }
  device mixer "DM3"  as mixer    { in CH[1..2]  : xlr  out L, R : xlr }
}

cam1.SDI -> sw.1      : sdi 30m "V-01"
mic1.OUT -> mixer.CH1 : xlr 20m "A-01"
output
会場ステージラックV-01 30mA-01 20mFX3SDISM58OUTATEM12PGMDM3CH1CH2LR

groupgroup を入れられます。会場の中にステージとラックがあり、ステージの中にカメラがある。現場を歩く人にとってはどちらの階層も実在し、箱が実際に置かれている場所を指すのは一番内側です。

nested.khmclean
diagram "会場" { direction: LR }

group venue "幕張メッセ" {
  group stage "ステージ" {
    device cam "FX3" as camera { out SDI : sdi }
  }
  group rack "ラック" {
    device sw "ATEM" as switcher { in 1 : sdi }
  }
}

cam.SDI -> sw.1 : sdi 30m "V-01"
output
会場幕張メッセステージラックV-01 30mFX3SDIATEM1

機材が属するのは、それが書かれた group であって親ではありません。機材表に出るのは一番内側の名前です。人が歩いていく先がそこだからです。

06信号と互換判定

これが図を描くだけの道具との違うところです。すべての接続が「物理的に成立するか」を判定されます。

判定は両端のポートが宣言した型で行います。接続行の : <信号> が表すのはケーブルで、型を宣言していない端の穴埋めにしか使われません。ここを取り違えると、型を自分自身と比べることになり、どんな不一致も検出できなくなります。

判定意味扱い
ok普通の接続黙る
lossy通るが何かを失う、または部品が要る警告
incompatible能動変換なしには成立しない報告

検出する価値があるのは、プラグがぴたりと嵌まり、見た目に何もおかしくなく、そして何も出ない組み合わせです。下は2本ともコネクタを共有しているだけの配線です。

faults.khm2 diagnostic
device ext   "HDBaseT受信器"       as interface { out CAT : hdbaset }
device netsw "L2スイッチ"           as router    { in  1   : lan }
device cam   "カメラ"               as camera    { out SDI : sdi }
device fs    "フレームシンクロナイザ" as generic   { in  REF : genlock }

ext.CAT -> netsw.1 : hdbaset 20m "N-01"
cam.SDI -> fs.REF  : sdi     5m  "V-90"
output
N-01 20mV-90 5mHDBaseT受信器CATL2スイッチ1カメラSDIフレームシンクロナイザREF

判定には必ず理由が付き、その理由はケーブル表にも残ります。同種の組み合わせは他にも dmxxlrrcaspdifadatspdifcompositecomponentwordclocksdi があります。

現場の取り決めは compat で一度だけ、理由と一緒に書けます。理由は診断とケーブル表に流れるので、なぜ許したのかが図から失われません。

compat
compat aes -> xlr : ok    "社内基準:10m 未満なら可"
compat xlr -> rca : lossy "必ず DI を通す"

主な診断コードです。既定の重さは設定で変えられます。

コード意味既定
signal-mismatch両端が信号について食い違っている警告
adapter-requiredアダプタが要るのに宣言がない警告
adapter-insufficientvia はあるがケーブルでは橋渡しできないエラー
direction-mismatch出力どうし、入力どうしエラー
port-overbooked1つの入力に複数の送り出しエラー
implicit-device宣言していない機材を参照した警告
unconnected-port宣言したのに何もつながっていない既定オフ

例外は投げません。どの段階も診断を集めて最善の結果を返すので、誤りのある図もちゃんと描かれます。欠陥を見つけるために必要なのは、まさにその欠陥が写った絵だからです。

07使える単語

ここに出ている語は、このページが公開済みのパッケージから読み出したものです。手で書き写した一覧ではないので、コンパイラが受け付けない語が載ることも、受け付ける語が抜けることもありません。VS Code の補完も同じ出どころです。

信号種別 — ポートと結線の : の後に書きます。

映像

componentComponentBNC / RCA
compositeCompositeBNC / RCA
dpDisplayPortDisplayPort / DisplayPort Mini
dviDVIDVI-D / DVI-I
fiberFiberLC / SC / OpticalCON
hdbasetHDBaseTRJ45
hdmiHDMIHDMI / HDMI Mini / HDMI Micro
ndiNDIRJ45
sdiSDIBNC / DIN 1.0/2.3
st2110ST 2110RJ45 / SFP
vgaVGAD-sub 15
wireless-video無線映像コネクタなし

音声

adatADATTOSLINK
aesAES/EBUXLR / BNC
danteDanteRJ45
iemIEMコネクタなし
madiMADIBNC / SC
opticalOpticalTOSLINK
rcaRCARCA
spdifS/PDIFRCA / TOSLINK
speakonSpeakonNL4 / NL8
trrsTRRS 1/4"TRRS 1/4"
trrs35TRRS 3.5mmTRRS 3.5mm
trsTRS 1/4"TRS 1/4"
trs35TRS 3.5mmTRS 3.5mm
uhfワイヤレス (UHF)コネクタなし
xlrXLRXLR-M / XLR-F / Mini XLR-M / Mini XLR-F / Mini XLR-4M / Mini XLR-4F

制御

dmxDMXXLR-5 / XLR-3
gpioGPIOTerminal / D-sub
irIRコネクタなし
midiMIDIDIN-5 / TRS 3.5mm
rs232RS-232D-sub 9
rs422RS-422D-sub 9
rs485RS-485D-sub 9 / XLR
wireless-dmx無線 DMXコネクタなし

ネットワーク

bluetoothBluetoothコネクタなし
lanLANRJ45
usbUSBUSB-A / USB-B / USB-C / USB Micro-B / USB Mini-B
wifiWi-Fiコネクタなし

電源

acACIEC C13 / IEC C14 / NEMA
dcDCBarrel / XLR-4
poePoERJ45
usbpdUSB PDUSB-C

同期

genlockGenlockBNC
timecodeTimecodeBNC / XLR
wordclockWord ClockBNC

汎用

generic

一覧に無い信号は signal で自分で定義できます。「信号と互換判定」を参照してください。

機材種別device … as の後に書きます。

cameraswitchermixerrecorderplayerdisplayprojectorspeakermicrophoneamplifiercomputerconvertertransmitterreceivermatrixpatchbayrouterinterfacegeneric

ケーブル色[color=…] に書きます。英語と日本語のどちらでも同じ色になります。#0af のような16進表記も使えます。

red
blue
green
yellow
orange
purple
black
white
graygrey
brown
pink

長さの単位 — 数値に続けて書きます。30m 6ft のように空白を空けません。

mmcmminft

テーマdiagram { theme: … } に書きます。

lightdarkmonoblueprint

08変換をはさむ

受動的なアダプタや変換ケーブルが途中に入ることを宣言します。

via.khmclean
device pc  "PC"       as computer { out HDMI : hdmi }
device mon "モニター" as display  { in  DVI  : dvi }

pc.HDMI -> mon.DVI : hdmi 2m "V-01" via "HDMI-DVI変換ケーブル"
output
V-01 2m ⇄PCHDMIモニターDVI

via は警告を黙らせる道具ではありません。部品を資材表に載せる宣言です。線には変換の印が付き、アダプタが明細に出ます。

ケーブルで本当に橋渡しできる組み合わせ(HDMI↔DVI、DP→HDMI など)なら via で診断が消えます。宣言しなければ報告され、必要な部品の名前が示されます。一方、どんなケーブルでも橋渡しできない組み合わせ(SDI→HDMI など)では via を書いても診断は消えません。それは電源の要る箱なので、ケーブルの属性ではなく機材として図に置くべきものです。

converter.khm
# 誤り:SDI を HDMI に変えるケーブルは存在しない
cam.SDI -> mon.HDMI : sdi via "SDI-HDMI変換"

# 正しい:変換器は機材
device conv "BMD Mini Converter SDI-HDMI" as converter {
  in  SDI  : sdi
  out HDMI : hdmi
}
cam.SDI   -> conv.SDI : sdi
conv.HDMI -> mon.HDMI : hdmi

09無線

無線区間はケーブルではないので、長さの代わりに周波数やチャンネルを持ちます。線は破線で描かれます。

wireless.khmclean
device mic "ワイヤレスマイク" as microphone { out RF : uhf }
device rx  "受信機"           as interface  {
  in  RF  : uhf
  out CH1 : xlr
}
device desk "卓" as mixer { in CH1 : xlr }

mic.RF -> rx.RF     : uhf [ch=38]
rx.CH1 -> desk.CH1  : xlr 3m "A-01"
output
ch 38A-01 3mワイヤレスマイクRF受信機RFCH1CH1

受信機を通さずマイクを卓へ直結すれば、そこで指摘が出ます。無線と有線の境界も判定の対象です。

10何かに乗っている信号

NDI は映像ですが、線を流れているのは Ethernet です。無線 LAN なら電波です。図が語りたいのは NDI で、物理を決めるのは Ethernet や WiFiover はこの2つを分けて書きます。

over.khmclean
device cam "中継カメラ"       as camera   { out WIFI : ndi }
device ap  "アクセスポイント" as router   { io  WIFI : ndi
                                             out LAN  : ndi }
device pc  "収録PC"           as recorder { in  LAN  : ndi }

cam.WIFI -> ap.WIFI : ndi over wifi [ch=36]
ap.LAN   -> pc.LAN  : ndi over lan 20m "N-01"
output
ch 36N-01 20m中継カメラWIFIアクセスポイントWIFILAN収録PCLAN

乗り物が物理を決めます。 over wifi の区間はコネクタを持たずチャンネルを持ち、無線表に出ます。over lan の区間は RJ45 で長さと番号を持ち、ケーブル表に出ます。名前と色は中身が決めます。

ケーブル表

番号送出受け信号長さ送出端受け端
N-01アクセスポイント収録PCNDI20m

無線表

番号送出受け信号乗り物チャンネル
中継カメラアクセスポイントNDIWi-Fich 36

over を書かなければ、信号は自分自身の乗り物です。これまでどおりの動きになります。

11箱に付いているコネクタ

信号種別が複数のコネクタを持つとき、口はどれが付いているかを書けます。性別はケーブルの性質ではなく、機器の口の性質だからです。

connector.khmclean
device dk "卓" as mixer   { out CH[1..2] : xlr [connector=XLR-M] }
device sp "SP" as speaker { in  IN       : xlr [connector=XLR-F] }

dk.CH1 -> sp.IN : xlr 10m "A-01"
output
A-01 10mCH1CH2SPIN

ケーブルの端は導かれます。 プラグは逆の性別と噛み合うので、オスの出力にはメスの端が来ます。口に1回書けば、そこに届くすべてのケーブルが自動的に一致します。

ケーブル表

番号送出受け信号長さ送出端受け端
A-01SPXLR10mXLR-FXLR-M

xlr は組み込みで唯一、コネクタ欄がである型です。他は「どれか」の意味で、usb は A か B か C。対でない型ではケーブル端は逆ではなく同じ名前になります。

殻の大小はコネクタであって、型ではありません。 カメラは micro HDMI、スイッチャーはフルサイズ、あいだのケーブルは何も変換していません。だから hdmi が3つとも持ちます。型を分ければ、成立している接続に不一致が出てしまいます。

shell.khmclean
device cam "SONY α7 IV" as camera   { out HDMI  : hdmi [connector="HDMI Micro"] }
device sw  "ATEM Mini"  as switcher { in  HDMI1 : hdmi [connector=HDMI] }

cam.HDMI -> sw.HDMI1 : hdmi 3m "V-01"
output
V-01 3mSONY α7 IVHDMIATEM MiniHDMI1

書く価値は表にあります。HDMI Micro → HDMIHDMI → HDMI とは別のケーブルで、持って来たか来なかったかのどちらかです。DisplayPort MiniUSB Micro-BDIN 1.0/2.3、3.5mm の MIDI、ボディパックの Mini XLR も同じです。

ケーブル表

番号送出受け信号長さ送出端受け端
V-01SONY α7 IVATEM MiniHDMI3mHDMI MicroHDMI

殻を変えるだけの小物は adapter です。 こう書けばケーブルはふつうの HDMI-HDMI に戻り、アダプタは資材表に1個だけ載ります。なくせる部品はそちらに載るのが正しい書類です。

shell-adapter.khmclean
device cam "SONY α7 IV" as camera   { out HDMI  : hdmi [connector="HDMI Micro"] }
adapter mh "micro-HDMI 変換アダプタ" { in IN : hdmi [connector="HDMI Micro"]  out OUT : hdmi [connector=HDMI] }
device sw  "ATEM Mini"  as switcher { in  HDMI1 : hdmi [connector=HDMI] }

cam.HDMI -> mh.IN    : hdmi
mh.OUT   -> sw.HDMI1 : hdmi 3m "V-01"
output
V-01 3mSONY α7 IVHDMImicro-HDMI 変換アダプタINOUTATEM MiniHDMI1

ケーブル表

番号送出受け信号長さ送出端受け端
V-01micro-HDMI 変換アダプタATEM MiniHDMI3mHDMIHDMI

部材表

部材つながる先
micro-HDMI 変換アダプタ1SONY α7 IV / ATEM Mini

空白を含む値は引用符で囲みます: [connector="HDMI Micro"]。殻の名前はたいてい空白を含みます。

12成型ケーブルと、長さ未定

尻尾が全部成型された分岐ケーブルは、部材であると同時にケーブルです。van に積まれ、番号が振られ、積む人が見るのはケーブル表です。as cable を足すと部材表ではなくケーブル表に出ます。

moulded.khmclean
device  dk  "卓" as mixer { out MAIN : xlr }
adapter fan "XLR4分岐ケーブル" as cable 5m "C-01" {
  in  IN : xlr
  out A  : xlr
  out B  : xlr
}
device sp1 "SP1" as speaker { in IN : xlr }
device sp2 "SP2" as speaker { in IN : xlr }

dk.MAIN -> fan.IN : xlr
fan.A   -> sp1.IN : xlr
fan.B   -> sp2.IN : xlr
output
MAINXLR4分岐ケーブルINABSP1INSP2IN

ケーブル表

番号送出受け信号長さ送出端受け端
C-01XLR4分岐ケーブル卓 / SP1 / SP2XLR5m

部材表

(空)

1個の物が1行です。プラグごとに3行にはなりません。部材表からは外れるので二重に数えられません。as cable のうしろには結線と同じく長さとケーブル番号を書けます。

長さがまだ決まっていないときは ?m と書きます。長さを省くこともできますが、その空欄は「まだ測っていない」と「誰も考えていない」の2つを同時に意味します。van に積む人が見る表では、片方だけが残っている仕事です。

unknown.khmclean
device dk  "卓"   as mixer   { out L, R, SUB : xlr }
device sp1 "SP1"  as speaker { in IN : xlr }
device sp2 "SP2"  as speaker { in IN : xlr }
device sub "サブ" as speaker { in IN : xlr }

dk.L   -> sp1.IN : xlr 15m "A-01"   # 測った
dk.R   -> sp2.IN : xlr ?m  "A-02"   # ケーブルは要る。長さはこれから
dk.SUB -> sub.IN : xlr     "A-03"   # 長さについて何も言っていない
output
A-01 15mA-02 ?mA-03LRSUBSP1INSP2INサブIN

ケーブル表

番号送出受け信号長さ送出端受け端
A-01SP1XLR15m
A-02SP2XLR?m
A-03サブXLR

単位は書きます。どの単位で測るかは未定の対象ではないからです。?m ?ft など、この言語が知っている単位すべてが使えます。

13機材ライブラリ

卓の16chを図ごとに書き直す必要はありません。model で一度定義し、device … from で何台でも実体化します。

library.khmclean
model dm3 "Yamaha DM3" as mixer {
  in  CH[1..16] : xlr
  out L, R      : xlr
  @vendor "Yamaha"
}

device foh from dm3
device mon from dm3 "モニター卓"
output
Yamaha DM3CH1CH2CH3CH4CH5CH6CH7CH8CH9CH10CH11CH12CH13CH14CH15CH16LRモニター卓CH1CH2CH3CH4CH5CH6CH7CH8CH9CH10CH11CH12CH13CH14CH15CH16LR

別ファイルに置いたものは use で読み込みます。読み込んだファイルに機材や接続が書かれていた場合は無視され、警告になります。ライブラリは定義を置く場所であって、図を置く場所ではないためです。

studio.khm
use "lib/yamaha.khm"

device foh from dm3 "FOH卓"

14見た目

diagram ブロック
diagram "Studio A" {
  direction: LR      # LR(左→右、既定)| TB(上→下)
  theme: light       # light(既定)| dark | mono | blueprint
  spacing: 60        # 機材どうしの間隔(px)
}
テーマ用途
light既定。画面とカラー印刷
dark暗い画面
mono白黒印刷とコピー
blueprint設備図面の青焼き調

mono は色をいっさい使いません。信号は線種で区別され、[color=…] で指定した被覆色は無視されます。コピーを通った色が残っているふりをしても誰の役にも立たないからです。

mono.khmclean
diagram "白黒印刷用" { theme: mono }

device cam "カメラ"       as camera   { out SDI : sdi }
device sw  "スイッチャー" as switcher { in 1 : sdi  out PGM : sdi }
device rec "レコーダー"   as recorder { in SDI : sdi }

cam.SDI -> sw.1    : sdi 30m "V-01" [color=青]
sw.PGM  -> rec.SDI : sdi 2m  "V-10"
output
白黒印刷用V-01 30mV-10 2mカメラSDIスイッチャー1PGMレコーダーSDI

テーマは -t/--theme でも渡せますが、ソース中の diagram { theme: … } が勝ちます。図は自分がどう見えるべきかを知っていて、呼び出し側は既定値しか知らないからです。

15出力と埋め込み

SVG のほか、編集できる draw.io ファイル、ケーブル表・機材表の TSV が出せます。

Markdown には kumihimo のコードフェンスをそのまま埋め込めます。ビルド時に SVG になります。

markdown
```kumihimo
cam.SDI -> sw.1 : sdi 30m "V-01"
```

import rehypeKumihimo from '@love-rox/kumihimo-rehype';

unified()
  .use(remarkParse)
  .use(remarkRehype)
  .use(rehypeKumihimo, { theme: "dark", onDiagnostics: report })
  .use(rehypeStringify);

React・Vue・Astro のコンポーネントもあります。コンパイルは非同期で、新しい図ができるまで前の図が画面に残り、遅れて終わった古いコンパイルが新しい結果を上書きすることはありません。

React
import { Kumihimo, useKumihimo } from '@love-rox/kumihimo-react';

<Kumihimo source={src} theme="dark" onDiagnostics={report} />;

const { svg, diagram, diagnostics, pending, error } = useKumihimo(src);

onDiagnostics を使えば、誤配線のきれいな絵をそのまま公開してしまうことを避けられます。