rendx-engine 0.2.0 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/main.cjs CHANGED
@@ -64,6 +64,7 @@ __export(main_exports, {
64
64
  Renderer: () => Renderer,
65
65
  RoundShape: () => RoundShape,
66
66
  Scene: () => Scene,
67
+ Scheduler: () => Scheduler,
67
68
  SectorShape: () => SectorShape,
68
69
  SectorTransform: () => SectorTransform,
69
70
  Shape: () => Shape,
@@ -476,7 +477,7 @@ getEmitter_fn = function() {
476
477
  };
477
478
 
478
479
  // src/core/graphics.ts
479
- var _nameMap, _classlist, _Graphics_instances, removeFromNameMap_fn, updateMat2d_fn, updateWorldMatrix_fn, updateEZ_fn;
480
+ var _nameMap, _classlist, _Graphics_instances, removeFromNameMap_fn, inheritState_fn, updateMat2d_fn, updateWorldMatrix_fn, updateEZ_fn;
480
481
  var Graphics = class extends EventTarget {
481
482
  constructor() {
482
483
  super(...arguments);
@@ -592,6 +593,7 @@ var Graphics = class extends EventTarget {
592
593
  this.children.push(child);
593
594
  if (__privateGet(this, _nameMap).has(child.name)) throw new Error(`The name "${child.name}" is already used.`);
594
595
  if (child.name) __privateGet(this, _nameMap).set(child.name, child);
596
+ __privateMethod(this, _Graphics_instances, inheritState_fn).call(this, child);
595
597
  this.setDirty(true);
596
598
  return this;
597
599
  }
@@ -600,6 +602,7 @@ var Graphics = class extends EventTarget {
600
602
  child.parent = this;
601
603
  this.children.unshift(child);
602
604
  __privateMethod(this, _Graphics_instances, removeFromNameMap_fn).call(this, child);
605
+ __privateMethod(this, _Graphics_instances, inheritState_fn).call(this, child);
603
606
  this.setDirty(true);
604
607
  return this;
605
608
  }
@@ -842,6 +845,22 @@ _Graphics_instances = new WeakSet();
842
845
  removeFromNameMap_fn = function(g) {
843
846
  if (__privateGet(this, _nameMap).has(g.name)) __privateGet(this, _nameMap).delete(g.name);
844
847
  };
848
+ /**
849
+ * 将父节点的可继承状态(visible / display / pointerEvents)传播给新增子节点。
850
+ * 模拟 DOM 中 CSS 继承属性的行为:
851
+ * - 父级 pointer-events: none → 子级默认继承 none,除非子级显式覆盖
852
+ * - 父级 visibility: hidden → 同上
853
+ * - 父级 display: none → 整棵子树不渲染
854
+ *
855
+ * 使用 bySelf=false 调用,尊重子节点的 autoX 标记:
856
+ * - autoX=true(默认)→ 接受父级值
857
+ * - autoX=false(子节点显式设置过)→ 保持自身值不变
858
+ */
859
+ inheritState_fn = function(child) {
860
+ if (!this.visible) child.setVisible(false, false);
861
+ if (!this.display) child.setDisplay(false, false);
862
+ if (!this.pointerEvents) child.setPointerEvents(false, false);
863
+ };
845
864
  updateMat2d_fn = function() {
846
865
  if (!this.needUpdate) return;
847
866
  import_gl_matrix.mat2d.identity(this.matrix);
@@ -1251,7 +1270,7 @@ var Group = class extends Graphics {
1251
1270
 
1252
1271
  // src/scene/node.ts
1253
1272
  var import_gl_matrix3 = require("gl-matrix");
1254
- var import_rendx_bounding15 = require("rendx-bounding");
1273
+ var import_rendx_bounding16 = require("rendx-bounding");
1255
1274
 
1256
1275
  // src/shapes/symbol.ts
1257
1276
  var import_rendx_bounding2 = require("rendx-bounding");
@@ -1648,6 +1667,8 @@ var ArcShape = class extends Shape {
1648
1667
  };
1649
1668
 
1650
1669
  // src/shapes/path.ts
1670
+ var import_rendx_bounding9 = require("rendx-bounding");
1671
+ var import_rendx_path9 = require("rendx-path");
1651
1672
  var PathShape = class extends Shape {
1652
1673
  constructor() {
1653
1674
  super(...arguments);
@@ -1656,11 +1677,19 @@ var PathShape = class extends Shape {
1656
1677
  from(d) {
1657
1678
  this.d = d;
1658
1679
  this.p = null;
1680
+ if (this.autoNeedUpdate) this.needUpdate = true;
1681
+ }
1682
+ box() {
1683
+ const result = (0, import_rendx_path9.pathBBox)(this.d);
1684
+ if (result) {
1685
+ this.boundingBox = import_rendx_bounding9.BoundingBox.fromPoints(result[0], result[1], result[2], result[3]);
1686
+ }
1687
+ return this.boundingBox;
1659
1688
  }
1660
1689
  };
1661
1690
 
1662
1691
  // src/shapes/text.ts
1663
- var import_rendx_bounding9 = require("rendx-bounding");
1692
+ var import_rendx_bounding10 = require("rendx-bounding");
1664
1693
  var _attrs;
1665
1694
  var _TextShape = class _TextShape extends Shape {
1666
1695
  constructor() {
@@ -1693,7 +1722,7 @@ var _TextShape = class _TextShape extends Shape {
1693
1722
  if (measureFn && this.text) {
1694
1723
  const bb = measureFn(this.text, __privateGet(this, _attrs));
1695
1724
  if (bb) {
1696
- this.boundingBox = import_rendx_bounding9.BoundingBox.fromRect(this.x, this.y - bb.height, bb.width, bb.height);
1725
+ this.boundingBox = import_rendx_bounding10.BoundingBox.fromRect(this.x, this.y - bb.height, bb.width, bb.height);
1697
1726
  return this.boundingBox;
1698
1727
  }
1699
1728
  }
@@ -1724,7 +1753,7 @@ _TextShape.defaultMeasure = null;
1724
1753
  var TextShape = _TextShape;
1725
1754
 
1726
1755
  // src/shapes/line.ts
1727
- var import_rendx_bounding10 = require("rendx-bounding");
1756
+ var import_rendx_bounding11 = require("rendx-bounding");
1728
1757
  var LineShape = class extends Shape {
1729
1758
  constructor() {
1730
1759
  super(...arguments);
@@ -1756,13 +1785,13 @@ var LineShape = class extends Shape {
1756
1785
  }
1757
1786
  box() {
1758
1787
  const { x1, y1, x2, y2 } = this;
1759
- this.boundingBox = import_rendx_bounding10.BoundingBox.fromPoints(x1, y1, x2, y2);
1788
+ this.boundingBox = import_rendx_bounding11.BoundingBox.fromPoints(x1, y1, x2, y2);
1760
1789
  return this.boundingBox;
1761
1790
  }
1762
1791
  };
1763
1792
 
1764
1793
  // src/shapes/rect.ts
1765
- var import_rendx_bounding11 = require("rendx-bounding");
1794
+ var import_rendx_bounding12 = require("rendx-bounding");
1766
1795
  var RectShape = class extends Shape {
1767
1796
  constructor() {
1768
1797
  super(...arguments);
@@ -1792,13 +1821,13 @@ var RectShape = class extends Shape {
1792
1821
  }
1793
1822
  box() {
1794
1823
  const { x, y, width, height } = this;
1795
- this.boundingBox = import_rendx_bounding11.BoundingBox.fromRect(x, y, width, height);
1824
+ this.boundingBox = import_rendx_bounding12.BoundingBox.fromRect(x, y, width, height);
1796
1825
  return this.boundingBox;
1797
1826
  }
1798
1827
  };
1799
1828
 
1800
1829
  // src/shapes/circle.ts
1801
- var import_rendx_bounding12 = require("rendx-bounding");
1830
+ var import_rendx_bounding13 = require("rendx-bounding");
1802
1831
  var CircleShape = class extends Shape {
1803
1832
  constructor() {
1804
1833
  super(...arguments);
@@ -1825,13 +1854,13 @@ var CircleShape = class extends Shape {
1825
1854
  }
1826
1855
  box() {
1827
1856
  const { cx, cy, r } = this;
1828
- this.boundingBox = import_rendx_bounding12.BoundingBox.fromPoints(cx - r, cy - r, cx + r, cy + r);
1857
+ this.boundingBox = import_rendx_bounding13.BoundingBox.fromPoints(cx - r, cy - r, cx + r, cy + r);
1829
1858
  return this.boundingBox;
1830
1859
  }
1831
1860
  };
1832
1861
 
1833
1862
  // src/shapes/image.ts
1834
- var import_rendx_bounding13 = require("rendx-bounding");
1863
+ var import_rendx_bounding14 = require("rendx-bounding");
1835
1864
  var ImageShape = class extends Shape {
1836
1865
  constructor() {
1837
1866
  super(...arguments);
@@ -1875,15 +1904,15 @@ var ImageShape = class extends Shape {
1875
1904
  }
1876
1905
  box() {
1877
1906
  const { x, y, width, height } = this;
1878
- this.boundingBox = import_rendx_bounding13.BoundingBox.fromRect(x, y, width, height);
1907
+ this.boundingBox = import_rendx_bounding14.BoundingBox.fromRect(x, y, width, height);
1879
1908
  return this.boundingBox;
1880
1909
  }
1881
1910
  };
1882
1911
 
1883
1912
  // src/shapes/rect-buffer.ts
1884
- var import_rendx_bounding14 = require("rendx-bounding");
1913
+ var import_rendx_bounding15 = require("rendx-bounding");
1885
1914
  var import_rendx_shape8 = require("rendx-shape");
1886
- var import_rendx_path9 = require("rendx-path");
1915
+ var import_rendx_path10 = require("rendx-path");
1887
1916
  var RectBufferShape = class extends Shape {
1888
1917
  constructor() {
1889
1918
  super(...arguments);
@@ -1900,7 +1929,7 @@ var RectBufferShape = class extends Shape {
1900
1929
  build() {
1901
1930
  if (!this.needUpdate) return;
1902
1931
  if (this.mode === "render") {
1903
- if (!this.creator) this.creator = new import_rendx_path9.Path();
1932
+ if (!this.creator) this.creator = new import_rendx_path10.Path();
1904
1933
  else this.creator.clear();
1905
1934
  const { buffer } = this;
1906
1935
  for (let i = 0; i < buffer.length; i += 4) {
@@ -1947,7 +1976,7 @@ var RectBufferShape = class extends Shape {
1947
1976
  x1 = Math.max(x1, x + width);
1948
1977
  y1 = Math.max(y1, y + height);
1949
1978
  }
1950
- this.boundingBox = import_rendx_bounding14.BoundingBox.fromPoints(x0, y0, x1, y1);
1979
+ this.boundingBox = import_rendx_bounding15.BoundingBox.fromPoints(x0, y0, x1, y1);
1951
1980
  return this.boundingBox;
1952
1981
  }
1953
1982
  };
@@ -2050,7 +2079,7 @@ var _Node = class _Node extends Graphics {
2050
2079
  if (wx > maxX) maxX = wx;
2051
2080
  if (wy < minY) minY = wy;
2052
2081
  if (wy > maxY) maxY = wy;
2053
- return import_rendx_bounding15.BoundingBox.fromPoints(minX, minY, maxX, maxY);
2082
+ return import_rendx_bounding16.BoundingBox.fromPoints(minX, minY, maxX, maxY);
2054
2083
  }
2055
2084
  /**
2056
2085
  * 命中检测:将屏幕坐标通过逆世界矩阵变换为本地坐标,然后检测是否命中
@@ -2560,6 +2589,48 @@ createListener_fn = function(type) {
2560
2589
  };
2561
2590
  };
2562
2591
 
2592
+ // src/app.ts
2593
+ var import_eventemitter32 = __toESM(require("eventemitter3"), 1);
2594
+
2595
+ // src/scheduler.ts
2596
+ var _pendingState, _microTaskQueued, _onFlush;
2597
+ var Scheduler = class {
2598
+ constructor(onFlush) {
2599
+ __privateAdd(this, _pendingState, /* @__PURE__ */ new Set());
2600
+ __privateAdd(this, _microTaskQueued, false);
2601
+ __privateAdd(this, _onFlush);
2602
+ __privateSet(this, _onFlush, onFlush);
2603
+ }
2604
+ /**
2605
+ * 标记 state key 变更,批量到微任务统一通知。
2606
+ * 同一轮微任务内多次调用同一 key 只通知一次。
2607
+ */
2608
+ markState(key) {
2609
+ __privateGet(this, _pendingState).add(key);
2610
+ if (!__privateGet(this, _microTaskQueued)) {
2611
+ __privateSet(this, _microTaskQueued, true);
2612
+ queueMicrotask(() => {
2613
+ __privateSet(this, _microTaskQueued, false);
2614
+ const keys = new Set(__privateGet(this, _pendingState));
2615
+ __privateGet(this, _pendingState).clear();
2616
+ __privateGet(this, _onFlush).call(this, keys);
2617
+ });
2618
+ }
2619
+ }
2620
+ /** 是否有待通知的 state 变更 */
2621
+ get hasPending() {
2622
+ return __privateGet(this, _pendingState).size > 0;
2623
+ }
2624
+ /** 清空待通知队列(用于 dispose) */
2625
+ clear() {
2626
+ __privateGet(this, _pendingState).clear();
2627
+ __privateSet(this, _microTaskQueued, false);
2628
+ }
2629
+ };
2630
+ _pendingState = new WeakMap();
2631
+ _microTaskQueued = new WeakMap();
2632
+ _onFlush = new WeakMap();
2633
+
2563
2634
  // src/serialization.ts
2564
2635
  var SHAPE_FROM_KEYS = {
2565
2636
  text: ["text", "x", "y"],
@@ -2721,21 +2792,39 @@ function deserialize(json, cfg) {
2721
2792
  }
2722
2793
 
2723
2794
  // src/app.ts
2724
- var _rafId, _mounted, _container, _eventLayer, _resizeObserver, _plugins, _App_instances, tick_fn;
2795
+ var _rafId, _renderDirty, _mounted, _container, _eventLayer, _resizeObserver, _plugins, _state, _stateMeta, _scheduler, _App_instances, resolveIndex_fn, nextAvailableIndex_fn, frame_fn;
2725
2796
  var _App = class _App {
2726
2797
  /**
2727
2798
  * @param cfg - 引擎配置(width/height/layers/autoResize 等)
2728
2799
  */
2729
2800
  constructor(cfg = {}) {
2730
2801
  __privateAdd(this, _App_instances);
2802
+ /**
2803
+ * 中心化事件总线 — 纯信号(不传数据)。
2804
+ * 插件通过 `app.bus.emit('eventName')` 发布信号,
2805
+ * 消费方通过 `app.bus.on('eventName', handler)` 订阅。
2806
+ */
2807
+ this.bus = new import_eventemitter32.default();
2731
2808
  __privateAdd(this, _rafId, null);
2809
+ __privateAdd(this, _renderDirty, false);
2732
2810
  __privateAdd(this, _mounted, false);
2733
2811
  __privateAdd(this, _container, null);
2734
2812
  __privateAdd(this, _eventLayer);
2735
2813
  __privateAdd(this, _resizeObserver, null);
2736
2814
  __privateAdd(this, _plugins, []);
2815
+ // ========================
2816
+ // State Management
2817
+ // ========================
2818
+ __privateAdd(this, _state, /* @__PURE__ */ new Map());
2819
+ __privateAdd(this, _stateMeta, /* @__PURE__ */ new Map());
2820
+ __privateAdd(this, _scheduler);
2737
2821
  this.cfg = cfg;
2738
2822
  this.scene = new Scene();
2823
+ __privateSet(this, _scheduler, new Scheduler((keys) => {
2824
+ for (const key of keys) {
2825
+ this.bus.emit(`state:${key}`);
2826
+ }
2827
+ }));
2739
2828
  __privateSet(this, _eventLayer, new Layer("__event__", 99999, this.cfg, true));
2740
2829
  this.scene.registerLayer(__privateGet(this, _eventLayer));
2741
2830
  this.scene.registerLayer(new Layer("default", 0, this.cfg));
@@ -2808,7 +2897,30 @@ var _App = class _App {
2808
2897
  return this.scene.getLayer(name);
2809
2898
  }
2810
2899
  /**
2811
- * 注册插件(同名插件不会重复注册)
2900
+ * 获取或创建图层(get-or-create 语义)。
2901
+ * 多个插件声明同名图层时,只会创建一次。
2902
+ *
2903
+ * zIndex 语义:
2904
+ * - 传入时代表全局层级意图(负数 = default 之下,正数 = default 之上)
2905
+ * - 若与已有层冲突,自动向上偏移到最近可用值
2906
+ * - 省略时自动分配(当前最高非事件层 + 1)
2907
+ *
2908
+ * @param name - 层名称
2909
+ * @param zIndex - 全局层级意图(可选)
2910
+ */
2911
+ acquireLayer(name, zIndex) {
2912
+ const existing = this.scene.getLayer(name);
2913
+ if (existing) return existing;
2914
+ const index = zIndex !== void 0 ? __privateMethod(this, _App_instances, resolveIndex_fn).call(this, zIndex) : __privateMethod(this, _App_instances, nextAvailableIndex_fn).call(this);
2915
+ return this.addLayer(name, index);
2916
+ }
2917
+ /**
2918
+ * 注册插件。流程:
2919
+ * 1. 去重检查(同名跳过)
2920
+ * 2. 注册 state 声明(key 冲突则抛错)
2921
+ * 3. 自动 acquireLayer(声明的图层)
2922
+ * 4. 调用 plugin.install(app)
2923
+ *
2812
2924
  * @param plugin - 实现 Plugin 接口的插件实例
2813
2925
  */
2814
2926
  use(plugin) {
@@ -2816,6 +2928,22 @@ var _App = class _App {
2816
2928
  console.warn(`Plugin "${plugin.name}" is already registered.`);
2817
2929
  return this;
2818
2930
  }
2931
+ if (plugin.state) {
2932
+ for (const decl of plugin.state) {
2933
+ if (__privateGet(this, _stateMeta).has(decl.key)) {
2934
+ const owner = __privateGet(this, _stateMeta).get(decl.key).owner;
2935
+ throw new Error(`State key "${decl.key}" already declared by plugin "${owner}". Plugin "${plugin.name}" cannot redeclare it.`);
2936
+ }
2937
+ __privateGet(this, _stateMeta).set(decl.key, { owner: plugin.name, description: decl.description });
2938
+ __privateGet(this, _state).set(decl.key, decl.initial);
2939
+ }
2940
+ }
2941
+ if (plugin.layers) {
2942
+ const sorted = [...plugin.layers].sort((a, b) => (a.zIndex ?? 0) - (b.zIndex ?? 0));
2943
+ for (const decl of sorted) {
2944
+ this.acquireLayer(decl.name, decl.zIndex);
2945
+ }
2946
+ }
2819
2947
  __privateGet(this, _plugins).push(plugin);
2820
2948
  plugin.install(this);
2821
2949
  return this;
@@ -2824,6 +2952,40 @@ var _App = class _App {
2824
2952
  getPlugin(name) {
2825
2953
  return __privateGet(this, _plugins).find((p) => p.name === name);
2826
2954
  }
2955
+ // ========================
2956
+ // Centralized State
2957
+ // ========================
2958
+ /**
2959
+ * 写入 state(同步写入 + 异步批量通知)。
2960
+ * key 必须先由某个插件在 `state[]` 中声明,否则抛错。
2961
+ * 写入后立即可通过 `getState()` 读到最新值,通知在微任务中批量发出。
2962
+ */
2963
+ setState(key, value) {
2964
+ if (!__privateGet(this, _stateMeta).has(key)) {
2965
+ throw new Error(`State key "${key}" is not declared by any plugin. Plugins must declare state keys in their "state" array.`);
2966
+ }
2967
+ __privateGet(this, _state).set(key, value);
2968
+ __privateGet(this, _scheduler).markState(key);
2969
+ }
2970
+ /**
2971
+ * 读取 state(同步读取,始终返回最新值)。
2972
+ * @returns 对应 key 的当前值,不存在则返回 undefined
2973
+ */
2974
+ getState(key) {
2975
+ return __privateGet(this, _state).get(key);
2976
+ }
2977
+ /**
2978
+ * 导出完整 state 快照(调试/devtools 用)。
2979
+ * 返回每个 key 的当前值、所属插件和描述信息。
2980
+ */
2981
+ dumpState() {
2982
+ const result = {};
2983
+ for (const [key, value] of __privateGet(this, _state)) {
2984
+ const meta = __privateGet(this, _stateMeta).get(key);
2985
+ result[key] = { value, owner: meta.owner, description: meta.description };
2986
+ }
2987
+ return result;
2988
+ }
2827
2989
  /** 同步渲染一帧。适用于静态内容,仅重绘脏层 */
2828
2990
  render() {
2829
2991
  for (const layer of this.scene.layers) {
@@ -2832,10 +2994,12 @@ var _App = class _App {
2832
2994
  }
2833
2995
  }
2834
2996
  }
2835
- /** 请求异步渲染循环(rAF),有动画时自动继续,无变化时停止 */
2997
+ /** 请求异步渲染帧(幂等,一帧只执行一次)。无变化时自动停止 rAF */
2836
2998
  requestRender() {
2837
- if (__privateGet(this, _rafId) !== null) return;
2838
- __privateSet(this, _rafId, requestAnimationFrame((t) => __privateMethod(this, _App_instances, tick_fn).call(this, t)));
2999
+ __privateSet(this, _renderDirty, true);
3000
+ if (__privateGet(this, _rafId) === null) {
3001
+ __privateSet(this, _rafId, requestAnimationFrame((t) => __privateMethod(this, _App_instances, frame_fn).call(this, t)));
3002
+ }
2839
3003
  }
2840
3004
  /**
2841
3005
  * 调整画布尺寸,同步更新所有层、容器和视口矩阵
@@ -2861,6 +3025,26 @@ var _App = class _App {
2861
3025
  plugin.resize?.(width, height);
2862
3026
  }
2863
3027
  }
3028
+ // ========================
3029
+ // Cursor
3030
+ // ========================
3031
+ /**
3032
+ * 设置容器的鼠标光标样式。
3033
+ * @param cursor - CSS cursor 值(如 'pointer'、'crosshair'、'grab')
3034
+ */
3035
+ setCursor(cursor) {
3036
+ if (__privateGet(this, _container)) {
3037
+ __privateGet(this, _container).style.cursor = cursor;
3038
+ }
3039
+ }
3040
+ /**
3041
+ * 重置鼠标光标为默认值。
3042
+ */
3043
+ resetCursor() {
3044
+ if (__privateGet(this, _container)) {
3045
+ __privateGet(this, _container).style.cursor = "";
3046
+ }
3047
+ }
2864
3048
  clear() {
2865
3049
  if (__privateGet(this, _rafId) !== null) {
2866
3050
  cancelAnimationFrame(__privateGet(this, _rafId));
@@ -2876,6 +3060,10 @@ var _App = class _App {
2876
3060
  plugin.dispose?.();
2877
3061
  }
2878
3062
  __privateSet(this, _plugins, []);
3063
+ this.bus.removeAllListeners();
3064
+ __privateGet(this, _state).clear();
3065
+ __privateGet(this, _stateMeta).clear();
3066
+ __privateGet(this, _scheduler).clear();
2879
3067
  if (__privateGet(this, _resizeObserver)) {
2880
3068
  __privateGet(this, _resizeObserver).disconnect();
2881
3069
  __privateSet(this, _resizeObserver, null);
@@ -2910,7 +3098,17 @@ var _App = class _App {
2910
3098
  }
2911
3099
  /** 序列化所有渲染层的场景图为 JSON,可用于保存/回放 */
2912
3100
  toJSON() {
2913
- return serialize(this.scene.layers, this.cfg.width ?? 800, this.cfg.height ?? 600);
3101
+ const json = serialize(this.scene.layers, this.cfg.width ?? 800, this.cfg.height ?? 600);
3102
+ const pluginsData = {};
3103
+ for (const plugin of __privateGet(this, _plugins)) {
3104
+ if (plugin.serialize) {
3105
+ pluginsData[plugin.name] = plugin.serialize();
3106
+ }
3107
+ }
3108
+ if (Object.keys(pluginsData).length > 0) {
3109
+ json.plugins = pluginsData;
3110
+ }
3111
+ return json;
2914
3112
  }
2915
3113
  /**
2916
3114
  * 从 JSON 快照创建新的 App 实例(静态工厂方法)
@@ -2949,17 +3147,49 @@ var _App = class _App {
2949
3147
  __privateGet(this, _container).insertBefore(layer.renderer.el, __privateGet(this, _eventLayer).renderer.el);
2950
3148
  }
2951
3149
  }
3150
+ if (json.plugins) {
3151
+ for (const plugin of __privateGet(this, _plugins)) {
3152
+ const data = json.plugins[plugin.name];
3153
+ if (data && plugin.deserialize) {
3154
+ plugin.deserialize(data);
3155
+ }
3156
+ }
3157
+ }
2952
3158
  }
2953
3159
  };
2954
3160
  _rafId = new WeakMap();
3161
+ _renderDirty = new WeakMap();
2955
3162
  _mounted = new WeakMap();
2956
3163
  _container = new WeakMap();
2957
3164
  _eventLayer = new WeakMap();
2958
3165
  _resizeObserver = new WeakMap();
2959
3166
  _plugins = new WeakMap();
3167
+ _state = new WeakMap();
3168
+ _stateMeta = new WeakMap();
3169
+ _scheduler = new WeakMap();
2960
3170
  _App_instances = new WeakSet();
2961
- tick_fn = function(time) {
2962
- __privateSet(this, _rafId, null);
3171
+ /**
3172
+ * 解析 zIndex:若已被占用则向上偏移到最近可用值。
3173
+ * 保证返回值不会与任何已有层的 layerIndex 冲突。
3174
+ */
3175
+ resolveIndex_fn = function(desired) {
3176
+ const used = new Set(this.scene.layers.map((l) => l.layerIndex));
3177
+ while (used.has(desired)) desired++;
3178
+ return desired;
3179
+ };
3180
+ /**
3181
+ * 自动分配:当前最高非事件层 index + 1。
3182
+ * 保证返回值始终 >= 1(default 层固定为 0)。
3183
+ */
3184
+ nextAvailableIndex_fn = function() {
3185
+ let max = 0;
3186
+ for (const l of this.scene.layers) {
3187
+ if (!l.isEventLayer && l.layerIndex > max) max = l.layerIndex;
3188
+ }
3189
+ return max + 1;
3190
+ };
3191
+ frame_fn = function(time) {
3192
+ __privateSet(this, _renderDirty, false);
2963
3193
  this.scene.tick(time);
2964
3194
  let anyDirty = false;
2965
3195
  for (const layer of this.scene.layers) {
@@ -2968,8 +3198,10 @@ tick_fn = function(time) {
2968
3198
  anyDirty = true;
2969
3199
  }
2970
3200
  }
2971
- if (anyDirty) {
2972
- this.requestRender();
3201
+ if (anyDirty || __privateGet(this, _renderDirty)) {
3202
+ __privateSet(this, _rafId, requestAnimationFrame((t) => __privateMethod(this, _App_instances, frame_fn).call(this, t)));
3203
+ } else {
3204
+ __privateSet(this, _rafId, null);
2973
3205
  }
2974
3206
  };
2975
3207
  var App = _App;
@@ -3001,6 +3233,7 @@ var App = _App;
3001
3233
  Renderer,
3002
3234
  RoundShape,
3003
3235
  Scene,
3236
+ Scheduler,
3004
3237
  SectorShape,
3005
3238
  SectorTransform,
3006
3239
  Shape,