logo
By Lawrence

8 minutes

Make It Marketplace-Ready

TL;DR — Put a working componentA reusable piece of game behavior plus its data — the unit the marketplace ships, living in its own folder. into the marketplace's folder layout. Write the meta.json card that the catalog and the eject closureA component plus everything it needs to run, gathered automatically — the component and its dependencies, then their dependencies, all the way down. both read. Learn why the dependencies you write have to be honest.

Get Component Source: Eject and Acquire ended with a promise: next you write one. So far, every folder in your src/components/ came from somewhere else. You ejected Bullet and its whole dependency closure out of the package. Or you bought one from the catalog with cheddar. You own that code now, but you didn't write it. In this lesson you write your own component beside it. Call it Magnet. It has a pull radius that drags pickups toward the holder. When you finish, the two folders follow the same shape: same naming, same meta.json, and nothing marks yours as homemade. That sameness is what makes the next command possible.

The format that eject writes is the same format that submit reads. A component built in that shape needs no packaging step and no submission form — once the folder is right, you already have a marketplace component.

The folder a component lives in

Every component in the catalog uses one layout. Eject made it for Bullet. Now you make it for Magnet:

src/components/Magnet/
├── Magnet.ts        # the MagnetComponent (data) and MagnetSystem (behavior)
├── Magnet.test.ts   # a small test proving the behavior
└── meta.json        # the marketplace card: name, deps, category

That's the smallest shape: a main file, a test, and meta.json. Magnet.ts holds two classes. The component class is pure data. The system class is the behavior, and it runs on every render tick. Magnet.test.ts builds a tiny world, sets up a situation, and checks the result. This is how a curator confirms your code works. (A curator is the human reviewer who approves submissions.) They don't have to read every line and doubt it. And meta.json is the card the catalog shows and the eject tooling reads. Real catalog components often add extra files to this shape: a .core.ts for the pure logic, a .contract.test.ts, a .viz.tsx panel. So the Bullet you ejected lands as six files, not three. The three above are the floor every component shares.

The Magnet component folder: a main file, a test, and meta.json laid out like tools in a kit

Writing the MagnetComponent and MagnetSystem is ECSEntity-Component-System, the architecture @babylonjsmarket/arcade is built on — entities hold components (data), and systems run the behavior. (Entity-Component-SystemAn @babylonjsmarket/ecs class that declares a query and runs behavior each frame over the entities that match it.) work. That's the behavior that pulls pickups toward the holder. You learn it in Up to Speed with Arcade ECS, not here. This lesson covers what turns working code into catalog code: the metadata file beside it.

A hero holding a lodestone with a pull radius drawn around them, coins drifting inward, and a captured event flying off to other systems

What meta.json tells the catalog

meta.json tells the catalog how to describe your component. It also tells the eject tooling what your component brings along with it. This is not boilerplate you can fake. The closure algorithm from the last lesson reads the dependencies field directly. Only a handful of fields carry the whole card.

name is what the component is called in a scene and in the listing. description is the pitch a shopper reads in the BBS before spending cheddar. (The BBS is the terminal catalog browser from lesson 3.) A description runs long when the component has a whole event protocol to document — that's right for a component other components talk to — and stays short when the component keeps to itself. category files it under a catalog section, a genre or concern like core, shooter, or pinball — the shelf your listing sits on. components and systems name the classes this folder ships. And tags are the searchable labels the BBS filters on.

The field that matters most is dependencies. A component that leans on nothing else has an empty list. Magnet reads positions off MeshPrimitive, so its list says so. (MeshPrimitive is the built-in component that gives an entity a shape and position.) Put together, your card looks like this:

{
  "name": "Magnet",
  "description": "Pulls tagged pickups toward the holder; emits magnet.captured when one arrives so scoring and audio can react.",
  "category": "core",
  "components": ["MagnetComponent"],
  "systems": ["MagnetSystem"],
  "dependencies": ["MeshPrimitive"],
  "tags": ["core", "pickup"]
}

Keep dependencies honest. dependencies is the official list, but it isn't the only thing the closure checks. When someone ejects Magnet, the tooling also scans your files for ../Sibling/ imports as a backup. Magnet imports MeshPrimitive directly, so the scan would find it even if your list were empty. A directly-imported sibling gets caught either way. The real trap is a link the scan can't see: a shared EventBus event string, a tag, or a class you reach without importing it. These have no import line to follow. So the closure only knows about them if you write them into dependencies. The list is your promise that covers what the scan can't.

Where your component goes after review

Your component goes to the marketplace catalog — the same catalog you browsed in the BBS and pulled Bullet out of. Once a curator approves it, it becomes a listing under Components/, with the meta.json card you just wrote, and any member can unlock it and run bjs download Magnet.

It does not go into @babylonjsmarket/arcade or any other npm package. Those packages are the framework you build on; the catalog is where community components live, and the two are separate all the way down. Nobody has to npm install anything to use what you publish.

You now have a component in the exact marketplace shape, and a meta.json whose dependencies the closure can trust. That is everything the queue needs.

Next: Submit and Track Your Component — run the dry-run, send the diff payload, and follow your submission from pending to merged.

Was this page helpful?

We read every note — tell us what's working and what isn't.

↑↓ NavigateEnter SelectEsc CloseCtrl+K Open Search