@s0rt/3dvf 0.1.5 → 0.3.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/dist/cli/index.js CHANGED
@@ -3608,7 +3608,7 @@ var package_default;
3608
3608
  var init_package = __esm(() => {
3609
3609
  package_default = {
3610
3610
  name: "@s0rt/3dvf",
3611
- version: "0.1.5",
3611
+ version: "0.3.0",
3612
3612
  description: "shadcn-style Three.js function library CLI",
3613
3613
  type: "module",
3614
3614
  bin: {
@@ -3629,15 +3629,17 @@ var init_package = __esm(() => {
3629
3629
  test: "bun test"
3630
3630
  },
3631
3631
  dependencies: {
3632
- "@types/three": "^0.183.1",
3633
3632
  commander: "^12.1.0",
3634
3633
  ora: "^8.1.1",
3635
3634
  picocolors: "^1.1.1",
3636
3635
  prompts: "^2.4.2"
3637
3636
  },
3638
3637
  devDependencies: {
3638
+ "@types/bun": "^1.3.10",
3639
3639
  "@types/prompts": "^2.4.9",
3640
- typescript: "^5.7.0"
3640
+ "@types/three": "^0.183.1",
3641
+ typescript: "^5.7.0",
3642
+ vite: "^7.3.1"
3641
3643
  }
3642
3644
  };
3643
3645
  });
@@ -10033,7 +10035,11 @@ function writeRegistryItem(item, outputDir, version, cwd = process.cwd()) {
10033
10035
  for (const file of item.files) {
10034
10036
  const dest = join2(itemDir, file.path);
10035
10037
  mkdirSync(dirname(dest), { recursive: true });
10036
- writeFileSync2(dest, file.content, "utf-8");
10038
+ if (file.encoding === "base64") {
10039
+ writeFileSync2(dest, Buffer.from(file.content, "base64"));
10040
+ } else {
10041
+ writeFileSync2(dest, file.content, "utf-8");
10042
+ }
10037
10043
  written.push(dest);
10038
10044
  }
10039
10045
  const stampPath = join2(itemDir, VERSION_STAMP_FILE);
@@ -10041,7 +10047,7 @@ function writeRegistryItem(item, outputDir, version, cwd = process.cwd()) {
10041
10047
  return written;
10042
10048
  }
10043
10049
 
10044
- // src/cli/utils/packageManager.ts
10050
+ // src/cli/utils/package-manager.ts
10045
10051
  import { existsSync as existsSync2 } from "fs";
10046
10052
  import { join as join3 } from "path";
10047
10053
  import { execSync } from "child_process";
@@ -10113,16 +10119,22 @@ Done!`) + ` Added ${items.length} function(s) to ${config.outputDir}`);
10113
10119
  }
10114
10120
 
10115
10121
  // src/cli/commands/create.ts
10116
- var import_prompts = __toESM(require_prompts3(), 1);
10117
- import { existsSync as existsSync4, readFileSync as readFileSync3, writeFileSync as writeFileSync3, mkdirSync as mkdirSync2 } from "fs";
10118
- import { join as join5, dirname as dirname3 } from "path";
10122
+ var import_prompts2 = __toESM(require_prompts3(), 1);
10123
+ import { existsSync as existsSync5, readFileSync as readFileSync4, writeFileSync as writeFileSync4, mkdirSync as mkdirSync2, rmSync } from "fs";
10124
+ import { join as join6, dirname as dirname3 } from "path";
10119
10125
  import { fileURLToPath as fileURLToPath2 } from "url";
10120
10126
  import { execSync as execSync2 } from "child_process";
10121
10127
  init_config();
10122
- var import_picocolors2 = __toESM(require_picocolors(), 1);
10128
+ var import_picocolors3 = __toESM(require_picocolors(), 1);
10129
+
10130
+ // src/cli/utils/init-project.ts
10131
+ var import_prompts = __toESM(require_prompts3(), 1);
10132
+ import { existsSync as existsSync4, readFileSync as readFileSync3, writeFileSync as writeFileSync3 } from "fs";
10133
+ import { join as join5 } from "path";
10123
10134
  init_config();
10135
+ var import_picocolors2 = __toESM(require_picocolors(), 1);
10124
10136
 
10125
- // src/cli/utils/ownPkg.ts
10137
+ // src/cli/utils/own-pkg.ts
10126
10138
  import { readFileSync as readFileSync2, existsSync as existsSync3 } from "fs";
10127
10139
  import { join as join4, dirname as dirname2 } from "path";
10128
10140
  import { fileURLToPath } from "url";
@@ -10137,17 +10149,73 @@ function findPkg(dir) {
10137
10149
  }
10138
10150
  var __dirname2 = dirname2(fileURLToPath(import.meta.url));
10139
10151
  var ownPkg = JSON.parse(readFileSync2(findPkg(__dirname2), "utf-8"));
10140
- var ownPkg_default = ownPkg;
10152
+ var own_pkg_default = ownPkg;
10153
+
10154
+ // src/cli/utils/init-project.ts
10155
+ var THREE_VERSION = (own_pkg_default.devDependencies?.["@types/three"]).replace(/^\^|~/, "");
10156
+ async function initProject(cwd) {
10157
+ let config;
10158
+ if (configExists(cwd)) {
10159
+ config = readConfig(cwd);
10160
+ console.log(import_picocolors2.default.dim("3dvf.json already exists, skipping config prompt"));
10161
+ } else {
10162
+ const answers = await import_prompts.default([
10163
+ {
10164
+ type: "text",
10165
+ name: "outputDir",
10166
+ message: "Where should functions be installed?",
10167
+ initial: DEFAULT_CONFIG.outputDir
10168
+ }
10169
+ ], { onCancel: () => process.exit(1) });
10170
+ config = {
10171
+ outputDir: answers.outputDir,
10172
+ registry: DEFAULT_CONFIG.registry,
10173
+ typescript: true
10174
+ };
10175
+ writeConfig(config, cwd);
10176
+ console.log(import_picocolors2.default.green("✓") + " Created 3dvf.json");
10177
+ console.log(import_picocolors2.default.dim(` outputDir: ${config.outputDir}`));
10178
+ }
10179
+ const spinner = ora(`Installing three@${THREE_VERSION}...`).start();
10180
+ try {
10181
+ installDeps([`three@${THREE_VERSION}`], [`@types/three@${THREE_VERSION}`], cwd);
10182
+ spinner.succeed(`Installed three@${THREE_VERSION}`);
10183
+ } catch (err) {
10184
+ spinner.fail("Failed to install three");
10185
+ console.error(import_picocolors2.default.red(err.message));
10186
+ process.exit(1);
10187
+ }
10188
+ const tsconfigPath = join5(cwd, "tsconfig.json");
10189
+ if (existsSync4(tsconfigPath)) {
10190
+ const raw = readFileSync3(tsconfigPath, "utf-8");
10191
+ const stripped = raw.replace(/\/\*[\s\S]*?\*\//g, "").replace(/\/\/[^\n]*/g, "");
10192
+ const tsconfig = JSON.parse(stripped);
10193
+ tsconfig.compilerOptions ??= {};
10194
+ tsconfig.compilerOptions.paths = {
10195
+ ...tsconfig.compilerOptions.paths,
10196
+ "@3dvf/*": [`./${config.outputDir}/*`]
10197
+ };
10198
+ tsconfig.compilerOptions.typeRoots = [
10199
+ "node_modules",
10200
+ "node_modules/@types"
10201
+ ];
10202
+ const tsconfigJson = JSON.stringify(tsconfig, null, 2).replace(/"typeRoots"/, `// Needed to get types from @types/three subfolders https://stackoverflow.com/a/78599968 & https://github.com/microsoft/TypeScript/issues/54629#issuecomment-1589593147
10203
+ "typeRoots"`);
10204
+ writeFileSync3(tsconfigPath, tsconfigJson + `
10205
+ `, "utf-8");
10206
+ console.log(import_picocolors2.default.green("✓") + " Updated tsconfig.json");
10207
+ }
10208
+ return config;
10209
+ }
10141
10210
 
10142
10211
  // src/cli/commands/create.ts
10143
- var THREE_VERSION = (ownPkg_default.dependencies?.["@types/three"]).replace(/^\^|~/, "");
10144
10212
  var __dirname3 = dirname3(fileURLToPath2(import.meta.url));
10145
- var TEMPLATES_DIR = join5(__dirname3, "./templates/create");
10213
+ var TEMPLATES_DIR = join6(__dirname3, "./templates/create");
10146
10214
  function readTemplate(file) {
10147
- return readFileSync3(join5(TEMPLATES_DIR, file), "utf-8");
10215
+ return readFileSync4(join6(TEMPLATES_DIR, file), "utf-8");
10148
10216
  }
10149
- async function createCommand2(projectName) {
10150
- const answers = await import_prompts.default([
10217
+ async function createCommand2(projectName, { cwd = process.cwd() } = {}) {
10218
+ const answers = await import_prompts2.default([
10151
10219
  {
10152
10220
  type: projectName ? null : "text",
10153
10221
  name: "name",
@@ -10157,44 +10225,45 @@ async function createCommand2(projectName) {
10157
10225
  }
10158
10226
  ], { onCancel: () => process.exit(1) });
10159
10227
  const name = projectName ?? answers.name;
10160
- const targetDir = join5(process.cwd(), name);
10161
- if (existsSync4(targetDir)) {
10162
- console.error(import_picocolors2.default.red(`Directory "${name}" already exists.`));
10228
+ const targetDir = join6(cwd, name);
10229
+ if (existsSync5(targetDir)) {
10230
+ console.error(import_picocolors3.default.red(`Directory "${name}" already exists.`));
10163
10231
  process.exit(1);
10164
10232
  }
10233
+ function cleanup() {
10234
+ if (existsSync5(targetDir)) {
10235
+ rmSync(targetDir, { recursive: true, force: true });
10236
+ console.error(import_picocolors3.default.dim(`Removed ${name}/`));
10237
+ }
10238
+ }
10165
10239
  const scaffoldSpinner = ora("Scaffolding Vite project...").start();
10166
10240
  try {
10167
10241
  execSync2(`npm create vite@latest ${name} -- --template vanilla-ts`, {
10242
+ cwd,
10168
10243
  stdio: "pipe"
10169
10244
  });
10170
10245
  scaffoldSpinner.succeed("Scaffolded Vite project");
10171
10246
  } catch (err) {
10172
10247
  scaffoldSpinner.fail("Failed to scaffold Vite project");
10173
- console.error(import_picocolors2.default.red(err.message));
10248
+ console.error(import_picocolors3.default.red(err.message));
10249
+ cleanup();
10174
10250
  process.exit(1);
10175
10251
  }
10176
- const config = {
10177
- outputDir: DEFAULT_CONFIG.outputDir,
10178
- registry: DEFAULT_CONFIG.registry,
10179
- typescript: true
10180
- };
10181
- writeConfig(config, targetDir);
10182
- console.log(import_picocolors2.default.green("✓") + " Created 3dvf.json");
10183
- const depsSpinner = ora(`Installing three@${THREE_VERSION}...`).start();
10252
+ let config;
10184
10253
  try {
10185
- installDeps([`three@${THREE_VERSION}`], [`@types/three@${THREE_VERSION}`], targetDir);
10186
- depsSpinner.succeed(`Installed three@${THREE_VERSION}`);
10254
+ config = await initProject(targetDir);
10187
10255
  } catch (err) {
10188
- depsSpinner.fail("Failed to install three");
10189
- console.error(import_picocolors2.default.red(err.message));
10256
+ console.error(import_picocolors3.default.red(err.message));
10257
+ cleanup();
10190
10258
  process.exit(1);
10191
10259
  }
10192
- const registrySpinner = ora("Adding get-webgpu-viewer...").start();
10260
+ const registrySpinner = ora("Adding create-viewer...").start();
10193
10261
  let tree;
10194
10262
  try {
10195
- tree = await resolveTree(["get-webgpu-viewer"], config.registry);
10263
+ tree = await resolveTree(["create-viewer"], config.registry);
10196
10264
  } catch (err) {
10197
10265
  registrySpinner.fail(err.message);
10266
+ cleanup();
10198
10267
  process.exit(1);
10199
10268
  return;
10200
10269
  }
@@ -10206,85 +10275,44 @@ async function createCommand2(projectName) {
10206
10275
  if (deps.length || devDeps.length) {
10207
10276
  installDeps(deps, devDeps, targetDir);
10208
10277
  }
10209
- registrySpinner.succeed("Added get-webgpu-viewer");
10278
+ registrySpinner.succeed("Added create-viewer");
10210
10279
  const pm = detectPackageManager(targetDir);
10211
10280
  const run = pm === "npm" ? "npm run" : pm;
10212
- writeFileSync3(join5(targetDir, "index.html"), readTemplate("index.html").replace("__PROJECT_NAME__", name), "utf-8");
10213
- console.log(import_picocolors2.default.green("") + " Created index.html");
10214
- mkdirSync2(join5(targetDir, "src"), { recursive: true });
10215
- writeFileSync3(join5(targetDir, "src", "main.ts"), readTemplate("main.ts"), "utf-8");
10216
- console.log(import_picocolors2.default.green("✓") + " Created src/main.ts");
10217
- writeFileSync3(join5(targetDir, "README.md"), readTemplate("README.md").replace("__PROJECT_NAME__", name).replace("__DEV_CMD__", `${run} dev`), "utf-8");
10218
- console.log(import_picocolors2.default.green("") + " Created README.md");
10281
+ writeFileSync4(join6(targetDir, "vite.config.ts"), readTemplate("vite.config.ts").replace("__OUTPUT_DIR__", config.outputDir), "utf-8");
10282
+ installDeps([], ["@types/node"], targetDir);
10283
+ console.log(import_picocolors3.default.green("") + " Created vite.config.ts");
10284
+ writeFileSync4(join6(targetDir, "index.html"), readTemplate("index.html").replace("__PROJECT_NAME__", name), "utf-8");
10285
+ console.log(import_picocolors3.default.green("✓") + " Created index.html");
10286
+ mkdirSync2(join6(targetDir, "src"), { recursive: true });
10287
+ writeFileSync4(join6(targetDir, "src", "main.ts"), readTemplate("main.ts"), "utf-8");
10288
+ console.log(import_picocolors3.default.green("✓") + " Created src/main.ts");
10289
+ writeFileSync4(join6(targetDir, "README.md"), readTemplate("README.md").replace("__PROJECT_NAME__", name).replace("__DEV_CMD__", `${run} dev`), "utf-8");
10290
+ console.log(import_picocolors3.default.green("✓") + " Created README.md");
10219
10291
  console.log(`
10220
- ${import_picocolors2.default.green("✓")} Created ${import_picocolors2.default.bold(name)}
10292
+ ${import_picocolors3.default.green("✓")} Created ${import_picocolors3.default.bold(name)}
10221
10293
 
10222
- ${import_picocolors2.default.bold("Next steps:")}
10294
+ ${import_picocolors3.default.bold("Next steps:")}
10223
10295
 
10224
- ${import_picocolors2.default.cyan(`cd ${name}`)}
10225
- ${import_picocolors2.default.cyan(`${run} dev`)}
10296
+ ${import_picocolors3.default.cyan(`cd ${name}`)}
10297
+ ${import_picocolors3.default.cyan(`${run} dev`)}
10226
10298
  `);
10227
10299
  }
10228
10300
 
10229
10301
  // src/cli/commands/init.ts
10230
- var import_prompts2 = __toESM(require_prompts3(), 1);
10231
- import { existsSync as existsSync5 } from "fs";
10232
- import { join as join6 } from "path";
10233
- init_config();
10234
- var import_picocolors3 = __toESM(require_picocolors(), 1);
10235
- var THREE_VERSION2 = (ownPkg_default.dependencies?.["@types/three"]).replace(/^\^|~/, "");
10302
+ var import_picocolors4 = __toESM(require_picocolors(), 1);
10303
+ import { existsSync as existsSync6 } from "fs";
10304
+ import { join as join7 } from "path";
10236
10305
  async function initCommand() {
10237
- if (!existsSync5(join6(process.cwd(), "package.json"))) {
10238
- console.error(import_picocolors3.default.red("No package.json found. Run `init` from the root of your project."));
10239
- process.exit(1);
10240
- }
10241
- if (configExists()) {
10242
- console.log(import_picocolors3.default.yellow("3dvf.json already exists. Skipping init."));
10243
- return;
10244
- }
10245
- const answers = await import_prompts2.default([
10246
- {
10247
- type: "text",
10248
- name: "outputDir",
10249
- message: "Where should functions be installed?",
10250
- initial: DEFAULT_CONFIG.outputDir
10251
- },
10252
- {
10253
- type: "toggle",
10254
- name: "typescript",
10255
- message: "Use TypeScript?",
10256
- initial: true,
10257
- active: "yes",
10258
- inactive: "no"
10259
- }
10260
- ]);
10261
- if (answers.outputDir === undefined) {
10262
- console.log(import_picocolors3.default.red("Cancelled."));
10263
- process.exit(1);
10264
- }
10265
- const config = {
10266
- outputDir: answers.outputDir,
10267
- registry: DEFAULT_CONFIG.registry,
10268
- typescript: answers.typescript
10269
- };
10270
- writeConfig(config);
10271
- console.log(import_picocolors3.default.green("✓") + " Created 3dvf.json");
10272
- console.log(import_picocolors3.default.dim(` outputDir: ${config.outputDir}`));
10273
- const spinner = ora(`Installing three@${THREE_VERSION2}...`).start();
10274
- try {
10275
- const devDeps = answers.typescript ? [`@types/three@${THREE_VERSION2}`] : [];
10276
- installDeps([`three@${THREE_VERSION2}`], devDeps);
10277
- spinner.succeed(`Installed three@${THREE_VERSION2}`);
10278
- } catch (err) {
10279
- spinner.fail("Failed to install three");
10280
- console.error(import_picocolors3.default.red(err.message));
10306
+ if (!existsSync6(join7(process.cwd(), "package.json"))) {
10307
+ console.error(import_picocolors4.default.red("No package.json found. Run `init` from the root of your project."));
10281
10308
  process.exit(1);
10282
10309
  }
10310
+ await initProject(process.cwd());
10283
10311
  }
10284
10312
 
10285
10313
  // src/cli/commands/list.ts
10286
10314
  init_config();
10287
- var import_picocolors4 = __toESM(require_picocolors(), 1);
10315
+ var import_picocolors5 = __toESM(require_picocolors(), 1);
10288
10316
  async function listCommand() {
10289
10317
  let config;
10290
10318
  try {
@@ -10297,11 +10325,11 @@ async function listCommand() {
10297
10325
  try {
10298
10326
  const index = await fetchRegistryIndex(config.registry);
10299
10327
  spinner.stop();
10300
- console.log(import_picocolors4.default.bold(`
10328
+ console.log(import_picocolors5.default.bold(`
10301
10329
  Available functions (${index.items.length}):
10302
10330
  `));
10303
10331
  for (const item of index.items) {
10304
- console.log(` ${import_picocolors4.default.cyan(item.name)}`);
10332
+ console.log(` ${import_picocolors5.default.cyan(item)}`);
10305
10333
  }
10306
10334
  console.log();
10307
10335
  } catch (err) {
@@ -1,6 +1,6 @@
1
1
  # __PROJECT_NAME__
2
2
 
3
- A Three.js WebGPU project scaffolded with [3dvf](https://github.com/s0rt/3dvf).
3
+ A Three.js project scaffolded with [3dvf](https://github.com/s0rt/3dvf).
4
4
 
5
5
  ## Getting started
6
6
 
@@ -1,29 +1,15 @@
1
1
  import {
2
- Scene,
3
- Color,
4
- PerspectiveCamera,
5
2
  BoxGeometry,
6
3
  MeshPhongMaterial,
7
4
  Mesh,
8
5
  AmbientLight,
9
6
  DirectionalLight,
10
7
  } from "three";
11
- import { getWebGPUViewer } from "./lib/3dvf/get-webgpu-viewer";
8
+ import { createViewer } from "@3dvf/create-viewer/create-viewer";
12
9
 
13
10
  const container = document.getElementById("app") as HTMLElement;
14
11
 
15
- const scene = new Scene();
16
- scene.background = new Color(0x1a1a2e);
17
-
18
- const camera = new PerspectiveCamera(
19
- 75,
20
- container.clientWidth / container.clientHeight,
21
- 0.1,
22
- 1000
23
- );
24
- camera.position.z = 3;
25
-
26
- const { dispose, renderer } = getWebGPUViewer(container);
12
+ const { scene, dispose, camera, launch } = createViewer(container);
27
13
 
28
14
  const geometry = new BoxGeometry(1.2, 1.2, 1.2);
29
15
  const material = new MeshPhongMaterial({ color: 0x4fc3f7 });
@@ -37,18 +23,9 @@ const directionalLight = new DirectionalLight(0xffffff, 1);
37
23
  directionalLight.position.set(5, 5, 5);
38
24
  scene.add(directionalLight);
39
25
 
40
- function animate() {
41
- cube.rotation.x += 0.005;
42
- cube.rotation.y += 0.01;
43
- renderer.render(scene, camera);
44
- }
45
-
46
- renderer.setAnimationLoop(animate);
26
+ camera.position.set(4, 4, 4);
47
27
 
48
- window.addEventListener("resize", () => {
49
- camera.aspect = container.clientWidth / container.clientHeight;
50
- camera.updateProjectionMatrix();
51
- });
28
+ launch();
52
29
 
53
30
  // HMR cleanup
54
31
  if (import.meta.hot) {
@@ -0,0 +1,30 @@
1
+ import { defineConfig, type Plugin } from "vite";
2
+
3
+ import { join, dirname } from "path";
4
+ import { fileURLToPath } from "url";
5
+
6
+ import { readFileSync } from "fs";
7
+
8
+ const __filename = fileURLToPath(import.meta.url);
9
+ const __dirname = dirname(__filename);
10
+
11
+ function glslPlugin(): Plugin {
12
+ return {
13
+ name: "glsl-raw",
14
+ load(id) {
15
+ if (id.endsWith(".glsl")) {
16
+ const source = readFileSync(id, "utf-8");
17
+ return `export default ${JSON.stringify(source)};`;
18
+ }
19
+ },
20
+ };
21
+ }
22
+
23
+ export default defineConfig({
24
+ plugins: [glslPlugin()],
25
+ resolve: {
26
+ alias: {
27
+ "@3dvf": join(__dirname, "./__OUTPUT_DIR__"),
28
+ },
29
+ },
30
+ });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@s0rt/3dvf",
3
- "version": "0.1.5",
3
+ "version": "0.3.0",
4
4
  "description": "shadcn-style Three.js function library CLI",
5
5
  "type": "module",
6
6
  "bin": {
@@ -21,14 +21,16 @@
21
21
  "test": "bun test"
22
22
  },
23
23
  "dependencies": {
24
- "@types/three": "^0.183.1",
25
24
  "commander": "^12.1.0",
26
25
  "ora": "^8.1.1",
27
26
  "picocolors": "^1.1.1",
28
27
  "prompts": "^2.4.2"
29
28
  },
30
29
  "devDependencies": {
30
+ "@types/bun": "^1.3.10",
31
31
  "@types/prompts": "^2.4.9",
32
- "typescript": "^5.7.0"
32
+ "@types/three": "^0.183.1",
33
+ "typescript": "^5.7.0",
34
+ "vite": "^7.3.1"
33
35
  }
34
36
  }
package/readme.md ADDED
@@ -0,0 +1,55 @@
1
+ ## dev
2
+
3
+ ### link local cli
4
+
5
+ `bun link`
6
+
7
+ ### run the cli
8
+
9
+ `bun run dev`
10
+
11
+ ### run the registry
12
+
13
+ `bun run dev:registry`
14
+
15
+ Using `bunx 3dvf <command>` will now use the local cli.
16
+
17
+
18
+ ## troubleshotting
19
+
20
+ ### .glsl & vite
21
+
22
+ Using the `create` command will already apply this fix.
23
+
24
+ By default vite won't import .glsl files as we want it to, resulting in parsing errors.
25
+
26
+ You can either prepend import path with `?raw`, or, to avoid touching the 3dvf files, use the following plugin :
27
+
28
+ ```vite.config.ts
29
+ function glslPlugin(): Plugin {
30
+ return {
31
+ name: 'glsl-raw',
32
+ load(id) {
33
+ if (id.endsWith('.glsl')) {
34
+ const source = readFileSync(id, 'utf-8');
35
+ return `export default ${JSON.stringify(source)};`;
36
+ }
37
+ }
38
+ };
39
+ }
40
+ ```
41
+
42
+ And add it
43
+ ```vite.config.ts
44
+ {
45
+ plugins: [glslPlugin]
46
+ }
47
+ ```
48
+
49
+ ### .dds
50
+
51
+ ```vite.config.ts
52
+ {
53
+ assetsInclude: ['**/*.dds']
54
+ }
55
+ ```