共有パッケージ
エディター、ランタイム、そしてあなた自身のコードは、同じパッケージから組み立てられています。 そのうちのいくつかは、あなたも使えます。どれが使えるかは、コードがどこで動くかによります。
| パッケージ | 提供するもの | script | プラグイン | component 拡張 |
|---|---|---|---|---|
@was/ecs | entity、component、world | ✓ | ✓ | ✓ |
@was/engine | component のクラス群 | ✓ | ✓ | ✓ |
@was/signals | リアクティビティの仕組み | — | ✓ | ✓ |
@was/svdt | スキーマとバリデーション | ✓ | ✓ | — |
@was/utils | 小さなヘルパー | ✓ | ✓ | — |
@was/ui | エディター自身の component ライブラリ | — | ✓ | ✓ |
@was/icons | エディターのアイコンセット | — | ✓ | ✓ |
react | React 19 | — | ✓ | ✓ |
ctx.effect を通じてリアクティビティを得ますscript から signals パッケージを直接 import することはできません。ctx.effect は同じ仕組みに
寿命管理を付けたもので、エフェクトはリークせず、自分のオブジェクトとともに消えます。
@was/signals — リアクティビティの仕組み
プラットフォーム全体がこの上に建っています。値が「誰に読まれているか」を知っているので、 変更は、それに依存していたものだけを更新し、ほかには何も起こしません。
import { signal, computed, effect, batch, untracked } from '@was/signals';
const score = signal(0);
const doubled = computed(() => score.value * 2);
const stop = effect(() => {
render(score.value); // score が変わったときだけ再実行される
});
batch(() => {
score.value += 1;
score.value += 1; // エフェクトは 2 回ではなく 1 回だけ走る
});
stop();
| 関数 | はたらき |
|---|---|
signal(v) | 監視できる値。.value で読み書きします |
computed(fn) | 派生値。読んでいるものが変わったときだけ再計算されます |
effect(fn) | いま実行し、読んだものが変わるたびに再実行。停止関数を返します |
batch(fn) | 書き込みをまとめ、監視側を最後に 1 回だけ走らせます |
untracked(fn) | 依存にならずに読みます |
ref(obj) | オブジェクト全体を、末端までリアクティブにします |
snapshot(obj) | リアクティブでない素のコピー |
raw(obj) | 追跡なしの、元のオブジェクト |
readonly(obj) | 書き込めないビュー |
React のパネル向けには、useSignal・useComputed・useSignalEffect・useLiveSignal を備えた
対になるパッケージがあります。配線なしで、signal から component が再描画されます。
エディターとランタイムのふるまいを決めているのがこれです。ポーリングは行われず、念のための 再描画も起きません。パネルが更新されるのは、誰かに言われたからではなく、データが変わったからです。 → このエンジンを選ぶ理由
@was/ui — エディターの component
プラグインのパネルと component 拡張は、エディターが使っているのと同じライブラリで作れます。 だから、埋め込みのウェブページではなくネイティブに見えます。30 ほどの component があります。
Accordion · Avatar · Button · Card · Checkbox · Chip · CloseButton
DimensionInput · Draggable · Dropdown · Flag · Icon · IconButton · Input
Menu · Modal · Outside · Panel · Popover · Portal · Render · Scroll
Search · Section · Segmented · Select · Skeleton · Switcher · Tabs
Toast · Toolbar · Tooltip
アイコンセットの @was/icons もあります。
パネルは、ライブラリに同梱された決まったユーティリティクラスの集合を使います。text-[13px] の
ような任意の値は含まれないので、スケール外のサイズにはインラインの style を使ってください。
@was/ecs — 世界のモデル
Entity・Component・Space。プラグインは、エンジンが内部で使っているのとまったく同じ API で
シーンを読み書きします。別に用意された、機能の劣る「プラグイン API」は存在しません。
Space — 世界
| 呼び出し | 返すもの |
|---|---|
getEntity(id) | 1 つの entity、またはなし |
hasEntity(id) | 存在するかどうか |
getEntities() | すべての entity |
queryEntities(A, B, …) | それらの component をすべて持つ entity |
makeQueryEntities(A, B, …) | 同じクエリを事前に組み立てたもの。繰り返し使う用 |
createEntity(id?, components?) | 世界に追加された新しい entity |
addEntity(…e) · removeEntity(…e) | 入れる、または取り出す |
getSystem(S) · hasSystem(S) | system に手を伸ばす |
execute() | 1 フレーム実行する |
queryEntitiesインデックスに支えられているので、「light と transform を持つものすべて」を尋ねるのは安価です。
getEntities() は同じではありません。世界全体を渡してきて、あなたに絞り込ませます。
Entity — 世界の中のもの
| 呼び出し | はたらき |
|---|---|
getComponent(Type) | 1 つの component、または null |
getComponents(A, B) | 指定した順で、まとめて複数 |
hasComponent(A, B) | それらをすべて持っているか |
addComponent(…c) | 追加する。すでにある型の追加は無視されます |
removeComponent(…c) | クラスでもインスタンスでも指定して外す |
component(fn) | すべての component に対し、いまも今後も fn を実行 |
clone() · clean() | 複製する、または丸裸にする |
.id · .components | その id と、型をキーにした component |
Component — データ
| 呼び出し | はたらき |
|---|---|
.x または get('x') | フィールドを読む。エフェクトの中ではそれが購読にもなります |
$data | 全体を素のオブジェクトとして |
$rawData | 購読せずに、保存されているオブジェクトを読み取り専用で |
update({ … }) | 書き込む唯一の手段 |
updateAt(path, value) | 大きな component の奥に、全体を再検証せずに書き込む |
version(field?) | 変更のたびに進むカウンター。フィールドを読まずに依存できます |
reset(data?) | 既定値に戻す |
clone() | 複製 |
version() です大きな値を読むと、その中の葉すべてを購読することになります。代わりにバージョンのカウンターに 依存すれば、中身を全部見張らずに「変わった」ことだけを知れます。2 万件のリストでもパネルが 生き延びるのは、この仕組みのおかげです。
@was/engine — component のクラス群
すべての component の型がクラスとして用意されています。TransformComponent・
MaterialComponent・RigidBodyComponent など。クラスを import し、getComponent・
hasComponent・query に渡します。
全項目を含む一覧:コンポーネントのリファレンス
@was/svdt — スキーマ
component を記述しているバリデーション層です。解釈ではなくコンパイルされるので、アニメーションの 経路でパースがコストになりません。
import { s, compile } from '@was/svdt';
const schema = s.object({ speed: s.f64(1), name: s.string('') });
const codec = compile(schema); // 宣言時に 1 回だけコンパイルする。呼び出しごとにしてはいけない
const value = codec.parse(input);
形を記述する
数値: s.f32 s.f64 s.i8 s.u8 s.i16 s.u16 s.i32 s.u32。いずれも既定値を取ります。
スカラー: s.bool・s.string・s.color・s.literal・s.enum・s.unknown・s.ref。
ベクトル: s.vec2・s.vec3・s.mat4。
複合: s.object・s.variant・s.array・s.record・s.union・s.preprocess・s.lazy。
どれにもチェーンできるもの: .default(v)・.optional()・.nullable()・.min(n)・.max(n)・
.int()。
コンパイル済みコーデックが提供するもの
| 呼び出し | はたらき |
|---|---|
parse(input) | 検証して正規化。不正な入力では例外を投げます |
safeParse(input) | 同じことを、例外ではなく成功/エラーの形で返します |
parseAt(path, v) | ほかに触れずに 1 つのフィールドだけ検証 |
equals(a, b) | この形のために生成された深い比較 |
diff(a, b) | 何が変わったか |
apply(target, p) | 差分を適用する |
invert(p) | 差分を反転する。undo の土台です |
pack · unpack | コンパクトなバイナリ形式との相互変換 |
データではなくスキーマ自体を調べるには introspect・keys・requiredKeys があります。
@was/utils
どこでも使う小物です。pick・omit・assign・keys・values・entries・capitalize・
basename・extname・dispose(後片付け関数をまとめて 1 つにする)、そしてアップロード検証の
裏側にある MIME 関連のヘルパー。
次へ: 用語集