Skip to content

t1k:cocos:playable:parameter-scan

FieldValue
Moduleplayable
Version0.5.6
Effortmedium
Tools

Keywords: canvas-scan, component-scan, config-scan, discover, find-nodes, parameter-scan, scan, scene-scan

/t1k:cocos:playable:parameter-scan
[--mode ui|config|all] [--deep] [--canvas <path>] [--path <folder>]

Two-layer scene and config discovery engine for the flat-primitive parameter architecture. The scanner identifies parameterizable Cocos nodes and emits a report; the implement step consumes that report and produces flat-primitive PlayableConfig entries (one per node, with prefixed primitives — never ComponentParameter wrappers).

LayerFlagApprovalOutput
UI--mode uiNone (auto)Parameterizable nodes JSON
Config--mode configRequiredConfig candidates JSON
Both--mode allConfig onlyCombined report
IntentAction
”Parameterize all UI components”--mode ui → auto-generate per-node flat-primitive entries
”Scan nodes under a specific Canvas”--mode ui --canvas <path>
”Extract config values for params”--mode config → present candidates
”Find magic numbers in gameplay code”--mode config --deep
”Scan specific game folder”--mode config --path <folder>
”Full parameter pass”--mode all
ModeScopeMCP RequiredApproval
--mode uiCanvas descendants + component detectionYesNone
--mode config*Config.ts files in scripts/NoRequired
--mode config --deepAbove + magic numbers in gameplay codeNoRequired
--mode allUI (auto) then Config (review)YesConfig only
Old FlagMaps ToEmits Warning
--quick--mode ui (wired nodes only)Yes
--standard--mode uiYes
--deep (alone)--mode all --deepYes
CategoryKeywordsPrimitive
Healthhp, health, damage, healRangeParameter (0-1000)
Timingduration, delay, cooldown, intervalRangeParameter (0-60)
Speedspeed, velocity, rateRangeParameter (0-100)
Countscount, max, bullets, amountRangeParameter (0-99, step:1)
Distanceoffset, range, position, fovRangeParameter
Colorscolor, tint (hex literals)ColorParameter
Flagsenabled, active, visibleBooleanParameter

Finds all *Config.ts files in the target path and parses:

  • Exported const objects: export const GameConfig = { ... }
  • Individual exports: export const PLAYER_HP = 100

When --deep is specified, also scans .ts files for:

  • Numeric assignments: this.speed = 5;
  • Tween durations: .to(0.5, {...})
  • setTimeout values: setTimeout(fn, 3000)

Exclusions: Loop indices, array indices, import statements.

{
"mode": "config",
"configCandidates": [
{
"key": "PlayerMaxHP",
"value": 100,
"type": "number",
"category": "Gameplay-Combat",
"source": "GameConfig.ts:17",
"primitive": "RangeParameter"
}
],
"totalCandidates": 60
}

See references/config-detection.md for the full detection algorithm.

By default, scans nodes under Canvas (and any sibling BG canvas). Use --canvas to target a specific root:

Terminal window
--canvas "Canvas/SomeView/SafeArea"
--canvas "Canvas/BattleUI"
--canvas "Canvas/SomeView,Canvas/EndCard" # comma-separated

Path matching: exact path · suffix match · wildcard Canvas/*/SafeArea.

Step 1: Detect mode from user intent or flags
Step 2: Acquire scene data (MCP batch or scene JSON parse)
Step 3: For each node, detect components via manage_component get_all
Step 4: Build component signature per node
Step 5: Match signature against NodePreset (shape templates)
Step 6: Emit scan report JSON (flat-primitive shape per node)
PriorityComponentNotes
P0Node, UITransformAlways present on UI nodes
P0UIOpacityCommon, emits opacity (no prefix)
P0WidgetEmits widget-prefixed primitives
P1Sprite, Label, Button, CameraCore visual/interaction → prefixed primitives
P1RichText, ProgressBar, Slider, ToggleExtended UI → prefixed primitives
P2Layout, MaskLayout/clipping
SKIPParticleSystem*, Skeleton*, VideoPlayer, WebView, EditBox, ScrollView, PageViewExcluded
{
"scanRoot": "Canvas/SomeView/SafeArea",
"nodes": [
{
"uuid": "...",
"name": "Btn_CTA",
"path": "Canvas/SomeView/EndCard/Btn_CTA",
"components": ["cc.Node", "cc.UITransform", "cc.Sprite", "cc.Label", "cc.Button", "cc.UIOpacity"],
"matchedPreset": "Button",
"primitiveShape": {
"spriteColor": "#FFFFFF",
"spriteFrame": "",
"labelString": "PLAY",
"labelColor": "#000000",
"labelFontSize": 48,
"buttonTransition": "SCALE",
"buttonZoomScale": 1.1,
"buttonNormalColor": "#4CAF50",
"buttonPressedColor": "#388E3C",
"opacity": 255
},
"suggestedCategory": "UILayer-EndCard"
}
],
"codeDetectedGroups": [
{
"name": "Battle UI",
"properties": ["battleRoot", "scopeOverlay", "releaseLabel"],
"sourceFile": "BattleUIController.ts",
"suggestedCategory": "UILayer-Battle"
}
],
"presetsMatched": 3,
"groupsDetected": 1
}

Each node entry becomes ONE top-level ObjectParameter in PlayableConfig whose body is the primitiveShape map. The suggestedCategory becomes the entry’s category. No wrapper classes, no nested ObjectParameter.

When scanning code alongside scene nodes, detect @property({ group: 'X' }) decorators to identify logical UI groupings:

@property({ type: Node, group: 'Battle UI' })
battleRoot: Node = null;
@property({ type: Label, group: 'Battle UI' })
releaseLabel: Label = null;

Each grouped property is still its own top-level ObjectParameter. The group name becomes a shared category suggestion (UILayer-{Group}) so the dashboard sidebar collapses them together. Grouped properties do NOT produce a wrapper composite class — they produce N separate flat entries with one shared category.

  • Batch-check components. Do NOT pre-filter by name.
  • Use manage_component get_all per node when MCP is connected.
  • Read actual scene values for primitive defaults.
  • Never skip UIOpacity or Widget detection.
  • Report nodes with no parameterizable components as “skipped”.
  • Each scanned node → ONE ObjectParameter entry, never a wrapper class instance.
  • Component-prefixed primitives on multi-component nodes (spriteColor, labelString, buttonTransition). Single-field components skip the prefix (opacity).
  • references/config-detection.md — Config file parser + magic-number detector
  • references/property-group-detection.md@property group detection algorithm
  • Parent skill references/scan-strategy.md — Batch Canvas scanning approach
  • Parent skill references/field-coverage.md — Component → prefixed-primitive tables
  • Parent skill references/mcp-assignment.md — MCP health checks and batching

For large Canvas trees (100+ nodes), use the batch scanning script:

Terminal window
node scripts/batch-scan.cjs --canvas "Canvas/SomeView" --output scan-report.json --verbose

Options:

  • --canvas <path> — Root node path to scan
  • --output <file> — Output JSON file (default: stdout)
  • --delay <ms> — Delay between MCP calls (default: 50ms)
  • --verbose — Print progress to stderr

The script handles rate limiting automatically to avoid overwhelming the MCP server.

  • --auto disables review gates on every mode.
  • Scene values become primitive defaults; placeholder values pollute the parameter list.
  • RichText is a separate component from Label in Cocos 3.8+ — do not conflate.
  • Nodes with only Node + UITransform and no other components are non-parameterizable.
  • Batch script requires MCP server running (http://127.0.0.1:3000/mcp).
  • NodePreset is a shape template, not a wrapper class. A “Button” preset means “this node has Sprite+Label+Button+UIOpacity components → emit these prefixed primitives”, not “wrap them in a ButtonParameter class”.