Gemeinsame Pakete
Diese Pakete können Sie in Ihrem eigenen Code importieren. Hier sehen Sie, was Sie wo nutzen können und was jedes Paket bietet.
Im Code heißen die Objekte, die Sie im Editor sehen, Entitäten. Es ist dasselbe.
Welche Pakete Sie importieren können, hängt davon ab, wo Ihr Code läuft:
| Paket | Was es bietet | In einem Skript | In einem Plugin | In einer Komponenten-Erweiterung |
|---|---|---|---|---|
@was/ecs | Entitäten, Komponenten, die Welt | ✓ | ✓ | ✓ |
@was/engine | die Komponentenklassen | ✓ | ✓ | ✓ |
@was/signals | reaktive Werte | — | ✓ | ✓ |
@was/svdt | Schemas und Validierung | ✓ | ✓ | — |
@was/utils | kleine Hilfsfunktionen | ✓ | ✓ | — |
@was/ui | die Komponentenbibliothek des Editors | — | ✓ | ✓ |
@was/icons | die Icons des Editors | — | ✓ | ✓ |
react | React 19 | — | ✓ | ✓ |
ctx.effect nutzenEin Skript kann @was/signals nicht direkt importieren. Nutzen Sie stattdessen ctx.effect. Es
funktioniert genauso und endet, wenn sein Objekt verschwindet. So läuft danach nichts weiter.
@was/signals: reaktive Werte
Ein Signal ist ein Wert, der weiß, wer ihn liest. Ändert er sich, wird nur aktualisiert, was von ihm abhängt.
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); // läuft nur erneut, wenn sich score ändert
});
batch(() => {
score.value += 1;
score.value += 1; // Effekte laufen einmal, nicht zweimal
});
stop();
| Funktion | Was sie tut |
|---|---|
signal(v) | ein Wert, den man beobachten kann; lesen und schreiben über .value |
computed(fn) | ein abgeleiteter Wert, der nur neu berechnet wird, wenn sich das Gelesene ändert |
effect(fn) | läuft sofort und erneut, sobald sich das Gelesene ändert; gibt eine Stopp-Funktion zurück |
batch(fn) | fasst Schreibvorgänge zusammen, sodass Beobachter nur einmal am Ende laufen |
untracked(fn) | liest einen Wert, ohne von ihm abzuhängen |
ref(obj) | macht ein ganzes Objekt reaktiv, bis in jeden verschachtelten Wert |
snapshot(obj) | eine einfache, nicht reaktive Kopie |
raw(obj) | das zugrunde liegende Objekt, ohne Nachverfolgung |
readonly(obj) | eine Ansicht, in die man nicht schreiben kann |
Für React-Panels gibt es ein Begleitpaket mit useSignal, useComputed, useSignalEffect und
useLiveSignal. Eine Komponente rendert dann aus einem Signal neu, ohne zusätzliche Verdrahtung.
@was/ui: Editor-Komponenten
Bauen Sie Plugin-Panels und Komponenten-Erweiterungen aus denselben Komponenten, die der Editor nutzt. Ihre Panels sehen dann aus wie ein Teil des Editors und nicht wie eine eingebettete Webseite. Die Bibliothek enthält diese Komponenten:
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
Für Icons nutzen Sie @was/icons.
Panels können nur die Utility-Klassen nutzen, die mit der Bibliothek ausgeliefert werden. Beliebige
Werte wie text-[13px] sind nicht enthalten. Für Größen außerhalb der Skala nutzen Sie ein
Inline-style.
@was/ecs: Entitäten und Komponenten
Dieses Paket enthält Entity, Component und Space. Damit liest und ändert ein Plugin eine
Szene über die vollständige API, nicht über eine separate, eingeschränkte.
Space: die Welt
| Aufruf | Gibt zurück |
|---|---|
getEntity(id) | eine Entität oder nichts |
hasEntity(id) | ob sie existiert |
getEntities() | alle Entitäten |
queryEntities(A, B, …) | jede Entität, die alle diese Komponenten hat |
makeQueryEntities(A, B, …) | dieselbe Abfrage, einmal gebaut für wiederholte Nutzung |
createEntity(id?, components?) | eine neue Entität, bereits in der Welt |
addEntity(…e) · removeEntity(…e) | fügt eine Entität der Welt hinzu oder entfernt sie |
getSystem(S) · hasSystem(S) | ein System, oder ob es existiert |
execute() | berechnet einen Frame |
queryEntities findenDie Frage nach „allem mit Licht und Transformation“ ist so schnell beantwortet.
getEntities() liefert die ganze Welt, und Sie müssen selbst filtern.
Entity: ein Objekt in der Welt
| Aufruf | Was er tut |
|---|---|
getComponent(Type) | gibt eine Komponente zurück oder null |
getComponents(A, B) | gibt mehrere auf einmal zurück, in dieser Reihenfolge |
hasComponent(A, B) | prüft, ob alle vorhanden sind |
addComponent(…c) | fügt Komponenten hinzu; ein Typ, den sie schon hat, wird ignoriert |
removeComponent(…c) | entfernt Komponenten, per Klasse oder per Instanz |
component(fn) | ruft fn für jede Komponente auf, jetzt und künftig |
clone() · clean() | kopiert die Entität oder entfernt alle ihre Komponenten |
.id · .components | ihre Id und ihre Komponenten, nach Typ geordnet |
Component: die Daten
| Aufruf | Was er tut |
|---|---|
.x oder get('x') | liest ein Feld; innerhalb eines Effekts abonniert es das Feld auch |
$data | die ganze Komponente als einfaches Objekt |
$rawData | das gespeicherte Objekt, ohne Abonnement; nur zum Lesen |
update({ … }) | schreibt Daten. Nur so wird geschrieben. |
updateAt(path, value) | schreibt tief in eine große Komponente, ohne alles neu zu validieren |
version(field?) | ein Zähler, der bei jeder Änderung hochgeht. So hängen Sie von einem Feld ab, ohne es zu lesen |
reset(data?) | setzt auf die Standardwerte zurück |
clone() | erstellt eine Kopie |
version() für große Listen nutzenWer einen großen Wert liest, abonniert jedes Element darin. Hängen Sie stattdessen von seinem Versionszähler ab: Sie erfahren, dass er sich geändert hat, ohne jedes Element zu beobachten. So bleibt ein Panel auch mit einer Liste von zwanzigtausend Einträgen schnell.
@was/engine: Komponentenklassen
Jeder Komponententyp ist eine Klasse: TransformComponent, MaterialComponent,
RigidBodyComponent und so weiter. Importieren Sie die Klasse und übergeben Sie sie an
getComponent, hasComponent oder query.
Die vollständige Liste mit allen Feldern finden Sie in der Komponenten-Referenz.
@was/svdt: Schemas
Mit diesem Paket beschreiben Sie die Form Ihrer Daten und prüfen sie.
import { s, compile } from '@was/svdt';
const schema = s.object({ speed: s.f64(1), name: s.string('') });
const codec = compile(schema); // einmal kompilieren, dort wo Sie es deklarieren, nie bei jedem Aufruf
const value = codec.parse(input);
Eine Form beschreiben
- Zahlen:
s.f32 s.f64 s.i8 s.u8 s.i16 s.u16 s.i32 s.u32, jeweils mit Standardwert. - Skalare:
s.bool,s.string,s.color,s.literal,s.enum,s.unknown,s.ref. - Vektoren:
s.vec2,s.vec3,s.mat4. - Zusammengesetzte Typen:
s.object,s.variant,s.array,s.record,s.union,s.preprocess,s.lazy.
An jeden davon können Sie Folgendes anhängen: .default(v), .optional(), .nullable(),
.min(n), .max(n), .int().
Einen kompilierten Codec nutzen
| Aufruf | Was er tut |
|---|---|
parse(input) | prüft und normalisiert; wirft bei ungültiger Eingabe einen Fehler |
safeParse(input) | dasselbe, gibt aber Erfolg oder einen Fehler zurück, statt zu werfen |
parseAt(path, v) | prüft ein Feld, ohne den Rest anzufassen |
equals(a, b) | tiefer Vergleich |
diff(a, b) | gibt zurück, was sich geändert hat |
apply(target, p) | wendet einen Diff an |
invert(p) | kehrt einen Diff um |
pack · unpack | wandelt in eine kompakte Binärform um und zurück |
Um statt der Daten das Schema selbst zu untersuchen, nutzen Sie introspect, keys und
requiredKeys.
@was/utils
Kleine Hilfsfunktionen: pick, omit, assign, keys, values, entries, capitalize,
basename, extname, dispose (fasst Aufräumfunktionen zu einer zusammen) und MIME-Typ-Hilfen,
mit denen Sie Dateitypen prüfen.
Weiter: Glossar — die Begriffe, die in dieser Dokumentation vorkommen.