├── .github
├── FUNDING.yml
└── workflows
│ └── main.yml
├── .gitignore
├── .npmignore
├── .yarn
└── install-state.gz
├── .yarnrc.yml
├── LICENSE
├── cli.js
├── logo.svg
├── package.json
├── readme.md
├── rollup.config.js
├── src
├── bin
│ ├── DRACOLoader.js
│ └── GLTFLoader.js
├── gltfjsx.js
├── test.js
└── utils
│ ├── exports.js
│ ├── isVarName.js
│ ├── parser.js
│ └── transform.js
└── yarn.lock
/.github/FUNDING.yml:
--------------------------------------------------------------------------------
1 | # These are supported funding model platforms
2 |
3 | github: drcmda
4 | open_collective: react-three-fiber
5 |
--------------------------------------------------------------------------------
/.github/workflows/main.yml:
--------------------------------------------------------------------------------
1 | name: CI
2 | on:
3 | - push
4 | - pull_request
5 | jobs:
6 | test:
7 | name: Node.js ${{ matrix.node-version }}
8 | runs-on: ubuntu-latest
9 | strategy:
10 | fail-fast: false
11 | matrix:
12 | node-version:
13 | - 20
14 | - 18
15 | steps:
16 | - uses: actions/checkout@v3
17 | - uses: actions/setup-node@v3
18 | with:
19 | node-version: ${{ matrix.node-version }}
20 | - run: corepack enable
21 | - run: yarn install --immutable
22 | - run: npm test
23 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules/
2 | coverage/
3 | dist/
4 | types/
5 | Thumbs.db
6 | ehthumbs.db
7 | Desktop.ini
8 | $RECYCLE.BIN/
9 | .DS_Store
10 | .vscode
11 | .docz/
12 | package-lock.json
13 | coverage/
14 | .idea
15 | yarn-error.log
16 |
--------------------------------------------------------------------------------
/.npmignore:
--------------------------------------------------------------------------------
1 | example/
--------------------------------------------------------------------------------
/.yarn/install-state.gz:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pmndrs/gltfjsx/f4fbfa2a19ffa7c05b1a93745da7b4a7abd497f4/.yarn/install-state.gz
--------------------------------------------------------------------------------
/.yarnrc.yml:
--------------------------------------------------------------------------------
1 | nodeLinker: node-modules
2 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2020 Paul Henschel
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/cli.js:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env node
2 | 'use strict'
3 | import meow from 'meow'
4 | import { fileURLToPath } from 'url'
5 | import { dirname } from 'path'
6 | import gltfjsx from './src/gltfjsx.js'
7 | import { readPackageUpSync } from 'read-pkg-up'
8 |
9 | const __filename = fileURLToPath(import.meta.url)
10 | const __dirname = dirname(__filename)
11 |
12 | const cli = meow(
13 | `
14 | Usage
15 | $ npx gltfjsx [Model.glb] [options]
16 |
17 | Options
18 | --output, -o Output file name/path
19 | --types, -t Add Typescript definitions
20 | --keepnames, -k Keep original names
21 | --keepgroups, -K Keep (empty) groups, disable pruning
22 | --bones, -b Lay out bones declaratively (default: false)
23 | --meta, -m Include metadata (as userData)
24 | --shadows, s Let meshes cast and receive shadows
25 | --printwidth, w Prettier printWidth (default: 120)
26 | --precision, -p Number of fractional digits (default: 3)
27 | --draco, -d Draco binary path
28 | --root, -r Sets directory from which .gltf file is served
29 | --instance, -i Instance re-occuring geometry
30 | --instanceall, -I Instance every geometry (for cheaper re-use)
31 | --exportdefault, -E Use default export
32 | --transform, -T Transform the asset for the web (draco, prune, resize)
33 | --resolution, -R Resolution for texture resizing (default: 1024)
34 | --keepmeshes, -j Do not join compatible meshes
35 | --keepmaterials, -M Do not palette join materials
36 | --format, -f Texture format (default: "webp")
37 | --simplify, -S Mesh simplification (default: false)
38 | --ratio Simplifier ratio (default: 0)
39 | --error Simplifier error threshold (default: 0.0001)
40 | --console, -c Log JSX to console, won't produce a file
41 | --debug, -D Debug output
42 | `,
43 | {
44 | importMeta: import.meta,
45 | flags: {
46 | output: { type: 'string', shortFlag: 'o' },
47 | types: { type: 'boolean', shortFlag: 't' },
48 | keepnames: { type: 'boolean', shortFlag: 'k' },
49 | keepgroups: { type: 'boolean', shortFlag: 'K' },
50 | bones: { type: 'boolean', shortFlag: 'b', default: false },
51 | shadows: { type: 'boolean', shortFlag: 's' },
52 | printwidth: { type: 'number', shortFlag: 'p', default: 1000 },
53 | meta: { type: 'boolean', shortFlag: 'm' },
54 | precision: { type: 'number', shortFlag: 'p', default: 3 },
55 | draco: { type: 'string', shortFlag: 'd' },
56 | root: { type: 'string', shortFlag: 'r' },
57 | instance: { type: 'boolean', shortFlag: 'i' },
58 | instanceall: { type: 'boolean', shortFlag: 'I' },
59 | transform: { type: 'boolean', shortFlag: 'T' },
60 | resolution: { type: 'number', shortFlag: 'R', default: 1024 },
61 | degrade: { type: 'string', shortFlag: 'q', default: '' },
62 | degraderesolution: { type: 'number', shortFlag: 'Q', default: 512 },
63 | simplify: { type: 'boolean', shortFlag: 'S', default: false },
64 | keepmeshes: { type: 'boolean', shortFlag: 'j', default: false },
65 | keepmaterials: { type: 'boolean', shortFlag: 'M', default: false },
66 | format: { type: 'string', shortFlag: 'f', default: 'webp' },
67 | exportdefault: { type: 'boolean', shortFlag: 'E' },
68 | ratio: { type: 'number', default: 0.75 },
69 | error: { type: 'number', default: 0.001 },
70 | console: { type: 'boolean', shortFlag: 'c' },
71 | debug: { type: 'boolean', shortFlag: 'D' },
72 | },
73 | }
74 | )
75 |
76 | const { packageJson } = readPackageUpSync({ cwd: __dirname, normalize: false })
77 |
78 | if (cli.input.length === 0) {
79 | console.log(cli.help)
80 | } else {
81 | const config = {
82 | ...cli.flags,
83 | header: `Auto-generated by: https://github.com/pmndrs/gltfjsx
84 | Command: npx gltfjsx@${packageJson.version} ${process.argv.slice(2).join(' ')}`,
85 | }
86 | const file = cli.input[0]
87 | let nameExt = file.match(/[-_\w\d\s]+[.][\w]+$/i)[0]
88 | let name = nameExt.split('.').slice(0, -1).join('.')
89 | const output = config.output ?? name.charAt(0).toUpperCase() + name.slice(1) + (config.types ? '.tsx' : '.jsx')
90 | const showLog = (log) => {
91 | console.info('log:', log)
92 | }
93 | try {
94 | const response = await gltfjsx(file, output, { ...config, showLog, timeout: 0, delay: 1 })
95 | } catch (e) {
96 | console.error(e)
97 | }
98 | }
99 |
--------------------------------------------------------------------------------
/logo.svg:
--------------------------------------------------------------------------------
1 |
146 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "gltfjsx",
3 | "version": "6.5.2",
4 | "description": "GLTF to JSX converter",
5 | "scripts": {
6 | "build": "rollup -c",
7 | "test": "node src/test"
8 | },
9 | "type": "module",
10 | "keywords": [
11 | "gltf",
12 | "jsx",
13 | "react",
14 | "fiber",
15 | "three",
16 | "threejs",
17 | "webp"
18 | ],
19 | "author": "Paul Henschel",
20 | "maintainers": [
21 | "Max Rusan"
22 | ],
23 | "license": "MIT",
24 | "repository": {
25 | "type": "git",
26 | "url": "git+https://github.com/pmndrs/gltfjsx.git"
27 | },
28 | "bugs": {
29 | "url": "https://github.com/pmndrs/gltfjsx/issues"
30 | },
31 | "homepage": "https://github.com/pmndrs/gltfjsx#readme",
32 | "bin": "./cli.js",
33 | "main": "dist/index.cjs",
34 | "module": "dist/index.js",
35 | "engines": {
36 | "node": ">=16"
37 | },
38 | "dependencies": {
39 | "@gltf-transform/core": "4.1.0",
40 | "@gltf-transform/extensions": "4.1.0",
41 | "@gltf-transform/functions": "4.1.0",
42 | "@node-loader/babel": "^2.0.1",
43 | "draco3dgltf": "^1.5.7",
44 | "is-var-name": "^2.0.0",
45 | "keyframe-resample": "^0.1.0",
46 | "meow": "^12.1.1",
47 | "meshoptimizer": "^0.22.0",
48 | "prettier": "3.1.1",
49 | "read-pkg-up": "^10.1.0",
50 | "three": "0.159.0",
51 | "three-stdlib": "^2.28.7"
52 | },
53 | "optionalDependencies": {
54 | "jsdom": "^24.1.0",
55 | "jsdom-global": "^3.0.2",
56 | "libvips": "0.0.2",
57 | "sharp": "^0.33.5"
58 | },
59 | "resolutions": {
60 | "sharp": "<0.33.0",
61 | "@gltf-transform/core": "4.0.8",
62 | "@gltf-transform/extensions": "4.0.8",
63 | "@gltf-transform/functions": "4.0.8"
64 | },
65 | "devDependencies": {
66 | "@babel/core": "7.23.6",
67 | "@babel/plugin-proposal-class-properties": "^7.16.0",
68 | "@babel/plugin-transform-modules-commonjs": "7.23.3",
69 | "@babel/plugin-transform-parameters": "7.23.3",
70 | "@babel/plugin-transform-runtime": "7.23.6",
71 | "@babel/plugin-transform-template-literals": "7.23.3",
72 | "@babel/preset-env": "7.23.6",
73 | "@babel/preset-react": "7.23.3",
74 | "@babel/preset-typescript": "^7.23.3",
75 | "@rollup/plugin-babel": "^6.0.4",
76 | "@rollup/plugin-node-resolve": "^15.2.3",
77 | "chalk": "^5.3.0",
78 | "fast-glob": "^3.3.2",
79 | "fs-extra": "^11.2.0",
80 | "lint-staged": "^13.2.0",
81 | "rollup": "^4.9.1",
82 | "rollup-plugin-size-snapshot": "^0.12.0",
83 | "rollup-plugin-terser": "^7.0.2"
84 | },
85 | "prettier": {
86 | "semi": false,
87 | "trailingComma": "es5",
88 | "singleQuote": true,
89 | "jsxBracketSameLine": true,
90 | "tabWidth": 2,
91 | "printWidth": 120
92 | },
93 | "lint-staged": {
94 | "*.{js,jsx,ts,tsx}": [
95 | "prettier --write"
96 | ]
97 | },
98 | "collective": {
99 | "type": "opencollective",
100 | "url": "https://opencollective.com/react-three-fiber"
101 | },
102 | "packageManager": "yarn@4.4.0+sha256.5f228cb28f2edb97d8c3b667fb7b2fdcf06c46798e25ea889dad9e0b4bc2e2c1"
103 | }
104 |
--------------------------------------------------------------------------------
/readme.md:
--------------------------------------------------------------------------------
1 | https://user-images.githubusercontent.com/2223602/126318148-99da7ed6-a578-48dd-bdd2-21056dbad003.mp4
2 |
3 |
4 |
5 |
6 | [](https://www.npmjs.com/package/gltfjsx) [](https://discord.gg/ZZjjNvJ)
7 |
8 | A small command-line tool that turns GLTF assets into declarative and re-usable [react-three-fiber](https://github.com/pmndrs/react-three-fiber) JSX components.
9 |
10 | ### The GLTF workflow on the web is not ideal ...
11 |
12 | - GLTF is thrown whole into the scene which prevents re-use, in threejs objects can only be mounted once
13 | - Contents can only be found by traversal which is cumbersome and slow
14 | - Changes to queried nodes are made by mutation, which alters the source data and prevents re-use
15 | - Re-structuring content, making nodes conditional or adding/removing is cumbersome
16 | - Model compression is complex and not easily achieved
17 | - Models often have unnecessary nodes that cause extra work and matrix updates
18 |
19 | ### GLTFJSX fixes that
20 |
21 | - 🧑💻 It creates a virtual graph of all objects and materials. Now you can easily alter contents and re-use.
22 | - 🏎️ The graph gets pruned (empty groups, unnecessary transforms, ...) and will perform better.
23 | - ⚡️ It will optionally compress your model with up to 70%-90% size reduction.
24 |
25 | ## Usage
26 |
27 | ```text
28 | Usage
29 | $ npx gltfjsx [Model.glb] [options]
30 |
31 | Options
32 | --output, -o Output file name/path
33 | --types, -t Add Typescript definitions
34 | --keepnames, -k Keep original names
35 | --keepgroups, -K Keep (empty) groups, disable pruning
36 | --bones, -b Lay out bones declaratively (default: false)
37 | --meta, -m Include metadata (as userData)
38 | --shadows, s Let meshes cast and receive shadows
39 | --printwidth, w Prettier printWidth (default: 120)
40 | --precision, -p Number of fractional digits (default: 3)
41 | --draco, -d Draco binary path
42 | --root, -r Sets directory from which .gltf file is served
43 | --instance, -i Instance re-occuring geometry
44 | --instanceall, -I Instance every geometry (for cheaper re-use)
45 | --exportdefault, -E Use default export
46 | --transform, -T Transform the asset for the web (draco, prune, resize)
47 | --resolution, -R Resolution for texture resizing (default: 1024)
48 | --keepmeshes, -j Do not join compatible meshes
49 | --keepmaterials, -M Do not palette join materials
50 | --format, -f Texture format (default: "webp")
51 | --simplify, -S Mesh simplification (default: false)
52 | --ratio Simplifier ratio (default: 0)
53 | --error Simplifier error threshold (default: 0.0001)
54 | --console, -c Log JSX to console, won't produce a file
55 | --debug, -D Debug output
56 | ```
57 |
58 | ### A typical use-case
59 |
60 | First you run your model through gltfjsx. `npx` allows you to use npm packages without installing them.
61 |
62 | ```bash
63 | npx gltfjsx model.gltf --transform
64 | ```
65 |
66 | This will create a `Model.jsx` file that plots out all of the assets contents.
67 |
68 | ```jsx
69 | /*
70 | auto-generated by: https://github.com/pmdrs/gltfjsx
71 | author: abcdef (https://sketchfab.com/abcdef)
72 | license: CC-BY-4.0 (http://creativecommons.org/licenses/by/4.0/)
73 | source: https://sketchfab.com/models/...
74 | title: Model
75 | */
76 |
77 | import { useGLTF, PerspectiveCamera } from '@react-three/drei'
78 |
79 | export function Model(props) {
80 | const { nodes, materials } = useGLTF('/model-transformed.glb')
81 | return (
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 | )
91 | }
92 |
93 | useGLTF.preload('/model.gltf')
94 | ```
95 |
96 | Add your model to your `/public` folder as you would normally do. With the `--transform` flag it has created a compressed copy of it (in the above case `model-transformed.glb`). Without the flag just copy the original model.
97 |
98 | ```text
99 | /public
100 | model-transformed.glb
101 | ```
102 |
103 | The component can now be dropped into your scene.
104 |
105 | ```jsx
106 | import { Canvas } from '@react-three/fiber'
107 | import { Model } from './Model'
108 |
109 | function App() {
110 | return (
111 |