Aller au contenu principal

Paquets partagés

Vous pouvez importer ces paquets dans votre propre code. Voici ce que vous pouvez utiliser, où, et ce que chaque paquet vous apporte.

Les entités sont des objets

Dans le code, les objets que vous voyez dans l'éditeur s'appellent des entités (entities). C'est la même chose.

Les paquets que vous pouvez importer dépendent de l'endroit où votre code s'exécute :

PaquetCe qu'il vous apporteDans un scriptDans un pluginDans une extension de composant
@was/ecsles entités, les composants, le monde✓✓✓
@was/engineles classes de composants✓✓✓
@was/signalsdes valeurs réactives—✓✓
@was/svdtdes schémas et la validation✓✓—
@was/utilsde petites fonctions utilitaires✓✓—
@was/uila bibliothèque de composants de l'éditeur—✓✓
@was/iconsle jeu d'icônes de l'éditeur—✓✓
reactReact 19—✓✓
Dans un script, utilisez ctx.effect

Un script ne peut pas importer @was/signals directement. Utilisez ctx.effect à la place. Il fonctionne de la même façon, et il s'arrête quand son objet disparaît : rien ne reste en marche.

@was/signals : valeurs réactives​

Un signal est une valeur qui sait qui la lit. Quand elle change, seul ce qui en dépend se met à jour.

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); // ne se relance que quand score change
});

batch(() => {
score.value += 1;
score.value += 1; // les effets s'exécutent une fois, pas deux
});

stop();
FonctionCe qu'elle fait
signal(v)une valeur que l'on peut observer ; lisez et écrivez .value
computed(fn)une valeur dérivée, recalculée seulement quand ce qu'elle lit change
effect(fn)s'exécute tout de suite, puis à chaque changement de ce qu'elle a lu ; renvoie une fonction d'arrêt
batch(fn)regroupe des écritures, pour que les observateurs ne s'exécutent qu'une fois, à la fin
untracked(fn)lit une valeur sans en dépendre
ref(obj)rend tout un objet réactif, jusqu'à la moindre valeur imbriquée
snapshot(obj)une copie simple, non réactive
raw(obj)l'objet sous-jacent, sans suivi
readonly(obj)une vue dans laquelle on ne peut pas écrire

Pour les panneaux React, un paquet complémentaire vous donne useSignal, useComputed, useSignalEffect et useLiveSignal. Un composant se redessine alors à partir d'un signal, sans aucun branchement supplémentaire.

@was/ui : composants de l'éditeur​

Construisez les panneaux de vos plugins et vos extensions de composants avec les mêmes composants que l'éditeur. Vos panneaux ont alors l'air de faire partie de l'éditeur, et non d'une page web intégrée. La bibliothèque contient ces composants :

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

Pour les icônes, utilisez @was/icons.

La feuille de style est précompilée

Les panneaux ne peuvent utiliser que les classes utilitaires fournies avec la bibliothèque. Les valeurs arbitraires comme text-[13px] ne sont pas incluses. Pour une taille hors de l'échelle, utilisez un style en ligne.

@was/ecs : entités et composants​

Ce paquet contient Entity, Component et Space. Avec lui, un plugin lit et modifie une scène grâce à l'API complète, et non à une API séparée et limitée.

Space : le monde​

AppelRenvoie
getEntity(id)une entité, ou rien
hasEntity(id)si elle existe
getEntities()toutes les entités
queryEntities(A, B, …)toutes les entités qui ont tous ces composants
makeQueryEntities(A, B, …)la même requête, construite une fois pour être réutilisée
createEntity(id?, components?)une nouvelle entité, ajoutée au monde
addEntity(…e) · removeEntity(…e)ajoute une entité au monde ou l'en retire
getSystem(S) · hasSystem(S)un système, ou s'il existe
execute()exécute une image
Utilisez queryEntities pour trouver des entités

Demander ainsi « tout ce qui a une lumière et un transform » est rapide. getEntities() vous donne le monde entier, et c'est à vous de le filtrer.

Entity : un objet du monde​

AppelCe qu'il fait
getComponent(Type)renvoie un composant, ou null
getComponents(A, B)en renvoie plusieurs à la fois, dans cet ordre
hasComponent(A, B)vérifie si l'entité les a tous
addComponent(…c)ajoute des composants ; un type qu'elle a déjà est ignoré
removeComponent(…c)retire des composants, par classe ou par instance
component(fn)exécute fn pour chaque composant, présent et à venir
clone() · clean()copie l'entité, ou retire tous ses composants
.id · .componentsson id, et ses composants classés par type

Component : les données​

AppelCe qu'il fait
.x ou get('x')lit un champ ; dans un effet, s'y abonne aussi
$datale composant entier, sous forme d'objet simple
$rawDatal'objet stocké, sans abonnement ; en lecture seule
update({ … })écrit des données. C'est la seule façon d'écrire.
updateAt(path, value)écrit en profondeur dans un gros composant sans tout revalider
version(field?)un compteur qui augmente à chaque changement, pour dépendre d'un champ sans le lire
reset(data?)revient aux valeurs par défaut
clone()crée une copie
Utilisez version() pour les grandes listes

Lire une grosse valeur vous abonne à chacun de ses éléments. Dépendez plutôt de son compteur de version : vous savez qu'elle a changé sans surveiller chaque élément. C'est ainsi qu'un panneau reste rapide avec une liste de vingt mille éléments.

@was/engine : classes de composants​

Chaque type de composant est une classe : TransformComponent, MaterialComponent, RigidBodyComponent et les autres. Importez la classe et passez-la à getComponent, hasComponent ou query.

Pour la liste complète avec tous les champs, consultez la référence des composants.

@was/svdt : schémas​

Ce paquet vous permet de décrire la forme de vos données et de les vérifier.

import { s, compile } from '@was/svdt';

const schema = s.object({ speed: s.f64(1), name: s.string('') });
const codec = compile(schema); // compiler une seule fois, là où vous le déclarez, jamais à chaque appel
const value = codec.parse(input);

Décrire une forme​

  • Nombres : s.f32 s.f64 s.i8 s.u8 s.i16 s.u16 s.i32 s.u32, chacun avec une valeur par défaut.
  • Scalaires : s.bool, s.string, s.color, s.literal, s.enum, s.unknown, s.ref.
  • Vecteurs : s.vec2, s.vec3, s.mat4.
  • Composites : s.object, s.variant, s.array, s.record, s.union, s.preprocess, s.lazy.

Vous pouvez enchaîner ces méthodes sur n'importe lequel d'entre eux : .default(v), .optional(), .nullable(), .min(n), .max(n), .int().

Utiliser un codec compilé​

AppelCe qu'il fait
parse(input)valide et normalise ; lève une erreur si l'entrée est incorrecte
safeParse(input)la même chose, mais renvoie un succès ou une erreur au lieu de la lever
parseAt(path, v)valide un seul champ sans toucher au reste
equals(a, b)comparaison en profondeur
diff(a, b)renvoie ce qui a changé
apply(target, p)applique un diff
invert(p)inverse un diff
pack · unpackconvertit vers et depuis un format binaire compact

Pour examiner le schéma lui-même plutôt que des données, utilisez introspect, keys et requiredKeys.

@was/utils​

De petites fonctions utilitaires : pick, omit, assign, keys, values, entries, capitalize, basename, extname, dispose (qui réunit plusieurs fonctions de nettoyage en une seule), et des fonctions de types MIME pour vérifier le type des fichiers.


Suivant : Glossaire — les termes employés dans cette documentation.