CurioBlaze 🔥Instant hot-swap for Zen Engine game projects — no rebuild required. CurioBlaze watches your Features1. Asset Hot-Swap (
|
| Type | Description |
|---|---|
json |
Plain JSON files embedded under the json section of a bundle |
image / fontImage |
PNG/JPG converted to data:image/...;base64,... URIs inline |
spriteSheet / movieClip |
Sprite sheet JSON with texture reference resolved from spriteTexture |
spriteTexture |
Raw texture embedded as base64 |
spineAtlas |
.atlas text parsed and all page PNGs embedded as base64 |
spineSequence |
Spine JSON + atlas dependency list |
bitmapFont |
Raw .fnt text embedded as-is |
The source-to-target mapping is read from config/assetCollections.json on startup, indexed in memory, and looked up in O(1) per save event.
2. Config Hot-Swap (config/)
Changes to config files are automatically detected and processed based on their location:
Level Entity Configs — config/behaviors/, components/, prefabs/, levels/, states/
These files feed into the ECS (Entity-Component-System) level layout. Saving any file under these folders triggers a non-blocking child process:
node ./utilities/level-config-processor.js ./ ./config/levelConfig.json -r
This is the same command the process-levels gulp task runs. It resolves entity inheritance, deep-merges components, and writes the compiled output to:
dist/config/levels/desktop/levels.jsondist/config/levels/mobile/levels.json
Core Configs — config/core/
Files under config/core/ (e.g. gameConfig.json, paytableConfig.json) are bundled into large C_Config_*.json dictionaries. Changes to these files are patched in-place using the same fast worker-thread path as assets — the JSON key inside the bundle is updated directly without re-running any external script.
3. Non-Blocking Processing
All CPU-intensive work runs off the extension host thread so VS Code never freezes:
assets/andconfig/core/: processed in aworker_threadsWorker (hotSwapWorker.js). No UI blocking even for large base64 encodes.config/behaviors|components|...: processed viachild_process.exec. The child process runs independently; the extension host is free throughout.- A
ProcessingQueueserialises all jobs so dist files are never written concurrently. - 500 ms debounce prevents duplicate events from rapid OS-level saves.
4. Smart No-Op Detection
Before writing any file, the worker computes a SHA1 hash of the new content and compares it to the existing dist file. If nothing changed (e.g. Ctrl+S with no edits), the write is skipped entirely and no notification is shown. Completely silent.
5. Build Safety — Automatic Pause & Resume
When a full Gulp build runs, CurioBlaze pauses automatically to avoid interfering with the build's own dist writes:
- Lock file (primary):
gulpfile.jswrites.curioblaze-build-lockat build start and removes it at build end. CurioBlaze watches this for instant, zero-ambiguity detection. dist/folder deletion (fallback):gulp cleanemptiesdist/. CurioBlaze detects this and pauses.- VS Code Task API (secondary): catches builds started via the Run Task panel.
State is remembered: if you had hot-swap active before the build, it auto-resumes after. If you had it disabled, it stays disabled.
6. Backup & Rollback
Before overwriting any dist file, CurioBlaze creates a timestamped backup under .hotswap-backup/ in the same directory. The last 10 backups per file are kept.
Use the CurioBlaze: Rollback command to revert any dist file to its most recent backup.
7. Atomic Writes
Dist files are written to a .curioblaze.tmp temporary file first, then renamed atomically to the final path. The game's file watcher never sees a half-written file.
IntelliSense — Message Autocomplete & Config Validation
CurioBlaze provides rich IntelliSense for JSON config files across config/behaviors/, components/, prefabs/, and levels/.
Message Autocomplete
Type ${ inside any string value in a JSON config file to get autocomplete suggestions for every message constant in the codebase:
- Scans all TypeScript files under
src/(Game., Zen., Config.* namespaces) - Shows JSDoc descriptions explaining what each message does
- Supports hierarchical filtering — type
${Game.Transto narrow to transition messages - Also discovers bare string constants like
Config.Loading.Notifications.*andOrientationChanged:*
Behavior & Component Name Autocomplete
Inside "behaviors": [...] and "components": [...] arrays, CurioBlaze suggests all known entity names:
- Indexed from
config/behaviors/andconfig/components/directories - Shows entity type (e.g.
tweenOnMessage,sprite) and description
Validation (Diagnostics)
CurioBlaze highlights potential issues in your config files:
- ⚠️ Unknown message references —
${...}strings that don't match any known constant - ℹ️ Missing entity references — behavior/component names not found in config files
Go to Definition
Ctrl+Click (or F12) on any behavior or component name to jump directly to the JSON file where it's defined.
Index Refresh
The IntelliSense index auto-refreshes when source files change. Use CurioBlaze: Refresh Message Index from the command palette to force a rebuild.
Commands
| Command | Description |
|---|---|
CurioBlaze: Hot-Swap Current File |
Manually trigger a hot-swap for the file open in the editor |
CurioBlaze: Toggle Watcher |
Start or stop the file watcher |
CurioBlaze: Rollback |
Revert a dist file to its most recent backup |
CurioBlaze: Show Stats |
Show indexed source/target counts and watcher status |
CurioBlaze: Validate Dist Files |
Check all expected dist files exist and are valid JSON |
CurioBlaze: Open Affected Dist Files |
Open every dist bundle affected by the currently open source file |
CurioBlaze: Reload Config |
Re-parse assetCollections.json (after adding new assets) |
CurioBlaze: Refresh Message Index |
Re-scan TypeScript and config files to rebuild the IntelliSense index |
Settings
| Setting | Default | Description |
|---|---|---|
curioblaze.quietMode |
false |
When enabled, shows a compact toast with a "Details" link instead of full file-path logs |
How the current implementation works (end-to-end)
Save any file in the project
│
▼
fs.watch fallback fires (assets/ or config/ — always fires)
│
▼
scheduleProcessing() ── 500ms debounce ──▶ enqueueHotSwap()
│
├─ config/behaviors|components|prefabs|levels|states/*
│ │
│ ▼
│ ProcessingQueue job → runLevelConfigHotSwap()
│ │
│ ▼
│ child_process.exec:
│ node ./utilities/level-config-processor.js ./ ./config/levelConfig.json -r
│ │
│ ▼
│ Writes: dist/config/levels/desktop/levels.json
│ dist/config/levels/mobile/levels.json
│ │
│ ▼
│ Toast: 🔥 Level configs updated → ...
│
└─ assets/** or config/core/*
│
▼
AssetCollectionParser.getMappingForFile() → target bundle lookup
│
▼
ProcessingQueue job → runHotSwap()
│
▼
worker_threads Worker (hotSwapWorker.js):
• Read source file
• Patch target dist JSON in-place
• SHA1 compare — skip write if no content change
• Atomic write (temp file → rename)
│
▼
Toast: 🔥 filename → target.json (Xms)
Requirements
- Node.js installed and on
PATH(needed to runlevel-config-processor.jsin a child process) - The game project must have a
dist/folder already populated (run a fullgulp build-releasefirst) config/assetCollections.jsonmust exist at the workspace rootconfig/levelConfig.jsonmust exist for level config hot-swap
Quick Start
- Open the game project folder in VS Code as the workspace root.
- Press F5 in the CurioBlaze extension project to launch the Extension Development Host.
- In the Development Host, confirm the status bar shows
$(sync) CurioBlaze: Active. - Edit any file in
assets/orconfig/and save — the Output panel (CurioBlazechannel) will confirm what was updated.
Troubleshooting
| Symptom | Likely cause | Fix |
|---|---|---|
| Config changes not reflected | dist/ not populated |
Run a full build first |
| "Not in asset collections" warning | File not mapped in assetCollections.json |
Add an entry or use the Reload Config command |
| Level config update fails silently | level-config-processor.js missing |
Ensure utilities/level-config-processor.js exists in project root |
| Status bar shows "Build in progress…" | Build lock file stale | Check if a build is actually running; delete .curioblaze-build-lock manually if not |
| No logs in Output panel | Output channel not open | Open it: View → Output → select "CurioBlaze" |
Output Channel Logs
Open View → Output → CurioBlaze to see per-event logs including:
[fs.watch/config]or[fs.watch/assets]— source of the file event[dbg] isLevelConfig— whether the file was routed to the level pipeline[CurioBlaze][LevelCfg]— child process details (command, exit code, stdout/stderr)✅ Updated: filename (Xms)— confirmed write⏭ No content change— SHA1 matched, write skipped silently
See CHANGELOG.md for a full version history.