dazscript-framework 1.0.15 → 1.0.17

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/README.md CHANGED
@@ -501,7 +501,7 @@ The framework ships helpers for common Daz Studio tasks, all importable from `@d
501
501
  |---|---|
502
502
  | `scene-helper` | `getRoot()`, `getSelectedNode()`, `getNodes()` |
503
503
  | `node-helper` | Type checks (`isFigure`, `isBone`), transforms, visibility |
504
- | `property-helper` | Find, read, and adjust node properties |
504
+ | `property-helper` | Set paths, unlock, cast numeric types, and inspect property inputs/outputs |
505
505
  | `array-helper` | `distinct()`, `flatten()`, `groupBy()` |
506
506
  | `string-helper` | Case, trimming, splitting |
507
507
  | `directory-helper` | File and path operations |
File without changes
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dazscript-framework",
3
- "version": "1.0.15",
3
+ "version": "1.0.17",
4
4
  "author": "Freddy Diaz",
5
5
  "license": "MPL-2.0",
6
6
  "description": "",
@@ -0,0 +1,43 @@
1
+ import { beforeEach, describe, expect, it, vi } from 'vitest'
2
+ import { confirm, prompt } from './message-box-helper'
3
+
4
+ vi.mock('@dsf/common/log', () => ({ debug: vi.fn() }))
5
+
6
+ describe('message-box-helper', () => {
7
+ const question = vi.fn()
8
+
9
+ beforeEach(() => {
10
+ question.mockReset()
11
+ vi.stubGlobal('MessageBox', { question })
12
+ })
13
+
14
+ it('treats the first confirm button as ok', () => {
15
+ question.mockReturnValue(0)
16
+
17
+ expect(confirm('Continue?')).toEqual({ ok: true, cancel: false })
18
+ })
19
+
20
+ it('treats the second confirm button as cancel', () => {
21
+ question.mockReturnValue(1)
22
+
23
+ expect(confirm('Continue?')).toEqual({ ok: false, cancel: true })
24
+ })
25
+
26
+ it('treats the first prompt button as cancel so Esc is also cancel', () => {
27
+ question.mockReturnValue(0)
28
+
29
+ expect(prompt('Reset?', 'Reset', 'Zero', 'Default')).toEqual({ cancel: true, selection: -1 })
30
+ })
31
+
32
+ it('maps the second prompt button to the first selection', () => {
33
+ question.mockReturnValue(1)
34
+
35
+ expect(prompt('Reset?', 'Reset', 'Zero', 'Default')).toEqual({ cancel: false, selection: 0 })
36
+ })
37
+
38
+ it('maps the third prompt button to the second selection', () => {
39
+ question.mockReturnValue(2)
40
+
41
+ expect(prompt('Reset?', 'Reset', 'Zero', 'Default')).toEqual({ cancel: false, selection: 1 })
42
+ })
43
+ })
@@ -20,7 +20,7 @@ export const confirm = (message?: string): { ok: boolean, cancel: boolean } => {
20
20
  }
21
21
 
22
22
  export const prompt = (text: string, title: string, button0: string, button1?: string): { cancel: boolean, selection: number } => {
23
- const response = MessageBox.question(text, title, button0, button1 ?? "", "Cancel")
23
+ const response = MessageBox.question(text, title, "Cancel", button0, button1 ?? "")
24
24
 
25
- return { cancel: response === 0, selection: response };
26
- }
25
+ return { cancel: response === 0, selection: response - 1 };
26
+ }
@@ -0,0 +1,94 @@
1
+ import { describe, expect, it, vi } from 'vitest'
2
+ import { getPropertyInputs, getPropertyOutputs } from './property-helper'
3
+
4
+ vi.mock('@dsf/core/global', () => ({
5
+ sceneHelper: {
6
+ getInternalName: vi.fn(),
7
+ getNode: vi.fn(),
8
+ getUniqueMorphName: vi.fn(),
9
+ setInternalName: vi.fn(),
10
+ setPropertyPath: vi.fn()
11
+ }
12
+ }))
13
+
14
+ describe('property-helper relationships', () => {
15
+ const property = (name: string, inheritsTypes: string[] = []) => ({
16
+ name,
17
+ inherits: (type: string) => inheritsTypes.indexOf(type) >= 0,
18
+ getNumControllers: () => 0,
19
+ getController: () => null,
20
+ getNumSlaveControllers: () => 0,
21
+ getSlaveController: () => null,
22
+ getLinkProperty: () => null,
23
+ getFollowProperty: () => null
24
+ }) as any
25
+
26
+ it('gets input properties from normal and redirected controller properties', () => {
27
+ const driver = property('driver')
28
+ const redirectedDriver = property('redirectedDriver')
29
+ const controller = {
30
+ getProperty: () => driver,
31
+ getCurrentProperty: () => redirectedDriver
32
+ }
33
+ const driven = {
34
+ ...property('driven'),
35
+ getNumControllers: () => 1,
36
+ getController: () => controller
37
+ }
38
+
39
+ expect(getPropertyInputs(driven as any)).toEqual([
40
+ { property: driver, controller, source: 'controller' },
41
+ { property: redirectedDriver, controller, source: 'currentController' }
42
+ ])
43
+ })
44
+
45
+ it('gets input properties from direct numeric link and follow properties', () => {
46
+ const link = property('link')
47
+ const follow = property('follow')
48
+ const driven = {
49
+ ...property('driven', ['DzNumericProperty', 'DzFloatProperty']),
50
+ getLinkProperty: () => link,
51
+ getFollowProperty: () => follow
52
+ }
53
+
54
+ expect(getPropertyInputs(driven as any)).toEqual([
55
+ { property: link, controller: null, source: 'link' },
56
+ { property: follow, controller: null, source: 'follow' }
57
+ ])
58
+ })
59
+
60
+ it('gets output properties from slave controller owners', () => {
61
+ const output = property('output')
62
+ const controller = {
63
+ getOwner: () => output
64
+ }
65
+ const driver = {
66
+ ...property('driver'),
67
+ getNumSlaveControllers: () => 1,
68
+ getSlaveController: () => controller
69
+ }
70
+
71
+ expect(getPropertyOutputs(driver as any)).toEqual([
72
+ { property: output, controller, source: 'slaveController' }
73
+ ])
74
+ })
75
+
76
+ it('does not duplicate the same relation', () => {
77
+ const driver = property('driver')
78
+ const controller = {
79
+ getProperty: () => driver,
80
+ getCurrentProperty: () => driver
81
+ }
82
+ const driven = {
83
+ ...property('driven'),
84
+ getNumControllers: () => 2,
85
+ getController: () => controller
86
+ }
87
+
88
+ expect(getPropertyInputs(driven as any)).toEqual([
89
+ { property: driver, controller, source: 'controller' },
90
+ { property: driver, controller, source: 'currentController' }
91
+ ])
92
+ })
93
+
94
+ })
@@ -1,5 +1,19 @@
1
1
  import { sceneHelper } from '@dsf/core/global'
2
2
 
3
+ export type PropertyRelationSource = 'controller' | 'currentController' | 'link' | 'follow' | 'slaveController'
4
+
5
+ /**
6
+ * A property relationship discovered from Daz controller, link, follow, or slave-controller APIs.
7
+ */
8
+ export type PropertyRelation = {
9
+ /** The related input or output property. */
10
+ property: DzProperty
11
+ /** The controller that exposed the relation, or null for direct numeric property links. */
12
+ controller: DzController | null
13
+ /** The Daz API surface that exposed the relation. */
14
+ source: PropertyRelationSource
15
+ }
16
+
3
17
  /**
4
18
  * Sets the DzPropertyGroup path (and appropriate geometryregion_dz) for the given property.
5
19
  * @param property The property to change the path of.
@@ -18,6 +32,11 @@ export const getName = (property: DzProperty): string => {
18
32
  return sceneHelper.getInternalName(property).valueOf()
19
33
  }
20
34
 
35
+ /**
36
+ * Ensures the property's internal name is unique on its owning node.
37
+ * @param property The property whose internal name should be checked.
38
+ * @returns The unique internal name assigned to the property.
39
+ */
21
40
  export const ensureNameIsUnique = (property: DzProperty): string => {
22
41
  const name = getName(property)
23
42
  const uniqueName = sceneHelper.getUniqueMorphName(sceneHelper.getNode(property), name)
@@ -39,24 +58,122 @@ export const unlock = (property: DzProperty, then: (property: DzProperty) => voi
39
58
  if (locked) property.lock(false)
40
59
  }
41
60
 
61
+ /**
62
+ * Adds a property relation unless the same property, controller, and source were already collected.
63
+ * @param relations The relation collection to update.
64
+ * @param property The related property to add, or null to skip.
65
+ * @param controller The controller that exposed the relation, or null for direct property links.
66
+ * @param source The Daz API surface that exposed the relation.
67
+ */
68
+ const addRelation = (relations: PropertyRelation[], property: DzProperty | null, controller: DzController | null, source: PropertyRelationSource): void => {
69
+ if (!property) return
70
+
71
+ for (let relation of relations) {
72
+ if (relation.property === property && relation.controller === controller && relation.source === source) return
73
+ }
74
+
75
+ relations.push({ property, controller, source })
76
+ }
77
+
78
+ /**
79
+ * Gets the source property referenced by a controller.
80
+ * @param controller The controller to inspect.
81
+ * @param current If true, uses getCurrentProperty; otherwise, uses getProperty.
82
+ * @returns The controller's property, or null when the controller does not expose that method.
83
+ */
84
+ const getControllerProperty = (controller: DzController, current: boolean): DzProperty | null => {
85
+ const methodName = current ? 'getCurrentProperty' : 'getProperty'
86
+ const method = (controller as any)[methodName]
87
+ if (typeof method !== 'function') return null
88
+
89
+ return method.call(controller) as DzProperty | null
90
+ }
91
+
92
+ /**
93
+ * Gets properties that drive this property through controllers or direct numeric links.
94
+ * @param property The property whose input/driving properties should be collected.
95
+ * @returns Related input properties with the controller/source that exposed each relation.
96
+ */
97
+ export const getPropertyInputs = (property: DzProperty): PropertyRelation[] => {
98
+ const relations: PropertyRelation[] = []
99
+ const controllerCount = property.getNumControllers()
100
+
101
+ for (let index = 0; index < controllerCount; index++) {
102
+ const controller = property.getController(index)
103
+ addRelation(relations, getControllerProperty(controller, false), controller, 'controller')
104
+ addRelation(relations, getControllerProperty(controller, true), controller, 'currentController')
105
+ }
106
+
107
+ const numericProperty = cast<DzNumericProperty>(property, 'DzNumericProperty')
108
+ if (numericProperty) {
109
+ addRelation(relations, numericProperty.getLinkProperty(), null, 'link')
110
+ addRelation(relations, numericProperty.getFollowProperty(), null, 'follow')
111
+ }
112
+
113
+ return relations
114
+ }
115
+
116
+ /**
117
+ * Gets properties driven by this property through slave controllers.
118
+ * @param property The property whose output/driven properties should be collected.
119
+ * @returns Related output properties with the controller/source that exposed each relation.
120
+ */
121
+ export const getPropertyOutputs = (property: DzProperty): PropertyRelation[] => {
122
+ const relations: PropertyRelation[] = []
123
+ const controllerCount = property.getNumSlaveControllers()
124
+
125
+ for (let index = 0; index < controllerCount; index++) {
126
+ const controller = property.getSlaveController(index)
127
+ addRelation(relations, controller.getOwner(), controller, 'slaveController')
128
+ }
129
+
130
+ return relations
131
+ }
132
+
133
+ /**
134
+ * Checks whether a property is a Daz numeric property.
135
+ * @param property The property to check.
136
+ * @returns True if the property inherits DzNumericProperty.
137
+ */
42
138
  export const isNumeric = (property: DzProperty): boolean => {
43
139
  return property.inherits('DzNumericProperty')
44
140
  }
45
141
 
142
+ /**
143
+ * Casts a property to a specific Daz property type when it inherits that type.
144
+ * @param property The property to cast.
145
+ * @param type The Daz property class name to test.
146
+ * @returns The property typed as T, or null when it does not inherit the requested type.
147
+ */
46
148
  export const cast = <T extends DzProperty>(property: DzProperty, type: 'DzNumericProperty' | 'DzFloatProperty' | 'DzIntProperty'): T | null => {
47
149
  return property.inherits(type)
48
150
  ? property as T
49
151
  : null
50
152
  }
51
153
 
154
+ /**
155
+ * Casts a property to a numeric float or int property.
156
+ * @param property The property to cast.
157
+ * @returns The property as DzFloatProperty or DzIntProperty, or null if it is neither.
158
+ */
52
159
  export const toNumeric = (property: DzProperty): DzFloatProperty | DzIntProperty | null => {
53
160
  return toFloat(property) ?? toInt(property)
54
161
  }
55
162
 
163
+ /**
164
+ * Casts a property to a float property.
165
+ * @param property The property to cast.
166
+ * @returns The property as DzFloatProperty, or null if it is not one.
167
+ */
56
168
  export const toFloat = (property: DzProperty): DzFloatProperty | null => {
57
169
  return cast<DzFloatProperty>(property, 'DzFloatProperty')
58
170
  }
59
171
 
172
+ /**
173
+ * Casts a property to an int property.
174
+ * @param property The property to cast.
175
+ * @returns The property as DzIntProperty, or null if it is not one.
176
+ */
60
177
  export const toInt = (property: DzProperty): DzIntProperty | null => {
61
178
  return cast<DzIntProperty>(property, 'DzIntProperty')
62
- }
179
+ }
@@ -0,0 +1,122 @@
1
+ import { beforeEach, describe, expect, it, vi } from 'vitest'
2
+
3
+ vi.mock('./numeric-property-helper', () => ({ adjust: vi.fn() }))
4
+ vi.mock('@dsf/core/global', () => ({
5
+ sceneHelper: {
6
+ getInternalName: vi.fn(),
7
+ getNode: vi.fn(),
8
+ getUniqueMorphName: vi.fn(),
9
+ setInternalName: vi.fn(),
10
+ setPropertyPath: vi.fn()
11
+ }
12
+ }))
13
+
14
+ const { adjust } = await import('./numeric-property-helper')
15
+ const { bakeRotations, bakeScale, bakeTranslations, bakeTransforms, collectTransformBakePlan } = await import('./transform-bake-helper')
16
+
17
+ type TestProperty = {
18
+ name: string
19
+ path: string
20
+ value: number
21
+ outputs: TestProperty[]
22
+ getName: () => string
23
+ getPath: () => string
24
+ getValue: () => number
25
+ getNumSlaveControllers: () => number
26
+ getSlaveController: (index: number) => { getOwner: () => TestProperty }
27
+ getNumControllers: () => number
28
+ getController: () => null
29
+ inherits: (type: string) => boolean
30
+ }
31
+
32
+ const property = (name: string, path = '/Pose Controls'): TestProperty => {
33
+ const testProperty: TestProperty = {
34
+ name,
35
+ path,
36
+ value: 7,
37
+ outputs: [],
38
+ getName: () => testProperty.name,
39
+ getPath: () => testProperty.path,
40
+ getValue: () => testProperty.value,
41
+ getNumSlaveControllers: () => testProperty.outputs.length,
42
+ getSlaveController: (index: number) => ({ getOwner: () => testProperty.outputs[index] }),
43
+ getNumControllers: () => 0,
44
+ getController: () => null,
45
+ inherits: (type: string) => type === 'DzNumericProperty' || type === 'DzFloatProperty'
46
+ }
47
+
48
+ return testProperty
49
+ }
50
+
51
+ const link = (driver: TestProperty, output: TestProperty): void => {
52
+ driver.outputs.push(output)
53
+ }
54
+
55
+ beforeEach(() => {
56
+ vi.clearAllMocks()
57
+ })
58
+
59
+ describe('transform bake helper', () => {
60
+ it('plans recursive output reset and selected rotation capture', () => {
61
+ const master = property('body_ctrl_rHandGrasp')
62
+ const middle = property('body_ctrl_rFingersGrasp')
63
+ const rotation = property('ZRotate', '/General/Transforms/Rotation')
64
+ const corrective = property('Value', '/Hidden/Base Correctives/Hands')
65
+ link(master, middle)
66
+ link(middle, rotation)
67
+ link(rotation, corrective)
68
+
69
+ const plan = collectTransformBakePlan(master, { rotations: true })
70
+
71
+ expect(plan.resetProperties).toEqual([master, middle, rotation, corrective])
72
+ expect(plan.capturedProperties).toEqual([rotation])
73
+ })
74
+
75
+ it('bakes selected transforms by capturing final values, zeroing chain, then restoring captures', () => {
76
+ const master = property('master')
77
+ const rotation = property('XRotate', '/General/Transforms/Rotation')
78
+ rotation.value = 45
79
+ link(master, rotation)
80
+
81
+ bakeTransforms(master, { rotations: true })
82
+
83
+ expect(adjust).toHaveBeenNthCalledWith(1, master, 0)
84
+ expect(adjust).toHaveBeenNthCalledWith(2, rotation, 0)
85
+ expect(adjust).toHaveBeenNthCalledWith(3, rotation, 45)
86
+ })
87
+
88
+ it('filters translations and scale independently', () => {
89
+ const master = property('master')
90
+ const translation = property('XTranslate', '/General/Transforms/Translation')
91
+ const rotation = property('XRotate', '/General/Transforms/Rotation')
92
+ const scale = property('XScale', '/General/Transforms/Scale')
93
+ link(master, translation)
94
+ link(master, rotation)
95
+ link(master, scale)
96
+
97
+ expect(collectTransformBakePlan(master, { translations: true }).capturedProperties).toEqual([translation])
98
+ expect(collectTransformBakePlan(master, { rotations: true }).capturedProperties).toEqual([rotation])
99
+ expect(collectTransformBakePlan(master, { scale: true }).capturedProperties).toEqual([scale])
100
+ })
101
+
102
+ it('exposes focused bake helpers', () => {
103
+ const master = property('master')
104
+ const translation = property('YTranslate', '/General/Transforms/Translation')
105
+ const rotation = property('YRotate', '/General/Transforms/Rotation')
106
+ const scale = property('YScale', '/General/Transforms/Scale')
107
+ link(master, translation)
108
+ link(master, rotation)
109
+ link(master, scale)
110
+
111
+ bakeRotations(master)
112
+ expect(adjust).toHaveBeenLastCalledWith(rotation, 7)
113
+
114
+ vi.clearAllMocks()
115
+ bakeTranslations(master)
116
+ expect(adjust).toHaveBeenLastCalledWith(translation, 7)
117
+
118
+ vi.clearAllMocks()
119
+ bakeScale(master)
120
+ expect(adjust).toHaveBeenLastCalledWith(scale, 7)
121
+ })
122
+ })
@@ -0,0 +1,172 @@
1
+ import { adjust } from './numeric-property-helper'
2
+ import { getPropertyOutputs } from './property-helper'
3
+
4
+ export type TransformBakeOptions = {
5
+ rotations?: boolean
6
+ translations?: boolean
7
+ scale?: boolean
8
+ maxDepth?: number
9
+ }
10
+
11
+ export type TransformBakePlan = {
12
+ resetProperties: DzProperty[]
13
+ capturedProperties: TransformBakeProperty[]
14
+ }
15
+
16
+ type TransformBakeProperty = DzFloatProperty | DzIntProperty | DzBoolProperty
17
+
18
+ type CapturedPropertyValue = {
19
+ property: TransformBakeProperty
20
+ value: number
21
+ }
22
+
23
+ const DEFAULT_MAX_DEPTH = 10
24
+
25
+ const hasProperty = (properties: DzProperty[], property: DzProperty): boolean => {
26
+ for (let index = 0; index < properties.length; index++) {
27
+ if (properties[index] === property) return true
28
+ }
29
+
30
+ return false
31
+ }
32
+
33
+ const isTransformBakeProperty = (property: DzProperty): property is TransformBakeProperty => {
34
+ return property.inherits('DzFloatProperty') || property.inherits('DzIntProperty') || property.inherits('DzBoolProperty')
35
+ }
36
+
37
+ const getPropertyName = (property: DzProperty): string => {
38
+ const getName = (property as any).getName
39
+ if (typeof getName === 'function') return String(getName.call(property))
40
+
41
+ return String((property as any).name ?? '')
42
+ }
43
+
44
+ const getPropertyPath = (property: DzProperty): string => {
45
+ const getPath = (property as any).getPath
46
+ if (typeof getPath === 'function') return String(getPath.call(property))
47
+
48
+ return ''
49
+ }
50
+
51
+ const isRotationProperty = (property: DzProperty): boolean => {
52
+ const name = getPropertyName(property)
53
+ return getPropertyPath(property) === '/General/Transforms/Rotation'
54
+ || name === 'XRotate'
55
+ || name === 'YRotate'
56
+ || name === 'ZRotate'
57
+ }
58
+
59
+ const isTranslationProperty = (property: DzProperty): boolean => {
60
+ const name = getPropertyName(property)
61
+ return getPropertyPath(property) === '/General/Transforms/Translation'
62
+ || name === 'XTranslate'
63
+ || name === 'YTranslate'
64
+ || name === 'ZTranslate'
65
+ }
66
+
67
+ const isScaleProperty = (property: DzProperty): boolean => {
68
+ const name = getPropertyName(property)
69
+ return getPropertyPath(property) === '/General/Transforms/Scale'
70
+ || name === 'Scale'
71
+ || name === 'XScale'
72
+ || name === 'YScale'
73
+ || name === 'ZScale'
74
+ }
75
+
76
+ const shouldCaptureProperty = (property: DzProperty, options: TransformBakeOptions): boolean => {
77
+ return (options.rotations === true && isRotationProperty(property))
78
+ || (options.translations === true && isTranslationProperty(property))
79
+ || (options.scale === true && isScaleProperty(property))
80
+ }
81
+
82
+ const collectRecursiveOutputProperties = (property: DzProperty, maxDepth: number): DzProperty[] => {
83
+ const outputs: DzProperty[] = []
84
+ const queue: DzProperty[] = [property]
85
+ const depths: number[] = [0]
86
+
87
+ for (let queueIndex = 0; queueIndex < queue.length; queueIndex++) {
88
+ const driver = queue[queueIndex]
89
+ const depth = depths[queueIndex]
90
+ if (depth >= maxDepth) continue
91
+
92
+ const relations = getPropertyOutputs(driver)
93
+ for (let relationIndex = 0; relationIndex < relations.length; relationIndex++) {
94
+ const output = relations[relationIndex].property
95
+ if (!output) continue
96
+ if (hasProperty(outputs, output)) continue
97
+
98
+ outputs.push(output)
99
+ if (!hasProperty(queue, output)) {
100
+ queue.push(output)
101
+ depths.push(depth + 1)
102
+ }
103
+ }
104
+ }
105
+
106
+ return outputs
107
+ }
108
+
109
+ export const collectTransformBakePlan = (property: DzProperty, options: TransformBakeOptions): TransformBakePlan => {
110
+ const outputs = collectRecursiveOutputProperties(property, options.maxDepth ?? DEFAULT_MAX_DEPTH)
111
+ const capturedProperties: TransformBakeProperty[] = []
112
+
113
+ for (let index = 0; index < outputs.length; index++) {
114
+ const output = outputs[index]
115
+ if (!isTransformBakeProperty(output)) continue
116
+ if (!shouldCaptureProperty(output, options)) continue
117
+
118
+ capturedProperties.push(output)
119
+ }
120
+
121
+ return {
122
+ resetProperties: [property].concat(outputs),
123
+ capturedProperties
124
+ }
125
+ }
126
+
127
+ const captureValues = (properties: TransformBakeProperty[]): CapturedPropertyValue[] => {
128
+ const values: CapturedPropertyValue[] = []
129
+
130
+ for (let index = 0; index < properties.length; index++) {
131
+ const property = properties[index]
132
+ values.push({ property, value: (property as any).getValue() })
133
+ }
134
+
135
+ return values
136
+ }
137
+
138
+ const resetProperties = (properties: DzProperty[]): void => {
139
+ for (let index = 0; index < properties.length; index++) {
140
+ const property = properties[index]
141
+ if (!isTransformBakeProperty(property)) continue
142
+
143
+ adjust(property, 0)
144
+ }
145
+ }
146
+
147
+ const restoreValues = (values: CapturedPropertyValue[]): void => {
148
+ for (let index = 0; index < values.length; index++) {
149
+ const captured = values[index]
150
+ adjust(captured.property, captured.value)
151
+ }
152
+ }
153
+
154
+ export const bakeTransforms = (property: DzProperty, options: TransformBakeOptions): void => {
155
+ const plan = collectTransformBakePlan(property, options)
156
+ const capturedValues = captureValues(plan.capturedProperties)
157
+
158
+ resetProperties(plan.resetProperties)
159
+ restoreValues(capturedValues)
160
+ }
161
+
162
+ export const bakeRotations = (property: DzProperty): void => {
163
+ bakeTransforms(property, { rotations: true })
164
+ }
165
+
166
+ export const bakeTranslations = (property: DzProperty): void => {
167
+ bakeTransforms(property, { translations: true })
168
+ }
169
+
170
+ export const bakeScale = (property: DzProperty): void => {
171
+ bakeTransforms(property, { scale: true })
172
+ }