dazscript-framework 0.1.8 → 0.1.10
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 +92 -0
- package/package.json +15 -2
- package/src/Install.dsa.ts +19 -0
- package/src/Uninstall.dsa.ts +19 -0
- package/src/dialog/builders/line-edit-builder.ts +1 -1
- package/src/dialog/builders/node-selection-builder.ts +13 -1
- package/src/dialog/input-dialog.ts +1 -1
- package/src/samples/config.ts +3 -0
- package/src/samples/hello-world.dsa.ts +13 -0
- package/src/samples/sample-dialog.dsa.ts +52 -0
- package/src/samples/sample-dialog.ts +49 -0
- package/src/shared/set-keyboard-shortcut.ts +2 -2
- package/webpack.config.js +70 -0
package/README.md
CHANGED
|
@@ -1 +1,93 @@
|
|
|
1
1
|
# DazScript Framework
|
|
2
|
+
|
|
3
|
+
The **DazScript Framework** is a TypeScript-based framework for writing Daz Studio scripts. It provides all the advantages of a typed language such as autocompletion, error checking, and method parameter documentation and hinting. The framework also includes a set of dialog helpers for rapid UI development.
|
|
4
|
+
|
|
5
|
+
## Benefits
|
|
6
|
+
|
|
7
|
+
- **Autocompletion:** Take advantage of IDE autocompletion for faster and more efficient script development.
|
|
8
|
+
- **Error Checking:** Catch potential errors early in the development process with TypeScript's static analysis.
|
|
9
|
+
- **Method Documentation & Hinting:** Get contextual documentation and hints for methods, classes, and parameters.
|
|
10
|
+
|
|
11
|
+
## Features
|
|
12
|
+
|
|
13
|
+
- TypeScript support with full IntelliSense.
|
|
14
|
+
- A powerful set of decorators and helper methods for building interactive scripts.
|
|
15
|
+
- Easy integration with Daz Studio for quick script deployment.
|
|
16
|
+
|
|
17
|
+
## Installation
|
|
18
|
+
|
|
19
|
+
To install the **DazScript Framework**, run the following command:
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
npm install dazscript-framework
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## Setup
|
|
26
|
+
|
|
27
|
+
After installing the package, you will need to configure a few files for your project.
|
|
28
|
+
|
|
29
|
+
1. **babel.config.js**
|
|
30
|
+
|
|
31
|
+
Create the file and add the following content:
|
|
32
|
+
|
|
33
|
+
```javascript
|
|
34
|
+
const sharedBabelConfig = require('dazscript-framework/babel');
|
|
35
|
+
|
|
36
|
+
module.exports = {
|
|
37
|
+
...sharedBabelConfig,
|
|
38
|
+
presets: [...sharedBabelConfig.presets],
|
|
39
|
+
plugins: [...sharedBabelConfig.plugins],
|
|
40
|
+
};
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
2. **package.json**
|
|
44
|
+
|
|
45
|
+
Add the following scripts to your package.json:
|
|
46
|
+
|
|
47
|
+
```json
|
|
48
|
+
"scripts": {
|
|
49
|
+
"prebuild": "npm run installer",
|
|
50
|
+
"build": "webpack --env outputPath=./out",
|
|
51
|
+
"postbuild": "npm run icons",
|
|
52
|
+
"watch": "webpack --env outputPath=./out --watch",
|
|
53
|
+
"icons": "copyfiles -u 1 src/**/*.png out/",
|
|
54
|
+
"installer": "node ./node_modules/dazscript-framework/dist/scripts/install-generator.js -p ./src/scripts -m /My Scripts"
|
|
55
|
+
}
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
3. **tsconfig.json**
|
|
59
|
+
|
|
60
|
+
Create the file and add the following content:
|
|
61
|
+
|
|
62
|
+
```json
|
|
63
|
+
{
|
|
64
|
+
"extends": "./node_modules/dazscript-framework/tsconfig.json",
|
|
65
|
+
"compilerOptions": {
|
|
66
|
+
"baseUrl": "./",
|
|
67
|
+
"paths": {
|
|
68
|
+
"shared/*": ["src/shared/*"],
|
|
69
|
+
"@dst/*": ["node_modules/dazscript-types/*"],
|
|
70
|
+
"@dsf/*": ["node_modules/dazscript-framework/src/*"]
|
|
71
|
+
}
|
|
72
|
+
},
|
|
73
|
+
"include": ["node_modules/dazscript-types/**/*", "src/**/*"]
|
|
74
|
+
}
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
4. **webpack.config.js**
|
|
78
|
+
Create the file and add the following content:
|
|
79
|
+
|
|
80
|
+
```javascript
|
|
81
|
+
const sharedWebpackConfig = require('dazscript-framework/webpack');
|
|
82
|
+
|
|
83
|
+
module.exports = (env, argv) => {
|
|
84
|
+
const sharedConfig = sharedWebpackConfig(env, argv);
|
|
85
|
+
|
|
86
|
+
return {
|
|
87
|
+
...sharedConfig,
|
|
88
|
+
// You can override or add more customizations here if needed
|
|
89
|
+
};
|
|
90
|
+
};
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
## Usage
|
package/package.json
CHANGED
|
@@ -1,9 +1,17 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dazscript-framework",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.10",
|
|
4
4
|
"author": "Freddy Diaz",
|
|
5
5
|
"license": "MPL-2.0",
|
|
6
6
|
"description": "",
|
|
7
|
+
"scripts": {
|
|
8
|
+
"prebuild": "npm run installer",
|
|
9
|
+
"build": "webpack --env outputPath=./out",
|
|
10
|
+
"postbuild": "npm run icons",
|
|
11
|
+
"watch": "webpack --env outputPath=./out --watch",
|
|
12
|
+
"icons": "copyfiles -u 1 src/**/*.png out/",
|
|
13
|
+
"installer": "node ./dist/scripts/install-generator.js -p ./src/samples -m /DazScriptFramework"
|
|
14
|
+
},
|
|
7
15
|
"keywords": [
|
|
8
16
|
"daz3d",
|
|
9
17
|
"daz studio",
|
|
@@ -20,7 +28,7 @@
|
|
|
20
28
|
},
|
|
21
29
|
"files": [
|
|
22
30
|
"tsconfig.json",
|
|
23
|
-
"webpack.config",
|
|
31
|
+
"webpack.config.js",
|
|
24
32
|
"babel.config.js",
|
|
25
33
|
"dist/**/*",
|
|
26
34
|
"src/**/*"
|
|
@@ -53,5 +61,10 @@
|
|
|
53
61
|
"typescript": "^5.2.2",
|
|
54
62
|
"webpack": "^5.88.2",
|
|
55
63
|
"webpack-cli": "^5.1.4"
|
|
64
|
+
},
|
|
65
|
+
"devDependencies": {
|
|
66
|
+
"@types/node": "^22.10.5",
|
|
67
|
+
"eslint": "^9.17.0",
|
|
68
|
+
"typescript": "^5.7.3"
|
|
56
69
|
}
|
|
57
70
|
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
|
|
2
|
+
import { installCustomActions as install } from '@dsf/helpers/custom-action-helper';
|
|
3
|
+
|
|
4
|
+
install([
|
|
5
|
+
{
|
|
6
|
+
"name": null,
|
|
7
|
+
"text": "Hello World",
|
|
8
|
+
"filePath": "samples/hello-world.dsa",
|
|
9
|
+
"menuPath": "/DazScriptFramework/samples",
|
|
10
|
+
"description": "hello-world"
|
|
11
|
+
},
|
|
12
|
+
{
|
|
13
|
+
"name": null,
|
|
14
|
+
"text": "Sample Dialog",
|
|
15
|
+
"filePath": "samples/sample-dialog.dsa",
|
|
16
|
+
"menuPath": "/DazScriptFramework/samples",
|
|
17
|
+
"description": "sample-dialog"
|
|
18
|
+
}
|
|
19
|
+
]);
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
|
|
2
|
+
import { uninstallCustomActions as uninstall } from '@dsf/helpers/custom-action-helper';
|
|
3
|
+
|
|
4
|
+
uninstall([
|
|
5
|
+
{
|
|
6
|
+
"name": null,
|
|
7
|
+
"text": "Hello World",
|
|
8
|
+
"filePath": "samples/hello-world.dsa",
|
|
9
|
+
"menuPath": "/DazScriptFramework/samples",
|
|
10
|
+
"description": "hello-world"
|
|
11
|
+
},
|
|
12
|
+
{
|
|
13
|
+
"name": null,
|
|
14
|
+
"text": "Sample Dialog",
|
|
15
|
+
"filePath": "samples/sample-dialog.dsa",
|
|
16
|
+
"menuPath": "/DazScriptFramework/samples",
|
|
17
|
+
"description": "sample-dialog"
|
|
18
|
+
}
|
|
19
|
+
]);
|
|
@@ -74,7 +74,7 @@ export default class LineEditBuilder extends WidgetBuilderBase<DzLineEdit> {
|
|
|
74
74
|
return this
|
|
75
75
|
}
|
|
76
76
|
|
|
77
|
-
|
|
77
|
+
value(text_: string | Observable<string>): this {
|
|
78
78
|
if (typeof text_ === 'string') {
|
|
79
79
|
this.widget.text = text_
|
|
80
80
|
}
|
|
@@ -31,13 +31,25 @@ export class NodeSelectionComboBoxBuilder extends WidgetBuilderBase<DzNodeSelect
|
|
|
31
31
|
return this
|
|
32
32
|
}
|
|
33
33
|
|
|
34
|
-
|
|
34
|
+
value(node: Observable<DzNode>): this {
|
|
35
35
|
this.widget.nodeSelectionChanged.scriptConnect(() => {
|
|
36
36
|
node.value = this.widget.getSelectedNode()
|
|
37
37
|
})
|
|
38
|
+
this.selected(node)
|
|
38
39
|
return this
|
|
39
40
|
}
|
|
40
41
|
|
|
42
|
+
changed(then: (node: DzNode) => void): this {
|
|
43
|
+
this.widget.nodeSelectionChanged.scriptConnect(() => {
|
|
44
|
+
then(this.widget.getSelectedNode())
|
|
45
|
+
})
|
|
46
|
+
return this
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
refresh(): void {
|
|
50
|
+
this.widget.update()
|
|
51
|
+
}
|
|
52
|
+
|
|
41
53
|
build(then?: (comboBox: DzNodeSelectionComboBox) => void): DzNodeSelectionComboBox {
|
|
42
54
|
return super.build()
|
|
43
55
|
}
|
|
@@ -23,6 +23,6 @@ export class InputDialog extends BasicDialog {
|
|
|
23
23
|
protected build(): void {
|
|
24
24
|
let add = this.add
|
|
25
25
|
|
|
26
|
-
add.edit().
|
|
26
|
+
add.edit().value(this.model.value$).validator(this.model.validator).focus()
|
|
27
27
|
}
|
|
28
28
|
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { debug } from '@dsf/common/log';
|
|
2
|
+
import { action } from '@dsf/core/action-decorator';
|
|
3
|
+
import { BaseScript } from '@dsf/core/base-script';
|
|
4
|
+
import { info } from '@dsf/helpers/message-box-helper';
|
|
5
|
+
|
|
6
|
+
@action({ text: 'Hello World' })
|
|
7
|
+
class HelloWorldScript extends BaseScript {
|
|
8
|
+
protected run(): void {
|
|
9
|
+
debug('Hello World!');
|
|
10
|
+
info('Hello World!');
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
new HelloWorldScript().exec();
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { debug, dump } from '@dsf/common/log';
|
|
2
|
+
import { action } from '@dsf/core/action-decorator';
|
|
3
|
+
import { BaseScript } from '@dsf/core/base-script';
|
|
4
|
+
import { error } from '@dsf/helpers/message-box-helper';
|
|
5
|
+
import { getNodes, getSelectedNode } from '@dsf/helpers/scene-helper';
|
|
6
|
+
import { SampleDialog, SampleDialogModel } from './sample-dialog';
|
|
7
|
+
|
|
8
|
+
@action({ text: 'Sample Dialog' })
|
|
9
|
+
class SampleDialogScript extends BaseScript {
|
|
10
|
+
protected run(): void {
|
|
11
|
+
let sceneNodes = getNodes()
|
|
12
|
+
let selectedNode = getSelectedNode()
|
|
13
|
+
if (!selectedNode) {
|
|
14
|
+
error('Please select a node.')
|
|
15
|
+
return
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
let model = new SampleDialogModel()
|
|
19
|
+
model.nodes$.value = sceneNodes
|
|
20
|
+
|
|
21
|
+
model.nodeLabel$.connect((label) => {
|
|
22
|
+
if (label === model.selectedNode$.value.getLabel()) return
|
|
23
|
+
model.selectedNode$.value.setLabel(label)
|
|
24
|
+
model.nodes$.value = getNodes()
|
|
25
|
+
})
|
|
26
|
+
|
|
27
|
+
let dialog = new SampleDialog(model)
|
|
28
|
+
|
|
29
|
+
model.selectedNode$.connect((node) => {
|
|
30
|
+
if (!node) return
|
|
31
|
+
debug(`Selected Node: ${node.getLabel()}`)
|
|
32
|
+
node.select(true)
|
|
33
|
+
model.nodeLabel$.value = node.getLabel()
|
|
34
|
+
model.showNode$.value = node.isVisible()
|
|
35
|
+
model.hideNode$.value = !node.isVisible()
|
|
36
|
+
})
|
|
37
|
+
dialog.onNodeVisibilityChanged = (node, visible) => {
|
|
38
|
+
node.setVisible(visible)
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
model.selectedNode$.value = selectedNode
|
|
42
|
+
|
|
43
|
+
if (!dialog.run()) {
|
|
44
|
+
debug(`Dialog Cancelled`)
|
|
45
|
+
return
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
debug(`Dialog Closed`)
|
|
49
|
+
dump(model)
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
new SampleDialogScript().exec();
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { BasicDialog } from '@dsf/dialog/basic-dialog';
|
|
2
|
+
import { Observable } from '@dsf/lib/observable';
|
|
3
|
+
import { AppSettings } from '@dsf/lib/settings';
|
|
4
|
+
import { config } from './config';
|
|
5
|
+
|
|
6
|
+
export class SampleDialogModel extends AppSettings {
|
|
7
|
+
constructor() {
|
|
8
|
+
super(`${config.author}/SampleDialog`);
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
selectedNode$ = new Observable<DzNode>()
|
|
12
|
+
nodes$ = new Observable<DzNode[]>()
|
|
13
|
+
nodeLabel$ = new Observable<string>()
|
|
14
|
+
showNode$ = new Observable<boolean>()
|
|
15
|
+
hideNode$ = new Observable<boolean>()
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export class SampleDialog extends BasicDialog {
|
|
19
|
+
constructor(private readonly model: SampleDialogModel) {
|
|
20
|
+
super(`Sample Dialog`);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
public onNodeChanged?: (node: DzNode) => void
|
|
24
|
+
|
|
25
|
+
public onNodeVisibilityChanged?: (node: DzNode, visible: boolean) => void
|
|
26
|
+
|
|
27
|
+
protected build(): void {
|
|
28
|
+
let add = this.add
|
|
29
|
+
let model = this.model
|
|
30
|
+
this.dialog.showAcceptButton(false)
|
|
31
|
+
this.dialog.setCancelButtonText(`Close`)
|
|
32
|
+
|
|
33
|
+
add.tab('General').build(() => {
|
|
34
|
+
add.group(`Selected Node`).build(() => {
|
|
35
|
+
add.nodeSelection().nodes(model.nodes$).value(model.selectedNode$)
|
|
36
|
+
add.horizontal((layout) => {
|
|
37
|
+
add.label(`Label:`)
|
|
38
|
+
layout.addSpacing(10)
|
|
39
|
+
add.edit().value(model.nodeLabel$)
|
|
40
|
+
})
|
|
41
|
+
|
|
42
|
+
add.group(`Visibility`).horizontal().build(() => {
|
|
43
|
+
add.radio(`Show`).value(model.showNode$).toolTip(`Show the selected node.`).toggled((checked) => { this.onNodeVisibilityChanged(model.selectedNode$.value, checked) })
|
|
44
|
+
add.radio(`Hide`).value(model.hideNode$).toolTip(`Hide the selected node.`)
|
|
45
|
+
})
|
|
46
|
+
})
|
|
47
|
+
})
|
|
48
|
+
}
|
|
49
|
+
}
|
|
@@ -63,14 +63,14 @@ class KeyboardShortcutDialog extends BasicDialog {
|
|
|
63
63
|
|
|
64
64
|
add.group('Assign Keyboard Shortcut').build((layout) => {
|
|
65
65
|
layout.spacing = 5
|
|
66
|
-
add.edit().
|
|
66
|
+
add.edit().value(model.actionLabel).readOnly(true)
|
|
67
67
|
add.comboEdit().focus().items([...letters, ...keys]).changed(this.key).edited(this.key)
|
|
68
68
|
add.checkbox('Control').value(model.control)
|
|
69
69
|
add.checkbox('Option / Alt').value(model.alt)
|
|
70
70
|
add.checkbox('Shift').value(model.shift)
|
|
71
71
|
add.checkbox('Command / Windows').value(model.windows)
|
|
72
72
|
add.group('Shortcut:').style({ flat: true }).build(() => {
|
|
73
|
-
add.edit().
|
|
73
|
+
add.edit().value(model.shortcut).readOnly(true)
|
|
74
74
|
})
|
|
75
75
|
})
|
|
76
76
|
}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
const path = require('path');
|
|
2
|
+
const glob = require('glob');
|
|
3
|
+
const TsconfigPathsPlugin = require('tsconfig-paths-webpack-plugin');
|
|
4
|
+
|
|
5
|
+
module.exports = (env, argv) => {
|
|
6
|
+
const isFileSpecified = env && env.file;
|
|
7
|
+
const entryFiles = isFileSpecified
|
|
8
|
+
? [`./src/${env.file}.dsa.ts`]
|
|
9
|
+
: glob.sync('./src/**/*.dsa.ts');
|
|
10
|
+
|
|
11
|
+
const outputPath =
|
|
12
|
+
env && env.outputPath
|
|
13
|
+
? path.resolve(env.outputPath)
|
|
14
|
+
: path.resolve(__dirname, 'out');
|
|
15
|
+
|
|
16
|
+
return {
|
|
17
|
+
mode: 'production',
|
|
18
|
+
optimization: {
|
|
19
|
+
usedExports: true,
|
|
20
|
+
},
|
|
21
|
+
entry: entryFiles.reduce((acc, filePath) => {
|
|
22
|
+
const entry = filePath.replace('.dsa.ts', '').replace('src/', '');
|
|
23
|
+
acc[entry] = `./${filePath}`;
|
|
24
|
+
return acc;
|
|
25
|
+
}, {}),
|
|
26
|
+
module: {
|
|
27
|
+
rules: [
|
|
28
|
+
{
|
|
29
|
+
test: /\.ts$/,
|
|
30
|
+
use: [
|
|
31
|
+
{
|
|
32
|
+
loader: 'babel-loader',
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
loader: 'ts-loader',
|
|
36
|
+
options: {
|
|
37
|
+
allowTsInNodeModules: true,
|
|
38
|
+
},
|
|
39
|
+
},
|
|
40
|
+
],
|
|
41
|
+
exclude: [
|
|
42
|
+
{
|
|
43
|
+
and: [path.resolve(__dirname, 'node_modules')],
|
|
44
|
+
not: [
|
|
45
|
+
path.resolve(__dirname, 'node_modules/dazscript-framework/src'),
|
|
46
|
+
],
|
|
47
|
+
},
|
|
48
|
+
],
|
|
49
|
+
},
|
|
50
|
+
],
|
|
51
|
+
},
|
|
52
|
+
resolve: {
|
|
53
|
+
extensions: ['.ts'],
|
|
54
|
+
plugins: [new TsconfigPathsPlugin()],
|
|
55
|
+
},
|
|
56
|
+
output: {
|
|
57
|
+
filename: '[name].dsa',
|
|
58
|
+
path: outputPath,
|
|
59
|
+
environment: {
|
|
60
|
+
arrowFunction: false,
|
|
61
|
+
bigIntLiteral: false,
|
|
62
|
+
const: false,
|
|
63
|
+
destructuring: false,
|
|
64
|
+
dynamicImport: false,
|
|
65
|
+
forOf: true,
|
|
66
|
+
module: false,
|
|
67
|
+
},
|
|
68
|
+
},
|
|
69
|
+
};
|
|
70
|
+
};
|