From 88bd40c9426d0fc694a2c9c98afef2dc4402410b Mon Sep 17 00:00:00 2001 From: threlte-bot Date: Tue, 16 Jul 2024 11:46:01 -0500 Subject: [PATCH] Initial commit --- .gitignore | 21 ++++ .npmrc | 1 + .prettierignore | 4 + .prettierrc | 8 ++ README.md | 38 +++++++ eslint.config.js | 33 ++++++ package.json | 40 ++++++++ scripts/model-pipeline.js | 149 ++++++++++++++++++++++++++++ src/app.d.ts | 13 +++ src/app.html | 12 +++ src/lib/components/App.svelte | 8 ++ src/lib/components/Scene.svelte | 60 +++++++++++ src/lib/components/models/README.md | 5 + src/lib/index.ts | 1 + src/routes/+page.svelte | 20 ++++ static/favicon.png | Bin 0 -> 1571 bytes static/models/threlte.glb | Bin 0 -> 6620 bytes svelte.config.js | 18 ++++ tsconfig.json | 19 ++++ vite.config.ts | 6 ++ 20 files changed, 456 insertions(+) create mode 100644 .gitignore create mode 100644 .npmrc create mode 100644 .prettierignore create mode 100644 .prettierrc create mode 100644 README.md create mode 100644 eslint.config.js create mode 100644 package.json create mode 100644 scripts/model-pipeline.js create mode 100644 src/app.d.ts create mode 100644 src/app.html create mode 100644 src/lib/components/App.svelte create mode 100644 src/lib/components/Scene.svelte create mode 100644 src/lib/components/models/README.md create mode 100644 src/lib/index.ts create mode 100644 src/routes/+page.svelte create mode 100644 static/favicon.png create mode 100644 static/models/threlte.glb create mode 100644 svelte.config.js create mode 100644 tsconfig.json create mode 100644 vite.config.ts diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..79518f7 --- /dev/null +++ b/.gitignore @@ -0,0 +1,21 @@ +node_modules + +# Output +.output +.vercel +/.svelte-kit +/build + +# OS +.DS_Store +Thumbs.db + +# Env +.env +.env.* +!.env.example +!.env.test + +# Vite +vite.config.js.timestamp-* +vite.config.ts.timestamp-* diff --git a/.npmrc b/.npmrc new file mode 100644 index 0000000..b6f27f1 --- /dev/null +++ b/.npmrc @@ -0,0 +1 @@ +engine-strict=true diff --git a/.prettierignore b/.prettierignore new file mode 100644 index 0000000..ab78a95 --- /dev/null +++ b/.prettierignore @@ -0,0 +1,4 @@ +# Package Managers +package-lock.json +pnpm-lock.yaml +yarn.lock diff --git a/.prettierrc b/.prettierrc new file mode 100644 index 0000000..9573023 --- /dev/null +++ b/.prettierrc @@ -0,0 +1,8 @@ +{ + "useTabs": true, + "singleQuote": true, + "trailingComma": "none", + "printWidth": 100, + "plugins": ["prettier-plugin-svelte"], + "overrides": [{ "files": "*.svelte", "options": { "parser": "svelte" } }] +} diff --git a/README.md b/README.md new file mode 100644 index 0000000..5ce6766 --- /dev/null +++ b/README.md @@ -0,0 +1,38 @@ +# create-svelte + +Everything you need to build a Svelte project, powered by [`create-svelte`](https://github.com/sveltejs/kit/tree/main/packages/create-svelte). + +## Creating a project + +If you're seeing this, you've probably already done this step. Congrats! + +```bash +# create a new project in the current directory +npm create svelte@latest + +# create a new project in my-app +npm create svelte@latest my-app +``` + +## Developing + +Once you've created a project and installed dependencies with `npm install` (or `pnpm install` or `yarn`), start a development server: + +```bash +npm run dev + +# or start the server and open the app in a new browser tab +npm run dev -- --open +``` + +## Building + +To create a production version of your app: + +```bash +npm run build +``` + +You can preview the production build with `npm run preview`. + +> To deploy your app, you may need to install an [adapter](https://kit.svelte.dev/docs/adapters) for your target environment. diff --git a/eslint.config.js b/eslint.config.js new file mode 100644 index 0000000..a351fa9 --- /dev/null +++ b/eslint.config.js @@ -0,0 +1,33 @@ +import js from '@eslint/js'; +import ts from 'typescript-eslint'; +import svelte from 'eslint-plugin-svelte'; +import prettier from 'eslint-config-prettier'; +import globals from 'globals'; + +/** @type {import('eslint').Linter.FlatConfig[]} */ +export default [ + js.configs.recommended, + ...ts.configs.recommended, + ...svelte.configs['flat/recommended'], + prettier, + ...svelte.configs['flat/prettier'], + { + languageOptions: { + globals: { + ...globals.browser, + ...globals.node + } + } + }, + { + files: ['**/*.svelte'], + languageOptions: { + parserOptions: { + parser: ts.parser + } + } + }, + { + ignores: ['build/', '.svelte-kit/', 'dist/'] + } +]; diff --git a/package.json b/package.json new file mode 100644 index 0000000..817b5b4 --- /dev/null +++ b/package.json @@ -0,0 +1,40 @@ +{ + "name": "portfolio", + "version": "0.0.1", + "private": true, + "scripts": { + "dev": "vite dev", + "build": "vite build", + "preview": "vite preview", + "check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json", + "check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch", + "lint": "prettier --check . && eslint .", + "format": "prettier --write .", + "model-pipeline:run": "node scripts/model-pipeline.js" + }, + "devDependencies": { + "@sveltejs/adapter-auto": "^3.0.0", + "@sveltejs/kit": "^2.0.0", + "@sveltejs/vite-plugin-svelte": "^3.0.0", + "@types/eslint": "^8.56.7", + "eslint": "^9.0.0", + "eslint-config-prettier": "^9.1.0", + "eslint-plugin-svelte": "^2.36.0", + "globals": "^15.0.0", + "prettier": "^3.1.1", + "prettier-plugin-svelte": "^3.1.2", + "svelte": "^4.2.7", + "svelte-check": "^3.6.0", + "tslib": "^2.4.1", + "typescript": "^5.0.0", + "typescript-eslint": "^8.0.0-alpha.20", + "vite": "^5.0.3", + "@types/three": "^0.159.0" + }, + "type": "module", + "dependencies": { + "three": "^0.159.0", + "@threlte/core": "^7.3.1", + "@threlte/extras": "^8.11.4" + } +} \ No newline at end of file diff --git a/scripts/model-pipeline.js b/scripts/model-pipeline.js new file mode 100644 index 0000000..b3e5356 --- /dev/null +++ b/scripts/model-pipeline.js @@ -0,0 +1,149 @@ +import { execSync } from 'node:child_process' +import { readdirSync, copyFileSync, unlinkSync, mkdirSync, existsSync } from 'node:fs' +import { join, resolve } from 'node:path' +import { exit } from 'node:process' + +/** + * This script is used to transform gltf and glb files into Threlte components. + * It uses the `@threlte/gltf` package to do so. + * It works in two steps: + * 1. Transform the gltf/glb files located in the sourceDir directory + * 2. Move the Threlte components to the targetDir directory + */ +const configuration = { + sourceDir: resolve(join('static', 'models')), + targetDir: resolve(join('src', 'lib', 'components', 'models')), + overwrite: false, + root: '/models/', + types: true, + keepnames: false, + meta: false, + shadows: false, + printwidth: 120, + precision: 2, + draco: null, + preload: false, + suspense: false, + isolated: false, + transform: { + enabled: false, + resolution: 1024, + simplify: { + enabled: false, + weld: 0.0001, + ratio: 0.75, + error: 0.001 + } + } +} + +// if the target directory doesn't exist, create it +mkdirSync(configuration.targetDir, { recursive: true }) + +// throw error if source directory doesn't exist +if (!existsSync(configuration.sourceDir)) { + throw new Error(`Source directory ${configuration.sourceDir} doesn't exist.`) +} + +// read the directory, filter for .glb and .gltf files and files *not* ending +// with -transformed.gltf or -transformed.glb as these should not be transformed +// again. +const gltfFiles = readdirSync(configuration.sourceDir).filter((file) => { + return ( + (file.endsWith('.glb') || file.endsWith('.gltf')) && + !file.endsWith('-transformed.gltf') && + !file.endsWith('-transformed.glb') + ) +}) + +if (gltfFiles.length === 0) { + console.log('No gltf or glb files found.') + exit() +} + +const filteredGltfFiles = gltfFiles.filter((file) => { + if (!configuration.overwrite) { + const componentFilename = file.split('.').slice(0, -1).join('.') + '.svelte' + const componentPath = join(configuration.targetDir, componentFilename) + if (existsSync(componentPath)) { + console.error(`File ${componentPath} already exists, skipping.`) + return false + } + } + return true +}) + +if (filteredGltfFiles.length === 0) { + console.log('No gltf or glb files to process.') + exit() +} + +filteredGltfFiles.forEach((file) => { + // run the gltf transform command on every file + const path = join(configuration.sourceDir, file) + + // parse the configuration + const args = [] + if (configuration.root) args.push(`--root ${configuration.root}`) + if (configuration.types) args.push('--types') + if (configuration.keepnames) args.push('--keepnames') + if (configuration.meta) args.push('--meta') + if (configuration.shadows) args.push('--shadows') + args.push(`--printwidth ${configuration.printwidth}`) + args.push(`--precision ${configuration.precision}`) + if (configuration.draco) args.push(`--draco ${configuration.draco}`) + if (configuration.preload) args.push('--preload') + if (configuration.suspense) args.push('--suspense') + if (configuration.isolated) args.push('--isolated') + if (configuration.transform.enabled) { + args.push(`--transform`) + args.push(`--resolution ${configuration.transform.resolution}`) + if (configuration.transform.simplify.enabled) { + args.push(`--simplify`) + args.push(`--weld ${configuration.transform.simplify.weld}`) + args.push(`--ratio ${configuration.transform.simplify.ratio}`) + args.push(`--error ${configuration.transform.simplify.error}`) + } + } + const formattedArgs = args.join(' ') + + // run the command + const cmd = `npx @threlte/gltf@latest ${path} ${formattedArgs}` + try { + execSync(cmd, { + cwd: configuration.sourceDir + }) + } catch (error) { + console.error(`Error transforming model: ${error}`) + } +}) + +// read dir again, but search for .svelte files only. +const svelteFiles = readdirSync(configuration.sourceDir).filter((file) => file.endsWith('.svelte')) + +svelteFiles.forEach((file) => { + // now move every file to /src/components/models + const path = join(configuration.sourceDir, file) + const newPath = join(configuration.targetDir, file) + copyFile: try { + // Sanity check, we checked earlier if the file exists. Still, the CLI takes + // a while, so who knows what happens in the meantime. + if (!configuration.overwrite) { + // check if file already exists + if (existsSync(newPath)) { + console.error(`File ${newPath} already exists, skipping.`) + break copyFile + } + } + copyFileSync(path, newPath) + } catch (error) { + console.error(`Error copying file: ${error}`) + } + + // remove the file from /static/models + try { + unlinkSync(path) + } catch (error) { + console.error(`Error removing file: ${error}`) + } +}) diff --git a/src/app.d.ts b/src/app.d.ts new file mode 100644 index 0000000..743f07b --- /dev/null +++ b/src/app.d.ts @@ -0,0 +1,13 @@ +// See https://kit.svelte.dev/docs/types#app +// for information about these interfaces +declare global { + namespace App { + // interface Error {} + // interface Locals {} + // interface PageData {} + // interface PageState {} + // interface Platform {} + } +} + +export {}; diff --git a/src/app.html b/src/app.html new file mode 100644 index 0000000..77a5ff5 --- /dev/null +++ b/src/app.html @@ -0,0 +1,12 @@ + + + + + + + %sveltekit.head% + + +
%sveltekit.body%
+ + diff --git a/src/lib/components/App.svelte b/src/lib/components/App.svelte new file mode 100644 index 0000000..4ae23fe --- /dev/null +++ b/src/lib/components/App.svelte @@ -0,0 +1,8 @@ + + + + + diff --git a/src/lib/components/Scene.svelte b/src/lib/components/Scene.svelte new file mode 100644 index 0000000..19b6b7e --- /dev/null +++ b/src/lib/components/Scene.svelte @@ -0,0 +1,60 @@ + + + + { + ref.lookAt(0, 1, 0) + }} + /> + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/lib/components/models/README.md b/src/lib/components/models/README.md new file mode 100644 index 0000000..af05256 --- /dev/null +++ b/src/lib/components/models/README.md @@ -0,0 +1,5 @@ +# Threlte Model Pipeline Components + +This directory holds automatically generated Threlte components from GLTF models. + +Place your models in `static/models` and run `npm run model-pipeline:run` to generate the components. diff --git a/src/lib/index.ts b/src/lib/index.ts new file mode 100644 index 0000000..856f2b6 --- /dev/null +++ b/src/lib/index.ts @@ -0,0 +1 @@ +// place files you want to import through the `$lib` alias in this folder. diff --git a/src/routes/+page.svelte b/src/routes/+page.svelte new file mode 100644 index 0000000..4d785b3 --- /dev/null +++ b/src/routes/+page.svelte @@ -0,0 +1,20 @@ + + +
+ +
+ + diff --git a/static/favicon.png b/static/favicon.png new file mode 100644 index 0000000000000000000000000000000000000000..825b9e65af7c104cfb07089bb28659393b4f2097 GIT binary patch literal 1571 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 literal 0 HcmV?d00001 diff --git a/svelte.config.js b/svelte.config.js new file mode 100644 index 0000000..4a82086 --- /dev/null +++ b/svelte.config.js @@ -0,0 +1,18 @@ +import adapter from '@sveltejs/adapter-auto'; +import { vitePreprocess } from '@sveltejs/vite-plugin-svelte'; + +/** @type {import('@sveltejs/kit').Config} */ +const config = { + // Consult https://kit.svelte.dev/docs/integrations#preprocessors + // for more information about preprocessors + preprocess: vitePreprocess(), + + kit: { + // adapter-auto only supports some environments, see https://kit.svelte.dev/docs/adapter-auto for a list. + // If your environment is not supported, or you settled on a specific environment, switch out the adapter. + // See https://kit.svelte.dev/docs/adapters for more information about adapters. + adapter: adapter() + } +}; + +export default config; diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..fc93cbd --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,19 @@ +{ + "extends": "./.svelte-kit/tsconfig.json", + "compilerOptions": { + "allowJs": true, + "checkJs": true, + "esModuleInterop": true, + "forceConsistentCasingInFileNames": true, + "resolveJsonModule": true, + "skipLibCheck": true, + "sourceMap": true, + "strict": true, + "moduleResolution": "bundler" + } + // Path aliases are handled by https://kit.svelte.dev/docs/configuration#alias + // except $lib which is handled by https://kit.svelte.dev/docs/configuration#files + // + // If you want to overwrite includes/excludes, make sure to copy over the relevant includes/excludes + // from the referenced tsconfig.json - TypeScript does not merge them in +} diff --git a/vite.config.ts b/vite.config.ts new file mode 100644 index 0000000..bbf8c7d --- /dev/null +++ b/vite.config.ts @@ -0,0 +1,6 @@ +import { sveltekit } from '@sveltejs/kit/vite'; +import { defineConfig } from 'vite'; + +export default defineConfig({ + plugins: [sveltekit()] +});