Structure and hosting

One hosting model — slots are named positions, child declarations are their occupants.

MotionActor has a single hosting relationship. There is no structural/mounted split and no second mechanism to learn.

  • A slot is a named hosting region: where a child can go.
  • A child declaration is a named occupant: who is there.
  • child(...) uses the slot matching its field name.
  • hostInSlot(...) adds an occupant during compilation using the same relationship.
const phoneSlots = defineSlots({
  statusBar: slot({ accepts: StatusBar }),
  app: slot(),
});

class Phone extends LayoutActor<typeof phoneSlots> {
  static slots = phoneSlots;

  statusBar = child(StatusBar); // occupies "statusBar"
  app = child(MailApp); // occupies "app"
}

Which form to use

Declare a field. Always-owned children that exist for the actor's whole life belong in the class body, where the type system can see them.

class Phone extends LayoutActor<typeof phoneSlots> {
  static slots = phoneSlots;
  statusBar = child(StatusBar);
}

Do not use onSpawn to wire fixed bindings

Falling back to onSpawn() just to pass parent state to a fixed child is the common mistake. Use an owner-aware factory instead — it keeps the child a declared field and the binding live.

Use it for

  • Actors that expose stable child regions: shells, panes, phones, windows.
  • Any host that should be able to accept content it does not itself define.

Resolved structure

Hosting shows up on every ResolvedActor as parentId, slotName and slotChildren, so a renderer can place children without knowing the actor family:

const phone = state.findActor(Phone);
phone.slotChildren.app; // ["mail-app-1"]

On this page