@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
|
@@ -4,14 +4,14 @@
|
|
|
4
4
|
*
|
|
5
5
|
* A proposal is a list of the modeller's own commands (ADR-0094). Running it applies them in the modeller as one step
|
|
6
6
|
* of its history: a revision on the figure open there, at the version the model saw; a new figure on a new figure the
|
|
7
|
-
* modeller opens. The outcome is said in words on every branch (`
|
|
7
|
+
* modeller opens. The outcome is said in words on every branch (`ai-proposal.ts`).
|
|
8
8
|
*/
|
|
9
9
|
import { i18next } from '@operato/i18n'
|
|
10
10
|
import { navigate } from '@operato/shell'
|
|
11
11
|
import { registerProposalHandler } from '@things-factory/ai-assistant/dist-client/index.js'
|
|
12
12
|
|
|
13
13
|
import { modellerPathOf } from './modeller/modeller-route.js'
|
|
14
|
-
import { pendNewFigure, runFigureProposal, type FigureApplyDetail } from './modeller/
|
|
14
|
+
import { pendNewFigure, runFigureProposal, type FigureApplyDetail } from './modeller/ai-proposal.js'
|
|
15
15
|
|
|
16
16
|
export const FIGURE_CANDIDATE_TOOL = 'proposeFigureCandidate'
|
|
17
17
|
|
|
@@ -20,7 +20,7 @@ registerProposalHandler(FIGURE_CANDIDATE_TOOL, async (proposal, context) => {
|
|
|
20
20
|
proposal,
|
|
21
21
|
{
|
|
22
22
|
offer(detail: FigureApplyDetail) {
|
|
23
|
-
window.dispatchEvent(new CustomEvent('figure-
|
|
23
|
+
window.dispatchEvent(new CustomEvent('figure-apply', { detail }))
|
|
24
24
|
return detail
|
|
25
25
|
},
|
|
26
26
|
openNew(steps) {
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import gql from 'graphql-tag'
|
|
2
2
|
import { client } from '@operato/graphql'
|
|
3
3
|
import { fetchFigure } from './index.js'
|
|
4
|
-
import type {
|
|
4
|
+
import type { FigureProductStore, FigureProductRecord } from '../modeller/product-session.js'
|
|
5
5
|
|
|
6
|
-
/**
|
|
7
|
-
export const
|
|
6
|
+
/** source is sent intact. No conversion into the old parts/base authoring representation. */
|
|
7
|
+
export const figureProductStore: FigureProductStore = {
|
|
8
8
|
async load(id) {
|
|
9
9
|
const record = await fetchFigure(id)
|
|
10
10
|
if (!record?.source) throw Error('Figure 정본이 없습니다.')
|
|
@@ -13,8 +13,8 @@ export const v3ProductStore: V3ProductStore = {
|
|
|
13
13
|
async save(request) {
|
|
14
14
|
const response = await client.mutate({
|
|
15
15
|
mutation: gql`
|
|
16
|
-
mutation
|
|
17
|
-
|
|
16
|
+
mutation SaveFigure($source: String!, $id: String, $expectedSource: String, $creationId: String, $thumbnail: String, $type: String) {
|
|
17
|
+
saveFigure(
|
|
18
18
|
source: $source
|
|
19
19
|
id: $id
|
|
20
20
|
expectedSource: $expectedSource
|
|
@@ -30,7 +30,7 @@ export const v3ProductStore: V3ProductStore = {
|
|
|
30
30
|
variables: request
|
|
31
31
|
})
|
|
32
32
|
if (response.errors?.length) throw Error(response.errors.map(e => e.message).join('\n'))
|
|
33
|
-
const result = response.data?.
|
|
33
|
+
const result = response.data?.saveFigure as FigureProductRecord | undefined
|
|
34
34
|
if (!result?.id || !result.source) throw Error('서버가 저장 결과를 돌려주지 않았습니다.')
|
|
35
35
|
return result
|
|
36
36
|
}
|
|
@@ -5,20 +5,20 @@
|
|
|
5
5
|
*
|
|
6
6
|
* Kept free of Lit, i18n and the shell so node tests read it directly; the handler and the page pass in what they own.
|
|
7
7
|
*/
|
|
8
|
-
import type {
|
|
8
|
+
import type { FigureProposalStep } from '@hatiolab/figure-model'
|
|
9
9
|
|
|
10
10
|
/** What the card carries, as `proposeFigureCandidate` returned it. */
|
|
11
11
|
export interface FigureProposalCard {
|
|
12
|
-
steps?:
|
|
12
|
+
steps?: FigureProposalStep[]
|
|
13
13
|
create?: boolean
|
|
14
14
|
figureId?: string
|
|
15
15
|
context?: string
|
|
16
16
|
revision?: number
|
|
17
17
|
}
|
|
18
18
|
|
|
19
|
-
/** The `figure-
|
|
19
|
+
/** The `figure-apply` event's detail. The page that takes it sets `applied`, and `error` when refused. */
|
|
20
20
|
export interface FigureApplyDetail {
|
|
21
|
-
steps:
|
|
21
|
+
steps: FigureProposalStep[]
|
|
22
22
|
create: boolean
|
|
23
23
|
context?: string
|
|
24
24
|
revision?: number
|
|
@@ -33,7 +33,7 @@ export interface FigureProposalTarget {
|
|
|
33
33
|
/** Offers the proposal to a modeller on screen. It comes back untouched when none took it. */
|
|
34
34
|
offer(detail: FigureApplyDetail): FigureApplyDetail
|
|
35
35
|
/** Opens a new figure in the modeller and applies the steps there; resolves once the page has, or has not. */
|
|
36
|
-
openNew(steps:
|
|
36
|
+
openNew(steps: FigureProposalStep[]): Promise<{ applied: boolean; error?: string; code?: string }>
|
|
37
37
|
}
|
|
38
38
|
|
|
39
39
|
export interface FigureProposalOutcome {
|
|
@@ -85,9 +85,9 @@ export async function runFigureProposal(card: FigureProposalCard, target: Figure
|
|
|
85
85
|
modeller on a new figure; the page takes it once it has started that figure. Left untaken, it lapses -- a later new
|
|
86
86
|
figure must not receive steps nobody is waiting for.
|
|
87
87
|
*/
|
|
88
|
-
let pending: { steps:
|
|
88
|
+
let pending: { steps: FigureProposalStep[]; settle: (result: { applied: boolean; error?: string; code?: string }) => void } | undefined
|
|
89
89
|
|
|
90
|
-
export function pendNewFigure(steps:
|
|
90
|
+
export function pendNewFigure(steps: FigureProposalStep[], ms = 10_000): Promise<{ applied: boolean; error?: string; code?: string }> {
|
|
91
91
|
pending?.settle({ applied: false, code: 'not-opened' })
|
|
92
92
|
return new Promise(resolve => {
|
|
93
93
|
const mine = {
|
|
@@ -104,7 +104,7 @@ export function pendNewFigure(steps: V3ProposalStep[], ms = 10_000): Promise<{ a
|
|
|
104
104
|
}
|
|
105
105
|
|
|
106
106
|
/** For the page, on a new figure it has just started: the steps waiting for it, and where to say how it went. */
|
|
107
|
-
export function takePendingNewFigure(): { steps:
|
|
107
|
+
export function takePendingNewFigure(): { steps: FigureProposalStep[]; settle: (result: { applied: boolean; error?: string; code?: string }) => void } | undefined {
|
|
108
108
|
const taken = pending
|
|
109
109
|
pending = undefined
|
|
110
110
|
return taken
|
|
@@ -1,14 +1,14 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import type {
|
|
1
|
+
import { compileFigureAsset, figureOccupiedBoxesOf, figureWritersOf } from '@hatiolab/figure-model'
|
|
2
|
+
import type { FigureAsset, FigureInputChange, FigureWorldBox } from '@hatiolab/figure-model'
|
|
3
3
|
|
|
4
|
-
import type { GizmoReach } from './
|
|
4
|
+
import type { GizmoReach } from './gizmo.js'
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
7
|
* 맞추기 — the align tools on a part: centre on X, centre on Z, stand on the floor,
|
|
8
8
|
* mirror on X or Z, snap to the grid.
|
|
9
9
|
*
|
|
10
10
|
* The asset's frame has the floor at y 0 and X and Z centred on 0, so centring puts the part's box centre on 0 and the floor puts its lowest point on
|
|
11
|
-
* y 0. The part's box is its evaluated, rotated extent (`
|
|
11
|
+
* y 0. The part's box is its evaluated, rotated extent (`figureOccupiedBoxesOf`), so a turned part lands by what it
|
|
12
12
|
* actually covers, not by its unturned size.
|
|
13
13
|
*
|
|
14
14
|
* Every tool writes the part's own position (and, for snap, size) inputs — the same ones the gizmo writes, and only
|
|
@@ -18,15 +18,15 @@ export type AlignTool = 'centre-x' | 'centre-z' | 'floor' | 'snap'
|
|
|
18
18
|
|
|
19
19
|
const AXES = ['x', 'y', 'z'] as const
|
|
20
20
|
|
|
21
|
-
export function boxOf(asset:
|
|
22
|
-
const geometry =
|
|
23
|
-
return
|
|
21
|
+
export function boxOf(asset: FigureAsset, part: string): FigureWorldBox | undefined {
|
|
22
|
+
const geometry = compileFigureAsset(asset).evaluate().geometry
|
|
23
|
+
return figureOccupiedBoxesOf(geometry, figureWritersOf(asset)).find(box => box.part === part)
|
|
24
24
|
}
|
|
25
25
|
|
|
26
26
|
/** The snapping grid: about five steps across the figure, on 1 · 2 · 5 multiples. */
|
|
27
|
-
export function gridStepOf(asset:
|
|
28
|
-
const geometry =
|
|
29
|
-
const boxes =
|
|
27
|
+
export function gridStepOf(asset: FigureAsset): number {
|
|
28
|
+
const geometry = compileFigureAsset(asset).evaluate().geometry
|
|
29
|
+
const boxes = figureOccupiedBoxesOf(geometry, figureWritersOf(asset))
|
|
30
30
|
if (!boxes.length) return 1
|
|
31
31
|
const span = Math.max(
|
|
32
32
|
...AXES.map(axis => {
|
|
@@ -38,12 +38,12 @@ export function gridStepOf(asset: V3Asset): number {
|
|
|
38
38
|
return niceStep(span)
|
|
39
39
|
}
|
|
40
40
|
|
|
41
|
-
export function alignChanges(asset:
|
|
41
|
+
export function alignChanges(asset: FigureAsset, part: string, reach: GizmoReach, tool: AlignTool): FigureInputChange[] {
|
|
42
42
|
if (!reach.translate) return []
|
|
43
43
|
const box = boxOf(asset, part)
|
|
44
44
|
if (!box) return []
|
|
45
45
|
const value = (id: string) => asset.designInputs[id] ?? 0
|
|
46
|
-
const set = (input: string, next: number):
|
|
46
|
+
const set = (input: string, next: number): FigureInputChange => ({ kind: 'set-design', input, unit: 'mm', value: Math.round(next) })
|
|
47
47
|
const at = (axis: 'x' | 'y' | 'z') => `${part}.position.${axis}`
|
|
48
48
|
switch (tool) {
|
|
49
49
|
case 'centre-x':
|
|
@@ -68,7 +68,7 @@ export function alignChanges(asset: V3Asset, part: string, reach: GizmoReach, to
|
|
|
68
68
|
* Where a mirrored copy goes: the same distance on the other side of the centre plane. The copy is made by
|
|
69
69
|
* `duplicate-part` first; this is the position the copy is then given.
|
|
70
70
|
*/
|
|
71
|
-
export function mirrorChanges(asset:
|
|
71
|
+
export function mirrorChanges(asset: FigureAsset, part: string, copy: string, axis: 'x' | 'z'): FigureInputChange[] {
|
|
72
72
|
const box = boxOf(asset, part)
|
|
73
73
|
if (!box) return []
|
|
74
74
|
const id = `${part}.position.${axis}`
|
|
@@ -76,7 +76,7 @@ export function mirrorChanges(asset: V3Asset, part: string, copy: string, axis:
|
|
|
76
76
|
}
|
|
77
77
|
|
|
78
78
|
/** Mirroring a part that already sits on the centre plane would put the copy inside it, so it is refused. */
|
|
79
|
-
export function canMirror(asset:
|
|
79
|
+
export function canMirror(asset: FigureAsset, part: string, axis: 'x' | 'z', reach: GizmoReach): boolean {
|
|
80
80
|
const box = reach.translate ? boxOf(asset, part) : undefined
|
|
81
81
|
return !!box && Math.abs(box.centre[axis]) >= 0.5
|
|
82
82
|
}
|
|
@@ -3,23 +3,23 @@ import { customElement, property, query } from 'lit/decorators.js'
|
|
|
3
3
|
import { i18next } from '@operato/i18n'
|
|
4
4
|
import { create, Model, niceGridStep } from '@hatiolab/things-scene'
|
|
5
5
|
|
|
6
|
-
import type { GizmoReach } from './
|
|
7
|
-
import type {
|
|
6
|
+
import type { GizmoReach } from './gizmo.js'
|
|
7
|
+
import type { FigureRenderPart } from './renderer.js'
|
|
8
8
|
import { DEFAULT_VIEW, sceneLook, WORKBENCH, type ViewSettings } from './figure-view.js'
|
|
9
|
-
import { boardFor, changedKeys, componentOf, gizmoResultOf, type Board } from './
|
|
10
|
-
import { JOINT_FAN } from './
|
|
11
|
-
import { ownerOf } from './
|
|
9
|
+
import { boardFor, changedKeys, componentOf, gizmoResultOf, type Board } from './stage-model.js'
|
|
10
|
+
import { JOINT_FAN } from './joint-fan.js'
|
|
11
|
+
import { ownerOf } from './fields.js'
|
|
12
12
|
|
|
13
13
|
/*
|
|
14
14
|
* The modeller's canvas -- a things-scene board in editing mode.
|
|
15
15
|
*
|
|
16
|
-
* Each body figure-model evaluates stands on the board as a `figure-
|
|
16
|
+
* Each body figure-model evaluates stands on the board as a `figure-part` component, so everything the canvas
|
|
17
17
|
* has comes from the scene, not from code of our own: picking and the orange outline, the gizmo with its snapping and
|
|
18
18
|
* live readout, box and shift selection, the camera (damping, zoom toward the cursor, double-click to fit, the six
|
|
19
19
|
* view presets and their keys), the studio environment, the coordinate ground, lights and shadows, supersampling.
|
|
20
20
|
* An earlier canvas drew the bodies with three.js directly and lost all of that (user, 2026-09-24: "why nerf it?").
|
|
21
21
|
*
|
|
22
|
-
* What the gizmo writes back to a component comes out as `part-transformed` in the inputs' terms (`
|
|
22
|
+
* What the gizmo writes back to a component comes out as `part-transformed` in the inputs' terms (`stage-model`),
|
|
23
23
|
* and the editor turns it into one step of the history; the next evaluation puts the component where the inputs say,
|
|
24
24
|
* so a change a part cannot take (a fastened part moved) springs back.
|
|
25
25
|
*/
|
|
@@ -53,8 +53,8 @@ const FAN_COLOUR = '#ff8a00'
|
|
|
53
53
|
/* The 2D side of the board, which the author never sees on this page but the scene paints. */
|
|
54
54
|
const PAPER = '#ffffff'
|
|
55
55
|
|
|
56
|
-
@customElement('figure-
|
|
57
|
-
export class
|
|
56
|
+
@customElement('figure-canvas')
|
|
57
|
+
export class FigureCanvas extends LitElement {
|
|
58
58
|
static styles = css`
|
|
59
59
|
:host {
|
|
60
60
|
position: relative;
|
|
@@ -79,7 +79,7 @@ export class FigureV3Canvas extends LitElement {
|
|
|
79
79
|
color: #f4f4f4;
|
|
80
80
|
}
|
|
81
81
|
`
|
|
82
|
-
@property({ attribute: false }) parts:
|
|
82
|
+
@property({ attribute: false }) parts: FigureRenderPart[] = []
|
|
83
83
|
@property({ attribute: false }) palette: Record<string, string> = {}
|
|
84
84
|
/** Which figure is open. Another one stands the board up again. */
|
|
85
85
|
@property() context = ''
|
|
@@ -89,12 +89,12 @@ export class FigureV3Canvas extends LitElement {
|
|
|
89
89
|
@property({ attribute: false }) view: ViewSettings = DEFAULT_VIEW
|
|
90
90
|
/**
|
|
91
91
|
* View only: nothing that happens on the board is told out. The card's picture is taken from a second canvas stood up
|
|
92
|
-
* off screen (`
|
|
92
|
+
* off screen (`thumbnail.ts`); the scene settles its components as it builds them, and a change told from there
|
|
93
93
|
* would reach the editor as an edit.
|
|
94
94
|
*/
|
|
95
95
|
@property({ type: Boolean }) viewOnly = false
|
|
96
|
-
/** Where the selected part turns and how far (`
|
|
97
|
-
@property({ attribute: false }) fan:
|
|
96
|
+
/** Where the selected part turns and how far (`joint-fan`): shown, never picked, never saved. */
|
|
97
|
+
@property({ attribute: false }) fan: FigureRenderPart | null = null
|
|
98
98
|
|
|
99
99
|
@query('div[stage]') private stage!: HTMLDivElement
|
|
100
100
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { driverValue } from '@hatiolab/figure-model'
|
|
2
|
-
import type {
|
|
2
|
+
import type { FigureAsset, FigureDriver, FigureInputChange } from '@hatiolab/figure-model'
|
|
3
3
|
|
|
4
4
|
/*
|
|
5
5
|
* The figure's clips: controls played by keys over time, grouped into clips that each run on one
|
|
@@ -28,7 +28,7 @@ export interface Clip {
|
|
|
28
28
|
|
|
29
29
|
const round = (n: number) => Math.round(n * 1000) / 1000
|
|
30
30
|
|
|
31
|
-
export function clipsOf(asset:
|
|
31
|
+
export function clipsOf(asset: FigureAsset): Clip[] {
|
|
32
32
|
const inputs = new Map(asset.document.model.inputs.map(i => [i.id, i]))
|
|
33
33
|
const clips = new Map<string, Clip>()
|
|
34
34
|
for (const d of asset.drivers ?? []) {
|
|
@@ -51,16 +51,16 @@ export function clipsOf(asset: V3Asset): Clip[] {
|
|
|
51
51
|
}
|
|
52
52
|
|
|
53
53
|
/** The controls no clip plays yet -- the ones a new track can take. One driver per control. */
|
|
54
|
-
export function undrivenOf(asset:
|
|
54
|
+
export function undrivenOf(asset: FigureAsset): string[] {
|
|
55
55
|
const driven = new Set((asset.drivers ?? []).map(d => d.state))
|
|
56
56
|
return asset.document.model.inputs.filter(i => i.role === 'state' && !driven.has(i.id)).map(i => i.id)
|
|
57
57
|
}
|
|
58
58
|
|
|
59
59
|
/** The pose a clip gives at a moment, as one batch of state changes -- one step of the history. */
|
|
60
|
-
export function poseAt(asset:
|
|
60
|
+
export function poseAt(asset: FigureAsset, clip: string, seconds: number): FigureInputChange[] {
|
|
61
61
|
const units = new Map(asset.document.model.inputs.map(i => [i.id, i.unit]))
|
|
62
62
|
return (asset.drivers ?? [])
|
|
63
|
-
.filter((d:
|
|
63
|
+
.filter((d: FigureDriver) => d.clip === clip)
|
|
64
64
|
.map(d => {
|
|
65
65
|
const unit = units.get(d.state)!
|
|
66
66
|
return { kind: 'set-state' as const, input: d.state, unit, value: driverValue(d, seconds, unit === 'deg' || unit === 'rad' ? unit : 'other') }
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { FigureAsset } from '@hatiolab/figure-model'
|
|
2
2
|
|
|
3
3
|
/*
|
|
4
4
|
* The figure's controls -- its state inputs: the values a board or a connector sets to pose
|
|
@@ -23,7 +23,7 @@ export interface Control {
|
|
|
23
23
|
step: number
|
|
24
24
|
}
|
|
25
25
|
|
|
26
|
-
export function controlsOf(asset:
|
|
26
|
+
export function controlsOf(asset: FigureAsset, values: Record<string, number> = {}): Control[] {
|
|
27
27
|
return asset.document.model.inputs
|
|
28
28
|
.filter(input => input.role === 'state')
|
|
29
29
|
.map(input => {
|