Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
aa9ebc5
convert inline worker generation to a post-processing step
DTCurrie Mar 3, 2026
9767af3
lint
DTCurrie Mar 3, 2026
f35b17e
Merge branch 'main' into make-worker-transform-post-process
DTCurrie Mar 3, 2026
788dc83
Merge branch 'make-worker-transform-post-process' of github.com:viam-…
DTCurrie Mar 4, 2026
a5928c2
Merge branch 'main' of github.com:viam-labs/motion-tools into make-wo…
DTCurrie Mar 4, 2026
c21c0c8
Merge branch 'main' of github.com:viam-labs/motion-tools into make-wo…
DTCurrie Apr 2, 2026
0a0d8fe
Merge branch 'main' into make-worker-transform-post-process
DTCurrie Apr 27, 2026
364db4f
Merge branch 'main' into make-worker-transform-post-process
DTCurrie Apr 28, 2026
8546a1e
Merge branch 'main' into make-worker-transform-post-process
DTCurrie Apr 30, 2026
78c1ef1
Merge branch 'main' into make-worker-transform-post-process
DTCurrie May 1, 2026
5e8ff89
Merge branch 'main' into make-worker-transform-post-process
DTCurrie May 4, 2026
2764dac
Merge branch 'main' of github.com:viam-labs/motion-tools into make-wo…
DTCurrie Jul 8, 2026
37dd415
fix wireit ordering, replaceAll, and ./worker.js path
github-actions[bot] Jul 8, 2026
6f127d5
lint
DTCurrie Jul 8, 2026
b3c8c12
Merge branch 'main' into make-worker-transform-post-process
DTCurrie Jul 8, 2026
8852e4b
fix vite config
DTCurrie Jul 8, 2026
8ce8ae0
Merge branch 'make-worker-transform-post-process' of github.com:viam-…
DTCurrie Jul 8, 2026
d9aa21f
Merge branch 'main' of github.com:viam-labs/motion-tools into make-wo…
DTCurrie Jul 8, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 0 additions & 3 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -53,9 +53,6 @@ vite.config.ts.timestamp-*
# Sentry Config File
.env.sentry-build-plugin

# Generated
*.inline.ts

# Protobuf
src/lib/buf
protos/vendor
Expand Down
21 changes: 8 additions & 13 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,11 @@
"go-build": "wireit",
"package": "wireit",
"svelte-sync": "wireit",
"prepare": "pnpm svelte-sync && pnpm build:workers || echo ''",
"prepare": "pnpm svelte-sync || echo ''",
"prepack": "wireit",
"preview": "vite preview",
"check": "wireit",
"check:watch": "svelte-kit sync && pnpm build:workers && svelte-check --tsconfig ./tsconfig.json --watch",
"check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch",
"format": "prettier --write . && ./scripts/eslint-progress.sh . --fix",
"lint": "wireit",
"lint:prettier": "wireit",
Expand Down Expand Up @@ -84,8 +84,7 @@
],
"dependencies": [
"proto:gen-ts",
"svelte-sync",
"build:workers"
"svelte-sync"
],
"packageLocks": [
"pnpm-lock.yaml"
Expand All @@ -103,14 +102,12 @@
}
},
"build:workers": {
"command": "node scripts/build-workers.js",
"command": "node scripts/post-process-workers.js",
Comment thread
DTCurrie marked this conversation as resolved.
"files": [
"scripts/build-workers.js",
"scripts/post-process-workers.js",
"src/lib/loaders/pcd/worker.ts"
],
"output": [
"src/lib/loaders/pcd/worker.inline.ts"
],
"output": [],
"packageLocks": [
"pnpm-lock.yaml"
]
Expand All @@ -129,7 +126,7 @@
]
},
"package": {
"command": "svelte-package && publint",
"command": "svelte-package && node scripts/post-process-workers.js && publint",
"files": [
"src/lib/**",
"svelte.config.js",
Expand All @@ -141,8 +138,7 @@
],
"dependencies": [
"proto:gen-ts",
"svelte-sync",
"build:workers"
"svelte-sync"
],
"packageLocks": [
"pnpm-lock.yaml"
Expand Down Expand Up @@ -184,7 +180,6 @@
"dependencies": [
"proto:gen-ts",
"svelte-sync",
"build:workers",
"vet"
],
"packageLocks": [
Expand Down
46 changes: 46 additions & 0 deletions scripts/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
# scripts/

Build and code generation scripts that run as part of the development workflow or publish pipeline.

---

## `post-process-workers.js`

**Run automatically as part of `pnpm run prepack`** (`svelte-package && node scripts/post-process-workers.js && publint`).

### What it does

After `svelte-package` copies `src/lib` into `dist/`, this script rewrites web worker references so the published package works correctly in consumer projects.

It scans `dist/` for files containing `new Worker(new URL(..., import.meta.url))`, bundles each referenced worker file into a self-contained IIFE using esbuild (inlining all dependencies like Three.js PCDLoader), replaces the `new Worker(new URL(...))` call with a Blob URL equivalent, and deletes the now-unnecessary worker `.js` files from `dist/`.

### Why we need it

This is a workaround for a [known open Vite bug](https://github.com/vitejs/vite/issues/21422). When a library uses `new Worker(new URL('./worker.js', import.meta.url))`, a consumer project's Vite dep optimizer moves the library to `.vite/deps/` but the worker file doesn't follow -- causing a runtime error.

`svelte-package` copies `.ts` files as-is (transpiled to JS), so there is no point in the library packaging pipeline where Vite's bundler runs and can resolve worker imports. The fix is to post-process `dist/` and inline the worker code so that consumers load it from a Blob URL with no file path dependency.

In dev mode within this project, Vite handles `new Worker(new URL(...))` natively with full HMR support -- no post-processing is needed.

---

## `model-pipeline.js`

**Run manually via `pnpm run model-pipeline:run`** when new 3D models need to be added to the project.

### What it does

Converts `.glb` and `.gltf` 3D model files into typed Threlte/Svelte components using [`@threlte/gltf`](https://threlte.xyz/docs/reference/gltf/getting-started).

Place model files in `static/models/`, then run the script. It:

1. Finds all `.glb`/`.gltf` files in `static/models/` (skipping already-transformed files)
2. Runs `@threlte/gltf` on each file to generate a typed Svelte component
3. Moves the generated `.svelte` files to `src/lib/components/models/`
4. Cleans up the intermediate files from `static/models/`

Configuration at the top of the file controls output options (TypeScript types, Draco compression, mesh simplification, etc.). By default `overwrite: false` -- existing components are not replaced.

### Why we need it

Hand-writing Three.js scene graphs for complex GLTF models is tedious and error-prone. `@threlte/gltf` generates Svelte components that exactly mirror the scene hierarchy of a model, including typed props for materials and geometry. This script automates the full pipeline from raw model file to usable Svelte component.
30 changes: 0 additions & 30 deletions scripts/build-workers.js

This file was deleted.

79 changes: 79 additions & 0 deletions scripts/post-process-workers.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
/**
* Post-processes dist/ after svelte-package to inline web workers.
*
* svelte-package copies worker.ts -> worker.js into dist/ alongside the files
* that reference them. But dist/index.js files still contain
* `new Worker(new URL('./worker.js', import.meta.url))` which breaks when
* consumed by another Vite project's dep optimizer.
*
* This script:
* 1. Scans dist/ for JS files containing the `new Worker(new URL(...))` pattern
* 2. Bundles the referenced worker file with esbuild into a self-contained IIFE
* 3. Rewrites the worker instantiation to use a Blob URL instead
* 4. Deletes the now-unnecessary worker.js file from dist/
*/

import { build } from 'esbuild'
import { globSync, readFileSync, unlinkSync, writeFileSync } from 'node:fs'
import path from 'node:path'

const WORKER_PATTERN =
/new Worker\(new URL\(['"]([^'"]+)['"]\s*,\s*import\.meta\.url\)\s*(?:,\s*\{[^}]*\})?\)/g
Comment thread
DTCurrie marked this conversation as resolved.

const distFiles = globSync('dist/**/*.js')
const deleted = new Set()

for (const file of distFiles) {
if (deleted.has(path.resolve(file))) continue

const code = readFileSync(file, 'utf8')
const matches = [...code.matchAll(WORKER_PATTERN)]

if (matches.length === 0) continue

let result = code

for (const match of matches) {
const [fullMatch, workerRelPath] = match
const workerAbsPath = path.resolve(path.dirname(file), workerRelPath)

console.log(`Inlining worker ${workerRelPath} referenced in ${file}`)

const bundle = await build({
entryPoints: [workerAbsPath],
bundle: true,
format: 'iife',
write: false,
minify: true,
})

const bundledCode = bundle.outputFiles[0].text
const escaped = bundledCode
.replaceAll('\\', '\\\\')
.replaceAll('`', '\\`')
.replaceAll('$', String.raw`\$`)

const replacement = [
`(function() {`,
` const __workerCode = \`${escaped}\``,
` const __blob = new Blob([__workerCode], { type: 'text/javascript' })`,
` return new Worker(URL.createObjectURL(__blob))`,
`})()`,
].join('\n')

result = result.replaceAll(fullMatch, replacement)

try {
unlinkSync(workerAbsPath)
deleted.add(workerAbsPath)
console.log(`Deleted ${workerAbsPath}`)
} catch {
console.warn(`Could not delete ${workerAbsPath} -- may already be removed`)
}
}

writeFileSync(file, result)
console.log(`Rewrote ${file}`)
}

console.log('Post-processed all workers in dist/')
6 changes: 1 addition & 5 deletions src/lib/loaders/pcd/index.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,6 @@
import type { Message, SuccessMessage } from './messages'

import { workerCode } from './worker.inline'

const blob = new Blob([workerCode], { type: 'text/javascript' })
const url = URL.createObjectURL(blob)
const worker = new Worker(url)
const worker = new Worker(new URL('worker.js', import.meta.url), { type: 'module' })

let requestId = 0
const pending = new Map<
Expand Down
9 changes: 8 additions & 1 deletion vite.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,14 @@ export default defineConfig({
// @testing-library/svelte is excluded so its Svelte components aren't
// pre-bundled, but its CJS grandchild aria-query (via @testing-library/dom)
// must still be optimized or Rolldown won't expose its named exports.
include: ['@testing-library/svelte > @testing-library/dom'],
//
// PCDLoader is imported by the pcd web worker (loaders/pcd/worker.ts). Vite
// discovers worker deps lazily, so without this the dep optimizer re-bundles
// mid-run and reloads the page, flaking out whatever tests are importing then.
include: [
'@testing-library/svelte > @testing-library/dom',
'three/examples/jsm/loaders/PCDLoader.js',
],
exclude: ['@testing-library/svelte'],
},
build: {
Expand Down
Loading