@threlte/gltf 3.0.0-next.0 → 3.0.0-next.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/.prettierrc +10 -0
- package/CHANGELOG.md +60 -0
- package/README.md +41 -11
- package/package.json +7 -5
- package/src/index.js +9 -8
- package/src/utils/Options.d.ts +22 -0
- package/src/utils/glftLoader.js +1 -1
- package/src/utils/parser.js +39 -33
- package/src/utils/transform.js +16 -4
package/.prettierrc
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
{
|
|
2
|
+
"useTabs": false,
|
|
3
|
+
"singleQuote": true,
|
|
4
|
+
"trailingComma": "none",
|
|
5
|
+
"semi": false,
|
|
6
|
+
"printWidth": 100,
|
|
7
|
+
"plugins": ["prettier-plugin-svelte"],
|
|
8
|
+
"overrides": [{ "files": "*.svelte", "options": { "parser": "svelte" } }],
|
|
9
|
+
"singleAttributePerLine": true
|
|
10
|
+
}
|
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,65 @@
|
|
|
1
1
|
# @threlte/gltf
|
|
2
2
|
|
|
3
|
+
## 3.0.0-next.10
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 60fcc29: Bump dev dependencies
|
|
8
|
+
|
|
9
|
+
## 3.0.0-next.9
|
|
10
|
+
|
|
11
|
+
### Patch Changes
|
|
12
|
+
|
|
13
|
+
- cec4b57: update deps
|
|
14
|
+
|
|
15
|
+
## 3.0.0-next.8
|
|
16
|
+
|
|
17
|
+
### Patch Changes
|
|
18
|
+
|
|
19
|
+
- b7045f5: Svelte dependency update
|
|
20
|
+
|
|
21
|
+
## 3.0.0-next.7
|
|
22
|
+
|
|
23
|
+
### Patch Changes
|
|
24
|
+
|
|
25
|
+
- 946e7a8: fix parser for animated assets
|
|
26
|
+
|
|
27
|
+
## 3.0.0-next.6
|
|
28
|
+
|
|
29
|
+
### Patch Changes
|
|
30
|
+
|
|
31
|
+
- 7a3281c: Split out gltf-related loaders into hooks for better tree shaking
|
|
32
|
+
|
|
33
|
+
## 3.0.0-next.5
|
|
34
|
+
|
|
35
|
+
### Patch Changes
|
|
36
|
+
|
|
37
|
+
- fa8a61c: Bump Svelte compiler version
|
|
38
|
+
|
|
39
|
+
## 3.0.0-next.4
|
|
40
|
+
|
|
41
|
+
### Patch Changes
|
|
42
|
+
|
|
43
|
+
- 54bdef9: Fix gltf parser template for isolated components
|
|
44
|
+
|
|
45
|
+
## 3.0.0-next.3
|
|
46
|
+
|
|
47
|
+
### Patch Changes
|
|
48
|
+
|
|
49
|
+
- bb726da: fix prettier formatting
|
|
50
|
+
|
|
51
|
+
## 3.0.0-next.2
|
|
52
|
+
|
|
53
|
+
### Patch Changes
|
|
54
|
+
|
|
55
|
+
- 958c375: Fix T.Group parser error
|
|
56
|
+
|
|
57
|
+
## 3.0.0-next.1
|
|
58
|
+
|
|
59
|
+
### Patch Changes
|
|
60
|
+
|
|
61
|
+
- 36128d5: Replace events with callback props and slots with snippets
|
|
62
|
+
|
|
3
63
|
## 3.0.0-next.0
|
|
4
64
|
|
|
5
65
|
### Major Changes
|
package/README.md
CHANGED
|
@@ -116,9 +116,16 @@ Command: npx gltfjsx@0.0.1 ./stacy.glb
|
|
|
116
116
|
</script>
|
|
117
117
|
|
|
118
118
|
{#if $gltf}
|
|
119
|
-
<T
|
|
119
|
+
<T
|
|
120
|
+
is={ref}
|
|
121
|
+
{...$$restProps}
|
|
122
|
+
>
|
|
120
123
|
<T.Group name="Scene">
|
|
121
|
-
<T.Group
|
|
124
|
+
<T.Group
|
|
125
|
+
name="Stacy"
|
|
126
|
+
rotation={[Math.PI / 2, 0, 0]}
|
|
127
|
+
scale={0.01}
|
|
128
|
+
>
|
|
122
129
|
<T is={$gltf.nodes.mixamorigHips} />
|
|
123
130
|
<T.SkinnedMesh
|
|
124
131
|
name="stacy"
|
|
@@ -166,7 +173,11 @@ You can re-use it, it will re-use geometries and materials out of the box:
|
|
|
166
173
|
Or make the model dynamic. Change its colors for example:
|
|
167
174
|
|
|
168
175
|
```svelte
|
|
169
|
-
<T.Mesh
|
|
176
|
+
<T.Mesh
|
|
177
|
+
geometry={$gltf.nodes.robot.geometry}
|
|
178
|
+
material={$gltf.materials.metal}
|
|
179
|
+
material.color="green"
|
|
180
|
+
/>
|
|
170
181
|
```
|
|
171
182
|
|
|
172
183
|
Or exchange materials:
|
|
@@ -181,7 +192,10 @@ Make contents conditional:
|
|
|
181
192
|
|
|
182
193
|
```svelte
|
|
183
194
|
{#if condition}
|
|
184
|
-
<T.Mesh
|
|
195
|
+
<T.Mesh
|
|
196
|
+
geometry={$gltf.nodes.robot.geometry}
|
|
197
|
+
material={$gltf.materials.metal}
|
|
198
|
+
/>}
|
|
185
199
|
{/if}
|
|
186
200
|
```
|
|
187
201
|
|
|
@@ -193,7 +207,7 @@ You don't need to do anything if your models are draco compressed, since `useGlt
|
|
|
193
207
|
|
|
194
208
|
#### ⚡️ Auto-transform (compression, resize)
|
|
195
209
|
|
|
196
|
-
With the `--transform` flag it creates a binary-packed, draco-compressed, texture-resized (1024x1024), webp compressed, deduped, instanced and pruned
|
|
210
|
+
With the `--transform` flag it creates a binary-packed, draco-compressed, texture-resized (1024x1024), webp compressed, deduped, instanced and pruned \*.glb ready to be consumed on a web site. It uses [glTF-Transform](https://github.com/donmccurdy/glTF-Transform). This can reduce the size of an asset by 70%-90%.
|
|
197
211
|
|
|
198
212
|
It will not alter the original but create a copy and append `[modelname]-transformed.glb`.
|
|
199
213
|
|
|
@@ -218,7 +232,16 @@ Command: npx gltfjsx@0.0.1 ./stacy.glb -t
|
|
|
218
232
|
|
|
219
233
|
export const ref = new Group()
|
|
220
234
|
|
|
221
|
-
type ActionName =
|
|
235
|
+
type ActionName =
|
|
236
|
+
| 'pockets'
|
|
237
|
+
| 'rope'
|
|
238
|
+
| 'swingdance'
|
|
239
|
+
| 'jump'
|
|
240
|
+
| 'react'
|
|
241
|
+
| 'shrug'
|
|
242
|
+
| 'wave'
|
|
243
|
+
| 'golf'
|
|
244
|
+
| 'idle'
|
|
222
245
|
type GLTFResult = {
|
|
223
246
|
nodes: {
|
|
224
247
|
stacy: THREE.SkinnedMesh
|
|
@@ -232,9 +255,16 @@ Command: npx gltfjsx@0.0.1 ./stacy.glb -t
|
|
|
232
255
|
</script>
|
|
233
256
|
|
|
234
257
|
{#if $gltf}
|
|
235
|
-
<T
|
|
258
|
+
<T
|
|
259
|
+
is={ref}
|
|
260
|
+
{...$$restProps}
|
|
261
|
+
>
|
|
236
262
|
<T.Group name="Scene">
|
|
237
|
-
<T.Group
|
|
263
|
+
<T.Group
|
|
264
|
+
name="Stacy"
|
|
265
|
+
rotation={[Math.PI / 2, 0, 0]}
|
|
266
|
+
scale={0.01}
|
|
267
|
+
>
|
|
238
268
|
<T is={$gltf.nodes.mixamorigHips} />
|
|
239
269
|
<T.SkinnedMesh
|
|
240
270
|
name="stacy"
|
|
@@ -256,9 +286,10 @@ Command: npx gltfjsx@0.0.1 ./stacy.glb -t
|
|
|
256
286
|
|
|
257
287
|
If your GLTF contains animations it will add [@threlte/extras's `useGltfAnimations`](https://threlte.xyz/extras/use-gltf-animations) hook, which extracts all clips and prepares them as actions:
|
|
258
288
|
|
|
259
|
-
```
|
|
289
|
+
```ts
|
|
260
290
|
const gltf = useGltf('/stacy.glb')
|
|
261
|
-
|
|
291
|
+
|
|
292
|
+
export const {(actions, mixer)} = useGltfAnimations(gltf, ref)
|
|
262
293
|
```
|
|
263
294
|
|
|
264
295
|
If you want to play an animation you can do so at any time:
|
|
@@ -285,7 +316,6 @@ gltfLoader.load(url, (gltf) => {
|
|
|
285
316
|
})
|
|
286
317
|
```
|
|
287
318
|
|
|
288
|
-
|
|
289
319
|
## Contributing
|
|
290
320
|
|
|
291
321
|
Contributions are what make the open source community such an amazing place to learn, inspire, and create. Any contributions you make are **greatly appreciated**.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@threlte/gltf",
|
|
3
|
-
"version": "3.0.0-next.
|
|
3
|
+
"version": "3.0.0-next.10",
|
|
4
4
|
"description": "GLTF to Threlte converter",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"keywords": [
|
|
@@ -39,10 +39,10 @@
|
|
|
39
39
|
"jsdom-global": "^3.0.2",
|
|
40
40
|
"meow": "^11.0.0",
|
|
41
41
|
"meshoptimizer": "^0.18.1",
|
|
42
|
-
"prettier": "^2.
|
|
43
|
-
"prettier-plugin-svelte": "^2.
|
|
42
|
+
"prettier": "^3.2.5",
|
|
43
|
+
"prettier-plugin-svelte": "^3.2.2",
|
|
44
44
|
"sharp": "^0.32.0",
|
|
45
|
-
"svelte": "^
|
|
45
|
+
"svelte": "^5.1.10",
|
|
46
46
|
"three": "0.122.0",
|
|
47
47
|
"three-stdlib": "^2.21.8"
|
|
48
48
|
},
|
|
@@ -66,6 +66,8 @@
|
|
|
66
66
|
]
|
|
67
67
|
},
|
|
68
68
|
"scripts": {
|
|
69
|
-
"cleanup": "rimraf node_modules"
|
|
69
|
+
"cleanup": "rimraf node_modules",
|
|
70
|
+
"lint": "prettier --check .",
|
|
71
|
+
"format": "prettier --write ."
|
|
70
72
|
}
|
|
71
73
|
}
|
package/src/index.js
CHANGED
|
@@ -51,17 +51,18 @@ export default function (file, output, options) {
|
|
|
51
51
|
gltfLoader.parse(
|
|
52
52
|
arrayBuffer,
|
|
53
53
|
'',
|
|
54
|
-
(gltf) => {
|
|
54
|
+
async (gltf) => {
|
|
55
55
|
const raw = parse(filePath, gltf, options)
|
|
56
56
|
try {
|
|
57
|
-
const prettiered = prettier.format(raw, {
|
|
58
|
-
semi: false,
|
|
59
|
-
bracketSameLine: true,
|
|
60
|
-
svelteBracketNewLine: false,
|
|
61
|
-
printWidth: options.printwidth || 120,
|
|
62
|
-
svelteBracketNewLine: true,
|
|
57
|
+
const prettiered = await prettier.format(raw, {
|
|
63
58
|
singleQuote: true,
|
|
64
|
-
|
|
59
|
+
trailingComma: 'none',
|
|
60
|
+
semi: false,
|
|
61
|
+
printWidth: 100,
|
|
62
|
+
parser: 'svelte',
|
|
63
|
+
plugins: ['prettier-plugin-svelte'],
|
|
64
|
+
overrides: [{ files: '*.svelte', options: { parser: 'svelte' } }],
|
|
65
|
+
singleAttributePerLine: true
|
|
65
66
|
})
|
|
66
67
|
stream.write(prettiered)
|
|
67
68
|
stream.end()
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
export type Options = {
|
|
2
|
+
output?: string
|
|
3
|
+
types?: boolean
|
|
4
|
+
keepnames?: boolean
|
|
5
|
+
keepgroups?: boolean
|
|
6
|
+
shadows?: boolean
|
|
7
|
+
printwidth?: number
|
|
8
|
+
meta?: boolean
|
|
9
|
+
precision?: number
|
|
10
|
+
isolated?: boolean
|
|
11
|
+
preload?: boolean
|
|
12
|
+
suspense?: boolean
|
|
13
|
+
draco?: string
|
|
14
|
+
root?: string
|
|
15
|
+
transform?: boolean
|
|
16
|
+
resolution?: number
|
|
17
|
+
simplify?: boolean
|
|
18
|
+
weld?: number
|
|
19
|
+
ratio?: number
|
|
20
|
+
error?: number
|
|
21
|
+
debug?: boolean
|
|
22
|
+
}
|
package/src/utils/glftLoader.js
CHANGED
package/src/utils/parser.js
CHANGED
|
@@ -1,6 +1,12 @@
|
|
|
1
1
|
import THREE from 'three'
|
|
2
2
|
import isVarName from './isVarName.js'
|
|
3
3
|
|
|
4
|
+
/**
|
|
5
|
+
* @param {string} fileName
|
|
6
|
+
* @param {import('three/examples/jsm/loaders/GLTFLoader').GLTF} gltf
|
|
7
|
+
* @param {import('./Options.d.ts').Options} options
|
|
8
|
+
* @returns {string}
|
|
9
|
+
*/
|
|
4
10
|
function parse(fileName, gltf, options = {}) {
|
|
5
11
|
const url = fileName
|
|
6
12
|
const animations = gltf.animations
|
|
@@ -460,29 +466,22 @@ function parse(fileName, gltf, options = {}) {
|
|
|
460
466
|
// 2nd pass to eliminate hard to swat left-overs
|
|
461
467
|
const scene = printThrelte(gltf.scene)
|
|
462
468
|
|
|
463
|
-
const useGltfOptions =
|
|
464
|
-
options.transform && options.draco
|
|
465
|
-
|
|
466
|
-
useDraco: options.draco
|
|
467
|
-
}
|
|
468
|
-
: options.transform
|
|
469
|
-
? {
|
|
470
|
-
useDraco: true
|
|
471
|
-
}
|
|
472
|
-
: undefined
|
|
469
|
+
const useGltfOptions = {
|
|
470
|
+
draco: options.transform && options.draco ? (options.draco ? options.transform : true) : false
|
|
471
|
+
}
|
|
473
472
|
|
|
474
473
|
const imports = `
|
|
475
474
|
${options.types ? `\nimport type * as THREE from 'three'` : ''}
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
]
|
|
475
|
+
${hasAnimations ? `import { Group } from 'three'` : ''}
|
|
476
|
+
${options.types ? `import type { Snippet } from 'svelte'` : ''}
|
|
477
|
+
import { ${['T', options.types && !options.isolated ? 'type Props' : '']
|
|
480
478
|
.filter(Boolean)
|
|
481
479
|
.join(', ')} } from '@threlte/core'
|
|
482
480
|
import { ${[
|
|
483
481
|
'useGltf',
|
|
484
482
|
hasAnimations ? 'useGltfAnimations' : '',
|
|
485
|
-
options.suspense ? 'useSuspense' : ''
|
|
483
|
+
options.suspense ? 'useSuspense' : '',
|
|
484
|
+
useGltfOptions.draco ? 'useDraco' : ''
|
|
486
485
|
]
|
|
487
486
|
.filter(Boolean)
|
|
488
487
|
.join(', ')} } from '@threlte/extras'
|
|
@@ -490,7 +489,7 @@ function parse(fileName, gltf, options = {}) {
|
|
|
490
489
|
|
|
491
490
|
const useGltf = `${options.suspense ? 'suspend(' : ''}useGltf${
|
|
492
491
|
options.types ? '<GLTFResult>' : ''
|
|
493
|
-
}('${url}'${useGltfOptions ? `, ${
|
|
492
|
+
}('${url}'${useGltfOptions.draco ? `, { dracoLoader: useDraco(${typeof useGltfOptions.draco === 'string' ? `'${useGltfOptions.draco}'` : ''}) }` : ''})${
|
|
494
493
|
options.suspense ? ')' : ''
|
|
495
494
|
}`
|
|
496
495
|
|
|
@@ -507,7 +506,6 @@ ${parseExtras(gltf.parser.json.asset && gltf.parser.json.asset.extras)}-->
|
|
|
507
506
|
${
|
|
508
507
|
options.preload
|
|
509
508
|
? `
|
|
510
|
-
|
|
511
509
|
<script context="module"${options.types ? ' lang="ts"' : ''}>
|
|
512
510
|
${imports}
|
|
513
511
|
|
|
@@ -530,23 +528,31 @@ ${
|
|
|
530
528
|
<script${options.types ? ' lang="ts"' : ''}>
|
|
531
529
|
${!options.preload ? imports : ''}
|
|
532
530
|
|
|
533
|
-
${options.types && !options.isolated ? 'type $$Events = Events<THREE.Group>' : ''}
|
|
534
|
-
${
|
|
535
|
-
options.types && !options.isolated
|
|
536
|
-
? 'type $$Slots = Slots<THREE.Group> & { fallback: {}; error: { error: any } }'
|
|
537
|
-
: ''
|
|
538
|
-
}
|
|
539
|
-
|
|
540
531
|
let {
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
532
|
+
fallback,
|
|
533
|
+
error,
|
|
534
|
+
children,
|
|
535
|
+
${options.isolated ? '' : 'ref = $bindable(),'}
|
|
536
|
+
${options.isolated ? '' : '...props'}
|
|
537
|
+
}${
|
|
538
|
+
options.types
|
|
539
|
+
? `: ${options.isolated ? '' : 'Props<THREE.Group> & '} {
|
|
540
|
+
${options.isolated ? '' : 'ref?: THREE.Group'}
|
|
541
|
+
children?: ${options.isolated ? 'Snippet' : 'Snippet<[{ ref: THREE.Group }]>'}
|
|
542
|
+
fallback?: Snippet
|
|
543
|
+
error?: Snippet<[{ error: Error }]>
|
|
544
|
+
}`
|
|
545
|
+
: ''
|
|
546
|
+
} = $props()
|
|
544
547
|
|
|
545
548
|
${!options.preload && options.suspense ? 'const suspend = useSuspense()' : ''}
|
|
546
549
|
|
|
550
|
+
${hasAnimations && options.isolated ? 'const ref = new Group()' : hasAnimations ? 'ref = new Group()' : ''}
|
|
551
|
+
|
|
547
552
|
${options.types && !options.preload ? printThrelteTypes(objects, animations) : ''}
|
|
548
553
|
|
|
549
554
|
${!options.preload ? `const gltf = ${useGltf}` : 'const gltf = load()'}
|
|
555
|
+
|
|
550
556
|
${
|
|
551
557
|
hasAnimations
|
|
552
558
|
? `export const { actions, mixer } = useGltfAnimations${
|
|
@@ -556,17 +562,17 @@ ${
|
|
|
556
562
|
}
|
|
557
563
|
</script>
|
|
558
564
|
|
|
559
|
-
|
|
565
|
+
<${hasAnimations ? 'T is={ref}' : 'T.Group'} ${!hasAnimations && !options.isolated ? 'bind:ref' : ''} dispose={false} ${!options.isolated ? '{...props}' : ''}>
|
|
560
566
|
{#await gltf}
|
|
561
|
-
|
|
567
|
+
{@render fallback?.()}
|
|
562
568
|
{:then gltf}
|
|
563
569
|
${scene}
|
|
564
|
-
{:catch
|
|
565
|
-
|
|
570
|
+
{:catch err}
|
|
571
|
+
{@render error?.({ error: err })}
|
|
566
572
|
{/await}
|
|
567
573
|
|
|
568
|
-
|
|
569
|
-
|
|
574
|
+
{@render children?.(${options.isolated ? '' : '{ ref }'})}
|
|
575
|
+
</${hasAnimations ? 'T' : 'T.Group'}>
|
|
570
576
|
`
|
|
571
577
|
}
|
|
572
578
|
|
package/src/utils/transform.js
CHANGED
|
@@ -1,5 +1,13 @@
|
|
|
1
1
|
import { NodeIO } from '@gltf-transform/core'
|
|
2
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
simplify,
|
|
4
|
+
weld,
|
|
5
|
+
dedup,
|
|
6
|
+
resample,
|
|
7
|
+
prune,
|
|
8
|
+
textureCompress,
|
|
9
|
+
draco
|
|
10
|
+
} from '@gltf-transform/functions'
|
|
3
11
|
import { ALL_EXTENSIONS } from '@gltf-transform/extensions'
|
|
4
12
|
import { MeshoptDecoder, MeshoptEncoder, MeshoptSimplifier } from 'meshoptimizer'
|
|
5
13
|
import draco3d from 'draco3dgltf'
|
|
@@ -12,7 +20,7 @@ async function transform(file, output, config = {}) {
|
|
|
12
20
|
'draco3d.decoder': await draco3d.createDecoderModule(),
|
|
13
21
|
'draco3d.encoder': await draco3d.createEncoderModule(),
|
|
14
22
|
'meshopt.decoder': MeshoptDecoder,
|
|
15
|
-
'meshopt.encoder': MeshoptEncoder
|
|
23
|
+
'meshopt.encoder': MeshoptEncoder
|
|
16
24
|
})
|
|
17
25
|
|
|
18
26
|
const document = await io.read(file)
|
|
@@ -28,7 +36,7 @@ async function transform(file, output, config = {}) {
|
|
|
28
36
|
// Resize and convert textures (using webp and sharp)
|
|
29
37
|
textureCompress({ targetFormat: 'webp', encoder: sharp, resize: [resolution, resolution] }),
|
|
30
38
|
// Add Draco compression.
|
|
31
|
-
draco()
|
|
39
|
+
draco()
|
|
32
40
|
]
|
|
33
41
|
|
|
34
42
|
if (config.simplify) {
|
|
@@ -36,7 +44,11 @@ async function transform(file, output, config = {}) {
|
|
|
36
44
|
// Weld vertices
|
|
37
45
|
weld({ tolerance: config.weld ?? 0.0001 }),
|
|
38
46
|
// Simplify meshes
|
|
39
|
-
simplify({
|
|
47
|
+
simplify({
|
|
48
|
+
simplifier: MeshoptSimplifier,
|
|
49
|
+
ratio: config.ratio ?? 0.75,
|
|
50
|
+
error: config.error ?? 0.001
|
|
51
|
+
})
|
|
40
52
|
)
|
|
41
53
|
}
|
|
42
54
|
|