Paquetes compartidos
Puedes importar estos paquetes en tu propio código. Aquí verás qué puedes usar en cada sitio y qué te da cada paquete.
En el código, los objetos que ves en el editor se llaman entidades (entities). Son lo mismo.
Los paquetes que puedes importar dependen de dónde se ejecuta tu código:
| Paquete | Qué te da | En un script | En un plugin | En una extensión de componente |
|---|---|---|---|---|
@was/ecs | entidades, componentes, el mundo | ✓ | ✓ | ✓ |
@was/engine | las clases de componente | ✓ | ✓ | ✓ |
@was/signals | valores reactivos | — | ✓ | ✓ |
@was/svdt | esquemas y validación | ✓ | ✓ | — |
@was/utils | pequeñas utilidades | ✓ | ✓ | — |
@was/ui | la propia biblioteca de componentes del editor | — | ✓ | ✓ |
@was/icons | el juego de iconos del editor | — | ✓ | ✓ |
react | React 19 | — | ✓ | ✓ |
ctx.effectUn script no puede importar @was/signals directamente. Usa ctx.effect en su lugar. Funciona
igual y se detiene cuando desaparece su objeto, así que no queda nada en marcha.
@was/signals: valores reactivos
Una señal (signal) es un valor que sabe quién lo lee. Cuando cambia, solo se actualiza lo que depende de él.
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); // vuelve a ejecutarse solo cuando cambia score
});
batch(() => {
score.value += 1;
score.value += 1; // los efectos se ejecutan una vez, no dos
});
stop();
| Función | Qué hace |
|---|---|
signal(v) | un valor que se puede observar; lees y escribes .value |
computed(fn) | un valor derivado, que solo se recalcula cuando cambia lo que lee |
effect(fn) | se ejecuta ahora y otra vez cada vez que cambia lo que ha leído; devuelve una función para detenerlo |
batch(fn) | agrupa escrituras para que los observadores se ejecuten una sola vez al final |
untracked(fn) | lee un valor sin depender de él |
ref(obj) | hace reactivo un objeto entero, hasta el último valor anidado |
snapshot(obj) | una copia simple, no reactiva |
raw(obj) | el objeto original, sin seguimiento |
readonly(obj) | una vista en la que no se puede escribir |
Para paneles de React, un paquete complementario te da useSignal, useComputed,
useSignalEffect y useLiveSignal. Así un componente se vuelve a renderizar a partir de una
señal sin ninguna conexión extra.
@was/ui: componentes del editor
Crea los paneles de tus plugins y tus extensiones de componente con los mismos componentes que usa el editor. Así tus paneles parecen parte del editor, y no una página web incrustada. La biblioteca tiene estos componentes:
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
Para los iconos, usa @was/icons.
Los paneles solo pueden usar las clases de utilidad que incluye la biblioteca. Los valores
arbitrarios como text-[13px] no están incluidos. Para tamaños que no están en la escala, usa un
style en línea.
@was/ecs: entidades y componentes
Este paquete tiene Entity, Component y Space. Con él, un plugin lee y cambia una escena a
través de la API completa, no de una API aparte y limitada.
Space: el mundo
| Llamada | Devuelve |
|---|---|
getEntity(id) | una entidad, o nada |
hasEntity(id) | si existe |
getEntities() | todas |
queryEntities(A, B, …) | todas las entidades que tienen todos esos componentes |
makeQueryEntities(A, B, …) | la misma consulta, creada una vez para usarla muchas veces |
createEntity(id?, components?) | una entidad nueva, añadida al mundo |
addEntity(…e) · removeEntity(…e) | añade una entidad al mundo o la quita |
getSystem(S) · hasSystem(S) | un sistema, o si existe |
execute() | ejecuta un fotograma |
queryEntities para encontrar entidadesAsí, pedir «todo lo que tenga una luz y un transform» es rápido.
getEntities() te da el mundo entero, y tienes que filtrarlo tú.
Entity: un objeto del mundo
| Llamada | Qué hace |
|---|---|
getComponent(Type) | devuelve un componente, o null |
getComponents(A, B) | devuelve varios a la vez, en ese orden |
hasComponent(A, B) | comprueba si los tiene todos |
addComponent(…c) | añade componentes; si ya tiene uno de ese tipo, se ignora |
removeComponent(…c) | quita componentes, por clase o por instancia |
component(fn) | ejecuta fn para cada componente, ahora y en el futuro |
clone() · clean() | copia la entidad, o le quita todos sus componentes |
.id · .components | su id y sus componentes, indexados por tipo |
Component: los datos
| Llamada | Qué hace |
|---|---|
.x o get('x') | lee un campo; dentro de un efecto, además se suscribe a él |
$data | el componente entero como objeto simple |
$rawData | el objeto guardado, sin suscribirse; de solo lectura |
update({ … }) | escribe datos. Es la única forma de escribir. |
updateAt(path, value) | escribe en lo profundo de un componente grande sin volver a validarlo entero |
version(field?) | un contador que sube cuando algo cambia, para que puedas depender de un campo sin leerlo |
reset(data?) | vuelve a los valores por defecto |
clone() | hace una copia |
version() para listas grandesLeer un valor grande te suscribe a cada elemento que contiene. Depende mejor de su contador de versión: sabes que ha cambiado sin observar cada elemento. Así es como un panel sigue siendo rápido con una lista de veinte mil elementos.
@was/engine: clases de componente
Cada tipo de componente es una clase: TransformComponent, MaterialComponent,
RigidBodyComponent y las demás. Importa la clase y pásala a getComponent, hasComponent o
query.
Para ver la lista completa con todos los campos, consulta la referencia de componentes.
@was/svdt: esquemas
Con este paquete describes la forma de tus datos y los compruebas.
import { s, compile } from '@was/svdt';
const schema = s.object({ speed: s.f64(1), name: s.string('') });
const codec = compile(schema); // compila una vez, donde lo declaras, nunca en cada llamada
const value = codec.parse(input);
Describe una forma
- Números:
s.f32 s.f64 s.i8 s.u8 s.i16 s.u16 s.i32 s.u32, cada uno con un valor por defecto. - Escalares:
s.bool,s.string,s.color,s.literal,s.enum,s.unknown,s.ref. - Vectores:
s.vec2,s.vec3,s.mat4. - Compuestos:
s.object,s.variant,s.array,s.record,s.union,s.preprocess,s.lazy.
Puedes encadenar estos métodos en cualquiera de ellos: .default(v), .optional(),
.nullable(), .min(n), .max(n), .int().
Usa un códec compilado
| Llamada | Qué hace |
|---|---|
parse(input) | valida y normaliza; lanza un error si la entrada no es válida |
safeParse(input) | lo mismo, pero devuelve un resultado correcto o un error en lugar de lanzarlo |
parseAt(path, v) | valida un campo sin tocar el resto |
equals(a, b) | comparación profunda |
diff(a, b) | devuelve lo que ha cambiado |
apply(target, p) | aplica un diff |
invert(p) | invierte un diff |
pack · unpack | convierte a una forma binaria compacta y viceversa |
Para inspeccionar el propio esquema en lugar de los datos, usa introspect, keys y
requiredKeys.
@was/utils
Pequeñas utilidades: pick, omit, assign, keys, values, entries, capitalize,
basename, extname, dispose (combina varias funciones de limpieza en una) y utilidades de tipos
MIME para comprobar tipos de archivo.
Siguiente: Glosario: los términos que se usan en esta documentación.