babylonjs-editor-cli 5.0.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.
Files changed (82) hide show
  1. package/bin/babylonjs-editor-cli.js +3 -0
  2. package/build/index.node.js +21 -0
  3. package/build/package.json +34 -0
  4. package/build/src/export.mjs +2 -0
  5. package/build/src/export.mjs.map +1 -0
  6. package/build/src/index.mjs +22 -0
  7. package/build/src/index.mjs.map +1 -0
  8. package/build/src/pack/assets/assets.mjs +26 -0
  9. package/build/src/pack/assets/assets.mjs.map +1 -0
  10. package/build/src/pack/assets/ktx.mjs +121 -0
  11. package/build/src/pack/assets/ktx.mjs.map +1 -0
  12. package/build/src/pack/assets/material.mjs +53 -0
  13. package/build/src/pack/assets/material.mjs.map +1 -0
  14. package/build/src/pack/assets/particle-system.mjs +75 -0
  15. package/build/src/pack/assets/particle-system.mjs.map +1 -0
  16. package/build/src/pack/assets/process.mjs +78 -0
  17. package/build/src/pack/assets/process.mjs.map +1 -0
  18. package/build/src/pack/assets/texture.mjs +61 -0
  19. package/build/src/pack/assets/texture.mjs.map +1 -0
  20. package/build/src/pack/geometry.mjs +19 -0
  21. package/build/src/pack/geometry.mjs.map +1 -0
  22. package/build/src/pack/pack.mjs +127 -0
  23. package/build/src/pack/pack.mjs.map +1 -0
  24. package/build/src/pack/scene.mjs +241 -0
  25. package/build/src/pack/scene.mjs.map +1 -0
  26. package/build/src/tools/extract.mjs +51 -0
  27. package/build/src/tools/extract.mjs.map +1 -0
  28. package/build/src/tools/fs.mjs +9 -0
  29. package/build/src/tools/fs.mjs.map +1 -0
  30. package/build/src/tools/ktx.mjs +36 -0
  31. package/build/src/tools/ktx.mjs.map +1 -0
  32. package/build/src/tools/process.mjs +21 -0
  33. package/build/src/tools/process.mjs.map +1 -0
  34. package/build/src/tools/scalar.mjs +23 -0
  35. package/build/src/tools/scalar.mjs.map +1 -0
  36. package/build/src/tools/scene.mjs +68 -0
  37. package/build/src/tools/scene.mjs.map +1 -0
  38. package/build/src/tools/worker.mjs +35 -0
  39. package/build/src/tools/worker.mjs.map +1 -0
  40. package/build/src/tools/workers/md5.mjs +10 -0
  41. package/build/src/tools/workers/md5.mjs.map +1 -0
  42. package/declaration/src/export.d.mts +1 -0
  43. package/declaration/src/index.d.mts +1 -0
  44. package/declaration/src/pack/assets/assets.d.mts +11 -0
  45. package/declaration/src/pack/assets/ktx.d.mts +28 -0
  46. package/declaration/src/pack/assets/material.d.mts +11 -0
  47. package/declaration/src/pack/assets/particle-system.d.mts +12 -0
  48. package/declaration/src/pack/assets/process.d.mts +9 -0
  49. package/declaration/src/pack/assets/texture.d.mts +7 -0
  50. package/declaration/src/pack/geometry.d.mts +10 -0
  51. package/declaration/src/pack/pack.d.mts +5 -0
  52. package/declaration/src/pack/scene.d.mts +13 -0
  53. package/declaration/src/tools/extract.d.mts +8 -0
  54. package/declaration/src/tools/fs.d.mts +2 -0
  55. package/declaration/src/tools/ktx.d.mts +3 -0
  56. package/declaration/src/tools/process.d.mts +5 -0
  57. package/declaration/src/tools/scalar.d.mts +8 -0
  58. package/declaration/src/tools/scene.d.mts +21 -0
  59. package/declaration/src/tools/worker.d.mts +18 -0
  60. package/declaration/src/tools/workers/md5.d.mts +1 -0
  61. package/esbuild.mjs +57 -0
  62. package/package.json +34 -0
  63. package/src/export.mts +1 -0
  64. package/src/index.mts +28 -0
  65. package/src/pack/assets/assets.mts +46 -0
  66. package/src/pack/assets/ktx.mts +158 -0
  67. package/src/pack/assets/material.mts +86 -0
  68. package/src/pack/assets/particle-system.mts +109 -0
  69. package/src/pack/assets/process.mts +102 -0
  70. package/src/pack/assets/texture.mts +91 -0
  71. package/src/pack/geometry.mts +38 -0
  72. package/src/pack/pack.mts +159 -0
  73. package/src/pack/scene.mts +346 -0
  74. package/src/tools/extract.mts +74 -0
  75. package/src/tools/fs.mts +11 -0
  76. package/src/tools/ktx.mts +44 -0
  77. package/src/tools/process.mts +21 -0
  78. package/src/tools/scalar.mts +28 -0
  79. package/src/tools/scene.mts +90 -0
  80. package/src/tools/worker.mts +39 -0
  81. package/src/tools/workers/md5.mts +13 -0
  82. package/tsconfig.json +21 -0
@@ -0,0 +1,86 @@
1
+ import { join } from "node:path/posix";
2
+
3
+ import fs from "fs-extra";
4
+
5
+ import { extractTextureAssetFromDataString, extractTextureAssetFromUrl } from "../../tools/extract.mjs";
6
+
7
+ import { compressFileToKtx } from "./ktx.mjs";
8
+ import { getExtractedTextureOutputPath } from "./texture.mjs";
9
+
10
+ export interface IProcessExportedMaterialOptions {
11
+ force: boolean;
12
+ publicDir: string;
13
+ exportedAssets: string[];
14
+ optimize: boolean;
15
+ }
16
+
17
+ export async function processExportedMaterial(absolutePath: string, options: IProcessExportedMaterialOptions) {
18
+ const materialData = await fs.readJSON(absolutePath);
19
+ if (materialData.customType !== "BABYLON.NodeMaterial") {
20
+ return;
21
+ }
22
+
23
+ const extractedTexturesOutputPath = getExtractedTextureOutputPath(options.publicDir);
24
+ await fs.ensureDir(extractedTexturesOutputPath);
25
+
26
+ const relativePaths = await extractNodeMaterialTextures(materialData, {
27
+ extractedTexturesOutputPath,
28
+ });
29
+
30
+ await fs.writeJSON(absolutePath, materialData, {
31
+ encoding: "utf-8",
32
+ });
33
+
34
+ await Promise.all(
35
+ relativePaths.map(async (relativePath) => {
36
+ const finalPath = join(options.publicDir, relativePath);
37
+
38
+ options.exportedAssets.push(finalPath);
39
+
40
+ await compressFileToKtx(finalPath, {
41
+ force: options.force,
42
+ exportedAssets: options.exportedAssets,
43
+ });
44
+ })
45
+ );
46
+ }
47
+
48
+ export interface IExtractNodeMaterialTexturesOptions {
49
+ extractedTexturesOutputPath: string;
50
+ }
51
+
52
+ export async function extractNodeMaterialTextures(materialData: any, options: IExtractNodeMaterialTexturesOptions) {
53
+ const blocks = materialData.blocks.filter(
54
+ (block: any) => (block.customType === "BABYLON.TextureBlock" || block.customType === "BABYLON.ImageSourceBlock") && block.texture?.name
55
+ );
56
+
57
+ const relativePaths: string[] = [];
58
+
59
+ await Promise.all(
60
+ blocks.map(async (block: any) => {
61
+ if (block.texture?.name?.startsWith("http://") || block.texture.name.startsWith("https://")) {
62
+ const relativePath = await extractTextureAssetFromUrl(block.texture.name, {
63
+ ...options,
64
+ });
65
+
66
+ if (relativePath) {
67
+ relativePaths.push(relativePath);
68
+ block.texture.name = block.texture.url = relativePath;
69
+ }
70
+ }
71
+
72
+ if (block.texture.name?.startsWith("data:")) {
73
+ const relativePath = await extractTextureAssetFromDataString(block.texture.name, {
74
+ ...options,
75
+ });
76
+
77
+ if (relativePath) {
78
+ relativePaths.push(relativePath);
79
+ block.texture.name = block.texture.url = relativePath;
80
+ }
81
+ }
82
+ })
83
+ );
84
+
85
+ return relativePaths;
86
+ }
@@ -0,0 +1,109 @@
1
+ import { join } from "node:path/posix";
2
+
3
+ import fs from "fs-extra";
4
+
5
+ import { extractTextureAssetFromDataString, extractTextureAssetFromUrl } from "../../tools/extract.mjs";
6
+
7
+ import { compressFileToKtx } from "./ktx.mjs";
8
+ import { getExtractedTextureOutputPath } from "./texture.mjs";
9
+
10
+ export interface IProcessExportedMaterialOptions {
11
+ force: boolean;
12
+ publicDir: string;
13
+ exportedAssets: string[];
14
+ optimize: boolean;
15
+ }
16
+
17
+ export async function processExportedNodeParticleSystemSet(absolutePath: string, options: IProcessExportedMaterialOptions) {
18
+ const particleSystemData = await fs.readJSON(absolutePath);
19
+ if (particleSystemData.customType !== "BABYLON.NodeParticleSystemSet") {
20
+ return;
21
+ }
22
+
23
+ const extractedTexturesOutputPath = getExtractedTextureOutputPath(options.publicDir);
24
+ await fs.ensureDir(extractedTexturesOutputPath);
25
+
26
+ const relativePaths = await extractNodeParticleSystemSetTextures(particleSystemData, {
27
+ extractedTexturesOutputPath,
28
+ });
29
+
30
+ await fs.writeJSON(absolutePath, particleSystemData, {
31
+ encoding: "utf-8",
32
+ });
33
+
34
+ await Promise.all(
35
+ relativePaths.map(async (relativePath) => {
36
+ const finalPath = join(options.publicDir, relativePath);
37
+
38
+ options.exportedAssets.push(finalPath);
39
+
40
+ if (options.optimize) {
41
+ await compressFileToKtx(finalPath, {
42
+ force: options.force,
43
+ exportedAssets: options.exportedAssets,
44
+ });
45
+ }
46
+ })
47
+ );
48
+ }
49
+
50
+ export interface IExtractParticleSystemTexturesOptions {
51
+ extractedTexturesOutputPath: string;
52
+ }
53
+
54
+ export async function extractParticleSystemTextures(particleSystemData: any, options: IExtractParticleSystemTexturesOptions) {
55
+ let relativePath: string | null = null;
56
+
57
+ if (particleSystemData.texture?.name.startsWith("http://") || particleSystemData.texture?.name.startsWith("https://")) {
58
+ relativePath = await extractTextureAssetFromUrl(particleSystemData.texture.name, {
59
+ ...options,
60
+ });
61
+ } else if (particleSystemData.texture?.name.startsWith("data:")) {
62
+ relativePath = await extractTextureAssetFromDataString(particleSystemData.texture.name, {
63
+ ...options,
64
+ });
65
+ }
66
+
67
+ if (relativePath) {
68
+ particleSystemData.texture.name = relativePath;
69
+ particleSystemData.texture.url = particleSystemData.texture.name;
70
+ }
71
+
72
+ return relativePath;
73
+ }
74
+
75
+ export async function extractNodeParticleSystemSetTextures(particleSystemData: any, options: IExtractParticleSystemTexturesOptions) {
76
+ const blocks = particleSystemData.blocks.filter((block) => block.customType === "BABYLON.ParticleTextureSourceBlock");
77
+
78
+ const relativePaths: string[] = [];
79
+
80
+ await Promise.all(
81
+ blocks.map(async (block: any) => {
82
+ if (block.url?.startsWith("http://") || block.url?.startsWith("https://")) {
83
+ const relativePath = await extractTextureAssetFromUrl(block.url, {
84
+ ...options,
85
+ });
86
+
87
+ if (relativePath) {
88
+ relativePaths.push(relativePath);
89
+ block.url = `/scene/${relativePath}`;
90
+ }
91
+ }
92
+
93
+ if (block.textureDataUrl?.startsWith("data:")) {
94
+ const relativePath = await extractTextureAssetFromDataString(block.textureDataUrl, {
95
+ ...options,
96
+ });
97
+
98
+ if (relativePath) {
99
+ relativePaths.push(relativePath);
100
+ delete block.textureDataUrl;
101
+ block.url = `/scene/${relativePath}`;
102
+ block.serializedCachedData = false;
103
+ }
104
+ }
105
+ })
106
+ );
107
+
108
+ return relativePaths;
109
+ }
@@ -0,0 +1,102 @@
1
+ import { basename, extname, join } from "node:path/posix";
2
+
3
+ import fs from "fs-extra";
4
+
5
+ import { compressFileToKtx } from "./ktx.mjs";
6
+ import { ICreateAssetsOptions } from "./assets.mjs";
7
+ import { processExportedTexture } from "./texture.mjs";
8
+ import { processExportedMaterial } from "./material.mjs";
9
+ import { processExportedNodeParticleSystemSet } from "./particle-system.mjs";
10
+
11
+ const supportedImagesExtensions: string[] = [".jpg", ".jpeg", ".webp", ".png", ".bmp"];
12
+ const supportedCubeTexturesExtensions: string[] = [".env", ".dds"];
13
+ const supportedAudioExtensions: string[] = [".mp3", ".wav", ".wave", ".ogg"];
14
+ const supportedJsonExtensions: string[] = [".material", ".gui", ".cinematic", ".npss", ".json"];
15
+ const supportedMiscExtensions: string[] = [".3dl", ".exr", ".hdr"];
16
+
17
+ const supportedExtensions: string[] = [
18
+ ...supportedImagesExtensions,
19
+ ...supportedCubeTexturesExtensions,
20
+ ...supportedAudioExtensions,
21
+ ...supportedJsonExtensions,
22
+ ...supportedMiscExtensions,
23
+ ];
24
+
25
+ export interface IProcessAssetFileOptions extends ICreateAssetsOptions {
26
+ outputAssetsDir: string;
27
+ exportedAssets: string[];
28
+ optimize: boolean;
29
+ cache: Record<string, string>;
30
+ compressedTexturesEnabled: boolean;
31
+ }
32
+
33
+ export async function processAssetFile(file: string, options: IProcessAssetFileOptions) {
34
+ const isNavMesh = file.includes(".navmesh");
35
+ const extension = extname(file).toLocaleLowerCase();
36
+
37
+ if (!isNavMesh && !supportedExtensions.includes(extension)) {
38
+ return;
39
+ }
40
+
41
+ if (basename(file).startsWith("editor_preview")) {
42
+ return;
43
+ }
44
+
45
+ const relativePath = file.replace(join(options.projectDir, "/"), "");
46
+ const split = relativePath.split("/");
47
+
48
+ let path = "";
49
+ for (let i = 0; i < split.length - 1; ++i) {
50
+ try {
51
+ await fs.ensureDir(join(options.publicDir, path, split[i]));
52
+ } catch (e) {
53
+ // Catch silently.
54
+ }
55
+
56
+ path = join(path, split[i]);
57
+ }
58
+
59
+ let isNewFile = false;
60
+
61
+ const fileStat = await fs.stat(file);
62
+ const hash = fileStat.mtimeMs.toString();
63
+
64
+ isNewFile = !options.cache[relativePath] || options.cache[relativePath] !== hash;
65
+
66
+ options.cache[relativePath] = hash;
67
+
68
+ const finalPath = join(options.publicDir, relativePath);
69
+ const finalPathExists = await fs.pathExists(finalPath);
70
+
71
+ if (isNewFile || !finalPathExists) {
72
+ await fs.copyFile(file, finalPath);
73
+ }
74
+
75
+ options.exportedAssets.push(finalPath);
76
+
77
+ if (options.optimize && options.compressedTexturesEnabled) {
78
+ await compressFileToKtx(finalPath, {
79
+ force: isNewFile,
80
+ exportedAssets: options.exportedAssets,
81
+ });
82
+ }
83
+
84
+ if (options.optimize) {
85
+ if (supportedImagesExtensions.includes(extension)) {
86
+ await processExportedTexture(finalPath, {
87
+ ...options,
88
+ force: isNewFile,
89
+ });
90
+ } else if (extension === ".material") {
91
+ await processExportedMaterial(finalPath, {
92
+ ...options,
93
+ force: isNewFile,
94
+ });
95
+ } else if (extension === ".npss") {
96
+ await processExportedNodeParticleSystemSet(finalPath, {
97
+ ...options,
98
+ force: isNewFile,
99
+ });
100
+ }
101
+ }
102
+ }
@@ -0,0 +1,91 @@
1
+ import { basename, dirname, extname, join } from "node:path/posix";
2
+
3
+ import sharp from "sharp";
4
+ import fs from "fs-extra";
5
+
6
+ import { getPowerOfTwoUntil } from "../../tools/scalar.mjs";
7
+
8
+ import { compressFileToKtx } from "./ktx.mjs";
9
+
10
+ export function getExtractedTextureOutputPath(publicDir: string) {
11
+ return join(publicDir, "assets", "editor-generated_extracted-textures");
12
+ }
13
+
14
+ export interface IComputeExportedTextureOptions {
15
+ force: boolean;
16
+ exportedAssets: string[];
17
+ compressedTexturesEnabled: boolean;
18
+ }
19
+
20
+ export async function processExportedTexture(absolutePath: string, options: IComputeExportedTextureOptions): Promise<void> {
21
+ const extension = extname(absolutePath).toLocaleLowerCase();
22
+
23
+ const metadata = await sharp(absolutePath).metadata();
24
+ if (!metadata.width || !metadata.height) {
25
+ return console.error(`Failed to compute exported image "${absolutePath}". Image metadata is invalid.`);
26
+ }
27
+
28
+ const width = metadata.width;
29
+ const height = metadata.height;
30
+
31
+ const isPowerOfTwo = width === getPowerOfTwoUntil(width) || height === getPowerOfTwoUntil(height);
32
+
33
+ type _DownscaledTextureSize = {
34
+ width: number;
35
+ height: number;
36
+ };
37
+
38
+ const availableSizes: _DownscaledTextureSize[] = [];
39
+
40
+ let midWidth = (width * 0.66) >> 0;
41
+ let midHeight = (height * 0.66) >> 0;
42
+
43
+ if (isPowerOfTwo) {
44
+ midWidth = getPowerOfTwoUntil(midWidth);
45
+ midHeight = getPowerOfTwoUntil(midHeight);
46
+ }
47
+
48
+ availableSizes.push({
49
+ width: midWidth,
50
+ height: midHeight,
51
+ });
52
+
53
+ let lowWidth = (width * 0.33) >> 0;
54
+ let lowHeight = (height * 0.33) >> 0;
55
+
56
+ if (isPowerOfTwo) {
57
+ lowWidth = getPowerOfTwoUntil(lowWidth);
58
+ lowHeight = getPowerOfTwoUntil(lowHeight);
59
+ }
60
+
61
+ availableSizes.push({
62
+ width: lowWidth,
63
+ height: lowHeight,
64
+ });
65
+
66
+ for (const size of availableSizes) {
67
+ const nameWithoutExtension = basename(absolutePath).replace(extension, "");
68
+ const finalName = `${nameWithoutExtension}_${size.width}_${size.height}${extension}`;
69
+ const finalPath = join(dirname(absolutePath), finalName);
70
+
71
+ options.exportedAssets.push(finalPath);
72
+
73
+ if (options.force || !(await fs.pathExists(finalPath))) {
74
+ try {
75
+ const buffer = await sharp(absolutePath).resize(size.width, size.height).toBuffer();
76
+
77
+ await fs.writeFile(finalPath, buffer);
78
+
79
+ console.log(`Exported scaled texture "${finalName}"`);
80
+ } catch (e) {
81
+ console.error(`Failed to export image scaled image "${finalName}"`);
82
+ }
83
+ }
84
+
85
+ if (options.compressedTexturesEnabled) {
86
+ await compressFileToKtx(finalPath, {
87
+ ...options,
88
+ });
89
+ }
90
+ }
91
+ }
@@ -0,0 +1,38 @@
1
+ import { join } from "node:path/posix";
2
+
3
+ import fs from "fs-extra";
4
+
5
+ import { readSceneDirectories } from "../tools/scene.mjs";
6
+
7
+ export interface ICreateGeometryFilesOptions {
8
+ sceneFile: string;
9
+ sceneName: string;
10
+ publicDir: string;
11
+ exportedAssets: string[];
12
+ babylonjsEditorToolsVersion: string;
13
+
14
+ directories: Awaited<ReturnType<typeof readSceneDirectories>>;
15
+ }
16
+
17
+ export async function createGeometryFiles(options: ICreateGeometryFilesOptions) {
18
+ await fs.ensureDir(join(options.publicDir, options.sceneName));
19
+ await fs.ensureDir(join(options.publicDir, options.sceneName, "morphTargets"));
20
+
21
+ await Promise.all(
22
+ options.directories.geometryFiles.map(async (file) => {
23
+ const destination = join(options.publicDir, options.sceneName, file);
24
+ await fs.copyFile(join(options.sceneFile, "geometries", file), destination);
25
+ options.exportedAssets.push(destination);
26
+ })
27
+ );
28
+
29
+ if (options.babylonjsEditorToolsVersion >= "5.2.6") {
30
+ await Promise.all(
31
+ options.directories.morphTargetFiles.map(async (file) => {
32
+ const destination = join(options.publicDir, options.sceneName, "morphTargets", file);
33
+ await fs.copyFile(join(options.sceneFile, "morphTargets", file), destination);
34
+ options.exportedAssets.push(destination);
35
+ })
36
+ );
37
+ }
38
+ }
@@ -0,0 +1,159 @@
1
+ import fs from "fs-extra";
2
+ import { resolve } from "node:path";
3
+ import { basename, extname, join } from "node:path/posix";
4
+
5
+ import ora from "ora";
6
+ import cliSpinners from "cli-spinners";
7
+
8
+ import { normalizedGlob } from "../tools/fs.mjs";
9
+ import { locatePVRTexTool, setPVRTexToolAbsolutePath } from "../tools/ktx.mjs";
10
+ import { ensureSceneDirectories, readSceneDirectories } from "../tools/scene.mjs";
11
+
12
+ import { createAssets } from "./assets/assets.mjs";
13
+ import { createBabylonScene } from "./scene.mjs";
14
+ import { createGeometryFiles } from "./geometry.mjs";
15
+
16
+ export interface IPackOptions {
17
+ optimize: boolean;
18
+ pvrTexToolAbsolutePath?: string;
19
+ }
20
+
21
+ export async function pack(projectDir: string, options: IPackOptions) {
22
+ const cwd = process.cwd();
23
+
24
+ if (projectDir !== cwd) {
25
+ projectDir = resolve(cwd, projectDir);
26
+ }
27
+
28
+ projectDir = projectDir.replace(/\\/g, "/");
29
+
30
+ // Load project configuration
31
+ const projectFiles = await fs.readdir(projectDir);
32
+ const projectConfigurationFile = projectFiles.find((file) => extname(file).toLowerCase() === ".bjseditor");
33
+
34
+ let projectConfiguration = {
35
+ compressedTexturesEnabled: false,
36
+ };
37
+
38
+ if (projectConfigurationFile) {
39
+ projectConfiguration = await fs.readJSON(join(projectDir, projectConfigurationFile));
40
+ }
41
+
42
+ // Locate PVRTexToolCLI
43
+ if (projectConfiguration.compressedTexturesEnabled) {
44
+ if (options.pvrTexToolAbsolutePath) {
45
+ setPVRTexToolAbsolutePath(options.pvrTexToolAbsolutePath);
46
+ } else {
47
+ await locatePVRTexTool();
48
+ }
49
+ }
50
+
51
+ const assetsDirectory = join(projectDir, "assets");
52
+ const publicDir = join(projectDir, "public/scene");
53
+
54
+ await fs.ensureDir(publicDir);
55
+
56
+ const baseAssetsDir = join(projectDir, "assets");
57
+ const outputAssetsDir = join(publicDir, "assets");
58
+
59
+ await fs.ensureDir(outputAssetsDir);
60
+
61
+ const exportedAssets: string[] = [];
62
+
63
+ let cache: Record<string, string> = {};
64
+ try {
65
+ cache = await fs.readJSON(join(projectDir, "assets/.export-cache.json"));
66
+ } catch (e) {
67
+ // Catch silently.
68
+ }
69
+
70
+ // Pack assets
71
+ const assetsLog = ora(`Packing assets...`);
72
+ assetsLog.spinner = cliSpinners.dots14;
73
+ assetsLog.start();
74
+
75
+ await createAssets({
76
+ ...options,
77
+ ...projectConfiguration,
78
+ cache,
79
+ projectDir,
80
+ publicDir,
81
+ baseAssetsDir,
82
+ outputAssetsDir,
83
+ exportedAssets,
84
+ });
85
+
86
+ assetsLog.succeed(`Packed assets`);
87
+
88
+ // Get babylonjs-editor-tools version
89
+ let babylonjsEditorToolsVersion = "5.0.0";
90
+ try {
91
+ const pkg = await fs.readJSON(join(projectDir, "node_modules/babylonjs-editor-tools/package.json"));
92
+ babylonjsEditorToolsVersion = pkg.version;
93
+ } catch (e) {
94
+ // Catch silently.
95
+ }
96
+
97
+ // Pack scenes
98
+ const sceneFiles = await normalizedGlob(`${assetsDirectory}/**/*`, {
99
+ nodir: false,
100
+ ignore: {
101
+ ignored: (p) => !p.isDirectory() || extname(p.name).toLocaleLowerCase() !== ".scene",
102
+ },
103
+ });
104
+
105
+ for (const sceneFile of sceneFiles) {
106
+ const sceneFilename = basename(sceneFile);
107
+ const sceneName = basename(sceneFile, extname(sceneFile));
108
+
109
+ const sceneLog = ora(`Packing ${sceneFilename}...`);
110
+ sceneLog.spinner = cliSpinners.dots14;
111
+ sceneLog.start();
112
+
113
+ await ensureSceneDirectories(sceneFile);
114
+
115
+ const directories = await readSceneDirectories(sceneFile);
116
+ const config = await fs.readJSON(join(sceneFile, "config.json"));
117
+
118
+ await createBabylonScene({
119
+ ...options,
120
+ ...projectConfiguration,
121
+ config,
122
+ directories,
123
+ publicDir,
124
+ sceneFile,
125
+ sceneName,
126
+ exportedAssets,
127
+ babylonjsEditorToolsVersion,
128
+ });
129
+
130
+ // Copy geometry files
131
+ await createGeometryFiles({
132
+ directories,
133
+ publicDir,
134
+ sceneFile,
135
+ sceneName,
136
+ exportedAssets,
137
+ babylonjsEditorToolsVersion,
138
+ });
139
+
140
+ sceneLog.succeed(`Packed ${sceneFilename}`);
141
+ }
142
+
143
+ // Save cache
144
+ await fs.writeJSON(join(projectDir, "assets/.export-cache.json"), cache, {
145
+ encoding: "utf-8",
146
+ spaces: "\t",
147
+ });
148
+
149
+ // Clean
150
+ const publicFiles = await normalizedGlob(join(publicDir, "**/*"), {
151
+ nodir: true,
152
+ });
153
+
154
+ publicFiles.forEach((file) => {
155
+ if (!exportedAssets.includes(file.toString())) {
156
+ fs.remove(file);
157
+ }
158
+ });
159
+ }