Skip to content

t1k:cocos:playable:mechanic-split

FieldValue
Moduleplayable
Version2.14.4
Efforthigh
Tools—

Keywords: by-type layout, mechanic split, modularize gameplay, portable mechanic, refactor folder, reusable module, uuid safe move, vertical slice

/t1k:cocos:playable:mechanic-split
[<cocos-root>] [--audit-only] [--resume <phase-file>] [--mechanics-from <manifest>]

Turns assets/scripts/<GameName>/ from a by-type layout (core/, ui/, managers/, effects/) into vertical mechanic folders — grid-board/, block-drag/, line-clear/, goals/ — each self-contained enough to copy into a different game. The library grows as folders inside the game root: plain git mv, no CPM tooling.

Scope is in-place split only — no package extraction, no publishing, no wiring a mechanic into another project (that is the t1k-cocos-playable-modularize family’s job). <GameName> differs per project and Phase 0 detects it; never hardcode it, and never leave it hardcoded in an import.

Gameplay code is grouped by type, a second project wants one of its mechanics, or a file has grown past ~400 lines holding several unrelated concerns.

Two entry points — standalone and delegated

Section titled “Two entry points — standalone and delegated”

This skill runs from two different callers, and which one you are changes how the mechanic list is decided:

  • Standalone (unchanged): Phases 0-3 derive the mechanic list from the coupling matrix and references/decision-rubric.md. Self-classified, per the workflow above.
  • Delegated from t1k-cocos-playable-modularize Tier 2.6 (--mechanics-from <manifest>): the mechanic list is the design doc’s module table, read from the manifest (modules[].name + modules[].files). Phases 0-2 (detect root, inventory, coupling/blocker audit) still run — their output is what makes the move safe, and the blocker scan is still needed — but Phase 3’s own classification is SKIPPED. Phase 4 onward is unchanged.

Why: re-deriving boundaries inside a pipeline that already has a design-doc module map produces two competing module maps decided by different methods. The design doc is the authority there; t1k-cocos-playable-modularize decides boundaries, this skill executes them in place.

Failure mode, stated plainly: if --mechanics-from names a manifest that is absent or unreadable, or its modules[] is empty, STOP and say so. Never fall back silently to self-classification — a silent fallback is indistinguishable from the delegated path having worked (rules/negative-result-scope.md; rules/errors-over-silent-fallbacks in development-principles.md).

Non-negotiable: component identity is uuid-derived

Section titled “Non-negotiable: component identity is uuid-derived”

Every .ts has a sibling .ts.meta carrying a uuid. Scenes and prefabs reference components by a compressed cid derived from that uuid — not by class name, not by path. A mid-sized playable typically carries a few dozen scene/prefab files and a few dozen distinct script cids; count yours in Phase 1 rather than assuming.

So a split is a move, never an add-then-delete. git mv the .ts and its .ts.meta together and refs survive; drop the .meta and the editor mints a fresh uuid, turning every reference into a silent Missing Script.

Snapshot cid counts before each move and diff after. A non-empty diff means git checkout — never repair it in the editor, which mints more new uuids. Commands and the full table: references/move-safety.md.

Two stages with a mandatory human review between them. Phases 0-3 are read-only and always run; Phase 4 never starts in the same turn that presents the plan.

PhaseDoesWrites
0Detect the game root under assets/scripts/—
1Inventory files, LOC, orphan metas—
2Coupling matrix, shared kernel, external imports, blockersaudit/*.md
3Classify mechanics, order leaf-first, resolve decisions, write the planplan.md, phase-*.md
⛔REVIEW GATE — stop and hand the plan to the user—
4Move one mechanic: git mv, rewrite imports, barrel + README, verify, commitsource
5Reuse verification per mechanicREADME.md

Phase detail and stop conditions: references/split-workflow.md. Plan layout and what each phase file must carry: references/plan-artifact.md.

Phases 0-3 are read-only and token-heavy — delegate them to ONE background t1k-code-reviewer, never a new agent and never a fan-out. The gate stays in the main session (a background agent has no user to answer it). Phase 4 goes to a FOREGROUND sub-agent, one mechanic at a time; background only for an explicit unattended batch. Brief template and both cases: references/agent-brief.md.

After Phase 3, present in chat: the mechanic table with coupling numbers and split order, the blockers by file:line, exactly what phase 1 touches, and the decisions the audit already resolved on the user’s behalf, with rationale — flag any to reverse. Phase 3 never defers a structural decision to this gate or to Phase 4 (rubric: references/decision-rubric.md). Then AskUserQuestion — three options, never assumed:

OptionThen
Cook nowRun Phase 4 for the first unchecked phase, in this session
Hand back a resume commandPrint the copy-pasteable line, stop, change nothing
Revise the planTake the correction, rewrite the plan, gate again

The resume line names a real file, so a fresh session needs no memory of this one: /t1k:cook plans/<plan-dir>/phase-02-<mechanic>.md. Each phase file is self-sufficient by construction — “as discussed above” and a BLOCKED/“do not guess” heading are the same defect: the next session has no above, and no one to resolve the surfaced decision either.

After each phase lands, tick its checkbox in plan.md and advance the Resume line in the same commit as the move.

A vertical slice another game could adopt. Not a layer, not a single class. All four must hold: nameable without the game (line-clear, not <GameName>Stuff) · deleting the folder removes exactly one capability · it owns its own signals and data · its dependencies fit in a short table.

Folder shape, the barrel-import rule, and the required README.md contract: references/mechanic-shape.md.

Audit the kernel before believing the coupling matrix

Section titled “Audit the kernel before believing the coupling matrix”

The files everyone imports — Enums.ts, Interfaces.ts, GameSignals.ts — routinely mix generic types with game-specific ones, making every mechanic look more coupled than it is. Split contaminated kernel files first. Watch too for one game-specific concern threaded through generic classes; cutting it is usually the highest-leverage single edit. Numbers: references/worked-example.md.

Four blockers that compile fine and destroy reuse

Section titled “Four blockers that compile fine and destroy reuse”
BlockerWhy it kills reuse
db://assets/scripts/<GameName>/... self-importBakes the folder name in; breaks on copy
Import from the game root barrelCircular; pulls the whole module graph
Import escaping assets/ (4+ ../)Not part of the build; usually dead auto-import
Deep cross-mechanic import past the barrelContract stops describing real dependencies

Scans and fixes: references/portability-blockers.md.

Verification — a compiler gate exists, and it is not the whole story

Section titled “Verification — a compiler gate exists, and it is not the whole story”

Despite the common claim that a Cocos project has no CLI build, the editor ships its own tsc and the generated config already maps db://assets/*. ~/.claude/skills/t1k-cocos-playable-mechanic-split/scripts/tsc-gate.sh <cocos-root> compiles assets/ in seconds, is proven to go red on a broken import, and refuses to pass if it checked zero files. Run it after every mechanic move, beside the cid diff. The path is anchored at the installed skill, not at your Cocos project — the script ships with this skill, so a project-relative scripts/tsc-gate.sh will not resolve.

It still does not prove reuse: everything compiles because everything else is still there. That test is copying <mechanic>/ + _shared/ into an empty folder — does every import resolve inside the copy or appear in the README’s Depends on table? Anything else is undeclared coupling: record it, do not delete it to pass.

Likewise, “uses SignalBus” is not “decoupled”. Count signal fires against direct singleton calls — the direct calls are the actual coupling.

  • Editor open during a move races the asset importer into regenerating metas. Close it before Phase 4, and never delete a .ts without the pre-delete reference check. Commit each move by explicit pathspec — git add -A sweeps in the editor’s own regenerated files and makes the cid diff unattributable.
  • Batching mechanics into one commit makes a broken cid diff unattributable.
  • Scaffolding empty subfolders — create logic/, signals/ only when non-empty.
  • Renaming classes during the split. Scene refs survive (cid is uuid-derived) but every importer breaks. Move first, rename later, separate commits.
  • Inline lambdas in signalBus.subscribe — unsubscribe() uses indexOf(), so a lambda never unsubscribes. Named arrow-function class fields only.
  • A mechanic depending on 4+ others is not a mechanic — report it as a boundary decision instead of moving it.
  • An agent that returns a summary but writes no plan files has failed; re-spawn it rather than reconstructing the plan from its message.

references/worked-example.md — one real Phase 1-3 run with its coupling numbers · references/decision-rubric.md — the tie-breaker rubric and decisions.md format · t1k-cocos-playable-modularize — the primary entry point for a project already in the modularize pipeline, and this skill’s caller via Tier 2.6; the peer family this skill also defers packaging and publishing to · t1k-cocos-playable-signalbus · t1k-cocos-playable-gameflow · t1k-cocos-base-code-conventions