bjs inject routes into one of two namespaces. The choice — arcade or viz — is the first thing the tool resolves, and the rest of the run depends on it.
arcade vs viz
The arcade namespace is the per-component layout of @babylonjsmarket/arcade. Each component lives in its own folder under src/components/<Name>/ and gets a lazy resolver in src/registry.ts. This is the same layout as @babylonjsmarket/arcade itself — same folder shape, same scene-loader convention, same eject behaviour. Components that do something in the game world (a new physics body type, a new camera mode, a new enemy AI brain) belong here.
The viz namespace is @babylonjsmarket/viz, the debug/visualization layer over @babylonjsmarket/ecs. It's flat, not per-component: every file lives in one of three layers — core, solid, or ecs — and the layer's index.ts re-exports it. Components that visualize, debug, or step through ECS state (a Solid debug panel, a custom State stepper, a panel-debugging System) belong here.
The split exists because viz depends on Solid and a few debug-only utilities that an arcade component shouldn't pull in. Mixing them would force every consumer of arcade to ship Solid even when they don't render any panels.
When to use which
Pick arcade when:
- Your component is a Component+System pair that ticks every frame.
- The System reads/writes mesh handles, physics bodies, or scene state.
- The Component data is the kind of thing you'd describe in scene JSON.
Pick viz when:
- Your code subclasses
PanelDebuggerSystemorStateStepperSystem. - Your code imports anything from
@babylonjsmarket/viz. - Your code is a Solid panel that reads ECS state but doesn't mutate the world.
The two are not mutually exclusive at the project level — your project can promote some components to arcade and others to viz. But each bjs inject run targets exactly one namespace.
Auto-detect rules
When you don't pass --target, the tool reads every .ts/.tsx in the seed's closure and applies this check, in order:
In plain English:
- Any file in the closure imports from
@babylonjsmarket/viz→ viz. - Any file extends
PanelDebuggerSystemorStateStepperSystem→ viz. - Otherwise → arcade.
A seed with no viz markers always routes to arcade. A seed with a single Solid panel that imports from viz routes to viz — even if most of the seed is plain.
Multi-seed runs
When you pass several names in one run, every seed must individually agree on the target. The tool re-runs detection per-seed and aborts on mismatch:
Two valid responses: pass --target to force the call (rare — usually means one seed is in the wrong target), or run the two seeds separately.
Overriding the target
--target skips auto-detection entirely. Use it when:
- You want certainty and don't want the tool's heuristic involved.
- A seed is on the boundary and the auto-detect picks wrong.
- You're injecting a seed via
--sourcethat the auto-detect can't reason about confidently.
An unknown target value is rejected:
Viz layer routing
Once the target is viz, every file is classified into one of three layers. The classifier is in src/cli/detect-target.ts:
The order matters. A .tsx file that imports solid-js lands in solid even if it also extends Component. A file named FooSystem.ts lands in ecs even if it doesn't subclass anything.
Test files travel with their subject. Foo.test.ts looks up Foo.ts or Foo.tsx in the same seed, takes the subject's layer, and rides along. When the subject isn't co-injected, tests default to core — meaning your test ships, but you'll want to double-check it lands somewhere sensible.
Overriding the layer
--layer only applies to viz and forces every file in the seed (and its closure) into one layer. Use it when:
- Auto-classification splits files across layers and you want one folder.
- You're shipping a seed that doesn't fit the heuristic cleanly.
The classifier is usually right. Reach for --layer after a dry-run shows files going somewhere wrong.
An unknown layer value is rejected:
What the layers mean in viz
core/— renderer-free, framework-free utilities. Pure-TypeScript helpers,definePanelfactories without Solid wrappers, state schemas. The bottom of the stack.solid/— Solid components that render panels..tsxfiles that importsolid-js. The presentation layer.ecs/— System and Component subclasses that integrate with the ecs framework.*System.ts, classes extendingSystemorComponent. The integration layer.
A typical viz seed touches more than one layer: a .core.ts of pure logic, a .ts with a System, a .viz.tsx for the panel. The classifier splits them per file; barrels per layer pick them up.
What's next
The next section, inject in practice, runs a worked example end to end with the dry-run plan and the file diffs.