prefab-only-construction-cocos
Prefab-Only Construction (Cocos) — No Code-Built Nodes / UI / Scene-Wiring
Section titled “Prefab-Only Construction (Cocos) — No Code-Built Nodes / UI / Scene-Wiring”Scope: Cocos Creator runtime & gameplay TypeScript (
cc.Component, node, prefab). Does NOT govern editor extensions, genuinely reusable factory utilities, or tests (see Carve-outs). This is the Cocos sibling ofprefab-only-construction-unity.md.
In Cocos runtime/gameplay code you MUST NOT construct node hierarchies, UI, or wire
scene references in code. Everything visual/structural is authored as a prefab
(or in the scene) in the editor and spawned as a prefab at runtime; cross-node
references are assigned via @property in the editor, saved in the scene/prefab asset.
Banned in runtime/gameplay code:
new Node(...)+addChild(...)to build a runtime visual/entity or a container.addComponent(cc.Sprite)/addComponent(cc.Label)/addComponent(...)chains that assemble a visual hierarchy in code.- Building
UITransform/Widget/Layout/ label / sprite trees procedurally. - Code scene-wiring:
find(...),getChildByName(...),getComponentInChildren(...)used to locate/assemble what should be an editor-assigned@propertyreference. Cross-node references are wired in the editor. - Auto-creating a “root”/container node in code (e.g. a
BoardRoot) — that is a prefab too.
The ONE permitted construction form — spawn a prefab:
// Author CardView.prefab / BoardRoot.prefab in the editor, then:const node = instantiate(this.cardPrefab); // or ObjectPoolManager spawnthis.boardRoot.addChild(node);node.getComponent(CardView)!.configure(this.config, size); // set DATA on existing refsnode.getComponent(CardView)!.bind(card);instantiate(prefab)is allowed and encouraged — that IS prefab spawning.- Prefer a pool (
ObjectPoolManager, seet1k-cocos-playable-object-pool) for anything spawned/recycled repeatedly;code-quality-cocos.md’s pattern-trigger table already makes pooling mandatory for per-spawn/in-loopinstantiate()/new Node(). A plaininstantiate(prefab)is fine for a fixed one-time set. - After spawning, configure via a
configure(...)/bind(...)method on the prefab’s@ccclasscomponent that sets data (size, color, text, spriteFrame) on already-serialized@propertyrefs — it must NOT create children. - Every runtime visual, entity, HUD element, popup, tile, card, and container/root = its own prefab. Adding a pure-logic (non-visual) component to an already-spawned prefab instance is fine.
Author via the Cocos MCP, not code
Section titled “Author via the Cocos MCP, not code”When the prefab or scene must be created or modified — new node, new component, wiring a
@property, restructuring a hierarchy — drive the Cocos Creator MCP tools, NOT a
hand-written scene-building script:
| Need | Tool |
|---|---|
| Create / modify / delete a node | manage_node |
| Restructure / reparent a hierarchy | manage_node_hierarchy |
| Apply changes into a prefab | manage_prefab (update) |
| Add / remove / set a component’s properties | manage_component |
| Create / query / save the scene | manage_scene, manage_scene_query |
Create a new .ts/asset so @ccclass registers | manage_asset (create, url=db://...) |
| Confirm you’re targeting the right project first | manage_project (get_info path) |
A one-off “build my scene / wire my refs” script is not authoring — use the MCP. Load
t1k-cocos-playable-editor-tools + t1k-cocos-playable-tooling-gotchas and heed the gotchas
that make this succeed first try:
- A new
.tswritten with the plain Write tool is not auto-imported and its@ccclassdoes not register — create scripts viamanage_asset action=create url=db://assets/.... - A custom
@ccclass__type__in scene/prefab JSON uses the compressed cid (not the raw uuid, not the class name); built-incc.*components use the literal class name. - A
@propertynode reference takes a node uuid, not a component uuid. - Any legitimately runtime-created node defaults to
Layers.Enum.DEFAULTand renders invisible under a Canvas — copy the parent’slayerbeforeaddChild(). manage_prefab updatemay report “Editor rejected apply-prefab” even on success — do NOT retry; verify by grepping the.prefabfor the child uuid.
Carve-outs (allowed — this rule does not apply)
Section titled “Carve-outs (allowed — this rule does not apply)”- Editor extension tooling (an editor panel/extension whose job is to author the prefab this rule requires) may build hierarchies freely.
- Genuinely reusable factory utilities — a shared, tested spawner used from ≥3 sites — may construct nodes; a per-feature one-off may not.
- Pure-logic (non-visual, non-
@ccclass) TypeScript — plain domain/application classes have no nodes to build (seecode-conventions-cocos.md§ “Feature modules & testability”). - Unit tests (Vitest,
environment: 'node') may construct whatever they need. - 1 documented one-off bootstrap node created once at boot (e.g. a
DontDestroyOnLoad-style service host) — document the choice in a code comment so the next reader doesn’t “fix” it.
- The prefab/scene is the SSOT for visuals & layout: artists/designers edit it in the editor without touching code, and what you see in the editor is what ships.
- Code-built UI can’t be previewed, drifts from the editor, mixes presentation with logic, and re-authors the same hierarchy on every developer’s read.
- Editor-
@propertyreferences are visible, diffable, and don’t silently resolve tonullon rename the wayfind("Name")string lookups do — and they preserve the UUID identity thatgame-asset-slot-handoff-cocos.mddepends on.
How to apply / Test
Section titled “How to apply / Test”If a new Node(...), addComponent(cc.Sprite), createChild/createLabel, or
find/getChildByName in runtime code could be replaced by instantiate(prefab) (or a
pool spawn) + a configure()/bind() data call, it is a violation — author the prefab via the
MCP, wire its children as @property in the editor, spawn it. If the construction is genuinely
an editor extension, a reusable factory, a test, or a documented one-off bootstrap, the rule
does not apply — say so in a code comment.
A tools: grant does not guarantee the MCP is reachable at runtime
Section titled “A tools: grant does not guarantee the MCP is reachable at runtime”t1k-cocos-developer and t1k-cocos-debugger carry mcp__cocos-creator__* grants so they can
follow this rule directly. Under model-router transparent mode, a routed hop only forwards
MCP servers listed in the consumer’s modelRouter.security.allowedMcpServers — a sonnet-tier
agent (t1k-cocos-developer) can be delegated to a cheap provider with no cocos-creator entry
in that allowlist, in which case the grant is present in frontmatter but absent at runtime.
t1k-cocos-debugger is model: opus, which never routes, so this only bites the implementer
path. If a routed t1k-cocos-developer reports the mcp__cocos-creator__* tools as unavailable,
check the consumer’s allowedMcpServers before assuming the kit regressed.
Related
Section titled “Related”prefab-only-construction-unity.md— the Unity sibling (this rule mirrors it for Cocos).code-quality-cocos.md— mandatory pattern triggers (pooling for per-spawnnew Node()).code-conventions-cocos.md—@ccclass/@property, SignalBus named-method rule, logic outsidecc.Component.game-asset-slot-handoff-cocos.md— UUID identity: why overwrite-in-place beats add-then-delete.t1k-cocos-playable-object-pool— spawn/recycle prefabs throughObjectPoolManager.t1k-cocos-playable-editor-tools/t1k-cocos-playable-tooling-gotchas— Cocos MCP authoring + gotchas.