@things-factory/figure-ui 10.1.75 → 10.1.76
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/client/figure-assistant.ts +3 -3
- package/client/graphql/{v3-store.ts → store.ts} +6 -6
- package/client/modeller/{v3-ai-proposal.ts → ai-proposal.ts} +8 -8
- package/client/modeller/{v3-align.ts → align.ts} +14 -14
- package/client/modeller/{v3-canvas.ts → canvas.ts} +13 -13
- package/client/modeller/{v3-clips.ts → clips.ts} +5 -5
- package/client/modeller/{v3-controls.ts → controls.ts} +2 -2
- package/client/modeller/{v3-editor.ts → editor.ts} +117 -117
- package/client/modeller/{figure-v3-capability.ts → figure-capability-panel.ts} +7 -7
- package/client/modeller/{figure-v3-clips.ts → figure-clips.ts} +10 -10
- package/client/modeller/{figure-v3-controls.ts → figure-controls.ts} +9 -9
- package/client/modeller/{v3-figure-facts.ts → figure-facts.ts} +11 -11
- package/client/modeller/{figure-v3-first-save.ts → figure-first-save.ts} +3 -3
- package/client/modeller/figure-history-panel.ts +1 -1
- package/client/modeller/{figure-v3-links.ts → figure-links.ts} +35 -35
- package/client/modeller/{figure-v3-material.ts → figure-material-panel.ts} +20 -20
- package/client/modeller/{figure-v3-parts.ts → figure-parts.ts} +15 -15
- package/client/modeller/{figure-v3-preview.ts → figure-preview.ts} +14 -14
- package/client/modeller/{figure-v3-properties.ts → figure-properties.ts} +25 -25
- package/client/modeller/{figure-v3-recipe-catalog.ts → figure-recipe-catalog.ts} +10 -10
- package/client/modeller/{figure-v3-verdict.ts → figure-verdict.ts} +24 -24
- package/client/modeller/gate-findings.ts +2 -2
- package/client/modeller/{v3-gizmo.ts → gizmo.ts} +11 -11
- package/client/modeller/{v3-joint-drag.ts → joint-drag.ts} +11 -11
- package/client/modeller/{v3-joint-fan.ts → joint-fan.ts} +13 -13
- package/client/modeller/{v3-links.ts → links.ts} +59 -59
- package/client/modeller/{v3-live.ts → live.ts} +9 -9
- package/client/modeller/{v3-maturity.ts → maturity.ts} +65 -65
- package/client/modeller/modeller-route.ts +1 -1
- package/client/modeller/{v3-occupancy.ts → occupancy.ts} +6 -6
- package/client/modeller/{v3-palette.ts → palette.ts} +3 -3
- package/client/modeller/{v3-preview-model.ts → preview-model.ts} +8 -8
- package/client/modeller/{v3-product-session.ts → product-session.ts} +25 -25
- package/client/modeller/{v3-recipe-source.ts → recipe-source.ts} +2 -2
- package/client/modeller/{v3-recipes.ts → recipes.ts} +9 -9
- package/client/modeller/{v3-renderer.ts → renderer.ts} +16 -16
- package/client/modeller/{v3-stage-model.ts → stage-model.ts} +15 -15
- package/client/modeller/{v3-thumbnail.ts → thumbnail.ts} +8 -8
- package/client/pages/figure-list-page.ts +4 -4
- package/client/pages/{figure-v3-modeller-page.ts → figure-modeller-page.ts} +37 -37
- package/client/route.ts +1 -5
- package/dist-client/figure-assistant.js +3 -3
- package/dist-client/figure-assistant.js.map +1 -1
- package/dist-client/graphql/store.d.ts +3 -0
- package/dist-client/graphql/store.js +39 -0
- package/dist-client/graphql/store.js.map +1 -0
- package/dist-client/modeller/ai-proposal.d.ts +51 -0
- package/dist-client/modeller/ai-proposal.js +64 -0
- package/dist-client/modeller/ai-proposal.js.map +1 -0
- package/dist-client/modeller/align.d.ts +30 -0
- package/dist-client/modeller/align.js +75 -0
- package/dist-client/modeller/align.js.map +1 -0
- package/dist-client/modeller/canvas.d.ts +72 -0
- package/dist-client/modeller/canvas.js +379 -0
- package/dist-client/modeller/canvas.js.map +1 -0
- package/dist-client/modeller/clips.d.ts +39 -0
- package/dist-client/modeller/clips.js +58 -0
- package/dist-client/modeller/clips.js.map +1 -0
- package/dist-client/modeller/controls.d.ts +28 -0
- package/dist-client/modeller/controls.js +28 -0
- package/dist-client/modeller/controls.js.map +1 -0
- package/dist-client/modeller/editor.d.ts +203 -0
- package/dist-client/modeller/editor.js +1526 -0
- package/dist-client/modeller/editor.js.map +1 -0
- package/dist-client/modeller/fields.d.ts +45 -0
- package/dist-client/modeller/fields.js +83 -0
- package/dist-client/modeller/fields.js.map +1 -0
- package/dist-client/modeller/figure-capability-panel.d.ts +22 -0
- package/dist-client/modeller/figure-capability-panel.js +141 -0
- package/dist-client/modeller/figure-capability-panel.js.map +1 -0
- package/dist-client/modeller/figure-clips.d.ts +31 -0
- package/dist-client/modeller/figure-clips.js +268 -0
- package/dist-client/modeller/figure-clips.js.map +1 -0
- package/dist-client/modeller/figure-controls.d.ts +36 -0
- package/dist-client/modeller/figure-controls.js +226 -0
- package/dist-client/modeller/figure-controls.js.map +1 -0
- package/dist-client/modeller/figure-facts.d.ts +35 -0
- package/dist-client/modeller/figure-facts.js +55 -0
- package/dist-client/modeller/figure-facts.js.map +1 -0
- package/dist-client/modeller/figure-first-save.d.ts +20 -0
- package/dist-client/modeller/figure-first-save.js +118 -0
- package/dist-client/modeller/figure-first-save.js.map +1 -0
- package/dist-client/modeller/figure-history-panel.d.ts +1 -1
- package/dist-client/modeller/figure-history-panel.js.map +1 -1
- package/dist-client/modeller/figure-links.d.ts +77 -0
- package/dist-client/modeller/figure-links.js +649 -0
- package/dist-client/modeller/figure-links.js.map +1 -0
- package/dist-client/modeller/figure-material-panel.d.ts +39 -0
- package/dist-client/modeller/figure-material-panel.js +323 -0
- package/dist-client/modeller/figure-material-panel.js.map +1 -0
- package/dist-client/modeller/figure-parts.d.ts +69 -0
- package/dist-client/modeller/figure-parts.js +559 -0
- package/dist-client/modeller/figure-parts.js.map +1 -0
- package/dist-client/modeller/figure-preview.d.ts +34 -0
- package/dist-client/modeller/figure-preview.js +346 -0
- package/dist-client/modeller/figure-preview.js.map +1 -0
- package/dist-client/modeller/figure-properties.d.ts +45 -0
- package/dist-client/modeller/figure-properties.js +239 -0
- package/dist-client/modeller/figure-properties.js.map +1 -0
- package/dist-client/modeller/figure-recipe-catalog.d.ts +38 -0
- package/dist-client/modeller/figure-recipe-catalog.js +399 -0
- package/dist-client/modeller/figure-recipe-catalog.js.map +1 -0
- package/dist-client/modeller/figure-verdict.d.ts +64 -0
- package/dist-client/modeller/figure-verdict.js +787 -0
- package/dist-client/modeller/figure-verdict.js.map +1 -0
- package/dist-client/modeller/first-save.d.ts +17 -0
- package/dist-client/modeller/first-save.js +26 -0
- package/dist-client/modeller/first-save.js.map +1 -0
- package/dist-client/modeller/gate-findings.d.ts +2 -2
- package/dist-client/modeller/gate-findings.js +2 -2
- package/dist-client/modeller/gate-findings.js.map +1 -1
- package/dist-client/modeller/gizmo.d.ts +72 -0
- package/dist-client/modeller/gizmo.js +111 -0
- package/dist-client/modeller/gizmo.js.map +1 -0
- package/dist-client/modeller/help.d.ts +18 -0
- package/dist-client/modeller/help.js +37 -0
- package/dist-client/modeller/help.js.map +1 -0
- package/dist-client/modeller/joint-drag.d.ts +19 -0
- package/dist-client/modeller/joint-drag.js +97 -0
- package/dist-client/modeller/joint-drag.js.map +1 -0
- package/dist-client/modeller/joint-fan.d.ts +9 -0
- package/dist-client/modeller/joint-fan.js +276 -0
- package/dist-client/modeller/joint-fan.js.map +1 -0
- package/dist-client/modeller/keys.d.ts +22 -0
- package/dist-client/modeller/keys.js +26 -0
- package/dist-client/modeller/keys.js.map +1 -0
- package/dist-client/modeller/links.d.ts +267 -0
- package/dist-client/modeller/links.js +480 -0
- package/dist-client/modeller/links.js.map +1 -0
- package/dist-client/modeller/live.d.ts +37 -0
- package/dist-client/modeller/live.js +68 -0
- package/dist-client/modeller/live.js.map +1 -0
- package/dist-client/modeller/maturity.d.ts +120 -0
- package/dist-client/modeller/maturity.js +313 -0
- package/dist-client/modeller/maturity.js.map +1 -0
- package/dist-client/modeller/modeller-route.d.ts +1 -1
- package/dist-client/modeller/modeller-route.js +1 -1
- package/dist-client/modeller/modeller-route.js.map +1 -1
- package/dist-client/modeller/occupancy.d.ts +18 -0
- package/dist-client/modeller/occupancy.js +24 -0
- package/dist-client/modeller/occupancy.js.map +1 -0
- package/dist-client/modeller/palette.d.ts +7 -0
- package/dist-client/modeller/palette.js +46 -0
- package/dist-client/modeller/palette.js.map +1 -0
- package/dist-client/modeller/preview-model.d.ts +47 -0
- package/dist-client/modeller/preview-model.js +68 -0
- package/dist-client/modeller/preview-model.js.map +1 -0
- package/dist-client/modeller/product-session.d.ts +510 -0
- package/dist-client/modeller/product-session.js +157 -0
- package/dist-client/modeller/product-session.js.map +1 -0
- package/dist-client/modeller/recipe-source.d.ts +8 -0
- package/dist-client/modeller/recipe-source.js +14 -0
- package/dist-client/modeller/recipe-source.js.map +1 -0
- package/dist-client/modeller/recipes.d.ts +37 -0
- package/dist-client/modeller/recipes.js +103 -0
- package/dist-client/modeller/recipes.js.map +1 -0
- package/dist-client/modeller/refusals.d.ts +68 -0
- package/dist-client/modeller/refusals.js +142 -0
- package/dist-client/modeller/refusals.js.map +1 -0
- package/dist-client/modeller/renderer.d.ts +40 -0
- package/dist-client/modeller/renderer.js +73 -0
- package/dist-client/modeller/renderer.js.map +1 -0
- package/dist-client/modeller/stage-model.d.ts +39 -0
- package/dist-client/modeller/stage-model.js +147 -0
- package/dist-client/modeller/stage-model.js.map +1 -0
- package/dist-client/modeller/thumbnail.d.ts +3 -0
- package/dist-client/modeller/thumbnail.js +75 -0
- package/dist-client/modeller/thumbnail.js.map +1 -0
- package/dist-client/pages/figure-list-page.d.ts +1 -1
- package/dist-client/pages/figure-list-page.js +4 -4
- package/dist-client/pages/figure-list-page.js.map +1 -1
- package/dist-client/pages/figure-modeller-page.d.ts +102 -0
- package/dist-client/pages/figure-modeller-page.js +548 -0
- package/dist-client/pages/figure-modeller-page.js.map +1 -0
- package/dist-client/route.d.ts +1 -1
- package/dist-client/route.js +1 -5
- package/dist-client/route.js.map +1 -1
- package/dist-client/tsconfig.tsbuildinfo +1 -1
- package/docs/product-cutover.md +25 -0
- package/package.json +5 -5
- package/test/{v3-ai-proposal.test.ts → ai-proposal.test.ts} +6 -6
- package/test/{v3-align.test.ts → align.test.ts} +8 -8
- package/test/browser/modeller-page.js +30 -30
- package/test/browser/modeller.check.mjs +14 -14
- package/test/browser/serve.mjs +1 -1
- package/test/browser/thumbnail-page.js +6 -6
- package/test/{v3-clips.test.ts → clips.test.ts} +18 -18
- package/test/{v3-controls.test.ts → controls.test.ts} +15 -15
- package/test/{v3-fields.test.ts → fields.test.ts} +13 -13
- package/test/figure-assistant-surface.test.ts +3 -3
- package/test/{v3-first-save.test.ts → first-save.test.ts} +10 -10
- package/test/fixtures/joint-column.json +2 -2
- package/test/fixtures/joint-roller.json +2 -2
- package/test/fixtures/robot-arm-6dof.json +2 -2
- package/test/{v3-gizmo.test.ts → gizmo.test.ts} +33 -33
- package/test/{v3-joint-drag.test.ts → joint-drag.test.ts} +17 -17
- package/test/{v3-joint-fan.test.ts → joint-fan.test.ts} +18 -18
- package/test/joints.ts +6 -6
- package/test/{v3-keys.test.ts → keys.test.ts} +2 -2
- package/test/{v3-layout.test.ts → layout.test.ts} +8 -8
- package/test/{v3-links.test.ts → links.test.ts} +201 -201
- package/test/{v3-live.test.ts → live.test.ts} +18 -18
- package/test/{v3-material.test.ts → material.test.ts} +12 -12
- package/test/{v3-maturity.test.ts → maturity.test.ts} +74 -74
- package/test/modeller-route.test.ts +5 -6
- package/test/{v3-palette-icons.test.ts → palette-icons.test.ts} +1 -1
- package/test/{v3-parts-wiring.test.ts → parts-wiring.test.ts} +5 -5
- package/test/{v3-preview.test.ts → preview.test.ts} +12 -12
- package/test/{v3-product-session.test.ts → product-session.test.ts} +17 -17
- package/test/{v3-product-write.test.ts → product-write.test.ts} +20 -20
- package/test/{v3-properties.test.ts → properties.test.ts} +24 -24
- package/test/{v3-recipes.test.ts → recipes.test.ts} +9 -9
- package/test/{v3-refusals.test.ts → refusals.test.ts} +43 -43
- package/test/{v3-release-panel.test.ts → release-panel.test.ts} +21 -21
- package/test/renderer.test.ts +24 -0
- package/test/resolve-ts-siblings.mjs +1 -1
- package/test/{v3-scene-canvas.test.ts → scene-canvas.test.ts} +6 -6
- package/test/{v3-stage-model.test.ts → stage-model.test.ts} +5 -5
- package/test/{v3-theme.test.ts → theme.test.ts} +4 -4
- package/test/{v3-thumbnail.test.ts → thumbnail.test.ts} +4 -4
- package/test/{v3-verdict.test.ts → verdict.test.ts} +17 -17
- package/test/{v3-view.test.ts → view.test.ts} +2 -2
- package/things-factory.config.js +2 -3
- package/translations/en.json +2 -2
- package/translations/ja.json +2 -2
- package/translations/ko.json +2 -2
- package/translations/ms.json +2 -2
- package/translations/zh.json +2 -2
- package/docs/v3-product-cutover.md +0 -25
- package/test/v3-renderer.test.ts +0 -24
- /package/client/modeller/{v3-fields.ts → fields.ts} +0 -0
- /package/client/modeller/{v3-first-save.ts → first-save.ts} +0 -0
- /package/client/modeller/{v3-help.ts → help.ts} +0 -0
- /package/client/modeller/{v3-keys.ts → keys.ts} +0 -0
- /package/client/modeller/{v3-refusals.ts → refusals.ts} +0 -0
|
@@ -51,7 +51,7 @@ function tsSibling(specifier, parentURL, stripExtension) {
|
|
|
51
51
|
* ── 패키지 이름 하나만 예외다: `@hatiolab/things-scene` (2026-09-24) ─────────────────────────
|
|
52
52
|
* 이 패키지의 client 는 브라우저 코드이고, things-scene 은 판이 둘이다 — 브라우저용 `things-scene.mjs` 와
|
|
53
53
|
* 서버 전송용 `things-scene-transfer.mjs`. Node 는 `exports` 의 `node` 조건으로 전송 판을 고르는데, 그 판에는
|
|
54
|
-
* figure 가 없다(`
|
|
54
|
+
* figure 가 없다(`buildFigureGeometry` · `registerFigure` …). 모델러 소스를 Node 에서 시험하면 **브라우저가
|
|
55
55
|
* 받을 판**을 봐야 맞다. 그래서 이 이름만 브라우저 판으로 되짚는다. 다른 패키지 이름은 그대로 둔다.
|
|
56
56
|
*/
|
|
57
57
|
const SCENE_BROWSER_BUNDLE = (() => {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/*
|
|
2
2
|
* **편집 캔버스는 things-scene 편집 모드 위에 선다** (사용자 2026-09-24).
|
|
3
3
|
*
|
|
4
|
-
* 부품마다 `figure-
|
|
4
|
+
* 부품마다 `figure-part` 컴포넌트로 판에 세우면 고르기 · 주황 테두리 · 기즈모와 스냅 · 박스 선택 · 카메라(감속 ·
|
|
5
5
|
* 커서 쪽 확대 · 더블클릭 맞추기 · 시점 1~6) · 스튜디오 환경 · 좌표 바탕 · 조명과 그림자가 씬에서 온다. 여기서는 그
|
|
6
6
|
* 배선과, 몸체 ↔ 컴포넌트의 대응이 왕복하는지를 잰다.
|
|
7
7
|
*/
|
|
@@ -10,11 +10,11 @@ import assert from 'node:assert/strict'
|
|
|
10
10
|
import { readFileSync } from 'node:fs'
|
|
11
11
|
import { fileURLToPath } from 'node:url'
|
|
12
12
|
|
|
13
|
-
import { changedKeys, componentOf, gizmoResultOf } from '../client/modeller/
|
|
14
|
-
import type {
|
|
13
|
+
import { changedKeys, componentOf, gizmoResultOf } from '../client/modeller/stage-model.ts'
|
|
14
|
+
import type { FigureRenderPart } from '../client/modeller/renderer.ts'
|
|
15
15
|
|
|
16
16
|
const read = (path: string) => readFileSync(fileURLToPath(new URL(path, import.meta.url)), 'utf8')
|
|
17
|
-
const canvas = read('../client/modeller/
|
|
17
|
+
const canvas = read('../client/modeller/canvas.ts')
|
|
18
18
|
const board = { width: 2000, height: 2000 }
|
|
19
19
|
|
|
20
20
|
const turned = (deg: number) => {
|
|
@@ -25,7 +25,7 @@ const turned = (deg: number) => {
|
|
|
25
25
|
[-Math.sin(a), 0, Math.cos(a)]
|
|
26
26
|
]
|
|
27
27
|
}
|
|
28
|
-
const box = (t: number[], r = turned(0)):
|
|
28
|
+
const box = (t: number[], r = turned(0)): FigureRenderPart => ({
|
|
29
29
|
id: 'block',
|
|
30
30
|
shape: { provider: 'box', dimensions: { width: 200, height: 100, depth: 60 } },
|
|
31
31
|
pose: { r, t },
|
|
@@ -43,7 +43,7 @@ test('things-scene 의 판을 편집 모드로 세우고, 보기 설정은 판
|
|
|
43
43
|
|
|
44
44
|
test('몸체는 자기 상자로 서고, 씬의 낱말(width·depth·height · left·top·zPos · 회전)로 적힌다', () => {
|
|
45
45
|
const state = componentOf(box([100, 50, -30]), { 'palette.primary': '#123456' }, board)!
|
|
46
|
-
assert.equal(state.type, 'figure-
|
|
46
|
+
assert.equal(state.type, 'figure-part')
|
|
47
47
|
assert.equal(state.name, 'block')
|
|
48
48
|
assert.deepEqual([state.width, state.depth, state.height], [200, 100, 60])
|
|
49
49
|
assert.equal(state.left, 100 + 1000 - 100)
|
|
@@ -6,14 +6,14 @@
|
|
|
6
6
|
import { test } from 'node:test'
|
|
7
7
|
import assert from 'node:assert/strict'
|
|
8
8
|
|
|
9
|
-
import {
|
|
9
|
+
import { addFigureBox, compileFigureAsset, createFigureAsset } from '@hatiolab/figure-model'
|
|
10
10
|
|
|
11
|
-
import {
|
|
12
|
-
import { boardFor } from '../client/modeller/
|
|
11
|
+
import { drawableFigureParts } from '../client/modeller/renderer.ts'
|
|
12
|
+
import { boardFor } from '../client/modeller/stage-model.ts'
|
|
13
13
|
|
|
14
14
|
const partsOf = (height: number) =>
|
|
15
|
-
|
|
16
|
-
|
|
15
|
+
drawableFigureParts(
|
|
16
|
+
compileFigureAsset(addFigureBox(createFigureAsset('Probe'), { id: 'post', size: { x: 100, y: height, z: 100 }, position: { x: 0, y: height / 2, z: 0 } }))
|
|
17
17
|
.evaluate().geometry
|
|
18
18
|
)
|
|
19
19
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/*
|
|
2
2
|
* **모델러는 테마를 따른다** (2026-09-24).
|
|
3
3
|
*
|
|
4
|
-
*
|
|
4
|
+
* 캔버스와 편집기는 색을 박아 두었다. 어두운 테마에서 가운데만 밝은 판이 떴고, 경계선과 눌린 단추 · 오류 칸도
|
|
5
5
|
* 밝은 색 그대로였다. 색은 셸의 토큰에서 온다(UX 결정 — 바탕은 surface-container, 눌림은 secondary-container,
|
|
6
6
|
* 오류는 error-container).
|
|
7
7
|
*/
|
|
@@ -11,8 +11,8 @@ import { readFileSync } from 'node:fs'
|
|
|
11
11
|
import { fileURLToPath } from 'node:url'
|
|
12
12
|
|
|
13
13
|
const read = (path: string) => readFileSync(fileURLToPath(new URL(path, import.meta.url)), 'utf8')
|
|
14
|
-
const canvas = read('../client/modeller/
|
|
15
|
-
const editor = read('../client/modeller/
|
|
14
|
+
const canvas = read('../client/modeller/canvas.ts')
|
|
15
|
+
const editor = read('../client/modeller/editor.ts')
|
|
16
16
|
|
|
17
17
|
/** Hex colours that are not a `var(--token, #fallback)` fallback. */
|
|
18
18
|
const fixed = (text: string) =>
|
|
@@ -21,7 +21,7 @@ const fixed = (text: string) =>
|
|
|
21
21
|
.match(/#[0-9a-fA-F]{6}\b|#[0-9a-fA-F]{3}\b(?![\w-])/g) ?? []
|
|
22
22
|
|
|
23
23
|
test('편집기에 박힌 색이 없다 — 토큰의 대체값만 남는다', () => {
|
|
24
|
-
assert.deepEqual(fixed(editor), [], '
|
|
24
|
+
assert.deepEqual(fixed(editor), [], 'editor.ts')
|
|
25
25
|
})
|
|
26
26
|
|
|
27
27
|
test('캔버스 바탕은 작업대 회색 — 판의 하늘색이라 환경 탭에서 바꾼다', () => {
|
|
@@ -13,17 +13,17 @@ import { fileURLToPath } from 'node:url'
|
|
|
13
13
|
const read = (path: string) => readFileSync(fileURLToPath(new URL(path, import.meta.url)), 'utf8')
|
|
14
14
|
|
|
15
15
|
test('the save takes the card picture from a view-only canvas, through the scene’s 3D snapshot', () => {
|
|
16
|
-
const shooter = read('../client/modeller/
|
|
16
|
+
const shooter = read('../client/modeller/thumbnail.ts')
|
|
17
17
|
assert.ok(shooter.includes('shooter.viewOnly = true'))
|
|
18
18
|
assert.ok(shooter.includes('return shooter.snapshot ? await shooter.snapshot(WIDTH, HEIGHT) : undefined'))
|
|
19
19
|
assert.ok(!shooter.includes('thumbnail?.()'), 'no call to a method the canvas does not have')
|
|
20
20
|
|
|
21
|
-
const canvas = read('../client/modeller/
|
|
21
|
+
const canvas = read('../client/modeller/canvas.ts')
|
|
22
22
|
assert.ok(canvas.includes('async snapshot(width = 480, height = 360)'))
|
|
23
23
|
assert.ok(canvas.includes("await layer.snapshot3d(width, height, 'image/webp', 0.85)"), 'the 3D view, not the 2D sheet')
|
|
24
24
|
const watch = canvas.slice(canvas.indexOf(' private watchScene()'), canvas.indexOf(' private showSelected()'))
|
|
25
25
|
assert.ok(watch.includes('|| this.viewOnly) return'), 'a view-only canvas tells the editor nothing')
|
|
26
26
|
|
|
27
|
-
const editor = read('../client/modeller/
|
|
28
|
-
assert.ok(editor.includes('const thumbnail = await
|
|
27
|
+
const editor = read('../client/modeller/editor.ts')
|
|
28
|
+
assert.ok(editor.includes('const thumbnail = await captureFigureThumbnail('), 'the save asks for it')
|
|
29
29
|
})
|
|
@@ -12,32 +12,32 @@ import assert from 'node:assert/strict'
|
|
|
12
12
|
import { readFileSync } from 'node:fs'
|
|
13
13
|
import { fileURLToPath } from 'node:url'
|
|
14
14
|
|
|
15
|
-
import {
|
|
15
|
+
import { addFigureBox, createFigureAsset, figureCostOf } from '@hatiolab/figure-model'
|
|
16
16
|
|
|
17
17
|
import { capacityFrom, SCENE_BUDGET } from '../client/modeller/scene-budget.ts'
|
|
18
18
|
|
|
19
19
|
const read = (path: string) => readFileSync(fileURLToPath(new URL(path, import.meta.url)), 'utf8')
|
|
20
|
-
const verdict = read('../client/modeller/figure-
|
|
21
|
-
const page = read('../client/pages/figure-
|
|
20
|
+
const verdict = read('../client/modeller/figure-verdict.ts')
|
|
21
|
+
const page = read('../client/pages/figure-modeller-page.ts')
|
|
22
22
|
const graphql = read('../client/graphql/index.ts')
|
|
23
23
|
|
|
24
|
-
test('개수는 목록 카드와 같은 셈이다 —
|
|
25
|
-
let asset =
|
|
26
|
-
asset =
|
|
27
|
-
asset =
|
|
28
|
-
const cost =
|
|
24
|
+
test('개수는 목록 카드와 같은 셈이다 — 원가를 같은 capacityFrom 에 넣는다', () => {
|
|
25
|
+
let asset = createFigureAsset('Probe')
|
|
26
|
+
asset = addFigureBox(asset, { id: 'a', size: { x: 100, y: 100, z: 100 }, position: { x: 0, y: 50, z: 0 } })
|
|
27
|
+
asset = addFigureBox(asset, { id: 'b', size: { x: 100, y: 100, z: 100 }, position: { x: 200, y: 50, z: 0 } })
|
|
28
|
+
const cost = figureCostOf(asset)
|
|
29
29
|
|
|
30
30
|
assert.equal(cost.groups, 2, '전제: 그려지는 부품 둘이 묶음 둘')
|
|
31
31
|
assert.equal(capacityFrom(cost.groups, cost.triangles)?.instances, Math.floor(SCENE_BUDGET.groupsOnScreen / 2))
|
|
32
|
-
const maturity = read('../client/modeller/
|
|
32
|
+
const maturity = read('../client/modeller/maturity.ts')
|
|
33
33
|
assert.ok(/capacityFrom\(cost\.groups, cost\.triangles\)/.test(maturity), '판정 탭이 카드와 같은 함수로 센다')
|
|
34
|
-
assert.ok(/report = asset \?
|
|
34
|
+
assert.ok(/report = asset \? figureReportOf\(asset\) : undefined/.test(verdict), '탭은 그 셈을 부르고 보여 줄 뿐이다')
|
|
35
35
|
assert.ok(/instances: report\?\.capacity\.instances/.test(verdict), '탭 이름표의 개수도 같은 셈에서 온다')
|
|
36
36
|
})
|
|
37
37
|
|
|
38
38
|
test('판정은 발행 패널과 같은 서버 문에서 온다 — 화면이 따로 판정하지 않는다', () => {
|
|
39
39
|
assert.ok(verdict.includes('inspectFigureDraft(source, this.figureId)'), '편집 중인 원본을 보낸다')
|
|
40
|
-
assert.ok(!/
|
|
40
|
+
assert.ok(!/inspectFigureAsset/.test(verdict), '화면이 제 판정을 가지면 발행 패널과 다른 말을 한다')
|
|
41
41
|
|
|
42
42
|
const fields = (name: string) => {
|
|
43
43
|
const start = graphql.indexOf(`${name}(`, graphql.indexOf(`query ${name[0].toUpperCase()}${name.slice(1)}`))
|
|
@@ -55,21 +55,21 @@ test('판정 탭은 발행 패널과 같은 두 판정에 「부품에 맞추기
|
|
|
55
55
|
const panel = read('../client/modeller/figure-history-panel.ts')
|
|
56
56
|
const codes = (text: string) => [...text.matchAll(/'(part-outside-occupancy|occupancy-undeclared)'/g)].map(m => m[1]).sort()
|
|
57
57
|
assert.deepEqual(codes(verdict), codes(panel.slice(panel.indexOf('private offersFit'))))
|
|
58
|
-
assert.ok(/<figure-
|
|
58
|
+
assert.ok(/<figure-verdict[\s\S]*?@fit-base-to-parts=\$\{this\.fitToParts\}/.test(page), '누르면 공간 선언으로 이어진다')
|
|
59
59
|
})
|
|
60
60
|
|
|
61
61
|
test('판정과 이력은 편집기의 탭에 서고, 감추되 떼지 않는다', () => {
|
|
62
|
-
const editor = read('../client/modeller/
|
|
63
|
-
assert.ok(/<figure-
|
|
64
|
-
assert.ok(/<figure-
|
|
65
|
-
assert.ok(/<figure-
|
|
62
|
+
const editor = read('../client/modeller/editor.ts')
|
|
63
|
+
assert.ok(/<figure-verdict[\s\S]*?\.source=\$\{this\.draftSource\(\)\}/.test(page), '편집 중인 원본을 넘긴다')
|
|
64
|
+
assert.ok(/<figure-verdict[\s\S]*?\.figureType=/.test(page), '타입을 바꾸면 다시 판정한다')
|
|
65
|
+
assert.ok(/<figure-verdict\s+slot="verdict"/.test(page) && /<figure-history-panel\s+slot="history"/.test(page))
|
|
66
66
|
assert.ok(editor.includes(`<div panel flush ?off=\${tab !== 'verdict'}><slot name="verdict"></slot></div>`), '고르지 않은 탭은 감춘다 — 판정은 마지막 답을 지킨다')
|
|
67
67
|
assert.ok(/@capacity-changed=/.test(page) && page.includes('.instances=${this.instances}'), '개수를 편집기에 넘긴다')
|
|
68
68
|
assert.ok(editor.includes("this.renderTab('verdict', 'insights', i18next.t('figure.label.maturity'), this.instances)"), '개수가 탭 이름표에 남는다')
|
|
69
69
|
})
|
|
70
70
|
|
|
71
71
|
test('판정 탭의 말은 다섯 말 모두에 있다 — 없으면 키가 그대로 찍힌다', () => {
|
|
72
|
-
const maturity = read('../client/modeller/
|
|
72
|
+
const maturity = read('../client/modeller/maturity.ts')
|
|
73
73
|
const keys = [...(verdict + maturity).matchAll(/'(figure\.[a-z.-]*[a-z])'/g)].map(m => m[1])
|
|
74
74
|
assert.ok(keys.includes('figure.text.verdict-asking'), '전제: 삼항 안의 키도 센다')
|
|
75
75
|
for (const lang of ['ko', 'en', 'ja', 'zh', 'ms']) {
|
|
@@ -10,9 +10,9 @@ import { fileURLToPath } from 'node:url'
|
|
|
10
10
|
const read = (path: string) => readFileSync(fileURLToPath(new URL(path, import.meta.url)), 'utf8')
|
|
11
11
|
|
|
12
12
|
test('환경 탭 — 설정은 판의 상태 이름이고, 도형이 아니라 브라우저에 둔다', () => {
|
|
13
|
-
const editor = read('../client/modeller/
|
|
13
|
+
const editor = read('../client/modeller/editor.ts')
|
|
14
14
|
assert.ok(editor.includes('<figure-settings .view=${this.view} @update-view=${(e: CustomEvent) => this.setView(e.detail.view)}></figure-settings>'))
|
|
15
|
-
assert.ok(editor.includes("localStorage.setItem('figure-
|
|
15
|
+
assert.ok(editor.includes("localStorage.setItem('figure-view'"))
|
|
16
16
|
assert.doesNotMatch(editor.slice(editor.indexOf('private setView'), editor.indexOf('private setView') + 400), /session/, '설정은 세션(도형)에 닿지 않는다')
|
|
17
17
|
const view = read('../client/modeller/figure-view.ts')
|
|
18
18
|
assert.ok(view.includes("'studio',") && view.includes("'rainy'"), '환경 여덟')
|
package/things-factory.config.js
CHANGED
|
@@ -5,9 +5,8 @@ export default {
|
|
|
5
5
|
route,
|
|
6
6
|
routes: [
|
|
7
7
|
{ tagname: 'figure-list-page', page: 'figure-list' },
|
|
8
|
-
/*
|
|
9
|
-
{ tagname: 'figure-
|
|
10
|
-
{ tagname: 'figure-v3-modeller-page', page: 'figure-v3-modeller' }
|
|
8
|
+
/* The shell builds the DOM from this table. */
|
|
9
|
+
{ tagname: 'figure-modeller-page', page: 'figure-modeller' }
|
|
11
10
|
],
|
|
12
11
|
bootstrap
|
|
13
12
|
}
|
package/translations/en.json
CHANGED
|
@@ -311,7 +311,7 @@
|
|
|
311
311
|
"figure.text.bound-by-triangles": "triangles reach the limit first ({per} per instance, {budget} per drawing).",
|
|
312
312
|
"figure.text.budget-measured-on": "Measured on {gpu}, {on}. A figure standing still costs nothing — only what is on screen and redrawn counts.",
|
|
313
313
|
"figure.text.budget-not-measured-yet": "this target has not been measured yet.",
|
|
314
|
-
"figure.text.budgets-not-in
|
|
314
|
+
"figure.text.budgets-not-in": "off-palette surfaces are not in the format, so they are not shown. the part-count limit shows once a detail level is set.",
|
|
315
315
|
"figure.text.trend-chart-title": "drawing cost by instance count",
|
|
316
316
|
"figure.text.trend-chart-lead": "flat lines stay the same as instances grow. instances of the same size share them.",
|
|
317
317
|
"figure.text.trend-at-count": "at {n}",
|
|
@@ -377,7 +377,7 @@
|
|
|
377
377
|
"figure.text.joint-value-beyond-limits": "outside the joint limits.",
|
|
378
378
|
"figure.text.limit-comes-from-level": "the detail level sets this limit.",
|
|
379
379
|
"figure.text.maturity-blocked-no-binding": "state display is not measured yet.",
|
|
380
|
-
"figure.text.maturity-blocked-no-detail-level": "the
|
|
380
|
+
"figure.text.maturity-blocked-no-detail-level": "the format has no detail level. the budgets and placement scale above take its place.",
|
|
381
381
|
"figure.text.maturity-blocked-no-parts": "nothing to measure — there are no parts.",
|
|
382
382
|
"figure.text.maturity-consistency-because": "checks texture use, recommended segment counts and the number of materials.",
|
|
383
383
|
"figure.text.maturity-consistency-clean": "no issues",
|
package/translations/ja.json
CHANGED
|
@@ -311,7 +311,7 @@
|
|
|
311
311
|
"figure.text.bound-by-triangles": "三角形が先に上限に達します (1 個あたり {per}、図面あたり {budget})。",
|
|
312
312
|
"figure.text.budget-measured-on": "{gpu} で {on} に測定した値です。静止している図形は負荷になりません — 画面に見えて再描画されるものだけを数えます。",
|
|
313
313
|
"figure.text.budget-not-measured-yet": "this target has not been measured yet.",
|
|
314
|
-
"figure.text.budgets-not-in
|
|
314
|
+
"figure.text.budgets-not-in": "パレット外の表面は 形式にない項目のため表示しません。部品数の上限は詳細度を決めると表示されます。",
|
|
315
315
|
"figure.text.trend-chart-title": "インスタンス数による描画コスト",
|
|
316
316
|
"figure.text.trend-chart-lead": "平らな線はインスタンスが増えても変わらない値です。同じサイズのインスタンスが共有します。",
|
|
317
317
|
"figure.text.trend-at-count": "{n}個のとき",
|
|
@@ -377,7 +377,7 @@
|
|
|
377
377
|
"figure.text.joint-value-beyond-limits": "関節の可動範囲外です。",
|
|
378
378
|
"figure.text.limit-comes-from-level": "the detail level sets this limit.",
|
|
379
379
|
"figure.text.maturity-blocked-no-binding": "状態表現はまだ測定していません。",
|
|
380
|
-
"figure.text.maturity-blocked-no-detail-level": "
|
|
380
|
+
"figure.text.maturity-blocked-no-detail-level": "形式には詳細等級がありません。上の上限と配置規模で判断します。",
|
|
381
381
|
"figure.text.maturity-blocked-no-parts": "nothing to measure — there are no parts.",
|
|
382
382
|
"figure.text.maturity-consistency-because": "テクスチャの使用、推奨分割数の遵守、材質の種類数を確認します。",
|
|
383
383
|
"figure.text.maturity-consistency-clean": "no issues",
|
package/translations/ko.json
CHANGED
|
@@ -311,7 +311,7 @@
|
|
|
311
311
|
"figure.text.bound-by-triangles": "삼각형이 먼저 한도에 도달합니다 (1개당 {per}, 도면당 {budget}).",
|
|
312
312
|
"figure.text.budget-measured-on": "{gpu} 에서 {on} 에 잰 값입니다. 가만히 서 있는 도형은 값을 치르지 않습니다 — 화면에 보이고 다시 그려지는 것만 셉니다.",
|
|
313
313
|
"figure.text.budget-not-measured-yet": "아직 실측 전 목표치입니다.",
|
|
314
|
-
"figure.text.budgets-not-in
|
|
314
|
+
"figure.text.budgets-not-in": "팔레트 외 표면 한도는 형식에 없는 항목이라 표시하지 않습니다. 부품 수 한도는 디테일 등급을 정하면 보입니다.",
|
|
315
315
|
"figure.text.trend-chart-title": "인스턴스 수에 따른 그리는 비용",
|
|
316
316
|
"figure.text.trend-chart-lead": "평평한 선은 인스턴스가 늘어도 그대로인 값입니다. 같은 크기의 인스턴스가 공유합니다.",
|
|
317
317
|
"figure.text.trend-at-count": "{n}개일 때",
|
|
@@ -377,7 +377,7 @@
|
|
|
377
377
|
"figure.text.joint-value-beyond-limits": "관절의 가동 범위 밖입니다.",
|
|
378
378
|
"figure.text.limit-comes-from-level": "이 한도는 디테일 등급이 정합니다.",
|
|
379
379
|
"figure.text.maturity-blocked-no-binding": "상태 표현은 아직 측정하지 않습니다.",
|
|
380
|
-
"figure.text.maturity-blocked-no-detail-level": "
|
|
380
|
+
"figure.text.maturity-blocked-no-detail-level": "형식에는 디테일 등급이 없습니다. 위의 한도와 배치 규모로 판단합니다.",
|
|
381
381
|
"figure.text.maturity-blocked-no-parts": "부품이 없어 측정할 것이 없습니다.",
|
|
382
382
|
"figure.text.maturity-consistency-because": "텍스처 사용 여부, 권장 분할 수 준수, 재질 종류 수를 확인합니다.",
|
|
383
383
|
"figure.text.maturity-consistency-clean": "문제 없음",
|
package/translations/ms.json
CHANGED
|
@@ -311,7 +311,7 @@
|
|
|
311
311
|
"figure.text.bound-by-triangles": "segi tiga mencapai had dahulu ({per} setiap satu, {budget} setiap lukisan).",
|
|
312
312
|
"figure.text.budget-measured-on": "Diukur pada {gpu}, {on}. Figura yang diam tidak menelan kos — hanya yang kelihatan dan dilukis semula dikira.",
|
|
313
313
|
"figure.text.budget-not-measured-yet": "this target has not been measured yet.",
|
|
314
|
-
"figure.text.budgets-not-in
|
|
314
|
+
"figure.text.budgets-not-in": "permukaan luar palet tiada dalam format ini, jadi tidak dipaparkan. had bilangan bahagian dipaparkan apabila tahap perincian ditetapkan.",
|
|
315
315
|
"figure.text.trend-chart-title": "kos lukisan mengikut bilangan instans",
|
|
316
316
|
"figure.text.trend-chart-lead": "garis mendatar kekal sama apabila instans bertambah. instans yang sama saiz berkongsinya.",
|
|
317
317
|
"figure.text.trend-at-count": "pada {n}",
|
|
@@ -377,7 +377,7 @@
|
|
|
377
377
|
"figure.text.joint-value-beyond-limits": "di luar had sendi.",
|
|
378
378
|
"figure.text.limit-comes-from-level": "the detail level sets this limit.",
|
|
379
379
|
"figure.text.maturity-blocked-no-binding": "paparan keadaan belum diukur.",
|
|
380
|
-
"figure.text.maturity-blocked-no-detail-level": "format
|
|
380
|
+
"figure.text.maturity-blocked-no-detail-level": "format tiada tahap perincian. had dan skala penempatan di atas menggantikannya.",
|
|
381
381
|
"figure.text.maturity-blocked-no-parts": "nothing to measure — there are no parts.",
|
|
382
382
|
"figure.text.maturity-consistency-because": "menyemak penggunaan tekstur, bilangan segmen yang disyorkan dan bilangan bahan.",
|
|
383
383
|
"figure.text.maturity-consistency-clean": "no issues",
|
package/translations/zh.json
CHANGED
|
@@ -311,7 +311,7 @@
|
|
|
311
311
|
"figure.text.bound-by-triangles": "三角形先达到上限 (每个 {per},每个图面 {budget})。",
|
|
312
312
|
"figure.text.budget-measured-on": "于 {on} 在 {gpu} 上实测。静止的图形不产生开销 — 只计算屏幕上被重绘的部分。",
|
|
313
313
|
"figure.text.budget-not-measured-yet": "this target has not been measured yet.",
|
|
314
|
-
"figure.text.budgets-not-in
|
|
314
|
+
"figure.text.budgets-not-in": "调色板外表面不属于 格式,因此不显示。设置细节等级后会显示部件数限额。",
|
|
315
315
|
"figure.text.trend-chart-title": "按实例数的绘制成本",
|
|
316
316
|
"figure.text.trend-chart-lead": "平线表示实例增加时保持不变的值,同尺寸的实例共享这些值。",
|
|
317
317
|
"figure.text.trend-at-count": "{n} 个时",
|
|
@@ -377,7 +377,7 @@
|
|
|
377
377
|
"figure.text.joint-value-beyond-limits": "超出关节的活动范围。",
|
|
378
378
|
"figure.text.limit-comes-from-level": "the detail level sets this limit.",
|
|
379
379
|
"figure.text.maturity-blocked-no-binding": "状态表现尚未测量。",
|
|
380
|
-
"figure.text.maturity-blocked-no-detail-level": "
|
|
380
|
+
"figure.text.maturity-blocked-no-detail-level": "格式没有细节等级。以上方的限额和布置规模进行判断。",
|
|
381
381
|
"figure.text.maturity-blocked-no-parts": "nothing to measure — there are no parts.",
|
|
382
382
|
"figure.text.maturity-consistency-because": "检查纹理使用、推荐分段数以及材质种类数量。",
|
|
383
383
|
"figure.text.maturity-consistency-clean": "no issues",
|
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
# V3 제품 현황
|
|
2
|
-
|
|
3
|
-
형식은 V3(`figure-v3-asset-1`) 하나다. V1·V2 형식은 2026-09-26 코드와 명세에서 제거했다.
|
|
4
|
-
|
|
5
|
-
## 제품 코드
|
|
6
|
-
|
|
7
|
-
- `client/modeller/v3-product-session.ts`: 모델 ID·로드·저장 경계를 V3 workspace에 연결한다. 다른 모델의 지연 응답을 버리며 로드 실패 시 이전 형상을 노출하지 않는다. UI/AI는 같은 리비전과 undo/redo를 사용한다. AI 편집은 요청 당시 context/revision을 필수로 받는다.
|
|
8
|
-
- `client/modeller/v3-canvas.ts`: things-scene 편집 모드의 판 위에 평가된 V3 형상을 부품마다 `figure-v3-part` 컴포넌트로 세운다. 새 문맥에서 렌더링이 실패하면 이전 모델을 지운다.
|
|
9
|
-
- `client/modeller/v3-editor.ts`: 부품 목록 · 캔버스 · 오른쪽 탭(속성 · 능력 · 움직임 · 판정 · 환경 · 이력). 실행 취소/다시 실행과 저장 연결.
|
|
10
|
-
- `client/graphql/v3-store.ts`: 정본을 그대로 `saveFigureV3`로 보낸다.
|
|
11
|
-
- figure-service의 `saveFigureV3`: 도메인 권한 검사, V3 검증, 정확한 이전 정본을 조건으로 하는 atomic UPDATE, 생성 요청 ID를 이용한 재시도. SQLite에서 지원하지 않는 행 잠금은 사용하지 않는다. 재지 않은 성능 점수/삼각형 수는 null로 둔다. 실제 운영 DB 저장 테스트는 아직 하지 않았다.
|
|
12
|
-
- `client/pages/figure-v3-modeller-page.ts`: 위 요소를 묶는 페이지. `route.ts`의 `figure-modeller`와 `figure-v3-modeller`가 이 페이지를 연다.
|
|
13
|
-
|
|
14
|
-
## 남은 항목
|
|
15
|
-
|
|
16
|
-
1. operato-figure의 AI-dock과 figure-service 도구/제안 생성기를 V3 정본 및 승인된 트랜잭션 계약으로 연결한다. 페이지 이벤트만 추가한 것은 AI 통합 완료가 아니다.
|
|
17
|
-
2. 발행 게이트, 썸네일, 카탈로그/배치 소비처가 V3 평가 결과를 사용하는지 확인한다.
|
|
18
|
-
|
|
19
|
-
## 검증
|
|
20
|
-
|
|
21
|
-
- figure-ui `npm test`: 251개 통과(2026-09-26).
|
|
22
|
-
- SQLite in-memory 테스트: 테넌트 경계·이전 정본 비교·오래된 편집 거절. 실제 TypeORM 리졸버/제품 DB end-to-end 검증을 대체하지 않는다.
|
|
23
|
-
- 브라우저 검사(`npm run test:browser`): 기즈모 끌기 · 자세 슬라이더를 실제 마우스로 조작한다.
|
|
24
|
-
|
|
25
|
-
배포는 사용자가 담당한다.
|
package/test/v3-renderer.test.ts
DELETED
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
import {test} from 'node:test'
|
|
2
|
-
import assert from 'node:assert/strict'
|
|
3
|
-
import * as THREE from 'three'
|
|
4
|
-
import {replaceV3Meshes} from '../client/modeller/v3-renderer.ts'
|
|
5
|
-
import type {V3RenderPart} from '../client/modeller/v3-renderer.ts'
|
|
6
|
-
const box=(id:string):V3RenderPart=>({id,shape:{provider:'box',dimensions:{width:100,height:200,depth:300}},pose:{r:[[1,0,0],[0,1,0],[0,0,1]],t:[0,100,0]},material:{token:'primary'}})
|
|
7
|
-
test('V3 renderer replaces rather than accumulates; empty scene disposes old resources',()=>{
|
|
8
|
-
const group=new THREE.Group();replaceV3Meshes(group,[box('a'),box('b')],{primary:'#123456'})
|
|
9
|
-
assert.equal(group.children.length,2);let disposed=0
|
|
10
|
-
const first=group.children[0] as THREE.Mesh;first.geometry.addEventListener('dispose',()=>disposed++)
|
|
11
|
-
replaceV3Meshes(group,[box('c')],{primary:'#123456'});assert.equal(group.children.length,1);assert.equal(group.children[0].name,'c');assert.equal(disposed,1)
|
|
12
|
-
replaceV3Meshes(group,[],{});assert.equal(group.children.length,0)
|
|
13
|
-
})
|
|
14
|
-
test('V3 renderer preserves scene on unsupported geometry and resolves pose/material',()=>{
|
|
15
|
-
const group=new THREE.Group();replaceV3Meshes(group,[box('a')],{primary:'#123456'})
|
|
16
|
-
const old=group.children[0],bounds=new THREE.Box3().setFromObject(group)
|
|
17
|
-
assert.equal(bounds.min.y,0);assert.equal(bounds.max.y,200)
|
|
18
|
-
assert.throws(()=>replaceV3Meshes(group,[box('b'),{...box('c'),shape:{provider:'unknown',dimensions:{}}}],{primary:'#123456'}),/Unsupported/)
|
|
19
|
-
assert.equal(group.children[0],old)
|
|
20
|
-
const p=box('glow');p.material={token:'primary',preset:'metal',transparent:true,emissive:{token:'primary',intensity:2,on:true}}
|
|
21
|
-
replaceV3Meshes(group,[p],{primary:'#123456'})
|
|
22
|
-
const material=(group.children[0] as THREE.Mesh).material as THREE.MeshStandardMaterial
|
|
23
|
-
assert.equal(material.metalness,0.8);assert.equal(material.transparent,true);assert.equal(material.emissiveIntensity,2)
|
|
24
|
-
})
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|