@fmsim/machine 2.0.0-beta.62 → 2.0.0-beta.63

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/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@fmsim/machine",
3
3
  "description": "Layout View를 구성하는 설비(machine)들과 유닛을 구현한 모듈입니다.",
4
4
  "author": "heartyoh",
5
- "version": "2.0.0-beta.62",
5
+ "version": "2.0.0-beta.63",
6
6
  "main": "dist/index.js",
7
7
  "module": "dist/index.js",
8
8
  "things-scene": true,
@@ -55,5 +55,5 @@
55
55
  "prettier --write"
56
56
  ]
57
57
  },
58
- "gitHead": "f6f17ee84a9875c460df1383baf8d717b502ac43"
58
+ "gitHead": "eaeeb4d9db1886ca2aa6a191bc120184ea446006"
59
59
  }
@@ -79,17 +79,26 @@ class MCSRealObject3D extends RealObjectGroup {
79
79
  // width, height 절대값 (음수 값은 양수로 취급).
80
80
  // `resizable:false` 컴포넌트(예: Scanner)는 state.width/height 가 없고
81
81
  // bounds 만 있을 수 있으므로 bounds 를 fallback 으로 사용.
82
+ //
83
+ // `??` only catches null/undefined — a property-panel input that produced
84
+ // NaN would slip through and corrupt every downstream Math.* call. Use a
85
+ // finite check so NaN falls through to bounds → 10 like missing values do.
82
86
  protected get absSize(): { w: number; h: number } {
83
87
  const state = (this.component.state || {}) as any
84
88
  const bounds = (this.component.bounds || {}) as any
85
- const width = state.width ?? bounds.width ?? 10
86
- const height = state.height ?? bounds.height ?? 10
89
+ const width = pickFinite(state.width, bounds.width, 10)
90
+ const height = pickFinite(state.height, bounds.height, 10)
87
91
  return { w: Math.abs(width), h: Math.abs(height) }
88
92
  }
89
93
 
90
94
  get effectiveDepth(): number {
91
95
  const { depth } = this.component.state
92
- if (depth) return depth
96
+ // Truthy `if (depth)` already rejected NaN/0/undefined, but be explicit
97
+ // so the intent (and the resolution chain) reads cleanly: only an
98
+ // explicit positive finite number wins; everything else → defaults.
99
+ if (typeof depth === 'number' && Number.isFinite(depth) && depth > 0) {
100
+ return depth
101
+ }
93
102
  if (this._config.defaultDepth) return this._config.defaultDepth
94
103
  const { w, h } = this.absSize
95
104
  return Math.min(w, h) * this._config.depthRatio
@@ -463,6 +472,20 @@ class MCSRealObject3D extends RealObjectGroup {
463
472
  }
464
473
  }
465
474
 
475
+ // ── 헬퍼 ────────────────────────────────────────────────
476
+
477
+ /**
478
+ * Returns the first argument that is a finite number. NaN slips past `??`
479
+ * (which only catches null/undefined), so without this a property-panel
480
+ * input producing NaN would corrupt absSize and cascade through Math.*.
481
+ */
482
+ function pickFinite(...candidates: unknown[]): number {
483
+ for (const c of candidates) {
484
+ if (typeof c === 'number' && Number.isFinite(c)) return c
485
+ }
486
+ return 0
487
+ }
488
+
466
489
  // ── 팩토리 등록 헬퍼 ─────────────────────────────────────
467
490
 
468
491
  function register(type: string, overrides: Partial<MCS3DConfig> = {}) {
@@ -70,6 +70,35 @@ export default class MCSMachine extends MCSStatusMixin(ContainerAbstract) {
70
70
  return LEGEND_MACHINE
71
71
  }
72
72
 
73
+ /**
74
+ * In 2D, ignore `state.alpha`; preserve everything else.
75
+ *
76
+ * things-scene's base prerender (component-drawing.ts:31, 44) does:
77
+ * const fade = (alpha || 1) - this._delta.fade
78
+ * if (fade) context.globalAlpha = fade
79
+ *
80
+ * It *overwrites* `globalAlpha` (not multiplies), so the inherited
81
+ * parent alpha is also lost — that's a base-layer quirk we match the
82
+ * recovery for. Then at line 48 it applies editMode+hidden dimming
83
+ * with a *= 0.5.
84
+ *
85
+ * Our recovery:
86
+ * 1. Capture the inherited `globalAlpha` *before* super runs.
87
+ * 2. Let super do its work (transforms / shadow / dim flags).
88
+ * 3. Restore globalAlpha to inherited × editMode-hidden dim factor —
89
+ * i.e., what super would have produced if our state.alpha were 1.
90
+ *
91
+ * 3D path is unaffected: 3D factories read `state.alpha` directly via
92
+ * their `updateAlpha()` implementations and continue to honor it (with
93
+ * per-config opacity fallback).
94
+ */
95
+ prerender(ctx: any) {
96
+ const inherited = ctx.globalAlpha
97
+ super.prerender(ctx)
98
+ const dim = this.app.isEditMode && this.hidden ? 0.5 : 1
99
+ ctx.globalAlpha = inherited * dim
100
+ }
101
+
73
102
  render(ctx) {
74
103
  var { round = 0, lineWidth } = this.state
75
104
  var { left, top, width, height } = this.bounds
package/src/mcs-unit.ts CHANGED
@@ -49,6 +49,17 @@ export default class MCSUnit extends MCSStatusMixin(ParentObjectMixin(ContainerA
49
49
  return LEGEND_UNIT
50
50
  }
51
51
 
52
+ /**
53
+ * In 2D, ignore `state.alpha`; preserve inherited alpha + editMode-hidden dim.
54
+ * See MCSMachine.prerender for the full rationale.
55
+ */
56
+ prerender(ctx: any) {
57
+ const inherited = ctx.globalAlpha
58
+ super.prerender(ctx)
59
+ const dim = this.app.isEditMode && this.hidden ? 0.5 : 1
60
+ ctx.globalAlpha = inherited * dim
61
+ }
62
+
52
63
  contains(x, y) {
53
64
  var { left, top, width, height, lineWidth = 0 } = this.state
54
65
  var extend = lineWidth / 2