v0.12.0
Tilemap Editor v2
A complete tilemap editing system, replacing the previous Tiled-import-only workflow. You can now create, paint, and edit tilemaps entirely within the editor.
Tile Palette & Painting Tools
A new Tile Palette panel provides 5 tools:
- Brush: paint individual tiles or stamp multi-tile regions
- Rectangle Fill: drag to fill a rectangular area
- Bucket Fill: flood-fill connected tiles (BFS, 10k tile limit)
- Eraser: remove tiles, also available via right-click with any tool
- Picker: sample a tile from the map to use as the current brush
Select stamp regions by dragging in the palette. Flip tiles horizontally/vertically with toolbar buttons.
Infinite Maps & Chunk Rendering
Tilemaps now support infinite maps (sparse chunk storage). The renderer uses 16×16 chunks with dirty flags for incremental vertex rebuilds — only dirty or animated chunks are rebuilt each frame. Off-screen chunks are culled at the chunk level.
Layer Management
Add, remove, rename, and reorder tilemap layers. Each layer renders independently with its own tile data and visibility toggle.
Native Tilemap Creation
Create tilemaps directly from the Hierarchy context menu without needing an external Tiled editor. Infinite map mode is available in the creation dialog.
Rich Text
The Text component now supports rich text with inline formatting tags:
<color=#FF0000>red text</color>— colored text spans<b>bold</b>,<i>italic</i>— font style- Inline images via
<img src="asset-path"/>tags - Enable with the
richTexttoggle on the Text component
The parser is stack-based with per-run font measurement and automatic line breaking.
Text Stroke & Shadow
New properties on the Text component:
- Stroke:
strokeColorandstrokeWidthfor text outlines - Shadow:
shadowColor,shadowBlur,shadowOffsetX,shadowOffsetYfor drop shadows
Stroke rendering draws all strokes before all fills to prevent visual overlap artifacts.
Data Binding
A new DataBinding component connects component properties to expressions that update automatically each frame.
- Template strings:
"Score: {Score.value}"— reference any resource or component property - Math expressions:
"{Health.current} / {Health.max} * 100"— recursive descent parser, noeval(WeChat compatible) - Auto type coercion: string ↔ number conversions handled automatically
- Editor UI: custom property editor with dropdown for selecting target properties from the entity’s components
- LRU expression cache: compiled expressions are cached for performance
Data binding evaluation is automatically skipped in editor edit mode to prevent scene corruption.
Unified Assets Architecture
A new 4-layer asset system replaces the legacy AssetServer:
- Assets: user-facing API with typed
loadTexture(),loadSpine(),loadPrefab()etc. - Catalog: address resolution, atlas frame queries, label-based asset groups, dependency graph
- AssetLoader: pluggable typed loaders (texture, spine, material, font, audio, tilemap, timeline, animclip, prefab)
- Backend: platform-specific data fetching (HTTP, embedded, WeChat)
Build pipeline generates a manifest catalog for addressable asset loading. Existing AssetServer consumers have been migrated.
CollectionView & Selectable
CollectionView
A virtual scrolling system replacing ListView, with pluggable layout providers:
- LinearLayout: vertical or horizontal list
- GridLayout: fixed-column grid with row/column gap
- FanLayout: radial fan arrangement with configurable angle range
Uses an adapter pattern with item pooling for efficient rendering of large datasets.
Selectable
New Selectable component (C++ builtin) with group-based mutual exclusion — selecting one entity in a group automatically deselects others. Select/deselect events are dispatched via UIEvents.
Spine API Expansion
- Animation queries: query current animation state, track entries, and mix info at runtime
- Event callbacks: listen for Spine animation events (start, end, complete, custom events)
- Constraint APIs: read and modify IK, transform, and path constraints
- Editor visibility: SpineAnimation respects entity visibility toggling in the editor
Physics API Expansion
- Shape cast: cast shapes through the physics world with configurable distance
- AABB overlap: query all bodies overlapping an axis-aligned bounding box
- Mass data: read and modify body mass, center of mass, and inertia at runtime
- Joint state: query joint reaction forces, anchor positions, and current limits
Self-Describing Component Metadata
Component metadata (asset fields, color fields, entity references, animatable properties) is now auto-generated from C++ annotations via EHT codegen:
defineBuiltin()reads defaults and field metadata from generatedCOMPONENT_META- Editor
defineSchema()infers Inspector property types from SDK metadata - Animation target enums generated from
ES_ANIMATABLEC++ annotations - Ptr field layouts generated from C++ struct definitions for zero-copy WASM reads
Declarative System Scheduling
Run Conditions
Systems can declare execution pre-conditions via runIf:
import { playModeOnly } from 'esengine';
app.addSystemToSchedule(Schedule.Update, mySystem, { runIf: playModeOnly,});Skipped systems have zero overhead — the condition is checked before parameter resolution.
System & Plugin Name Constants
Compile-safe constants for all system ordering and plugin dependency references:
import { SystemLabel, PluginName } from 'esengine';
app.addSystemToSchedule(Schedule.PostUpdate, mySystem, { runAfter: [SystemLabel.UILayout],});Disabled Tag
New Disabled tag component for excluding entities from processing:
import { Disabled } from 'esengine';
world.insert(entity, Disabled, {});const active = Query(Transform).without(Disabled);Plugin Dependency Sorting
app.addPlugins() performs topological sorting on dependency declarations, allowing plugins in any order.
Engine Internals
- Unified engine init via
corePlugin, centralizing ResourceManager and static API lifecycle - Extracted
App.runFrame_()to unify tick/mainLoop scheduling logic - O(1) entity name index updates via reverse
entityToName_map - Refactored
AssetRefCounterwith genericRefMap(175 → 99 lines) - Shared
ensureUIRenderer()utility inuiHelpers - Editor schemas moved into plugin
register()for lazy initialization - Split
RenderFrame.cppinto mask and submit files for maintainability - Deduplicated
BatchVertexandpackColorinto shared renderer header - Generated
PTR_LAYOUTSfrom C++ struct definitions, replacing manual offset tables - Atomic state swap for scene operations prevents load/unload race conditions
- WASM error throttling prevents console flood from repeated C++ exceptions
Bug Fixes
- Fixed entity name not available in spawn callbacks
- Fixed scene sleep/wake ignoring ShapeRenderer and ParticleEmitter
- Fixed input event listeners leaking on app destruction
- Fixed emscripten config not auto-generated on first compile
- Fixed emsdk cache file check after install
- Fixed editor visibility toggle for Image/UIRenderer components
- Fixed text overflow Visible mode clipping to container instead of expanding
- Fixed rich text stroke rendering order (strokes before fills)
- Fixed Play Mode script injection order (scripts loaded before scene deserialization)
- Fixed component schema preservation when script recompilation fails
- Fixed scene not synced before entering Play Mode
- Fixed circular schema imports causing editor startup failure