construct3-organize-events
Organize Construct 3 event sheet JSON into professional top-level groups with clear descriptions/comments while preserving original event order and game behavior. Use when Codex needs to clean up .c3p
SKILL.mdconstruct3-organize-events/SKILL.md
GitHubConstruct 3 Organize Events
Goal
Make Construct 3 event sheets easier to read in the editor by adding clean top-level groups and descriptions. Preserve behavior first; neatness is only useful if the project still runs the same.
Safe Refactor Rules
- Keep all variables and includes at the top of each event sheet.
- Preserve the relative order of executable events.
- Preserve existing
function-blockevents and place them in aFunctionsgroup if they are not already grouped. - Preserve every condition, action, child event,
Else, disabled flag,isOrBlock, wait order, and picked-object scope. - Do not extract action bodies into new functions unless the user explicitly asks for that and accepts behavior risk.
- Do not move a child event out of its parent.
- Do not split an
Elseblock away from the event it belongs to. - Use group
descriptionfields as comments. - Keep group names short and practical:
Setup,Input,Gameplay,Video And Scene Flow,Functions,Debug, etc.
Workflow
- Back up
eventSheetsbefore editing. - Inspect current event-sheet structure and existing groups/functions.
- Group top-level events only.
- Name groups based on event conditions, object names, and function names.
- Validate all JSON files.
- Count blocks/functions before and after; block and function counts should stay the same.
- Remind the user to reload/reopen Construct before saving.
Script
Run from the Construct 3 project root:
node C:\Users\Abhinav\.codex\skills\construct3-organize-events\scripts\organize_construct3_events.js --cwd .
Dry run:
node C:\Users\Abhinav\.codex\skills\construct3-organize-events\scripts\organize_construct3_events.js --cwd . --dry-run
The script:
- Reads
eventSheets/*.json - Leaves
*.uistate.jsonalone - Leaves variables/includes at the top
- Preserves existing groups
- Wraps ungrouped top-level blocks/functions/scripts into inferred groups
- Adds clear group descriptions
- Avoids extracting functions or rewriting event logic
Manual Grouping Guidance
Use these common group names:
Setup:on-start-of-layout, initial variables, pinning, source setup, initial object stateInput: keyboard, mouse, touch-start, control-mode eventsGameplay: main interactive events when no domain-specific name is obviousDrag And Drop:on-drag-start,on-drop, drag-drop activity logicMatching Activity: connector lines, pair checks, matching cards/textsTracing: checkpoints, touch dots, tracing phase/stateRecording Controls: microphone, recording, playback buttonsVideo And Scene Flow: video playback, pause, ended, scene transition, narration hooksProgress UI: loader/progress bar and loading text updatesScene Layer Routing: shared layer visibility and scene switching helpersFunctions: existing function blocksDebug: logs and temporary diagnostic events
Prefer project-specific group names when obvious, e.g. Butterfly Activity, Grapes Activity, Feather Activity.
Validation Commands
Parse all project JSON:
@'
const fs=require("fs"), path=require("path");
const files=["project.c3proj"];
for (const dir of ["eventSheets","layouts","families","objectTypes","timelines","flowcharts"]) {
if (!fs.existsSync(dir)) continue;
for (const f of fs.readdirSync(dir)) if (f.endsWith(".json")) files.push(path.join(dir,f));
}
for (const f of files) JSON.parse(fs.readFileSync(f,"utf8"));
console.log(`Parsed ${files.length} JSON files successfully.`);
'@ | node -
Count event structures:
@'
const fs=require("fs"), path=require("path");
for(const f of fs.readdirSync("eventSheets").filter(x=>x.endsWith(".json")&&!x.includes("uistate"))){
const d=JSON.parse(fs.readFileSync(path.join("eventSheets",f),"utf8"));
let blocks=0, funcs=0, vars=0, includes=0, groups=0;
function walk(e){ if(Array.isArray(e)) return e.forEach(walk); if(!e||typeof e!=="object") return;
if(e.eventType==="block") blocks++;
if(e.eventType==="function-block") funcs++;
if(e.eventType==="variable") vars++;
if(e.eventType==="include") includes++;
if(e.eventType==="group") groups++;
for(const v of Object.values(e)) walk(v);
}
walk(d.events||[]);
console.log(`${f}: blocks=${blocks}, funcs=${funcs}, vars=${vars}, includes=${includes}, groups=${groups}`);
}
'@ | node -