@hatiolab/figure-model 0.1.92 → 0.1.94
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/CHANGELOG.md +12 -12
- package/README.md +25 -25
- package/dist/{v3-asset-types.d.ts → asset-types.d.ts} +73 -67
- package/dist/asset-types.d.ts.map +1 -0
- package/dist/asset-types.js +2 -0
- package/dist/asset-types.js.map +1 -0
- package/dist/asset.d.ts +20 -0
- package/dist/asset.d.ts.map +1 -0
- package/dist/{v3-asset.js → asset.js} +49 -28
- package/dist/asset.js.map +1 -0
- package/dist/{v3-authoring-actions.d.ts → authoring-actions.d.ts} +77 -66
- package/dist/authoring-actions.d.ts.map +1 -0
- package/dist/{v3-authoring-actions.js → authoring-actions.js} +129 -104
- package/dist/authoring-actions.js.map +1 -0
- package/dist/{v3-authoring-session.d.ts → authoring-session.d.ts} +23 -21
- package/dist/authoring-session.d.ts.map +1 -0
- package/dist/{v3-authoring-session.js → authoring-session.js} +4 -4
- package/dist/authoring-session.js.map +1 -0
- package/dist/capabilities.d.ts +3 -0
- package/dist/capabilities.d.ts.map +1 -0
- package/dist/{v3-capabilities.js → capabilities.js} +8 -8
- package/dist/capabilities.js.map +1 -0
- package/dist/clip-keeping.d.ts +30 -0
- package/dist/clip-keeping.d.ts.map +1 -0
- package/dist/clip-keeping.js +77 -0
- package/dist/clip-keeping.js.map +1 -0
- package/dist/command-preview.d.ts +125 -0
- package/dist/command-preview.d.ts.map +1 -0
- package/dist/command-preview.js +246 -0
- package/dist/command-preview.js.map +1 -0
- package/dist/contract.d.ts +7 -0
- package/dist/contract.d.ts.map +1 -0
- package/dist/contract.js +12 -0
- package/dist/contract.js.map +1 -0
- package/dist/{v3-cost.d.ts → cost.d.ts} +5 -5
- package/dist/cost.d.ts.map +1 -0
- package/dist/{v3-cost.js → cost.js} +11 -11
- package/dist/cost.js.map +1 -0
- package/dist/{v3-create.d.ts → create.d.ts} +8 -8
- package/dist/{v3-create.d.ts.map → create.d.ts.map} +1 -1
- package/dist/{v3-create.js → create.js} +26 -26
- package/dist/create.js.map +1 -0
- package/dist/document.d.ts +5 -0
- package/dist/document.d.ts.map +1 -0
- package/dist/document.js +31 -0
- package/dist/document.js.map +1 -0
- package/dist/{v3-driver.d.ts → driver.d.ts} +10 -10
- package/dist/driver.d.ts.map +1 -0
- package/dist/{v3-driver.js → driver.js} +10 -10
- package/dist/driver.js.map +1 -0
- package/dist/{v3-editor-workspace.d.ts → editor-workspace.d.ts} +99 -73
- package/dist/editor-workspace.d.ts.map +1 -0
- package/dist/{v3-editor-workspace.js → editor-workspace.js} +48 -32
- package/dist/editor-workspace.js.map +1 -0
- package/dist/{v3-examples.d.ts → examples.d.ts} +5 -5
- package/dist/examples.d.ts.map +1 -0
- package/dist/{v3-examples.js → examples.js} +11 -11
- package/dist/examples.js.map +1 -0
- package/dist/{v3-follow.d.ts → follow.d.ts} +5 -5
- package/dist/follow.d.ts.map +1 -0
- package/dist/{v3-follow.js → follow.js} +2 -2
- package/dist/follow.js.map +1 -0
- package/dist/{v3-gate.d.ts → gate.d.ts} +36 -28
- package/dist/gate.d.ts.map +1 -0
- package/dist/{v3-gate.js → gate.js} +54 -48
- package/dist/gate.js.map +1 -0
- package/dist/{v3-graph-types.d.ts → graph-types.d.ts} +33 -33
- package/dist/graph-types.d.ts.map +1 -0
- package/dist/graph-types.js +2 -0
- package/dist/graph-types.js.map +1 -0
- package/dist/{v3-graph.d.ts → graph.d.ts} +14 -14
- package/dist/graph.d.ts.map +1 -0
- package/dist/{v3-graph.js → graph.js} +16 -16
- package/dist/graph.js.map +1 -0
- package/dist/index.d.ts +39 -33
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +39 -33
- package/dist/index.js.map +1 -1
- package/dist/{v3-instance-size.d.ts → instance-size.d.ts} +14 -14
- package/dist/instance-size.d.ts.map +1 -0
- package/dist/{v3-instance-size.js → instance-size.js} +13 -13
- package/dist/instance-size.js.map +1 -0
- package/dist/json.d.ts +12 -0
- package/dist/json.d.ts.map +1 -0
- package/dist/{v3-json.js → json.js} +13 -13
- package/dist/json.js.map +1 -0
- package/dist/kernel-version.d.ts +8 -0
- package/dist/kernel-version.d.ts.map +1 -0
- package/dist/{v3-kernel-version.js → kernel-version.js} +4 -4
- package/dist/kernel-version.js.map +1 -0
- package/dist/{v3-part-edit.d.ts → part-edit.d.ts} +12 -11
- package/dist/part-edit.d.ts.map +1 -0
- package/dist/{v3-part-edit.js → part-edit.js} +84 -68
- package/dist/part-edit.js.map +1 -0
- package/dist/proposal.d.ts +55 -0
- package/dist/proposal.d.ts.map +1 -0
- package/dist/{v3-proposal.js → proposal.js} +29 -21
- package/dist/proposal.js.map +1 -0
- package/dist/{v3-public-inputs.d.ts → public-inputs.d.ts} +4 -4
- package/dist/public-inputs.d.ts.map +1 -0
- package/dist/{v3-public-inputs.js → public-inputs.js} +3 -3
- package/dist/public-inputs.js.map +1 -0
- package/dist/recipe-build.d.ts +27 -0
- package/dist/recipe-build.d.ts.map +1 -0
- package/dist/{v3-recipe-build.js → recipe-build.js} +9 -9
- package/dist/recipe-build.js.map +1 -0
- package/dist/recipe-from-parts.d.ts +8 -0
- package/dist/recipe-from-parts.d.ts.map +1 -0
- package/dist/{v3-recipe-from-parts.js → recipe-from-parts.js} +9 -9
- package/dist/recipe-from-parts.js.map +1 -0
- package/dist/{v3-recipe.d.ts → recipe.d.ts} +25 -25
- package/dist/recipe.d.ts.map +1 -0
- package/dist/{v3-recipe.js → recipe.js} +30 -30
- package/dist/recipe.js.map +1 -0
- package/dist/release-contract.d.ts +19 -0
- package/dist/release-contract.d.ts.map +1 -0
- package/dist/{v3-release-contract.js → release-contract.js} +8 -7
- package/dist/release-contract.js.map +1 -0
- package/dist/{v3-render-batches.d.ts → render-batches.d.ts} +8 -8
- package/dist/render-batches.d.ts.map +1 -0
- package/dist/{v3-render-batches.js → render-batches.js} +4 -4
- package/dist/render-batches.js.map +1 -0
- package/dist/resize-plan.d.ts +61 -0
- package/dist/resize-plan.d.ts.map +1 -0
- package/dist/resize-plan.js +189 -0
- package/dist/resize-plan.js.map +1 -0
- package/dist/room.d.ts +53 -0
- package/dist/room.d.ts.map +1 -0
- package/dist/room.js +90 -0
- package/dist/room.js.map +1 -0
- package/dist/{v3-score.d.ts → score.d.ts} +19 -19
- package/dist/score.d.ts.map +1 -0
- package/dist/{v3-score.js → score.js} +32 -32
- package/dist/score.js.map +1 -0
- package/dist/shape-provider.d.ts +37 -0
- package/dist/shape-provider.d.ts.map +1 -0
- package/dist/shape-provider.js +69 -0
- package/dist/shape-provider.js.map +1 -0
- package/dist/{v3-shape-sampling.d.ts → shape-sampling.d.ts} +4 -4
- package/dist/shape-sampling.d.ts.map +1 -0
- package/dist/{v3-shape-sampling.js → shape-sampling.js} +3 -3
- package/dist/shape-sampling.js.map +1 -0
- package/dist/size-edit.d.ts +38 -0
- package/dist/size-edit.d.ts.map +1 -0
- package/dist/size-edit.js +178 -0
- package/dist/size-edit.js.map +1 -0
- package/dist/{v3-surface.d.ts → surface.d.ts} +5 -5
- package/dist/surface.d.ts.map +1 -0
- package/dist/{v3-surface.js → surface.js} +7 -7
- package/dist/surface.js.map +1 -0
- package/dist/{v3-words.d.ts → words.d.ts} +3 -3
- package/dist/words.d.ts.map +1 -0
- package/dist/{v3-words.js → words.js} +3 -3
- package/dist/words.js.map +1 -0
- package/docs/{assembly-constraints-v3.md → assembly-constraints.md} +1 -1
- package/docs/{v3-asset-persistence.md → asset-persistence.md} +8 -8
- package/docs/{v3-authoring-transactions.md → authoring-transactions.md} +2 -2
- package/docs/{v3-capability-bindings.md → capability-bindings.md} +8 -8
- package/docs/{v3-common-kernel-experiment.md → common-kernel-experiment.md} +4 -4
- package/docs/{v3-core-semantics.md → core-semantics.md} +5 -5
- package/docs/{v3-cutover.md → cutover.md} +4 -4
- package/docs/{v3-design.md → design.md} +11 -11
- package/docs/{v3-document-contract.md → document-contract.md} +9 -9
- package/docs/{v3-dryroom-profile-validation.md → dryroom-profile-validation.md} +4 -4
- package/docs/{v3-editor-integration.md → editor-integration.md} +6 -6
- package/docs/{v3-full-conveyor-validation.md → full-conveyor-validation.md} +4 -4
- package/docs/{v3-full-dryroom-validation.md → full-dryroom-validation.md} +4 -4
- package/docs/{v3-full-forklift-validation.md → full-forklift-validation.md} +5 -5
- package/docs/{v3-full-robot-validation.md → full-robot-validation.md} +4 -4
- package/docs/{v3-layout-system.md → layout-system.md} +4 -4
- package/docs/{v3-legacy-risk-audit-2026-09-23.md → legacy-risk-audit-2026-09-23.md} +5 -5
- package/docs/{v3-minimal-model.md → minimal-model.md} +6 -6
- package/docs/{v3-motion-contract.md → motion-contract.md} +3 -3
- package/docs/{v3-openusd-review.md → openusd-review.md} +8 -8
- package/docs/{v3-operator-contracts.md → operator-contracts.md} +6 -6
- package/docs/{v3-payload-collision-validation.md → payload-collision-validation.md} +4 -4
- package/docs/{v3-payload-contact-validation.md → payload-contact-validation.md} +5 -5
- package/docs/prototypes/README.md +10 -10
- package/docs/prototypes/{v3-asset-samples.mjs → asset-samples.mjs} +6 -6
- package/docs/prototypes/{v3-asset-store.mjs → asset-store.mjs} +3 -3
- package/docs/prototypes/{v3-asset-store.test.mjs → asset-store.test.mjs} +6 -6
- package/docs/prototypes/asset.mjs +1 -0
- package/docs/prototypes/{v3-asset.schema.json → asset.schema.json} +2 -2
- package/docs/prototypes/{v3-asset.test.mjs → asset.test.mjs} +10 -10
- package/docs/prototypes/authoring-session.mjs +1 -0
- package/docs/prototypes/{v3-authoring-session.test.mjs → authoring-session.test.mjs} +6 -6
- package/docs/prototypes/capability-plan.mjs +1 -0
- package/docs/prototypes/{v3-capability-plan.test.mjs → capability-plan.test.mjs} +5 -5
- package/docs/prototypes/{v3-capability-samples.mjs → capability-samples.mjs} +2 -2
- package/docs/prototypes/document.mjs +2 -0
- package/docs/prototypes/{v3-document.schema.json → document.schema.json} +1 -1
- package/docs/prototypes/{v3-document.test.mjs → document.test.mjs} +7 -7
- package/docs/prototypes/{v3-dryroom-mesh.mjs → dryroom-mesh.mjs} +1 -1
- package/docs/prototypes/{v3-dryroom-mesh.test.mjs → dryroom-mesh.test.mjs} +1 -1
- package/docs/prototypes/{v3-editor-browser.mjs → editor-browser.mjs} +13 -13
- package/docs/prototypes/editor-workspace.mjs +1 -0
- package/docs/prototypes/{v3-editor-workspace.test.mjs → editor-workspace.test.mjs} +3 -3
- package/docs/prototypes/{v3-feature-pattern.test.mjs → feature-pattern.test.mjs} +1 -1
- package/docs/prototypes/{v3-full-conveyor.mjs → full-conveyor.mjs} +2 -2
- package/docs/prototypes/{v3-full-conveyor.test.mjs → full-conveyor.test.mjs} +3 -3
- package/docs/prototypes/{v3-full-dryroom.mjs → full-dryroom.mjs} +2 -2
- package/docs/prototypes/{v3-full-dryroom.test.mjs → full-dryroom.test.mjs} +3 -3
- package/docs/prototypes/{v3-full-forklift.mjs → full-forklift.mjs} +2 -2
- package/docs/prototypes/{v3-full-forklift.test.mjs → full-forklift.test.mjs} +3 -3
- package/docs/prototypes/{v3-full-robot.mjs → full-robot.mjs} +2 -2
- package/docs/prototypes/{v3-full-robot.test.mjs → full-robot.test.mjs} +4 -4
- package/docs/prototypes/{v3-kernel.test.mjs → kernel.test.mjs} +1 -1
- package/docs/prototypes/{v3-layout.test.mjs → layout.test.mjs} +1 -1
- package/docs/prototypes/{v3-more-samples.test.mjs → more-samples.test.mjs} +2 -2
- package/docs/prototypes/{v3-payload-collision.mjs → payload-collision.mjs} +2 -2
- package/docs/prototypes/{v3-payload-collision.test.mjs → payload-collision.test.mjs} +3 -3
- package/docs/prototypes/{v3-payload-fit.mjs → payload-fit.mjs} +2 -2
- package/docs/prototypes/{v3-payload-fit.test.mjs → payload-fit.test.mjs} +4 -4
- package/docs/prototypes/render-full-dryroom.mjs +12 -12
- package/docs/prototypes/{v3-repeated-binding.mjs → repeated-binding.mjs} +1 -1
- package/docs/prototypes/{v3-repeated-binding.test.mjs → repeated-binding.test.mjs} +6 -6
- package/docs/prototypes/{v3-runtime-browser.mjs → runtime-browser.mjs} +26 -26
- package/docs/prototypes/{v3-samples.test.mjs → samples.test.mjs} +1 -1
- package/docs/prototypes/{v3-spatial-plan.test.mjs → spatial-plan.test.mjs} +1 -1
- package/docs/prototypes/typed-plan.mjs +3 -0
- package/docs/prototypes/{v3-typed-plan.test.mjs → typed-plan.test.mjs} +1 -1
- package/docs/prototypes/{v3-typed-repeat.test.mjs → typed-repeat.test.mjs} +2 -2
- package/docs/{v3-repeated-binding-validation.md → repeated-binding-validation.md} +4 -4
- package/docs/{v3-research-review.md → research-review.md} +2 -2
- package/docs/{v3-review-2026-09-22.md → review-2026-09-22.md} +10 -10
- package/docs/{v3-runtime-extraction.md → runtime-extraction.md} +16 -16
- package/docs/{v3-sample-validation-expanded.md → sample-validation-expanded.md} +5 -5
- package/docs/{v3-sample-validation.md → sample-validation.md} +3 -3
- package/docs/{v3-shape-dimension-contract.md → shape-dimension-contract.md} +12 -12
- package/docs/{v3-shapeassembly-reproduction.md → shapeassembly-reproduction.md} +4 -4
- package/docs/{v3-spatial-contracts.md → spatial-contracts.md} +5 -5
- package/docs/status.md +12 -0
- package/docs/{v3-storage-integration.md → storage-integration.md} +5 -5
- package/docs/{v3-typed-repeat-contracts.md → typed-repeat-contracts.md} +3 -3
- package/package.json +3 -3
- package/dist/v3-asset-types.d.ts.map +0 -1
- package/dist/v3-asset-types.js +0 -2
- package/dist/v3-asset-types.js.map +0 -1
- package/dist/v3-asset.d.ts +0 -8
- package/dist/v3-asset.d.ts.map +0 -1
- package/dist/v3-asset.js.map +0 -1
- package/dist/v3-authoring-actions.d.ts.map +0 -1
- package/dist/v3-authoring-actions.js.map +0 -1
- package/dist/v3-authoring-session.d.ts.map +0 -1
- package/dist/v3-authoring-session.js.map +0 -1
- package/dist/v3-capabilities.d.ts +0 -3
- package/dist/v3-capabilities.d.ts.map +0 -1
- package/dist/v3-capabilities.js.map +0 -1
- package/dist/v3-contract.d.ts +0 -7
- package/dist/v3-contract.d.ts.map +0 -1
- package/dist/v3-contract.js +0 -12
- package/dist/v3-contract.js.map +0 -1
- package/dist/v3-cost.d.ts.map +0 -1
- package/dist/v3-cost.js.map +0 -1
- package/dist/v3-create.js.map +0 -1
- package/dist/v3-document.d.ts +0 -5
- package/dist/v3-document.d.ts.map +0 -1
- package/dist/v3-document.js +0 -31
- package/dist/v3-document.js.map +0 -1
- package/dist/v3-driver.d.ts.map +0 -1
- package/dist/v3-driver.js.map +0 -1
- package/dist/v3-editor-workspace.d.ts.map +0 -1
- package/dist/v3-editor-workspace.js.map +0 -1
- package/dist/v3-examples.d.ts.map +0 -1
- package/dist/v3-examples.js.map +0 -1
- package/dist/v3-follow.d.ts.map +0 -1
- package/dist/v3-follow.js.map +0 -1
- package/dist/v3-gate.d.ts.map +0 -1
- package/dist/v3-gate.js.map +0 -1
- package/dist/v3-graph-types.d.ts.map +0 -1
- package/dist/v3-graph-types.js +0 -2
- package/dist/v3-graph-types.js.map +0 -1
- package/dist/v3-graph.d.ts.map +0 -1
- package/dist/v3-graph.js.map +0 -1
- package/dist/v3-instance-size.d.ts.map +0 -1
- package/dist/v3-instance-size.js.map +0 -1
- package/dist/v3-json.d.ts +0 -12
- package/dist/v3-json.d.ts.map +0 -1
- package/dist/v3-json.js.map +0 -1
- package/dist/v3-kernel-version.d.ts +0 -8
- package/dist/v3-kernel-version.d.ts.map +0 -1
- package/dist/v3-kernel-version.js.map +0 -1
- package/dist/v3-part-edit.d.ts.map +0 -1
- package/dist/v3-part-edit.js.map +0 -1
- package/dist/v3-proposal.d.ts +0 -42
- package/dist/v3-proposal.d.ts.map +0 -1
- package/dist/v3-proposal.js.map +0 -1
- package/dist/v3-public-inputs.d.ts.map +0 -1
- package/dist/v3-public-inputs.js.map +0 -1
- package/dist/v3-recipe-build.d.ts +0 -27
- package/dist/v3-recipe-build.d.ts.map +0 -1
- package/dist/v3-recipe-build.js.map +0 -1
- package/dist/v3-recipe-from-parts.d.ts +0 -8
- package/dist/v3-recipe-from-parts.d.ts.map +0 -1
- package/dist/v3-recipe-from-parts.js.map +0 -1
- package/dist/v3-recipe.d.ts.map +0 -1
- package/dist/v3-recipe.js.map +0 -1
- package/dist/v3-release-contract.d.ts +0 -19
- package/dist/v3-release-contract.d.ts.map +0 -1
- package/dist/v3-release-contract.js.map +0 -1
- package/dist/v3-render-batches.d.ts.map +0 -1
- package/dist/v3-render-batches.js.map +0 -1
- package/dist/v3-score.d.ts.map +0 -1
- package/dist/v3-score.js.map +0 -1
- package/dist/v3-shape-sampling.d.ts.map +0 -1
- package/dist/v3-shape-sampling.js.map +0 -1
- package/dist/v3-surface.d.ts.map +0 -1
- package/dist/v3-surface.js.map +0 -1
- package/dist/v3-words.d.ts.map +0 -1
- package/dist/v3-words.js.map +0 -1
- package/docs/prototypes/v3-asset.mjs +0 -1
- package/docs/prototypes/v3-authoring-session.mjs +0 -1
- package/docs/prototypes/v3-capability-plan.mjs +0 -1
- package/docs/prototypes/v3-document.mjs +0 -2
- package/docs/prototypes/v3-editor-workspace.mjs +0 -1
- package/docs/prototypes/v3-typed-plan.mjs +0 -3
- package/docs/v3-status.md +0 -50
- /package/docs/prototypes/{v3-kernel.mjs → kernel.mjs} +0 -0
- /package/docs/prototypes/{v3-linear-comparison.py → linear-comparison.py} +0 -0
- /package/docs/prototypes/{v3-semantics.test.mjs → semantics.test.mjs} +0 -0
|
@@ -2,20 +2,20 @@
|
|
|
2
2
|
import {createServer} from 'node:http'
|
|
3
3
|
import {readFile} from 'node:fs/promises'
|
|
4
4
|
import {chromium} from '/Users/super/.cache/codex-runtimes/codex-primary-runtime/dependencies/node/node_modules/playwright/index.mjs'
|
|
5
|
-
import {seed,defaults,evaluateFull,geometryOf,sourceGeometry} from './
|
|
6
|
-
import * as conveyor from './
|
|
7
|
-
import * as robot from './
|
|
8
|
-
import * as forklift from './
|
|
9
|
-
import {forkliftBindings} from './
|
|
10
|
-
import {compilePayloadInspection} from './
|
|
11
|
-
import {compileCollisionInspection} from './
|
|
5
|
+
import {seed,defaults,evaluateFull,geometryOf,sourceGeometry} from './full-dryroom.mjs'
|
|
6
|
+
import * as conveyor from './full-conveyor.mjs'
|
|
7
|
+
import * as robot from './full-robot.mjs'
|
|
8
|
+
import * as forklift from './full-forklift.mjs'
|
|
9
|
+
import {forkliftBindings} from './capability-samples.mjs'
|
|
10
|
+
import {compilePayloadInspection} from './payload-fit.mjs'
|
|
11
|
+
import {compileCollisionInspection} from './payload-collision.mjs'
|
|
12
12
|
const isConveyor=process.argv.includes('--conveyor')
|
|
13
13
|
const isRobot=process.argv.includes('--robot')
|
|
14
14
|
const isCollision=process.argv.includes('--collision')
|
|
15
15
|
const isPayload=process.argv.includes('--payload')||isCollision
|
|
16
16
|
const isForklift=process.argv.includes('--forklift')||isPayload
|
|
17
17
|
const pack=(items)=>items.map(x=>({id:x.id,material:x.material,geometry:x.geometry.toJSON()}))
|
|
18
|
-
const
|
|
18
|
+
const fromFigure=args=>pack(evaluateFull(args).map(x=>({...x,geometry:geometryOf(x)})))
|
|
19
19
|
const robotPose={...robot.defaults,'base-pan':30,'shoulder-lift':-35,'elbow-flex':65,'wrist-pitch':-25,'wrist-yaw':40,'tool-roll':20,gripper:50}
|
|
20
20
|
function payloadVariants(){
|
|
21
21
|
const sample=forkliftBindings(),p=(isCollision?compileCollisionInspection:compilePayloadInspection)(sample.model,sample.declaration)
|
|
@@ -50,9 +50,9 @@ const variants=isPayload?payloadVariants():isForklift?[
|
|
|
50
50
|
].map(([title,args])=>({title,parts:pack(conveyor.evaluateFull(args).map(x=>({...x,geometry:conveyor.geometryOf(x)})))}))
|
|
51
51
|
]:[
|
|
52
52
|
{title:'Source seed · six parts',parts:pack(seed.parts.map(p=>({id:p.name,material:p.material,geometry:sourceGeometry(p)})))},
|
|
53
|
-
{title:'V3 · same dimensions',parts:
|
|
54
|
-
{title:'V3 · portal bottom trimmed to floor',parts:
|
|
55
|
-
{title:'V3 · resized + lamps raised',parts:
|
|
53
|
+
{title:'V3 · same dimensions',parts:fromFigure(defaults)},
|
|
54
|
+
{title:'V3 · portal bottom trimmed to floor',parts:fromFigure({...defaults,bottom:0})},
|
|
55
|
+
{title:'V3 · resized + lamps raised',parts:fromFigure({...defaults,width:4800,height:3600,depth:7200,bottom:0,lampLift:100})}
|
|
56
56
|
]
|
|
57
57
|
const html=`<!doctype html><meta charset="utf-8"><style>body{margin:0;background:#e9edf2;font:16px sans-serif;color:#17283b}main{display:grid;grid-template-columns:1fr 1fr;gap:12px;padding:12px}section{background:white;border-radius:8px;overflow:hidden}h3{margin:12px;font-size:16px}canvas{display:block;width:100%}p{margin:12px;font-size:12px}</style><main></main><script type="module">
|
|
58
58
|
import * as T from '/three.module.js';
|
|
@@ -79,7 +79,7 @@ try{
|
|
|
79
79
|
browser=await chromium.launch({headless:true,executablePath:'/Applications/Google Chrome.app/Contents/MacOS/Google Chrome'});
|
|
80
80
|
const page=await browser.newPage({viewport:{width:1328,height:990},deviceScaleFactor:1});const errors=[];page.on('pageerror',e=>errors.push(String(e)));
|
|
81
81
|
await page.goto('http://127.0.0.1:'+server.address().port);await page.waitForFunction(()=>window.ready);
|
|
82
|
-
const screenshot='/private/tmp/figure-
|
|
82
|
+
const screenshot='/private/tmp/figure-full-'+(isCollision?'collision':isPayload?'payload':isForklift?'forklift':isRobot?'robot':isConveyor?'conveyor':'dryroom')+'.png';
|
|
83
83
|
await page.screenshot({path:screenshot,fullPage:true});
|
|
84
84
|
console.log(JSON.stringify({...await page.evaluate(()=>({results:window.results,comparison:window.comparison})),errors,screenshot},null,2));
|
|
85
85
|
if(errors.length)process.exitCode=1;
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import {test} from 'node:test'
|
|
2
2
|
import assert from 'node:assert/strict'
|
|
3
|
-
import {repeatedBinding} from './
|
|
4
|
-
import {compileCapabilities} from './
|
|
5
|
-
import {compileDocument,parseDocument,serializeDocument} from './
|
|
6
|
-
import {defaults} from './
|
|
3
|
+
import {repeatedBinding} from './repeated-binding.mjs'
|
|
4
|
+
import {compileCapabilities} from './capability-plan.mjs'
|
|
5
|
+
import {compileDocument,parseDocument,serializeDocument} from './document.mjs'
|
|
6
|
+
import {defaults} from './full-conveyor.mjs'
|
|
7
7
|
import Ajv from '../../../things-factory/node_modules/ajv/lib/ajv.js'
|
|
8
8
|
import fs from 'node:fs'
|
|
9
9
|
const near=(a,b)=>assert.ok(Math.abs(a-b)<1e-7)
|
|
@@ -36,8 +36,8 @@ test('reference origin rejects foreign feature/member, animated index, wrong bin
|
|
|
36
36
|
]){const s=repeatedBinding();edit(s);assert.throws(()=>compileCapabilities(s.model,s.declaration),e=>e.code===code)}
|
|
37
37
|
})
|
|
38
38
|
test('schema/serialization/reorder preserve occurrence identity and deletion behavior',()=>{
|
|
39
|
-
const s=repeatedBinding(),doc={version:'figure-
|
|
40
|
-
const validate=new Ajv().compile(JSON.parse(fs.readFileSync(new URL('./
|
|
39
|
+
const s=repeatedBinding(),doc={version:'figure-prototype-1',model:s.model,capabilities:s.declaration}
|
|
40
|
+
const validate=new Ajv().compile(JSON.parse(fs.readFileSync(new URL('./document.schema.json',import.meta.url))))
|
|
41
41
|
assert.ok(validate(doc),JSON.stringify(validate.errors))
|
|
42
42
|
const restored=parseDocument(serializeDocument(doc));restored.model.nodes.reverse()
|
|
43
43
|
const a=compileDocument(doc).evaluate(args),b=compileDocument(restored).evaluate(args)
|
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
// Run npm run build first. Exercises emitted ESM in Chrome, not a Node polyfill.
|
|
2
2
|
import {readFile} from 'node:fs/promises'
|
|
3
3
|
import assert from 'node:assert/strict'
|
|
4
|
-
import {sampleAsset} from './
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
4
|
+
import {sampleAsset} from './asset-samples.mjs'
|
|
5
|
+
import {compileFigureGraph} from '../../src/graph.ts'
|
|
6
|
+
import {compileFigureAsset} from '../../src/asset.ts'
|
|
7
7
|
import {chromium} from '/Users/super/.cache/codex-runtimes/codex-primary-runtime/dependencies/node/node_modules/playwright/index.mjs'
|
|
8
8
|
const url=source=>'data:text/javascript;base64,'+Buffer.from(source).toString('base64')
|
|
9
|
-
const contract=url(await readFile(new URL('../../dist/
|
|
10
|
-
const source=await readFile(new URL('../../dist/
|
|
11
|
-
assert.ok(source.includes('./
|
|
12
|
-
const entry=url(source.replace('./
|
|
13
|
-
const graphSource=await readFile(new URL('../../dist/
|
|
14
|
-
const graphEntry=url(graphSource.replace('./
|
|
9
|
+
const contract=url(await readFile(new URL('../../dist/contract.js',import.meta.url),'utf8'))
|
|
10
|
+
const source=await readFile(new URL('../../dist/json.js',import.meta.url),'utf8')
|
|
11
|
+
assert.ok(source.includes('./contract.js'))
|
|
12
|
+
const entry=url(source.replace('./contract.js',contract))
|
|
13
|
+
const graphSource=await readFile(new URL('../../dist/graph.js',import.meta.url),'utf8')
|
|
14
|
+
const graphEntry=url(graphSource.replace('./contract.js',contract))
|
|
15
15
|
const modules=new Map()
|
|
16
16
|
async function moduleUrl(name){
|
|
17
17
|
if(modules.has(name))return modules.get(name)
|
|
@@ -22,34 +22,34 @@ async function moduleUrl(name){
|
|
|
22
22
|
}
|
|
23
23
|
const entry=url(code);modules.set(name,entry);return entry
|
|
24
24
|
}
|
|
25
|
-
const assetEntry=await moduleUrl('
|
|
26
|
-
const workspaceEntry=await moduleUrl('
|
|
27
|
-
const createEntry=await moduleUrl('
|
|
25
|
+
const assetEntry=await moduleUrl('asset.js')
|
|
26
|
+
const workspaceEntry=await moduleUrl('editor-workspace.js')
|
|
27
|
+
const createEntry=await moduleUrl('create.js')
|
|
28
28
|
const browser=await chromium.launch({headless:true,executablePath:'/Applications/Google Chrome.app/Contents/MacOS/Google Chrome'})
|
|
29
29
|
try{
|
|
30
30
|
const page=await browser.newPage()
|
|
31
31
|
const result=await page.evaluate(async entry=>{
|
|
32
32
|
const module=await import(entry)
|
|
33
|
-
const value=module.
|
|
33
|
+
const value=module.parseFigureJson('{"name":"드라이룸 😀"}')
|
|
34
34
|
let duplicate
|
|
35
|
-
try{module.
|
|
36
|
-
return {buffer:typeof globalThis.Buffer,process:typeof globalThis.process,value,bytes:module.
|
|
35
|
+
try{module.parseFigureJson('{"a":1,"\\u0061":2}')}catch(e){duplicate=e.code}
|
|
36
|
+
return {buffer:typeof globalThis.Buffer,process:typeof globalThis.process,value,bytes:module.figureUtf8ByteLength('드라이룸 😀'),duplicate}
|
|
37
37
|
},entry)
|
|
38
38
|
assert.deepEqual(result,{buffer:'undefined',process:'undefined',value:{name:'드라이룸 😀'},bytes:17,duplicate:'JSON_DUPLICATE_KEY'})
|
|
39
39
|
console.log(JSON.stringify(result,null,2))
|
|
40
40
|
for(const kind of ['dryroom','conveyor','robot','forklift']){
|
|
41
41
|
const asset=sampleAsset(kind),model=asset.document.model,inputs={...asset.designInputs,...asset.stateDefaults}
|
|
42
|
-
const expected=
|
|
43
|
-
const actual=await page.evaluate(async({entry,model,inputs})=>(await import(entry)).
|
|
42
|
+
const expected=compileFigureGraph(model).evaluate(inputs)
|
|
43
|
+
const actual=await page.evaluate(async({entry,model,inputs})=>(await import(entry)).compileFigureGraph(model).evaluate(inputs),{entry:graphEntry,model,inputs})
|
|
44
44
|
// JSON normalizes -0 across the browser transport, not meaningful to the geometry contract.
|
|
45
45
|
assert.deepEqual(JSON.parse(JSON.stringify(actual)),JSON.parse(JSON.stringify(expected)))
|
|
46
46
|
console.log(kind+': browser/server values and geometry match; '+actual.geometry.length+' meshes')
|
|
47
|
-
const restored=await page.evaluate(async({entry,text})=>{const m=await import(entry);return m.
|
|
48
|
-
assert.deepEqual(JSON.parse(JSON.stringify(restored)),JSON.parse(JSON.stringify(
|
|
47
|
+
const restored=await page.evaluate(async({entry,text})=>{const m=await import(entry);return m.compileFigureAsset(m.parseFigureAsset(text)).evaluate()},{entry:assetEntry,text:JSON.stringify(asset)})
|
|
48
|
+
assert.deepEqual(JSON.parse(JSON.stringify(restored)),JSON.parse(JSON.stringify(compileFigureAsset(asset).evaluate())))
|
|
49
49
|
console.log(kind+': serialized asset, materials, palette and capability bindings match')
|
|
50
50
|
}
|
|
51
51
|
const editing=await page.evaluate(async({entry,forklift,robot})=>{
|
|
52
|
-
const w=(await import(entry)).
|
|
52
|
+
const w=(await import(entry)).createFigureEditorWorkspace(),first=w.open(forklift)
|
|
53
53
|
const edit=(revision,value)=>({context:first.context,origin:'ai',expectedRevision:revision,changes:[{kind:'set-design',input:'forkLength',unit:'mm',value}]})
|
|
54
54
|
const before=w.read();w.preview(edit(0,1275));const previewUnchanged=JSON.stringify(w.read())===JSON.stringify(before)
|
|
55
55
|
w.apply(edit(0,1275));const pending=w.export({context:first.context});w.apply(edit(1,1500))
|
|
@@ -63,14 +63,14 @@ try{
|
|
|
63
63
|
assert.deepEqual(editing,{previewUnchanged:true,staleSave:'REVISION_CONFLICT',revision:4,robotMeshes:10,staleEdit:'CONTEXT_CONFLICT',restored:1500,empty:0})
|
|
64
64
|
console.log(JSON.stringify({browserWorkspace:editing},null,2))
|
|
65
65
|
const authored=await page.evaluate(async({createEntry,assetEntry,workspaceEntry})=>{
|
|
66
|
-
const c=await import(createEntry),a=await import(assetEntry),w=(await import(workspaceEntry)).
|
|
67
|
-
const empty=c.
|
|
68
|
-
const model=c.
|
|
69
|
-
const opened=w.open(a.
|
|
66
|
+
const c=await import(createEntry),a=await import(assetEntry),w=(await import(workspaceEntry)).createFigureEditorWorkspace()
|
|
67
|
+
const empty=c.createFigureAsset('New V3'),emptyCount=a.compileFigureAsset(empty).evaluate().geometry.length
|
|
68
|
+
const model=c.addFigureBox(empty,{id:'gate',size:{x:800,y:2000,z:100},position:{x:0,y:1000,z:0}})
|
|
69
|
+
const opened=w.open(a.serializeFigureAsset(model))
|
|
70
70
|
w.apply({context:opened.context,origin:'ui',expectedRevision:0,changes:[{kind:'set-design',input:'gate.size.y',unit:'mm',value:1500}]})
|
|
71
|
-
const saved=w.export({context:opened.context}),restored=a.
|
|
71
|
+
const saved=w.export({context:opened.context}),restored=a.compileFigureAsset(a.parseFigureAsset(saved.text)).evaluate()
|
|
72
72
|
return {emptyCount,parts:restored.geometry.length,height:restored.geometry[0].shape.dimensions.height}
|
|
73
73
|
},{createEntry,assetEntry,workspaceEntry})
|
|
74
74
|
assert.deepEqual(authored,{emptyCount:0,parts:1,height:1500})
|
|
75
|
-
console.log(JSON.stringify({
|
|
75
|
+
console.log(JSON.stringify({newFigureAuthoring:authored}))
|
|
76
76
|
}finally{await browser.close()}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// Read-only design probes against checked-in product samples. NOT a
|
|
1
|
+
// Read-only design probes against checked-in product samples. NOT a renderer.
|
|
2
2
|
import fs from 'node:fs'
|
|
3
3
|
import { createHash } from 'node:crypto'
|
|
4
4
|
import assert from 'node:assert/strict'
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {test} from 'node:test'
|
|
2
2
|
import assert from 'node:assert/strict'
|
|
3
|
-
import {compile,ContractError} from './
|
|
3
|
+
import {compile,ContractError} from './typed-plan.mjs'
|
|
4
4
|
const near=(a,b)=>assert.ok(Number.isFinite(a)&&Math.abs(a-b)<1e-8,`${a} != ${b}`)
|
|
5
5
|
const equal=(a,b)=>a.forEach((v,i)=>near(v,b[i]))
|
|
6
6
|
const c=(id,value,unit='mm')=>({id,value,unit})
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import assert from 'node:assert/strict'
|
|
2
2
|
import {test} from 'node:test'
|
|
3
|
-
import {compile,ContractError} from './
|
|
3
|
+
import {compile,ContractError} from './typed-plan.mjs'
|
|
4
4
|
const near=(a,b)=>assert.ok(Math.abs(a-b)<1e-8,`${a} != ${b}`)
|
|
5
5
|
const c=(id,value,unit='mm')=>({id,value,unit})
|
|
6
6
|
function model(){return {version:'r3-scalar-1',inputs:[{id:'width',unit:'cm',min:1,max:1000}],constants:[c('zero',0),c('margin',10),c('radius',48)],nodes:[
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import fs from 'node:fs'
|
|
2
2
|
import {test} from 'node:test'
|
|
3
3
|
import assert from 'node:assert/strict'
|
|
4
|
-
import {compile} from './
|
|
5
|
-
import {meshOf,meshAudit} from './
|
|
4
|
+
import {compile} from './typed-plan.mjs'
|
|
5
|
+
import {meshOf,meshAudit} from './dryroom-mesh.mjs'
|
|
6
6
|
const seeds=JSON.parse(fs.readFileSync(new URL('../../../operato-application/packages/operato-figure/server/seed/figure-samples.json',import.meta.url)))
|
|
7
7
|
const c=(id,value,unit='mm')=>({id,value,unit})
|
|
8
8
|
const n=(id,op,args,outputs,params)=>({id,op,args,outputs,...(params?{params}:{})})
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
# 반복 요소의 기능/표면 참조 — 실험 검증
|
|
2
2
|
|
|
3
|
-
> 현재 구현·검증·제품 연결 상태는 [
|
|
3
|
+
> 현재 구현·검증·제품 연결 상태는 [구현·검증 현황](status.md)을 따른다. 본문의 단계별 연구/검증 기록은 제품 전체 완료 선언이 아니다.
|
|
4
4
|
|
|
5
5
|
## 이번 구현
|
|
6
6
|
|
|
7
7
|
전체 컨베이어의 반복 롤러를 선택하고 그 실제 끝면을 binding pose와 contact 후보로 사용할 수 있도록 했다. 반복 template를 별도 메시로 만들거나 선택한 항목을 한 번 더 렌더링하지 않는다.
|
|
8
8
|
|
|
9
|
-
- [예제](prototypes/
|
|
10
|
-
- [테스트](prototypes/
|
|
11
|
-
- [capability compiler](prototypes/
|
|
9
|
+
- [예제](prototypes/repeated-binding.mjs)
|
|
10
|
+
- [테스트](prototypes/repeated-binding.test.mjs)
|
|
11
|
+
- [capability compiler](prototypes/capability-plan.mjs)
|
|
12
12
|
|
|
13
13
|
현재 선언 버전은 `r3-capability-3`이다. pose는 기존 transform 출력 ID 또는 `{placement, feature}` 중 하나다. 후자는 실제 표면 출처 검사와 같은 경로로 처리한다. V1/V2 입력은 묵시적으로 바꾸지 않고 거부한다. 제품 데이터 마이그레이션을 수행한 것은 아니다.
|
|
14
14
|
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
# Figure v3 선행 연구 검토와 채택 판단
|
|
2
2
|
|
|
3
|
-
> 현재 구현·검증·제품 연결 상태는 [
|
|
3
|
+
> 현재 구현·검증·제품 연결 상태는 [구현·검증 현황](status.md)을 따른다. 본문의 단계별 연구/검증 기록은 제품 전체 완료 선언이 아니다.
|
|
4
4
|
|
|
5
5
|
2026-09-20 · 1차 원문/공식 문서 검토.
|
|
6
6
|
**문헌 검토이며 재현 실험 완료가 아니다. r1/r2도 아직 채택하지 않는다.**
|
|
7
7
|
|
|
8
|
-
후속 진행: [ShapeAssembly 공개 interpreter의 10개 격리 실행 기록](
|
|
8
|
+
후속 진행: [ShapeAssembly 공개 interpreter의 10개 격리 실행 기록](shapeassembly-reproduction.md).
|
|
9
9
|
이 문서의 문헌 기반 비교와 실제 실행 결과를 구분한다. 논문 benchmark 재현은 아직 아니다.
|
|
10
10
|
|
|
11
11
|
## 1. 결론
|
|
@@ -12,12 +12,12 @@ figure-model 0.1.32 (`54d30c2`) 기준. 문서를 읽고 판단한 것이 아니
|
|
|
12
12
|
|
|
13
13
|
### 구현이 하나다
|
|
14
14
|
|
|
15
|
-
프로토타입이 별도 구현을 들고 있지 않다. `docs/prototypes/
|
|
16
|
-
`src/
|
|
15
|
+
프로토타입이 별도 구현을 들고 있지 않다. `docs/prototypes/typed-plan.mjs` 는 세 줄이고
|
|
16
|
+
`src/graph.ts` 를 다시 내보낸다. 실험 143 개가 **제품 소스를 시험하고 있다.**
|
|
17
17
|
|
|
18
18
|
```
|
|
19
19
|
src/v3-*.ts 13 모듈 · 2,266 줄(시험 포함)
|
|
20
|
-
index.ts 10 개를 내보낸다 —
|
|
20
|
+
index.ts 10 개를 내보낸다 — compileFigureGraph · createFigureAsset · …
|
|
21
21
|
npm test 461 통과 · 0 빨강
|
|
22
22
|
node --test docs/prototypes/v3-*.test.mjs 143 통과 · 0 빨강
|
|
23
23
|
```
|
|
@@ -44,7 +44,7 @@ CYCLE: a: a -> b -> a
|
|
|
44
44
|
|
|
45
45
|
### 현황 문서가 정직하다
|
|
46
46
|
|
|
47
|
-
`
|
|
47
|
+
`status.md` 가 격리 UI 의 성공을 제품 배포로 적지 않고, 「소스 455 통과」가 V3 기능 수가
|
|
48
48
|
아니라고 먼저 밝힌다. 오늘 이 집이 여러 번 틀린 자리를 그쪽은 안 틀렸다.
|
|
49
49
|
|
|
50
50
|
## 2. 위험 — 위험 순
|
|
@@ -53,12 +53,12 @@ CYCLE: a: a -> b -> a
|
|
|
53
53
|
|
|
54
54
|
**V2 → V3 변환기가 없다.** 이름으로도 동작으로도 찾지 못했다.
|
|
55
55
|
|
|
56
|
-
`
|
|
56
|
+
`cutover.md` 는 「기존 자산도 V3 기준으로 변환하거나 재작성한다」고 적는데, **변환**에
|
|
57
57
|
해당하는 것이 없고 재작성만 있다. 네 대표 자산(드라이룸·컨베이어·로봇암·포크리프트)은
|
|
58
58
|
V2 seed 를 읽어 **결과를 견주는 용도**로 쓰고, V3 쪽은 손으로 적은 그래프다.
|
|
59
59
|
|
|
60
60
|
```js
|
|
61
|
-
// docs/prototypes/
|
|
61
|
+
// docs/prototypes/full-conveyor.mjs — 컨베이어 하나가 이 밀도로 60 줄
|
|
62
62
|
add('endX','halfLength',-60); add('legX','halfLength',-260); add('frameZ','halfWidth',-18)
|
|
63
63
|
```
|
|
64
64
|
|
|
@@ -78,7 +78,7 @@ ADR-0044 와 ADR-0051 이 닫은 문 셋이 V3 소스에 없다.
|
|
|
78
78
|
| `FIGURE_CAPABILITIES` 닫힌 목록 (ADR-0051 ④) | 0 | 0 |
|
|
79
79
|
| 파라미터 `range` | 0 | 1 |
|
|
80
80
|
|
|
81
|
-
`src/
|
|
81
|
+
`src/capabilities.ts` 는 있지만 **다른 것을 본다** — 표면 소유권과 수용 조건이다. 능력
|
|
82
82
|
이름은 `name()` 이 「빈 문자열이 아니면 통과」로 받는다. **`capabilities: ['hoist']` 가
|
|
83
83
|
V3 에서 다시 지나간다.** 그 구멍은 09-16 에 닫은 것이고, 닫기 전에는 검증과 발행을 지나
|
|
84
84
|
렌더링에서 죽었다.
|
|
@@ -88,7 +88,7 @@ V3 에서 다시 지나간다.** 그 구멍은 09-16 에 닫은 것이고, 닫
|
|
|
88
88
|
|
|
89
89
|
### ③ 지금 V3 를 저작할 길은 그래프 코드뿐이다
|
|
90
90
|
|
|
91
|
-
`
|
|
91
|
+
`status.md` 의 남은 작업이 「다른 primitive 추가, 삭제·재질·관계 편집」이다. 지금 서 있는
|
|
92
92
|
것은 빈 자산과 상자 하나다. 설계는 모델러와 AI 가 template 으로 이 식을 만든다고 하는데,
|
|
93
93
|
**그 template 이 아직 없다.**
|
|
94
94
|
|
|
@@ -105,7 +105,7 @@ V3 에서 다시 지나간다.** 그 구멍은 09-16 에 닫은 것이고, 닫
|
|
|
105
105
|
|
|
106
106
|
### ⑤ `Dynamic = any` 가 커널 디스패치 전체
|
|
107
107
|
|
|
108
|
-
`src/
|
|
108
|
+
`src/graph.ts` 에 17 자리다. 저자가 TODO 로 남겼고 현황 문서도 「내부 Dynamic 경계 축소」로
|
|
109
109
|
적어 두었다. 공개 API 는 타입이 있고 경계에서 검사하므로 **부채이지 결함은 아니다.**
|
|
110
110
|
|
|
111
111
|
## 3. 다음 한 걸음
|
|
@@ -124,4 +124,4 @@ V3 에서 다시 지나간다.** 그 구멍은 09-16 에 닫은 것이고, 닫
|
|
|
124
124
|
|
|
125
125
|
- 렌더링 결과의 시각 품질. 브라우저 확인은 저자가 했고 나는 다시 안 봤다.
|
|
126
126
|
- 성능. 자산 500 개 규모에서의 평가 비용은 재지 않았다.
|
|
127
|
-
- `
|
|
127
|
+
- `layout-system.md` 의 Flex/Grid 계약. 설계 문서만 있고 실측 안 했다.
|
|
@@ -1,25 +1,25 @@
|
|
|
1
1
|
# V3 런타임 정식 소스 이관 — 그래프·capability·자산
|
|
2
2
|
|
|
3
|
-
> 현재 구현·검증·제품 연결 상태는 [
|
|
3
|
+
> 현재 구현·검증·제품 연결 상태는 [구현·검증 현황](status.md)을 따른다. 본문의 단계별 연구/검증 기록은 제품 전체 완료 선언이 아니다.
|
|
4
4
|
|
|
5
|
-
> 최신 작업 기준: [V3 단일 체계 전환](
|
|
5
|
+
> 최신 작업 기준: [V3 단일 체계 전환](cutover.md). 아래의 버전별 제품 연결 방향은 과거 작업 기록이며, 향후 설계 조건에서 제외한다.
|
|
6
6
|
|
|
7
7
|
## 이번 이관 범위
|
|
8
8
|
|
|
9
|
-
실험용 JSON 입력 검사와 오류 계약을 `src/
|
|
9
|
+
실험용 JSON 입력 검사와 오류 계약을 `src/json.ts`, `src/contract.ts`의 strict TypeScript 소스로 옮겼다. 기본 빌드에서 JS·타입 선언을 생성하며 기존 package 루트에서 이름이 구분된 API로 내보낸다. package.json·의존성은 변경하지 않았다.
|
|
10
10
|
|
|
11
11
|
| 공개 API | 책임 |
|
|
12
12
|
|---|---|
|
|
13
|
-
|
|
|
14
|
-
|
|
|
15
|
-
|
|
|
16
|
-
|
|
|
13
|
+
| parseFigureJson | JSON 문법, 중복 키, 크기·깊이 제한, 유한 수 검사 |
|
|
14
|
+
| assertFigureJson | JS 객체의 순환, getter, 숨은 속성, symbol, 희소 배열 등 손실 직렬화 거부 |
|
|
15
|
+
| figureUtf8ByteLength | 브라우저와 서버의 동일 UTF-8 바이트 계산 |
|
|
16
|
+
| FigureContractError | code/path를 가진 공통 오류 |
|
|
17
17
|
|
|
18
18
|
**parseV3Json은 모델 의미 검증기가 아니다.** JSON 형식만 올바르면 V3 자산이 아닌 객체도 읽는다. V3 자산 버전·단위·그래프·appearance 검사는 여전히 자산 컴파일러가 담당한다. 공개된 이름이 전체 V3 지원이나 안정화 완료를 뜻하지 않는다.
|
|
19
19
|
|
|
20
20
|
## 단일 구현 유지
|
|
21
21
|
|
|
22
|
-
`docs/prototypes/
|
|
22
|
+
`docs/prototypes/document.mjs`는 새 모듈을 import/re-export한다. 원래 JSON 검사 구현은 제거했다. `typed-plan.mjs`의 ContractError도 정식 V3ContractError를 다시 내보낸다. 따라서 기존 실험 테스트도 이관된 코드와 같은 오류 타입을 사용한다.
|
|
23
23
|
|
|
24
24
|
문서·자산의 Buffer.byteLength를 TextEncoder 기반 계산으로 대체했다. 생산 소스에는 docs import, 절대경로, Node 내장 모듈 import가 없다. 실험 도구가 src에 의존하는 방향이며 역방향은 없다.
|
|
25
25
|
|
|
@@ -30,15 +30,15 @@
|
|
|
30
30
|
- `npm test`: 당시 소스 전체와 새 입력 경계 검사 포함 **442개 통과**.
|
|
31
31
|
- `node --test docs/prototypes/v3-*.test.mjs`: **143개 통과**.
|
|
32
32
|
- `npm run build`: 성공, JS와 타입 선언 생성.
|
|
33
|
-
- `node docs/prototypes/
|
|
33
|
+
- `node docs/prototypes/runtime-browser.mjs`: 실제 Chrome에서 빌드된 ESM 실행 성공. Buffer/process가 없는 상태에서 한글·이모지 UTF-8 계산과 이스케이프 중복 키 거부 확인.
|
|
34
34
|
|
|
35
35
|
브라우저 테스트는 생성된 두 모듈을 data URL로 로드하며 의존 URL만 치환한다. Node 폴리필을 주입하지 않는다. 이 테스트는 입력 런타임 검사이며 모델러 캔버스 통합 테스트가 아니다.
|
|
36
36
|
|
|
37
37
|
## 그래프 평가기 이관
|
|
38
38
|
|
|
39
|
-
`src/
|
|
39
|
+
`src/graph.ts`에 기존 평가기 전체를 옮기고 루트 API에 `compileFigureGraph`를 추가했다. `src/graph-types.ts`는 입력/상수/노드, 단위·차원, 좌표계 타입, 형상·배치, 평가 결과와 컴파일된 계획의 공개 타입을 정의한다.
|
|
40
40
|
|
|
41
|
-
실험 진입점 `docs/prototypes/
|
|
41
|
+
실험 진입점 `docs/prototypes/typed-plan.mjs`는 두 export만 남긴 호환 어댑터다. 단위 계산·위상 정렬·좌표계 검사·형상 생성·반복 배치의 구현을 두 벌 유지하지 않는다. 기존 연산자 버전과 실패 코드를 유지했다.
|
|
42
42
|
|
|
43
43
|
추가 검증:
|
|
44
44
|
|
|
@@ -57,10 +57,10 @@
|
|
|
57
57
|
|
|
58
58
|
| 소스 | 공개 API |
|
|
59
59
|
|---|---|
|
|
60
|
-
|
|
|
61
|
-
|
|
|
62
|
-
|
|
|
63
|
-
|
|
|
60
|
+
| capabilities.ts | compileFigureCapabilities |
|
|
61
|
+
| document.ts | compileFigureDocument, parseFigureDocument, serializeFigureDocument |
|
|
62
|
+
| asset.ts | compileFigureAsset, parseFigureAsset, serializeFigureAsset, captureFigureAuthoredInputs |
|
|
63
|
+
| asset-types.ts | 문서·자산·재질·binding 선언 및 평가 결과 타입 |
|
|
64
64
|
|
|
65
65
|
버전 식별자는 기존 실험 버전을 유지한다. 정식 소스에 포함되었다고 파일 포맷 안정화나 제품 저장 허용을 선언하지 않는다. package.json은 변경하지 않았다.
|
|
66
66
|
|
|
@@ -78,7 +78,7 @@
|
|
|
78
78
|
|
|
79
79
|
## 편집 트랜잭션·workspace 이관
|
|
80
80
|
|
|
81
|
-
`src/
|
|
81
|
+
`src/authoring-session.ts`와 `src/editor-workspace.ts`를 추가했다. 패키지 루트에서 `createFigureAuthoringSession`, `createFigureEditorWorkspace`와 요청·반환 타입을 제공한다. 기존 실험 파일 두 개는 re-export만 남겼다. 이번 두 모듈은 `any` 없이 기존 strict 설정으로 검사한다. 하위 평가기의 내부 Dynamic 경계까지 제거한 것은 아니다.
|
|
82
82
|
|
|
83
83
|
유지한 편집 계약:
|
|
84
84
|
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
# v3 샘플 검증 확대 — 16종
|
|
2
2
|
|
|
3
|
-
> 현재 구현·검증·제품 연결 상태는 [
|
|
3
|
+
> 현재 구현·검증·제품 연결 상태는 [구현·검증 현황](status.md)을 따른다. 본문의 단계별 연구/검증 기록은 제품 전체 완료 선언이 아니다.
|
|
4
4
|
|
|
5
|
-
2026-09-20. [1차 검사](
|
|
5
|
+
2026-09-20. [1차 검사](sample-validation.md)의 후속이다.
|
|
6
6
|
**당시 기존 함수 검사 / 명시한 v3 의도 후보 계산 / 기구학 수치 실험**을 구별한다.
|
|
7
7
|
테스트가 통과했다는 것은 아래 관찰이 재현됐다는 뜻이며, 결함이 해결됐다는 뜻이 아니다.
|
|
8
8
|
제품 소스, 서버, 원본 샘플을 변경하지 않았다.
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
|
|
17
17
|
```sh
|
|
18
18
|
# figure-model 루트, Node 25.6.0
|
|
19
|
-
node --test docs/prototypes/
|
|
19
|
+
node --test docs/prototypes/samples.test.mjs docs/prototypes/more-samples.test.mjs
|
|
20
20
|
```
|
|
21
21
|
|
|
22
22
|
- 모델 관련 검사 18개 통과(기존 5 + 추가 13).
|
|
@@ -99,8 +99,8 @@ v3는 명시한 접촉·containment·간극 assertion을 검사해야 하며,
|
|
|
99
99
|
1. 반복 의도·생성 단계·안정된 참조의 한 계약으로 두 반복 유형 처리.
|
|
100
100
|
2. geometry feature와 dimension 공유로 바닥·부착·개구부의 실제 일치 보장.
|
|
101
101
|
3. 원형/타원형, 상태 기반 형상 변화의 provider 계약 및 정의역.
|
|
102
|
-
4. 각 샘플 전체를 공통
|
|
102
|
+
4. 각 샘플 전체를 공통 evaluator로 변환해 크기/상태/반복을 함께 변경하는 시험.
|
|
103
103
|
5. renderer 외형 차분, 충돌/메시 검사, 성능 측정과 사용자 편집 흐름 검증.
|
|
104
104
|
|
|
105
105
|
이번 확대는 일부 새 모델을 수식에 대입하는 것에 그치지 않고 기존 사이징 함수를 재사용해
|
|
106
|
-
현행 동작을 측정했다. 그러나 완성된
|
|
106
|
+
현행 동작을 측정했다. 그러나 완성된 evaluator의 성공으로 포장하지 않는다.
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
# v3 실제 샘플 대입 검증 — 2026-09-20
|
|
2
2
|
|
|
3
|
-
> 현재 구현·검증·제품 연결 상태는 [
|
|
3
|
+
> 현재 구현·검증·제품 연결 상태는 [구현·검증 현황](status.md)을 따른다. 본문의 단계별 연구/검증 기록은 제품 전체 완료 선언이 아니다.
|
|
4
4
|
|
|
5
|
-
후속: [제품 시드 전체 + fixture 2종, 총 16종 확대 검증](
|
|
5
|
+
후속: [제품 시드 전체 + fixture 2종, 총 16종 확대 검증](sample-validation-expanded.md).
|
|
6
6
|
|
|
7
7
|
## 판정
|
|
8
8
|
|
|
@@ -25,7 +25,7 @@
|
|
|
25
25
|
figure-model 루트, Node 25.6.0:
|
|
26
26
|
|
|
27
27
|
```sh
|
|
28
|
-
node --test docs/prototypes/
|
|
28
|
+
node --test docs/prototypes/samples.test.mjs
|
|
29
29
|
```
|
|
30
30
|
|
|
31
31
|
5개 검사 통과. 아래의 제한적 수치 불변량에 대한 통과이지 시각 품질 인증이 아니다.
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
#
|
|
1
|
+
# shape-dimension contract — per-axis radii, elliptic sections, and dimensions that follow state
|
|
2
2
|
|
|
3
|
-
Status: **contract, fixed 2026-09-22 by the
|
|
3
|
+
Status: **contract, fixed 2026-09-22 by the designer** (ADR-0087, stage-review rulings 3 and 5). §1 (per-axis
|
|
4
4
|
dimensions) implemented the same day: `cylinder-shape@2`, `rounded-box@2`, `hollow-box@2`, and the sampler reading
|
|
5
5
|
them. §2–3 implemented the same night: dependence on state is tracked per value in the
|
|
6
6
|
compiler and printed as `dependence` beside `outputTypes`; every operator carries a `state` policy (`follows` or
|
|
7
7
|
`refuses`; an operator without one fails with `STATE_POLICY`); `occupancy.extent` may not depend on state
|
|
8
|
-
(`OCCUPANCY_STATE`); `
|
|
8
|
+
(`OCCUPANCY_STATE`); `inspectFigureAsset` covers the state range and reports `proven` (corners; no state-dependent
|
|
9
9
|
rotation), `sampled` (a rotation depends on state; corners plus per-input sweeps, step stated, not a proof) or
|
|
10
10
|
`defaults` (one state, as asked). The `bounded` method of §3 (swept envelope) is not implemented; such assets report
|
|
11
11
|
`sampled`. This is one rule for what a shape's dimensions are and what they may depend on. It is not three
|
|
@@ -72,7 +72,7 @@ actual shape dimension") made concrete. A dimension that scales with a state inp
|
|
|
72
72
|
Every value carries, next to its unit or frame, a **dependence set**: which state inputs its value can change with.
|
|
73
73
|
Inputs of role `state` start with `{self}`; constants and design inputs with `∅`; every operator's outputs carry the
|
|
74
74
|
union of its arguments' sets, unless the operator's contract says otherwise. This is the existing `stateful`
|
|
75
|
-
tracking in `
|
|
75
|
+
tracking in `compileFigureGraph`, made a first-class part of the type and printed in `outputTypes`.
|
|
76
76
|
|
|
77
77
|
### Every consuming operator declares its policy
|
|
78
78
|
|
|
@@ -92,7 +92,7 @@ declared occupancy is a state-independent contract; structure- and cost-changing
|
|
|
92
92
|
## 3. The occupancy holds over the whole valid state range
|
|
93
93
|
|
|
94
94
|
`occupancy` is the contract a board's placement relies on (ADR-0087 decision 7). A volume that is true at the
|
|
95
|
-
default state and false at another is not that contract. So `
|
|
95
|
+
default state and false at another is not that contract. So `inspectFigureAsset` answers for the **whole** valid state
|
|
96
96
|
range, and says how it knows:
|
|
97
97
|
|
|
98
98
|
| how the geometry depends on state | how the check is done | what the report says |
|
|
@@ -148,18 +148,18 @@ range, and says how it knows:
|
|
|
148
148
|
|
|
149
149
|
| 목록 | 무엇이 들어가는가 | 누가 쓰는가 |
|
|
150
150
|
| --- | --- | --- |
|
|
151
|
-
| `
|
|
152
|
-
| `
|
|
151
|
+
| `figureWorldBoxesOf` | 그리는 몸통만 (`visible === false` 제외) | renderer |
|
|
152
|
+
| `figureOccupiedBoxesOf` | 놓인 몸통 전부 (숨긴 것 포함) | occupancy 검사 |
|
|
153
153
|
|
|
154
|
-
## When `proven` may be said (added 2026-09-23, after two counterexamples from the
|
|
154
|
+
## When `proven` may be said (added 2026-09-23, after two counterexamples from the designer)
|
|
155
155
|
|
|
156
156
|
`proven` means the gate evaluated the corners of the state box and nothing else. That is only a proof when every
|
|
157
157
|
coordinate the figure draws takes its extreme at a corner, and the property that guarantees it is **multilinearity**:
|
|
158
158
|
degree one in each state input, holding the others fixed. A multilinear value stays multilinear however it is
|
|
159
159
|
combined, which is why it can be built up through a whole figure.
|
|
160
160
|
|
|
161
|
-
Every operator in the kernel is classified by name in `
|
|
162
|
-
a test compares that list against `
|
|
161
|
+
Every operator in the kernel is classified by name in `FIGURE_STATE_EXTREME_BASIS`, with no pattern and no default, and
|
|
162
|
+
a test compares that list against `FIGURE_OPERATORS`: a new operator is unclassified, and unclassified is `unknown`.
|
|
163
163
|
|
|
164
164
|
`multilinear`, under the conditions the gate checks: `add@1`; `mul@1` when no two arguments depend on the same state
|
|
165
165
|
input; `div@1` by a state-free denominator; `rigid@1` when no rotation angle depends on state; `axis-slide@1` when the
|
|
@@ -197,7 +197,7 @@ coverage, not correctness: the asset falls back to `sampled`, which states its s
|
|
|
197
197
|
`proven` is about one thing: every part stays inside the declared volume. Whether the figure touches the plane it
|
|
198
198
|
is mounted on is the *smallest* gap over its parts, and a smallest folds the way `min@1` folds. Two boxes at 20q
|
|
199
199
|
and 20(1−q) mm above the floor each touch it at one end of q and both float 10 mm in the middle, with every
|
|
200
|
-
coordinate linear in q (
|
|
200
|
+
coordinate linear in q (designer's counterexample, 2026-09-23). The corners were extremal and the gate still
|
|
201
201
|
missed it.
|
|
202
202
|
|
|
203
203
|
Reading it as the lowest point of the figure was no better: a box hanging entirely below the plane passed, because
|
|
@@ -216,7 +216,7 @@ figure is fastened. It is not read off `occupancy.bounds.y.max`: that moved the
|
|
|
216
216
|
someone widened the volume it takes up.
|
|
217
217
|
|
|
218
218
|
So an asset that needs the contact **names the face that makes it** — a placement and a `feature@1` on the same
|
|
219
|
-
shape, read by `
|
|
219
|
+
shape, read by `resolveFigureSurface`, the same reader the capability bindings use. The check is that face against the
|
|
220
220
|
plane, both ways. There is no smallest over parts left to fold, and what remains to ask is whether the face moves: a
|
|
221
221
|
face whose placement does not follow state sits in the same place at every state, so one evaluation settles it, and
|
|
222
222
|
a face that moves sends the asset to sampling, because corner extremality says nothing about an equality holding in
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# ShapeAssembly 공개 구현: 격리 재현 1차
|
|
2
2
|
|
|
3
|
-
> 현재 구현·검증·제품 연결 상태는 [
|
|
3
|
+
> 현재 구현·검증·제품 연결 상태는 [구현·검증 현황](status.md)을 따른다. 본문의 단계별 연구/검증 기록은 제품 전체 완료 선언이 아니다.
|
|
4
4
|
|
|
5
5
|
2026-09-20. 문헌을 읽은 결과가 아니라 공개 interpreter를 직접 실행한 기록.
|
|
6
6
|
**학습 모델/논문 benchmark/실제 Figure 자산의 재현은 아니다.**
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
|
|
11
11
|
- upstream: https://github.com/rkjones4/ShapeAssembly
|
|
12
12
|
- commit: `cc22bd84afb65e8e37c7d14bebd9a4a629b5d943`
|
|
13
|
-
- upstream checkout: `/private/tmp/figure-
|
|
13
|
+
- upstream checkout: `/private/tmp/figure-research.T0vBJG/ShapeAssembly`
|
|
14
14
|
- Python 3.12.14, torch 2.8.0, numpy 2.2.6, faiss-cpu 1.12.0.
|
|
15
15
|
- upstream 파일 수정 없음. `git status --short` 출력 없음 확인.
|
|
16
16
|
- 작성한 것은 외부 interpreter를 호출하고 좌표 잔차를 계산하는 별도 probe다.
|
|
@@ -19,9 +19,9 @@
|
|
|
19
19
|
- 오류가 난 사례만 제외하지 않았다. 10개 모두 실행 종료, 예외 없음.
|
|
20
20
|
|
|
21
21
|
```sh
|
|
22
|
-
/private/tmp/figure-
|
|
22
|
+
/private/tmp/figure-research.T0vBJG/venv/bin/python \
|
|
23
23
|
docs/prototypes/shapeassembly-probe.py \
|
|
24
|
-
/private/tmp/figure-
|
|
24
|
+
/private/tmp/figure-research.T0vBJG/ShapeAssembly
|
|
25
25
|
```
|
|
26
26
|
|
|
27
27
|
환경은 임시 폴더에 있으며 이후 정리될 수 있다.
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
# V3 타입·공간 그래프 통합 실험
|
|
2
2
|
|
|
3
|
-
> 현재 구현·검증·제품 연결 상태는 [
|
|
3
|
+
> 현재 구현·검증·제품 연결 상태는 [구현·검증 현황](status.md)을 따른다. 본문의 단계별 연구/검증 기록은 제품 전체 완료 선언이 아니다.
|
|
4
4
|
|
|
5
|
-
후속: [드라이룸 실제 단면·메시 검증](
|
|
5
|
+
후속: [드라이룸 실제 단면·메시 검증](dryroom-profile-validation.md).
|
|
6
6
|
|
|
7
7
|
상태: r3의 일부 계약 구현. 제품 런타임/정식 schema/전체 자산 변환이 아니다.
|
|
8
|
-
[숫자 타입 계약](
|
|
9
|
-
기존 무단위
|
|
8
|
+
[숫자 타입 계약](operator-contracts.md)의 동일 `compile/evaluate` 실행기를 확장했다.
|
|
9
|
+
기존 무단위 kernel을 따로 호출하거나 좌표를 두 번 계산하지 않는다.
|
|
10
10
|
|
|
11
11
|
## 1. 타입
|
|
12
12
|
|
|
@@ -53,7 +53,7 @@ placement가 만든 world point 사이 거리를 다른 geometry의 길이로
|
|
|
53
53
|
## 3. 실행 검증
|
|
54
54
|
|
|
55
55
|
```sh
|
|
56
|
-
node --test docs/prototypes/
|
|
56
|
+
node --test docs/prototypes/spatial-plan.test.mjs docs/prototypes/typed-plan.test.mjs
|
|
57
57
|
```
|
|
58
58
|
|
|
59
59
|
통합 공간 검사 7개 + 기존 scalar 검사 9개 통과.
|
package/docs/status.md
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
# 구현·검증 현황
|
|
2
|
+
|
|
3
|
+
> 이 파일은 짧은 안내다. 결정은 `operato-application/adr/`(ADR-0087 · ADR-0093 · ADR-0096), 현재 상태는
|
|
4
|
+
> `operato-application/packages/operato-figure/docs/CURRENT_STATUS.md` 가 정본이다.
|
|
5
|
+
|
|
6
|
+
기준일: 2026-09-27.
|
|
7
|
+
|
|
8
|
+
- 모델러·AI·저장·렌더러는 한 형식(`figure-asset-1`)을 쓴다. 옛 형식은 2026-09-26 코드와 명세에서 없앴다.
|
|
9
|
+
- 제품 서버 localhost:3300 은 이 형식으로 돈다(figure-model 0.1.92 · things-scene 10.1.60 · tf 10.1.75).
|
|
10
|
+
- 시험: `npm test`(타입 검사 + `src/*.test.ts`). 부품 지우기·복제의 부작용 시험은
|
|
11
|
+
`src/edit-side-effects.test.ts` — 도형 16 개의 모든 부품을 지우고 복제해 나머지가 그대로인지 본다.
|
|
12
|
+
- 실험 기록: `docs/prototypes/*.test.mjs` 와 날짜가 붙은 `docs/*.md` 는 당시의 기록이다.
|