occt-gltf-addon 0.1.0

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/CMakeLists.txt ADDED
@@ -0,0 +1,183 @@
1
+ cmake_minimum_required(VERSION 3.16)
2
+
3
+ project(occt_gltf_addon LANGUAGES CXX)
4
+
5
+ set(CMAKE_CXX_STANDARD 17)
6
+ set(CMAKE_CXX_STANDARD_REQUIRED ON)
7
+ set(CMAKE_POSITION_INDEPENDENT_CODE ON)
8
+
9
+ # --- Node / N-API via cmake-js ---
10
+ # cmake-js provides:
11
+ # - CMAKE_JS_INC: include dirs for Node headers
12
+ # - CMAKE_JS_LIB: link library for Node
13
+ if(NOT DEFINED CMAKE_JS_INC OR NOT DEFINED CMAKE_JS_LIB)
14
+ message(FATAL_ERROR "This project is intended to be built with cmake-js. Run: npm run build")
15
+ endif()
16
+
17
+ # node-addon-api include dir (header-only)
18
+ execute_process(
19
+ COMMAND node -p "require('node-addon-api').include"
20
+ WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR}
21
+ OUTPUT_VARIABLE NODE_ADDON_API_DIR
22
+ OUTPUT_STRIP_TRAILING_WHITESPACE
23
+ )
24
+ # node-addon-api returns a quoted string; strip quotes if present
25
+ string(REPLACE "\"" "" NODE_ADDON_API_DIR ${NODE_ADDON_API_DIR})
26
+
27
+ # --- OCCT ---
28
+ # You can override by exporting OCCT_ROOT=/path/to/your/occt/install-prefix
29
+ if(DEFINED ENV{OCCT_ROOT} AND NOT "$ENV{OCCT_ROOT}" STREQUAL "")
30
+ set(OCCT_ROOT "$ENV{OCCT_ROOT}" CACHE PATH "OCCT install prefix" FORCE)
31
+ else()
32
+ if(APPLE)
33
+ set(OCCT_ROOT "/opt/homebrew" CACHE PATH "OCCT install prefix (e.g. /opt/homebrew or /usr/local)")
34
+ else()
35
+ set(OCCT_ROOT "/usr" CACHE PATH "OCCT install prefix (e.g. /usr, /usr/local, or your custom install)")
36
+ endif()
37
+ endif()
38
+
39
+ find_path(OCCT_INCLUDE_DIR
40
+ NAMES Standard.hxx
41
+ PATHS
42
+ "${OCCT_ROOT}/include/opencascade"
43
+ "${OCCT_ROOT}/include"
44
+ NO_DEFAULT_PATH
45
+ )
46
+ if(NOT OCCT_INCLUDE_DIR)
47
+ message(FATAL_ERROR "OCCT headers not found. Expected Standard.hxx under ${OCCT_ROOT}/include/opencascade. Set -DOCCT_ROOT=...")
48
+ endif()
49
+
50
+ set(_OCCT_LIBDIRS
51
+ "${OCCT_ROOT}/lib"
52
+ "${OCCT_ROOT}/lib64"
53
+ "${OCCT_ROOT}/lib/x86_64-linux-gnu"
54
+ "${OCCT_ROOT}/lib/aarch64-linux-gnu"
55
+ "${OCCT_ROOT}/lib/arm64-linux-gnu"
56
+ )
57
+
58
+ function(_occt_find_lib outvar name)
59
+ find_library(${outvar}
60
+ NAMES ${name}
61
+ PATHS ${_OCCT_LIBDIRS}
62
+ NO_DEFAULT_PATH
63
+ )
64
+ if(NOT ${outvar})
65
+ message(FATAL_ERROR "OCCT library ${name} not found under ${OCCT_ROOT}. Set OCCT_ROOT=/path/to/occt.")
66
+ endif()
67
+ endfunction()
68
+
69
+ # Find one of multiple possible toolkit names (OCCT version differences).
70
+ function(_occt_find_lib_any outvar)
71
+ set(_names ${ARGN})
72
+ find_library(${outvar}
73
+ NAMES ${_names}
74
+ PATHS ${_OCCT_LIBDIRS}
75
+ NO_DEFAULT_PATH
76
+ )
77
+ if(NOT ${outvar})
78
+ string(JOIN ", " _namesStr ${_names})
79
+ message(FATAL_ERROR "OCCT library not found. Tried: ${_namesStr} under ${OCCT_ROOT}. Set OCCT_ROOT=/path/to/occt.")
80
+ endif()
81
+ endfunction()
82
+
83
+ # Minimal set for STEP reading + meshing + topology
84
+ _occt_find_lib(OCCT_TKernel TKernel)
85
+ _occt_find_lib(OCCT_TKMath TKMath)
86
+ _occt_find_lib(OCCT_TKG2d TKG2d)
87
+ _occt_find_lib(OCCT_TKG3d TKG3d)
88
+ _occt_find_lib(OCCT_TKGeomBase TKGeomBase)
89
+ _occt_find_lib(OCCT_TKBRep TKBRep)
90
+ _occt_find_lib(OCCT_TKTopAlgo TKTopAlgo)
91
+ _occt_find_lib(OCCT_TKMesh TKMesh)
92
+ _occt_find_lib(OCCT_TKXSBase TKXSBase)
93
+
94
+ # OCCT 8.x puts STEPControl_Reader into TKDESTEP; older OCCT uses TKSTEP (+ STEPBase/STEPAttr).
95
+ _occt_find_lib_any(OCCT_TKSTEP_LIKE TKDESTEP TKSTEP)
96
+
97
+ # XDE / OCAF toolkits for STEPCAFControl_Reader + document/labels/names
98
+ _occt_find_lib(OCCT_TKCDF TKCDF)
99
+ _occt_find_lib(OCCT_TKLCAF TKLCAF)
100
+ _occt_find_lib(OCCT_TKCAF TKCAF)
101
+ _occt_find_lib(OCCT_TKXCAF TKXCAF)
102
+
103
+ add_library(${PROJECT_NAME} SHARED
104
+ src/addon.cpp
105
+ src/convert_worker.cpp
106
+ src/occt_convert_xde.cpp
107
+ src/gltf_writer_scene.cpp
108
+ )
109
+
110
+ # --- Optional: Draco (KHR_draco_mesh_compression) ---
111
+ option(OCCT_GLTF_ADDON_ENABLE_DRACO "Enable Draco mesh compression support" ON)
112
+ if(OCCT_GLTF_ADDON_ENABLE_DRACO)
113
+ if(DEFINED ENV{DRACO_ROOT} AND NOT "$ENV{DRACO_ROOT}" STREQUAL "")
114
+ set(DRACO_ROOT "$ENV{DRACO_ROOT}" CACHE PATH "Draco install prefix" FORCE)
115
+ else()
116
+ set(DRACO_ROOT "" CACHE PATH "Draco install prefix (optional)")
117
+ endif()
118
+
119
+ find_path(DRACO_INCLUDE_DIR
120
+ NAMES draco/compression/encode.h
121
+ PATHS
122
+ "${DRACO_ROOT}/include"
123
+ "/usr/include"
124
+ "/opt/homebrew/include"
125
+ "/usr/local/include"
126
+ )
127
+ find_library(DRACO_LIBRARY
128
+ NAMES draco
129
+ PATHS
130
+ "${DRACO_ROOT}/lib"
131
+ "/usr/lib"
132
+ "/usr/lib/x86_64-linux-gnu"
133
+ "/opt/homebrew/lib"
134
+ "/usr/local/lib"
135
+ )
136
+
137
+ if(DRACO_INCLUDE_DIR AND DRACO_LIBRARY)
138
+ message(STATUS "Draco enabled: ${DRACO_LIBRARY}")
139
+ target_include_directories(${PROJECT_NAME} PRIVATE ${DRACO_INCLUDE_DIR})
140
+ target_link_libraries(${PROJECT_NAME} PRIVATE ${DRACO_LIBRARY})
141
+ target_compile_definitions(${PROJECT_NAME} PRIVATE OCCT_GLTF_WITH_DRACO=1)
142
+ else()
143
+ message(STATUS "Draco not found; building without Draco support. Install via 'brew install draco' or set DRACO_ROOT.")
144
+ endif()
145
+ endif()
146
+
147
+ target_include_directories(${PROJECT_NAME} PRIVATE
148
+ ${CMAKE_JS_INC}
149
+ ${NODE_ADDON_API_DIR}
150
+ ${OCCT_INCLUDE_DIR}
151
+ ${CMAKE_CURRENT_LIST_DIR}/src
152
+ )
153
+
154
+ target_compile_definitions(${PROJECT_NAME} PRIVATE
155
+ NAPI_CPP_EXCEPTIONS
156
+ )
157
+
158
+ target_link_libraries(${PROJECT_NAME} PRIVATE
159
+ ${CMAKE_JS_LIB}
160
+ ${OCCT_TKXSBase}
161
+ ${OCCT_TKSTEP_LIKE}
162
+ ${OCCT_TKXCAF}
163
+ ${OCCT_TKCAF}
164
+ ${OCCT_TKLCAF}
165
+ ${OCCT_TKCDF}
166
+ ${OCCT_TKMesh}
167
+ ${OCCT_TKTopAlgo}
168
+ ${OCCT_TKBRep}
169
+ ${OCCT_TKGeomBase}
170
+ ${OCCT_TKG3d}
171
+ ${OCCT_TKG2d}
172
+ ${OCCT_TKMath}
173
+ ${OCCT_TKernel}
174
+ )
175
+
176
+ # Ensure the loaded addon can locate OCCT dylibs at runtime.
177
+ set_target_properties(${PROJECT_NAME} PROPERTIES
178
+ PREFIX ""
179
+ SUFFIX ".node"
180
+ BUILD_RPATH "${_OCCT_LIBDIRS}"
181
+ INSTALL_RPATH "${_OCCT_LIBDIRS}"
182
+ )
183
+
package/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026
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
+
package/README.md ADDED
@@ -0,0 +1,74 @@
1
+ ### occt-gltf-addon
2
+
3
+ Node.js N-API 原生扩展:使用 OpenCascade (OCCT) 将 **STEP (.step/.stp)** 转换为 **glTF 2.0 (GLB)**。
4
+
5
+ #### 安装(从 npm 安装会本地编译)
6
+
7
+ 这个包默认会在 `npm install` 时执行本地编译(`cmake-js`)。
8
+
9
+ 你需要:
10
+ - **CMake + C++ 编译器 + Python3**
11
+ - **OCCT 安装**(共享库 + headers)
12
+
13
+ 通过环境变量指定 OCCT 安装前缀:
14
+
15
+ ```bash
16
+ export OCCT_ROOT=/path/to/occt/prefix
17
+ npm i occt-gltf-addon
18
+ ```
19
+
20
+ 可选(启用 Draco 压缩需要开发包):
21
+ - `brew install draco` / `apt-get install libdraco-dev`
22
+
23
+ 如需跳过编译(不推荐,运行时会找不到 `.node`):
24
+
25
+ ```bash
26
+ OCCT_GLTF_ADDON_SKIP_BUILD=1 npm i occt-gltf-addon
27
+ ```
28
+
29
+ ---
30
+
31
+ #### API
32
+
33
+ ```js
34
+ const { convertSTEPToGLTF } = require('occt-gltf-addon');
35
+
36
+ await convertSTEPToGLTF({
37
+ inputPath: '/abs/in.step',
38
+ outputPath: '/abs/out.glb',
39
+ tessellation: { linearDeflection: 0.1, angularDeflection: 0.5 },
40
+ });
41
+ ```
42
+
43
+ 支持一次调用输出多个变体(只做一次 STEP read + XDE transfer):
44
+
45
+ ```js
46
+ await convertSTEPToGLTF({
47
+ inputPath,
48
+ logLevel: 'info',
49
+ variants: [
50
+ { outputPath: 'out.min.glb', tessellation: { linearDeflection: 5, angularDeflection: Math.PI/3 } },
51
+ { outputPath: 'out.glb', tessellation: { linearDeflection: 0.1, angularDeflection: 0.5 } },
52
+ ],
53
+ });
54
+ ```
55
+
56
+ ---
57
+
58
+ #### 关键选项说明(简版)
59
+
60
+ - **tessellation.linearDeflection / angularDeflection**:B-Rep 三角化精度
61
+ - **tessellation.smoothNormals / normalCreaseAngle**:平滑法线(默认开,60° crease)
62
+ - **filter.minBBoxDiagonal**:按包围盒对角线过滤小零件(单位为 STEP/OCCT 导入后的单位,通常 mm)
63
+ - **output.unit**:`'m'|'cm'|'mm'`(默认导出为米)
64
+ - **output.bakeTransforms**:把节点变换烘焙进顶点并把 node matrix 归零(类似 Blender Apply)
65
+ - **output.center**:`'none'|'xy'|'xz'|'yz'`(配合 bake 使用;Y-up 时 `xz` 会 ground 到 `minY=0`;Z-up 时 `xy` 会 ground 到 `minZ=0`)
66
+ - **output.zUp**:导出为 **Z-up 坐标**(适配 three.js `THREE.Object3D.DEFAULT_UP.set(0,0,1)`);注意这会变成 **非标准 glTF(标准是 Y-up)**
67
+ - **output.draco**:启用 `KHR_draco_mesh_compression`(部分导入器不支持)
68
+
69
+ ---
70
+
71
+ #### License
72
+
73
+ 本 addon 代码以 MIT 发布;运行时依赖 OCCT(LGPL 2.1)与可选 Draco(Apache 2.0)。
74
+
package/example.js ADDED
@@ -0,0 +1,81 @@
1
+ const path = require('path');
2
+ const { convertSTEPToGLTF } = require('./index');
3
+
4
+ function ensureGlbExt(p) {
5
+ const parsed = path.parse(p);
6
+ if (!parsed.ext) return `${p}.glb`;
7
+ return p;
8
+ }
9
+
10
+ async function main() {
11
+ const inputPath = process.argv[2];
12
+ if (!inputPath) {
13
+ console.error('Usage: node example.js <input.step> [output.glb]');
14
+ console.error(' It will write 2 files: <output>.min.glb and <output>.glb');
15
+ process.exit(1);
16
+ }
17
+ const outputPathArg = process.argv[3] || path.join(process.cwd(), 'out.glb');
18
+ const outputPath = ensureGlbExt(outputPathArg);
19
+ const parsed = path.parse(outputPath);
20
+ const outputPathMin = path.join(parsed.dir, `${parsed.name}.min${parsed.ext}`);
21
+
22
+ // “正常”参数:你可以在这里调整成你想要的默认精度
23
+ const tessNormal = {
24
+ linearDeflection: 0.1,
25
+ angularDeflection: 0.5,
26
+ };
27
+
28
+ // “极简”参数:基于正常参数做粗化(更少三角面,更快)
29
+ const tessMin = {
30
+ linearDeflection: 5,
31
+ angularDeflection: Math.PI / 3,
32
+ };
33
+ const filterMin = {
34
+ minBBoxDiagonal: 60
35
+ };
36
+ const outputOpts = {
37
+ unit: 'm',
38
+ bakeTransforms: true,
39
+ center: 'xy', // 'none' | 'xy' | 'xz' | 'yz'
40
+ // If your runtime uses Z-up world (e.g. three.js: THREE.Object3D.DEFAULT_UP.set(0,0,1)),
41
+ // enable this to export Z-up coordinates (note: non-standard glTF; Y-up viewers may show it rotated).
42
+ zUp: true,
43
+ // Draco (KHR_draco_mesh_compression). NOTE: some importers (e.g. Blender) may not support Draco.
44
+ // draco: { enabled: true, compressionLevel: 7, quantizationBitsPosition: 14, quantizationBitsNormal: 10 },
45
+ draco: {
46
+ enabled: true,
47
+ compressionLevel: 7, // 0..10 (越大越小/越慢)
48
+ quantizationBitsPosition: 14, // 1..30
49
+ quantizationBitsNormal: 10, // 1..30
50
+ }
51
+ };
52
+
53
+ console.log('Writing (min):', outputPathMin);
54
+ console.log('Writing (normal):', outputPath);
55
+ await convertSTEPToGLTF({
56
+ inputPath,
57
+ logLevel: 'info', // 'quiet' | 'info' | 'debug'
58
+ variants: [
59
+ {
60
+ outputPath: outputPathMin,
61
+ tessellation: tessMin,
62
+ filter: filterMin,
63
+ output: outputOpts,
64
+ },
65
+ {
66
+ outputPath,
67
+ tessellation: tessNormal,
68
+ output: outputOpts,
69
+ },
70
+ ],
71
+ });
72
+
73
+ console.log('Wrote:', outputPathMin);
74
+ console.log('Wrote:', outputPath);
75
+ }
76
+
77
+ main().catch((e) => {
78
+ console.error(e);
79
+ process.exit(1);
80
+ });
81
+
package/index.d.ts ADDED
@@ -0,0 +1,71 @@
1
+ export as namespace OcctGltfAddon;
2
+ export = OcctGltfAddon;
3
+
4
+ declare namespace OcctGltfAddon {
5
+ type LogLevel = 0 | 1 | 2 | 'quiet' | 'info' | 'debug';
6
+
7
+ interface TessellationOptions {
8
+ linearDeflection?: number;
9
+ angularDeflection?: number; // radians
10
+ smoothNormals?: boolean;
11
+ normalCreaseAngle?: number; // radians
12
+ }
13
+
14
+ interface FilterOptions {
15
+ minBBoxDiagonal?: number;
16
+ }
17
+
18
+ type OutputUnit = 'm' | 'cm' | 'mm';
19
+ type CenterMode = 'none' | 'xy' | 'xz' | 'yz';
20
+
21
+ interface DracoOptions {
22
+ enabled?: boolean;
23
+ compressionLevel?: number; // 0..10
24
+ quantizationBitsPosition?: number; // 1..30
25
+ quantizationBitsNormal?: number; // 1..30
26
+ }
27
+
28
+ interface OutputOptions {
29
+ unit?: OutputUnit;
30
+ unitScale?: number;
31
+
32
+ bakeTransforms?: boolean;
33
+ center?: CenterMode;
34
+ // legacy booleans
35
+ centerXY?: boolean;
36
+ centerXZ?: boolean;
37
+ centerYZ?: boolean;
38
+
39
+ // Export Z-up coordinates (useful for three.js Z-up worlds). Non-standard glTF.
40
+ zUp?: boolean;
41
+ zup?: boolean;
42
+
43
+ // KHR_draco_mesh_compression
44
+ draco?: boolean | DracoOptions;
45
+ }
46
+
47
+ interface VariantOptions {
48
+ outputPath: string;
49
+ tessellation?: TessellationOptions;
50
+ filter?: FilterOptions;
51
+ output?: OutputOptions;
52
+ }
53
+
54
+ interface ConvertOptions {
55
+ inputPath: string;
56
+
57
+ // Single-output mode
58
+ outputPath?: string;
59
+ tessellation?: TessellationOptions;
60
+ filter?: FilterOptions;
61
+ output?: OutputOptions;
62
+
63
+ // Multi-output mode
64
+ variants?: VariantOptions[];
65
+
66
+ logLevel?: LogLevel;
67
+ }
68
+
69
+ function convertSTEPToGLTF(options: ConvertOptions): Promise<void>;
70
+ }
71
+
package/index.js ADDED
@@ -0,0 +1,52 @@
1
+ // CommonJS entrypoint. cmake-js outputs: build/<Config>/<target>.node
2
+ const fs = require('fs');
3
+ const path = require('path');
4
+
5
+ // Prefer prebuilt, platform-specific package when available (fast install, no local compile).
6
+ if (!process.env.OCCT_GLTF_ADDON_BINDING_PATH) {
7
+ try {
8
+ if (process.platform === 'linux' && process.arch === 'x64') {
9
+ // eslint-disable-next-line import/no-dynamic-require, global-require
10
+ module.exports = require('occt-gltf-addon-linux-x64');
11
+ return;
12
+ }
13
+ } catch (e) {
14
+ // ignore and fall back to local build output
15
+ }
16
+ }
17
+
18
+ const overridePath = process.env.OCCT_GLTF_ADDON_BINDING_PATH;
19
+ const candidates = overridePath
20
+ ? [overridePath]
21
+ : [
22
+ path.join(__dirname, 'build', 'Release', 'occt_gltf_addon.node'),
23
+ path.join(__dirname, 'build', 'RelWithDebInfo', 'occt_gltf_addon.node'),
24
+ path.join(__dirname, 'build', 'Debug', 'occt_gltf_addon.node'),
25
+ ];
26
+
27
+ let lastErr = null;
28
+ for (const p of candidates) {
29
+ try {
30
+ if (!fs.existsSync(p)) continue;
31
+ // eslint-disable-next-line import/no-dynamic-require, global-require
32
+ module.exports = require(p);
33
+ return;
34
+ } catch (e) {
35
+ lastErr = e;
36
+ }
37
+ }
38
+
39
+ const msg = [
40
+ '[occt-gltf-addon] Failed to load native addon (.node).',
41
+ `Tried: ${candidates.map((p) => JSON.stringify(p)).join(', ')}`,
42
+ '',
43
+ 'If you installed from npm, ensure native build succeeded:',
44
+ '- CMake + C++ toolchain are installed',
45
+ "- OCCT is installed and OCCT_ROOT points to its install prefix (e.g. '/opt/homebrew', '/usr', '/usr/local', or your custom install)",
46
+ '',
47
+ "You can try: 'npm rebuild occt-gltf-addon' (with OCCT_ROOT exported).",
48
+ ].join('\n');
49
+
50
+ // Preserve original error for debugging.
51
+ throw new Error(`${msg}\n\n${String(lastErr && (lastErr.stack || lastErr.message || lastErr))}`);
52
+
package/package.json ADDED
@@ -0,0 +1,71 @@
1
+ {
2
+ "name": "occt-gltf-addon",
3
+ "version": "0.1.0",
4
+ "description": "STEP (.step/.stp) to glTF (GLB) converter using OpenCascade (OCCT) via a Node.js N-API addon",
5
+ "type": "commonjs",
6
+ "main": "index.js",
7
+ "types": "index.d.ts",
8
+ "license": "MIT",
9
+ "repository": {
10
+ "type": "git",
11
+ "url": "git+https://github.com/Open-Cascade-SAS/OCCT.git",
12
+ "directory": "occt-gltf-addon"
13
+ },
14
+ "bugs": {
15
+ "url": "https://github.com/Open-Cascade-SAS/OCCT/issues"
16
+ },
17
+ "homepage": "https://github.com/Open-Cascade-SAS/OCCT/tree/master/occt-gltf-addon",
18
+ "keywords": [
19
+ "occt",
20
+ "opencascade",
21
+ "step",
22
+ "stp",
23
+ "gltf",
24
+ "glb",
25
+ "cad",
26
+ "napi",
27
+ "node-addon-api",
28
+ "addon"
29
+ ],
30
+ "engines": {
31
+ "node": ">=18"
32
+ },
33
+ "os": [
34
+ "darwin",
35
+ "linux"
36
+ ],
37
+ "cpu": [
38
+ "arm64",
39
+ "x64"
40
+ ],
41
+ "files": [
42
+ "index.js",
43
+ "index.d.ts",
44
+ "README.md",
45
+ "LICENSE",
46
+ "CMakeLists.txt",
47
+ "src/**",
48
+ "scripts/**",
49
+ "example.js"
50
+ ],
51
+ "scripts": {
52
+ "install": "node scripts/install.js",
53
+ "build": "cmake-js compile -O build",
54
+ "clean": "rm -rf build",
55
+ "rebuild": "npm run clean && npm run build",
56
+ "example": "node example.js",
57
+ "test": "node -e \"console.log('no tests')\"",
58
+
59
+ "docker:build:linux-amd64": "bash docker/build-linux-amd64.sh",
60
+ "docker:image:linux-amd64": "docker buildx build --platform linux/amd64 -f docker/Dockerfile.linux-amd64 -t occt-addon-build:linux-amd64 ../..",
61
+ "docker:image:linux-amd64:nocache": "docker buildx build --no-cache --platform linux/amd64 -f docker/Dockerfile.linux-amd64 -t occt-addon-build:linux-amd64 ../.."
62
+ },
63
+ "optionalDependencies": {
64
+ "occt-gltf-addon-linux-x64": "0.1.0"
65
+ },
66
+ "dependencies": {
67
+ "cmake-js": "^7.3.1",
68
+ "node-addon-api": "^7.1.0"
69
+ }
70
+ }
71
+
@@ -0,0 +1,79 @@
1
+ /* eslint-disable no-console */
2
+ const { spawnSync } = require('child_process');
3
+ const fs = require('fs');
4
+ const path = require('path');
5
+
6
+ function run(cmd, args, opts) {
7
+ const r = spawnSync(cmd, args, { stdio: 'inherit', ...opts });
8
+ if (r.error) throw r.error;
9
+ if (r.status !== 0) {
10
+ const e = new Error(`${cmd} exited with code ${r.status}`);
11
+ e.code = r.status;
12
+ throw e;
13
+ }
14
+ }
15
+
16
+ function note(msg) {
17
+ console.error(`[occt-gltf-addon] ${msg}`);
18
+ }
19
+
20
+ function main() {
21
+ if (process.env.OCCT_GLTF_ADDON_SKIP_BUILD === '1') {
22
+ note('Skipping native build (OCCT_GLTF_ADDON_SKIP_BUILD=1).');
23
+ return;
24
+ }
25
+
26
+ if (process.platform === 'win32') {
27
+ note('Windows is not supported by this package at the moment.');
28
+ process.exit(1);
29
+ }
30
+
31
+ const pkgRoot = path.join(__dirname, '..');
32
+
33
+ // If a platform-specific prebuilt package is installed and loadable, skip building from source.
34
+ // This avoids expensive compilation during "npm install".
35
+ const prebuiltName =
36
+ process.platform === 'linux' && process.arch === 'x64'
37
+ ? 'occt-gltf-addon-linux-x64'
38
+ : null;
39
+ if (prebuiltName) {
40
+ try {
41
+ // eslint-disable-next-line import/no-dynamic-require, global-require
42
+ require(prebuiltName);
43
+ note(`Using prebuilt binary from ${prebuiltName}; skipping local build.`);
44
+ return;
45
+ } catch (e) {
46
+ // Prebuilt missing or not loadable (e.g. GLIBC mismatch). Fall back to local build.
47
+ note(`Prebuilt package ${prebuiltName} not usable; falling back to local build.`);
48
+ }
49
+ }
50
+
51
+ // Helpful hint for first-time users.
52
+ if (!process.env.OCCT_ROOT) {
53
+ note("OCCT_ROOT is not set. If build fails, set OCCT_ROOT to your OCCT install prefix (e.g. '/opt/homebrew', '/usr', '/usr/local', or your custom install).");
54
+ }
55
+
56
+ // Use the locally installed cmake-js (dependency).
57
+ const cmakeJsBin = path.join(pkgRoot, 'node_modules', '.bin', process.platform === 'win32' ? 'cmake-js.cmd' : 'cmake-js');
58
+ if (!fs.existsSync(cmakeJsBin)) {
59
+ note(`cmake-js not found at ${cmakeJsBin}. Try: 'npm install' again.`);
60
+ process.exit(1);
61
+ }
62
+
63
+ note('Building native addon with cmake-js...');
64
+ run(cmakeJsBin, ['compile', '-O', 'build'], { cwd: pkgRoot, env: process.env });
65
+ }
66
+
67
+ try {
68
+ main();
69
+ } catch (e) {
70
+ note('Native build failed.');
71
+ note(String(e && (e.stack || e.message || e)));
72
+ note('Troubleshooting:');
73
+ note('- Ensure you have a C++ toolchain + CMake installed');
74
+ note('- Ensure OCCT is installed and OCCT_ROOT points to its prefix');
75
+ note('- On macOS (Apple Silicon): Homebrew OCCT is typically under /opt/homebrew');
76
+ note("- To skip building (not recommended): set OCCT_GLTF_ADDON_SKIP_BUILD=1");
77
+ process.exit(1);
78
+ }
79
+