From b26e61dcb444f152514ab7256fceb23ddc16e8a5 Mon Sep 17 00:00:00 2001 From: Abian Suarez Date: Fri, 25 Sep 2026 09:13:15 +0100 Subject: [PATCH 1/4] build: share dependency versions through pnpm catalogs --- CLAUDE.md | 1 + adapters/player-react/package.json | 10 +-- adapters/player-vue/package.json | 8 +- apps/extension/package.json | 18 ++-- package.json | 2 +- packages/exporter/package.json | 16 ++-- packages/player-core/package.json | 22 ++--- packages/schema/package.json | 10 +-- pnpm-lock.yaml | 140 ++++++++++++++++++++--------- pnpm-workspace.yaml | 31 +++++++ 10 files changed, 172 insertions(+), 86 deletions(-) diff --git a/CLAUDE.md b/CLAUDE.md index e2ba903..e2b1e81 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -38,6 +38,7 @@ Each workspace has its own `CLAUDE.md` with its build, test and gotcha notes. Re ## Dependencies - Pin every dependency to an exact version (`.npmrc` sets `save-exact=true`). The only ranges allowed are the adapters' `peerDependencies` (`react`, `vue`). +- Dependencies shared by more than one workspace live in the named `catalogs` of `pnpm-workspace.yaml` (`core`, `react`, `tailwind`, `tooling`) and are referenced as `catalog:`. Bump them there, never in a `package.json`. A dependency used by a single workspace stays pinned in its own `package.json` until a second workspace needs it. - pnpm 12 settings (`overrides`, `allowBuilds`) go in `pnpm-workspace.yaml`, never in `package.json`. Installs reject versions published less than 24h ago (`minimumReleaseAge`), so pick an older exact version instead of adding exclusions. New packages with install scripts must be added to `allowBuilds`. - `packages/*` and `adapters/*` are published to npm as public packages and ship only `dist/` (`files`). `apps/*` and the root stay `private`. Workspace deps use `workspace:*`, which pnpm rewrites to exact versions on publish. - Stay on TypeScript 6.x. TS 7.0 has no programmatic API, which breaks `dts-bundle-generator` (player-core) and `vue-tsc` (player-vue). diff --git a/adapters/player-react/package.json b/adapters/player-react/package.json index cba4d77..005e8e1 100644 --- a/adapters/player-react/package.json +++ b/adapters/player-react/package.json @@ -59,10 +59,10 @@ ], "devDependencies": { "@rsbuild/plugin-react": "2.1.0", - "@rslib/core": "1.0.1", - "@size-limit/file": "14.0.0", - "@types/react": "19.3.0", - "size-limit": "14.0.0", - "typescript": "6.0.3" + "@rslib/core": "catalog:tooling", + "@size-limit/file": "catalog:tooling", + "@types/react": "catalog:react", + "size-limit": "catalog:tooling", + "typescript": "catalog:core" } } diff --git a/adapters/player-vue/package.json b/adapters/player-vue/package.json index 4e0dd45..10a7c5c 100644 --- a/adapters/player-vue/package.json +++ b/adapters/player-vue/package.json @@ -59,11 +59,11 @@ ], "devDependencies": { "@rsbuild/plugin-vue": "2.0.1", - "@rslib/core": "1.0.1", - "@size-limit/file": "14.0.0", + "@rslib/core": "catalog:tooling", + "@size-limit/file": "catalog:tooling", "@vue/language-core": "3.3.11", - "size-limit": "14.0.0", - "typescript": "6.0.3", + "size-limit": "catalog:tooling", + "typescript": "catalog:core", "vue": "3.5.43", "vue-tsc": "3.3.11" } diff --git a/apps/extension/package.json b/apps/extension/package.json index 5a9f118..9673133 100644 --- a/apps/extension/package.json +++ b/apps/extension/package.json @@ -33,22 +33,22 @@ "idb": "8.0.3", "lucide-react": "1.47.0", "mediabunny": "1.59.0", - "react": "19.3.0", - "react-dom": "19.3.0", + "react": "catalog:react", + "react-dom": "catalog:react", "sonner": "2.0.8", "tailwind-merge": "3.7.0" }, "devDependencies": { - "@tailwindcss/vite": "4.3.3", + "@tailwindcss/vite": "catalog:tailwind", "@types/chrome": "0.3.0", - "@types/react": "19.3.0", - "@types/react-dom": "19.3.0", + "@types/react": "catalog:react", + "@types/react-dom": "catalog:react", "@wxt-dev/module-react": "1.2.2", - "tailwindcss": "4.3.3", + "tailwindcss": "catalog:tailwind", "tw-animate-css": "1.4.0", - "typescript": "6.0.3", - "vite": "8.3.0", - "vitest": "5.0.1", + "typescript": "catalog:core", + "vite": "catalog:tooling", + "vitest": "catalog:tooling", "wxt": "0.21.4" } } diff --git a/package.json b/package.json index 92dfd81..6d29ae4 100644 --- a/package.json +++ b/package.json @@ -20,7 +20,7 @@ "@changesets/cli": "3.0.3", "lefthook": "2.1.14", "turbo": "2.11.3", - "typescript": "6.0.3" + "typescript": "catalog:core" }, "packageManager": "pnpm@12.6.0", "engines": { diff --git a/packages/exporter/package.json b/packages/exporter/package.json index 83255ae..ef1c3ee 100644 --- a/packages/exporter/package.json +++ b/packages/exporter/package.json @@ -57,13 +57,13 @@ } ], "devDependencies": { - "@rslib/core": "1.0.1", - "@size-limit/file": "14.0.0", - "@vitest/browser": "5.0.1", - "@vitest/browser-playwright": "5.0.1", - "playwright": "1.63.0", - "size-limit": "14.0.0", - "typescript": "6.0.3", - "vitest": "5.0.1" + "@rslib/core": "catalog:tooling", + "@size-limit/file": "catalog:tooling", + "@vitest/browser": "catalog:tooling", + "@vitest/browser-playwright": "catalog:tooling", + "playwright": "catalog:tooling", + "size-limit": "catalog:tooling", + "typescript": "catalog:core", + "vitest": "catalog:tooling" } } diff --git a/packages/player-core/package.json b/packages/player-core/package.json index 1a6507a..7790e2b 100644 --- a/packages/player-core/package.json +++ b/packages/player-core/package.json @@ -53,21 +53,21 @@ } ], "devDependencies": { - "@size-limit/file": "14.0.0", + "@size-limit/file": "catalog:tooling", "@sveltejs/vite-plugin-svelte": "7.3.1", - "@tailwindcss/vite": "4.3.3", - "@vitest/browser": "5.0.1", - "@vitest/browser-playwright": "5.0.1", - "@vitest/ui": "5.0.1", + "@tailwindcss/vite": "catalog:tailwind", + "@vitest/browser": "catalog:tooling", + "@vitest/browser-playwright": "catalog:tooling", + "@vitest/ui": "catalog:tooling", "dts-bundle-generator": "9.5.1", - "playwright": "1.63.0", - "size-limit": "14.0.0", + "playwright": "catalog:tooling", + "size-limit": "catalog:tooling", "svelte": "5.57.1", - "tailwindcss": "4.3.3", - "typescript": "6.0.3", - "vite": "8.3.0", + "tailwindcss": "catalog:tailwind", + "typescript": "catalog:core", + "vite": "catalog:tooling", "vite-plugin-css-injected-by-js": "5.0.2", - "vitest": "5.0.1", + "vitest": "catalog:tooling", "vitest-browser-svelte": "3.1.0" } } diff --git a/packages/schema/package.json b/packages/schema/package.json index 30724d4..a546aca 100644 --- a/packages/schema/package.json +++ b/packages/schema/package.json @@ -46,11 +46,11 @@ "size": "size-limit" }, "devDependencies": { - "@rslib/core": "1.0.1", - "@size-limit/file": "14.0.0", - "size-limit": "14.0.0", - "typescript": "6.0.3", - "vitest": "5.0.1" + "@rslib/core": "catalog:tooling", + "@size-limit/file": "catalog:tooling", + "size-limit": "catalog:tooling", + "typescript": "catalog:core", + "vitest": "catalog:tooling" }, "size-limit": [ { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 1c0582e..e972507 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -162,6 +162,60 @@ settings: autoInstallPeers: true excludeLinksFromLockfile: false +catalogs: + core: + typescript: + specifier: 6.0.3 + version: 6.0.3 + react: + '@types/react': + specifier: 19.3.0 + version: 19.3.0 + '@types/react-dom': + specifier: 19.3.0 + version: 19.3.0 + react: + specifier: 19.3.0 + version: 19.3.0 + react-dom: + specifier: 19.3.0 + version: 19.3.0 + tailwind: + '@tailwindcss/vite': + specifier: 4.3.3 + version: 4.3.3 + tailwindcss: + specifier: 4.3.3 + version: 4.3.3 + tooling: + '@rslib/core': + specifier: 1.0.1 + version: 1.0.1 + '@size-limit/file': + specifier: 14.0.0 + version: 14.0.0 + '@vitest/browser': + specifier: 5.0.1 + version: 5.0.1 + '@vitest/browser-playwright': + specifier: 5.0.1 + version: 5.0.1 + '@vitest/ui': + specifier: 5.0.1 + version: 5.0.1 + playwright: + specifier: 1.63.0 + version: 1.63.0 + size-limit: + specifier: 14.0.0 + version: 14.0.0 + vite: + specifier: 8.3.0 + version: 8.3.0 + vitest: + specifier: 5.0.1 + version: 5.0.1 + importers: .: @@ -182,7 +236,7 @@ importers: specifier: 2.11.3 version: 2.11.3 typescript: - specifier: 6.0.3 + specifier: catalog:core version: 6.0.3 adapters/player-react: @@ -201,19 +255,19 @@ importers: specifier: 2.1.0 version: 2.1.0(@rsbuild/core@2.2.8)(@rspack/core@2.2.6(@swc/helpers@0.5.23)) '@rslib/core': - specifier: 1.0.1 + specifier: catalog:tooling version: 1.0.1(typescript@6.0.3) '@size-limit/file': - specifier: 14.0.0 + specifier: catalog:tooling version: 14.0.0(size-limit@14.0.0) '@types/react': - specifier: 19.3.0 + specifier: catalog:react version: 19.3.0 size-limit: - specifier: 14.0.0 + specifier: catalog:tooling version: 14.0.0 typescript: - specifier: 6.0.3 + specifier: catalog:core version: 6.0.3 adapters/player-vue: @@ -229,19 +283,19 @@ importers: specifier: 2.0.1 version: 2.0.1(@rsbuild/core@2.2.8)(@rspack/core@2.2.6(@swc/helpers@0.5.23))(@vue/compiler-sfc@3.5.43)(vue@3.5.43(typescript@6.0.3)) '@rslib/core': - specifier: 1.0.1 + specifier: catalog:tooling version: 1.0.1(typescript@6.0.3) '@size-limit/file': - specifier: 14.0.0 + specifier: catalog:tooling version: 14.0.0(size-limit@14.0.0) '@vue/language-core': specifier: 3.3.11 version: 3.3.11 size-limit: - specifier: 14.0.0 + specifier: catalog:tooling version: 14.0.0 typescript: - specifier: 6.0.3 + specifier: catalog:core version: 6.0.3 vue: specifier: 3.5.43 @@ -298,10 +352,10 @@ importers: specifier: 1.59.0 version: 1.59.0 react: - specifier: 19.3.0 + specifier: catalog:react version: 19.3.0 react-dom: - specifier: 19.3.0 + specifier: catalog:react version: 19.3.0(react@19.3.0) sonner: specifier: 2.0.8 @@ -311,34 +365,34 @@ importers: version: 3.7.0 devDependencies: '@tailwindcss/vite': - specifier: 4.3.3 + specifier: catalog:tailwind version: 4.3.3(vite@8.3.0(@types/node@26.6.2)(jiti@2.7.0)(yaml@2.9.1)) '@types/chrome': specifier: 0.3.0 version: 0.3.0 '@types/react': - specifier: 19.3.0 + specifier: catalog:react version: 19.3.0 '@types/react-dom': - specifier: 19.3.0 + specifier: catalog:react version: 19.3.0(@types/react@19.3.0) '@wxt-dev/module-react': specifier: 1.2.2 version: 1.2.2(vite@8.3.0(@types/node@26.6.2)(jiti@2.7.0)(yaml@2.9.1))(wxt@0.21.4(@rsbuild/core@2.2.8)(@rspack/core@2.2.6)(rolldown@1.2.9)(typescript@6.0.3)(vite@8.3.0(@types/node@26.6.2)(jiti@2.7.0)(yaml@2.9.1))) tailwindcss: - specifier: 4.3.3 + specifier: catalog:tailwind version: 4.3.3 tw-animate-css: specifier: 1.4.0 version: 1.4.0 typescript: - specifier: 6.0.3 + specifier: catalog:core version: 6.0.3 vite: - specifier: 8.3.0 + specifier: catalog:tooling version: 8.3.0(@types/node@26.6.2)(jiti@2.7.0)(yaml@2.9.1) vitest: - specifier: 5.0.1 + specifier: catalog:tooling version: 5.0.1(@types/node@26.6.2)(@vitest/browser-playwright@5.0.1)(@vitest/ui@5.0.1)(vite@8.3.0(@types/node@26.6.2)) wxt: specifier: 0.21.4 @@ -354,28 +408,28 @@ importers: version: 3.10.2 devDependencies: '@rslib/core': - specifier: 1.0.1 + specifier: catalog:tooling version: 1.0.1(typescript@6.0.3) '@size-limit/file': - specifier: 14.0.0 + specifier: catalog:tooling version: 14.0.0(size-limit@14.0.0) '@vitest/browser': - specifier: 5.0.1 + specifier: catalog:tooling version: 5.0.1(vite@8.3.0(@types/node@26.6.2))(vitest@5.0.1) '@vitest/browser-playwright': - specifier: 5.0.1 + specifier: catalog:tooling version: 5.0.1(playwright@1.63.0)(vite@8.3.0(@types/node@26.6.2))(vitest@5.0.1) playwright: - specifier: 1.63.0 + specifier: catalog:tooling version: 1.63.0 size-limit: - specifier: 14.0.0 + specifier: catalog:tooling version: 14.0.0 typescript: - specifier: 6.0.3 + specifier: catalog:core version: 6.0.3 vitest: - specifier: 5.0.1 + specifier: catalog:tooling version: 5.0.1(@types/node@26.6.2)(@vitest/browser-playwright@5.0.1)(@vitest/ui@5.0.1)(vite@8.3.0(@types/node@26.6.2)) packages/player-core: @@ -385,49 +439,49 @@ importers: version: link:../schema devDependencies: '@size-limit/file': - specifier: 14.0.0 + specifier: catalog:tooling version: 14.0.0(size-limit@14.0.0) '@sveltejs/vite-plugin-svelte': specifier: 7.3.1 version: 7.3.1(svelte@5.57.1)(vite@8.3.0(@types/node@26.6.2)(jiti@2.7.0)(yaml@2.9.1)) '@tailwindcss/vite': - specifier: 4.3.3 + specifier: catalog:tailwind version: 4.3.3(vite@8.3.0(@types/node@26.6.2)(jiti@2.7.0)(yaml@2.9.1)) '@vitest/browser': - specifier: 5.0.1 + specifier: catalog:tooling version: 5.0.1(vite@8.3.0(@types/node@26.6.2))(vitest@5.0.1) '@vitest/browser-playwright': - specifier: 5.0.1 + specifier: catalog:tooling version: 5.0.1(playwright@1.63.0)(vite@8.3.0(@types/node@26.6.2))(vitest@5.0.1) '@vitest/ui': - specifier: 5.0.1 + specifier: catalog:tooling version: 5.0.1(vitest@5.0.1) dts-bundle-generator: specifier: 9.5.1 version: 9.5.1 playwright: - specifier: 1.63.0 + specifier: catalog:tooling version: 1.63.0 size-limit: - specifier: 14.0.0 + specifier: catalog:tooling version: 14.0.0 svelte: specifier: 5.57.1 version: 5.57.1 tailwindcss: - specifier: 4.3.3 + specifier: catalog:tailwind version: 4.3.3 typescript: - specifier: 6.0.3 + specifier: catalog:core version: 6.0.3 vite: - specifier: 8.3.0 + specifier: catalog:tooling version: 8.3.0(@types/node@26.6.2)(jiti@2.7.0)(yaml@2.9.1) vite-plugin-css-injected-by-js: specifier: 5.0.2 version: 5.0.2(vite@8.3.0(@types/node@26.6.2)(jiti@2.7.0)(yaml@2.9.1)) vitest: - specifier: 5.0.1 + specifier: catalog:tooling version: 5.0.1(@types/node@26.6.2)(@vitest/browser-playwright@5.0.1)(@vitest/ui@5.0.1)(vite@8.3.0(@types/node@26.6.2)) vitest-browser-svelte: specifier: 3.1.0 @@ -440,19 +494,19 @@ importers: version: 1.5.0(typescript@6.0.3) devDependencies: '@rslib/core': - specifier: 1.0.1 + specifier: catalog:tooling version: 1.0.1(typescript@6.0.3) '@size-limit/file': - specifier: 14.0.0 + specifier: catalog:tooling version: 14.0.0(size-limit@14.0.0) size-limit: - specifier: 14.0.0 + specifier: catalog:tooling version: 14.0.0 typescript: - specifier: 6.0.3 + specifier: catalog:core version: 6.0.3 vitest: - specifier: 5.0.1 + specifier: catalog:tooling version: 5.0.1(@types/node@26.6.2)(@vitest/browser-playwright@5.0.1)(@vitest/ui@5.0.1)(vite@8.3.0(@types/node@26.6.2)) packages: diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index 4c98128..adc7fed 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -18,3 +18,34 @@ minimumReleaseAgeExclude: - '@turbo/windows-64@2.11.3' - '@turbo/windows-arm64@2.11.3' - turbo@2.11.3 + +# One version per shared dependency for the whole monorepo: package.json files reference +# these with `catalog:`, and `pnpm publish` swaps that for the real version. +catalogs: + # What every workspace builds with. + core: + typescript: 6.0.3 + + # React and its types, pinned together so the @types never lag behind the runtime. + react: + react: 19.3.0 + react-dom: 19.3.0 + "@types/react": 19.3.0 + "@types/react-dom": 19.3.0 + + # Tailwind and its Vite plugin (extension and player-core) move in lockstep. + tailwind: + tailwindcss: 4.3.3 + "@tailwindcss/vite": 4.3.3 + + # Shared build, test and size tooling. The @vitest/* packages must match vitest. + tooling: + vite: 8.3.0 + vitest: 5.0.1 + "@vitest/browser": 5.0.1 + "@vitest/browser-playwright": 5.0.1 + "@vitest/ui": 5.0.1 + playwright: 1.63.0 + size-limit: 14.0.0 + "@size-limit/file": 14.0.0 + "@rslib/core": 1.0.1 From 51e269ec6b454ca9dd79516bf58be5e425ac419b Mon Sep 17 00:00:00 2001 From: Abian Suarez Date: Fri, 25 Sep 2026 11:04:35 +0100 Subject: [PATCH 2/4] refactor(player-core): replace svelte with a signals-based dom layer --- CLAUDE.md | 2 +- .../editor/components/stage/HotspotLayer.tsx | 4 +- .../components/stage/player-visuals.css | 4 +- biome.json | 2 +- packages/player-core/.size-limit.mjs | 27 + packages/player-core/CLAUDE.md | 25 +- packages/player-core/package.json | 25 +- packages/player-core/rslib.config.ts | 38 + .../scripts/check-dist-imports.mjs | 53 + .../__test__/component/BrowserChrome.test.ts | 15 +- .../src/__test__/component/Hotspot.test.ts | 46 +- .../src/__test__/component/Navbar.test.ts | 48 +- .../src/__test__/component/PhotoLayer.test.ts | 61 +- .../src/__test__/component/Tooltip.test.ts | 105 +- .../src/__test__/component/VideoLayer.test.ts | 33 +- .../src/__test__/component/dom.test.ts | 294 ++++++ .../src/__test__/integration/Player.test.ts | 2 +- .../player-core/src/__test__/render-view.ts | 69 ++ packages/player-core/src/__test__/setup.ts | 6 +- .../src/components/BrowserChrome.svelte | 29 - .../player-core/src/components/Hotspot.svelte | 237 ----- .../player-core/src/components/Navbar.svelte | 209 ---- .../src/components/PhotoLayer.svelte | 341 ------- .../player-core/src/components/Player.svelte | 538 ---------- .../player-core/src/components/Tooltip.svelte | 253 ----- .../src/components/VideoLayer.svelte | 42 - packages/player-core/src/components/types.ts | 13 - packages/player-core/src/dom/h.ts | 259 +++++ packages/player-core/src/dom/signals.ts | 11 + packages/player-core/src/dom/styles.ts | 19 + packages/player-core/src/mount.ts | 59 +- .../src/ui/BrowserChrome/BrowserChrome.ts | 55 ++ .../src/ui/Hotspot/Hotspot.styles.ts | 170 ++++ .../player-core/src/ui/Hotspot/Hotspot.ts | 76 ++ .../src/ui/Navbar/Navbar.styles.ts | 136 +++ packages/player-core/src/ui/Navbar/Navbar.ts | 116 +++ .../src/ui/PhotoLayer/PhotoLayer.styles.ts | 92 ++ .../src/ui/PhotoLayer/PhotoLayer.ts | 298 ++++++ .../src/ui/Player/Player.styles.ts | 10 + packages/player-core/src/ui/Player/Player.ts | 523 ++++++++++ .../src/ui/Tooltip/Tooltip.styles.ts | 118 +++ .../player-core/src/ui/Tooltip/Tooltip.ts | 222 +++++ .../src/ui/VideoLayer/VideoLayer.styles.ts | 6 + .../src/ui/VideoLayer/VideoLayer.ts | 38 + packages/player-core/tsconfig.build.json | 11 + packages/player-core/tsconfig.json | 4 +- packages/player-core/vite.config.ts | 33 - packages/player-core/vitest.config.ts | 15 +- pnpm-lock.yaml | 915 ++++++++++++++---- pnpm-workspace.yaml | 3 +- 50 files changed, 3652 insertions(+), 2058 deletions(-) create mode 100644 packages/player-core/.size-limit.mjs create mode 100644 packages/player-core/rslib.config.ts create mode 100644 packages/player-core/scripts/check-dist-imports.mjs create mode 100644 packages/player-core/src/__test__/component/dom.test.ts create mode 100644 packages/player-core/src/__test__/render-view.ts delete mode 100644 packages/player-core/src/components/BrowserChrome.svelte delete mode 100644 packages/player-core/src/components/Hotspot.svelte delete mode 100644 packages/player-core/src/components/Navbar.svelte delete mode 100644 packages/player-core/src/components/PhotoLayer.svelte delete mode 100644 packages/player-core/src/components/Player.svelte delete mode 100644 packages/player-core/src/components/Tooltip.svelte delete mode 100644 packages/player-core/src/components/VideoLayer.svelte delete mode 100644 packages/player-core/src/components/types.ts create mode 100644 packages/player-core/src/dom/h.ts create mode 100644 packages/player-core/src/dom/signals.ts create mode 100644 packages/player-core/src/dom/styles.ts create mode 100644 packages/player-core/src/ui/BrowserChrome/BrowserChrome.ts create mode 100644 packages/player-core/src/ui/Hotspot/Hotspot.styles.ts create mode 100644 packages/player-core/src/ui/Hotspot/Hotspot.ts create mode 100644 packages/player-core/src/ui/Navbar/Navbar.styles.ts create mode 100644 packages/player-core/src/ui/Navbar/Navbar.ts create mode 100644 packages/player-core/src/ui/PhotoLayer/PhotoLayer.styles.ts create mode 100644 packages/player-core/src/ui/PhotoLayer/PhotoLayer.ts create mode 100644 packages/player-core/src/ui/Player/Player.styles.ts create mode 100644 packages/player-core/src/ui/Player/Player.ts create mode 100644 packages/player-core/src/ui/Tooltip/Tooltip.styles.ts create mode 100644 packages/player-core/src/ui/Tooltip/Tooltip.ts create mode 100644 packages/player-core/src/ui/VideoLayer/VideoLayer.styles.ts create mode 100644 packages/player-core/src/ui/VideoLayer/VideoLayer.ts create mode 100644 packages/player-core/tsconfig.build.json delete mode 100644 packages/player-core/vite.config.ts diff --git a/CLAUDE.md b/CLAUDE.md index e2b1e81..068aa60 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -41,4 +41,4 @@ Each workspace has its own `CLAUDE.md` with its build, test and gotcha notes. Re - Dependencies shared by more than one workspace live in the named `catalogs` of `pnpm-workspace.yaml` (`core`, `react`, `tailwind`, `tooling`) and are referenced as `catalog:`. Bump them there, never in a `package.json`. A dependency used by a single workspace stays pinned in its own `package.json` until a second workspace needs it. - pnpm 12 settings (`overrides`, `allowBuilds`) go in `pnpm-workspace.yaml`, never in `package.json`. Installs reject versions published less than 24h ago (`minimumReleaseAge`), so pick an older exact version instead of adding exclusions. New packages with install scripts must be added to `allowBuilds`. - `packages/*` and `adapters/*` are published to npm as public packages and ship only `dist/` (`files`). `apps/*` and the root stay `private`. Workspace deps use `workspace:*`, which pnpm rewrites to exact versions on publish. -- Stay on TypeScript 6.x. TS 7.0 has no programmatic API, which breaks `dts-bundle-generator` (player-core) and `vue-tsc` (player-vue). +- Stay on TypeScript 6.x. TS 7.0 has no programmatic API, which breaks `vue-tsc` (player-vue). diff --git a/apps/extension/entrypoints/editor/components/stage/HotspotLayer.tsx b/apps/extension/entrypoints/editor/components/stage/HotspotLayer.tsx index ad55285..a253619 100644 --- a/apps/extension/entrypoints/editor/components/stage/HotspotLayer.tsx +++ b/apps/extension/entrypoints/editor/components/stage/HotspotLayer.tsx @@ -168,7 +168,7 @@ export function HotspotLayer({ } as React.CSSProperties } > - {/* Same anatomy as the player's hotspot (Hotspot.svelte) */} + {/* Same anatomy as the player's hotspot (player-core ui/Hotspot/Hotspot.ts) */} @@ -221,7 +221,7 @@ function TooltipBubble({ const bg = hotspot.bgColor ?? defaultHotspotStyle.bgColor; const placement = layout?.placement; - // Box + tail as one outline — identical to the player's Tooltip.svelte. + // Box + tail as one outline — identical to the player's tooltip (player-core ui/Tooltip/Tooltip.ts). const d = layout ? bubblePath({ width: layout.width, diff --git a/apps/extension/entrypoints/editor/components/stage/player-visuals.css b/apps/extension/entrypoints/editor/components/stage/player-visuals.css index 2adee73..804c3f5 100644 --- a/apps/extension/entrypoints/editor/components/stage/player-visuals.css +++ b/apps/extension/entrypoints/editor/components/stage/player-visuals.css @@ -1,6 +1,6 @@ /* * The player's hotspot + tooltip look, mirrored for the editor stage so what you edit is what - * ships. Source of truth: packages/player-core/src/components/{Hotspot,Tooltip,PhotoLayer}.svelte + * ships. Source of truth: packages/player-core/src/ui/{Hotspot,Tooltip,PhotoLayer}/*.styles.ts * and packages/player-core/src/app.css (the --wd-* tokens). Keep the two in sync — these are * demo visuals, not editor UI, which is why they use literal colors instead of theme tokens. */ @@ -186,7 +186,7 @@ } } -/* the body: box + tail as one SVG outline (see HotspotLayer / player's Tooltip.svelte) */ +/* the body: box + tail as one SVG outline (see HotspotLayer / player-core ui/Tooltip/Tooltip.ts) */ .wd-body { position: absolute; inset: 0 auto auto 0; diff --git a/biome.json b/biome.json index 03bab34..f65f35f 100644 --- a/biome.json +++ b/biome.json @@ -83,7 +83,7 @@ }, "overrides": [ { - "includes": ["**/*.svelte", "**/*.vue"], + "includes": ["**/*.vue"], "linter": { "rules": { "style": { diff --git a/packages/player-core/.size-limit.mjs b/packages/player-core/.size-limit.mjs new file mode 100644 index 0000000..05b299c --- /dev/null +++ b/packages/player-core/.size-limit.mjs @@ -0,0 +1,27 @@ +// What a host app actually ships from this package: bundled, minified and brotlied by +// esbuild, with the schema left out (the host already has it through the adapters). +const shared = { + path: "dist/index.js", + ignore: ["@rustrak/openshowcase-schema"], +}; + +export default [ + { + ...shared, + name: "Player (JS + CSS)", + import: "{ Player }", + limit: "35 KB", + }, + { + ...shared, + name: "Tooltip geometry only (the player must tree-shake away)", + import: "{ bubblePath, computeTooltipPlacement }", + limit: "2 KB", + // esbuild keeps the CSS of JS modules it tree-shook away (Rollup, webpack and Rspack + // drop it, per `sideEffects`), so only the JS is measured here. + modifyEsbuildConfig: (config) => ({ + ...config, + external: [...(config.external ?? []), "*.css"], + }), + }, +]; diff --git a/packages/player-core/CLAUDE.md b/packages/player-core/CLAUDE.md index 5bea660..37c5a6e 100644 --- a/packages/player-core/CLAUDE.md +++ b/packages/player-core/CLAUDE.md @@ -1,25 +1,32 @@ # @rustrak/openshowcase-player-core -Framework-agnostic playback engine used by both adapters and by the extension's editor preview. Written in Svelte 5 (runes) + Tailwind v4, compiled to plain JS. Consumers never see Svelte. +Framework-agnostic playback engine used by both adapters and by the extension's editor preview. Plain TypeScript + Tailwind v4, with no UI framework: components are functions built on a small in-house DOM layer (`src/dom/`) over `alien-signals`. The published package depends on nothing but the schema. Keep it that way: the player is embedded in other people's apps, so it must not ship a framework runtime or pull in dependencies. ## Build -- `pnpm build`: Vite (CSS inlined into JS, no `.css` output) + `dts-bundle-generator` for `dist/index.d.ts`. -- **Keep `exports["."].default` pointing at `./dist/index.js`** (only `types` points at `src`). Resolving raw source forces every consumer's bundler to compile `.svelte` files, and the extension's build breaks. -- `@rustrak/openshowcase-schema` stays `external` in `vite.config.ts`. Inlining it bundles a second copy of valibot. -- `pnpm size`: 35 KB brotli budget for `dist/index.js`. -- `pnpm test`: Vitest projects `unit` (Node, for `core/`) and `component` (covers `__test__/component` + `__test__/integration` in real Chromium via Playwright, not jsdom). +- `pnpm build`: Rslib in bundleless mode (`rslib.config.ts`): one readable, unminified ESM file per source module, so a host that imports only the tooltip geometry doesn't get the player. The host app's bundler minifies. Vite is only used by Vitest. +- **No side effects at import time.** `package.json` declares `"sideEffects": ["**/*.css"]`: `dist/app.css` (Tailwind) is the only side-effect import. Components inject their own CSS when they're created (`injectStyles`). Don't add module-level code that touches the DOM or globals. +- **alien-signals is compiled into `dist/`**, not a dependency: it's a `devDependency`, only `src/dom/signals.ts` imports it, and a second, bundled lib in `rslib.config.ts` builds that module (alien-signals included) into `dist/dom/signals.js`. Import signals from `dom/signals`, never from `alien-signals` directly. +- `scripts/check-dist-imports.mjs` (run by `pnpm size`) fails if `dist/`'s JS imports any package but the schema, or if the public types (what `dist/index.d.ts` reaches) reference one. +- Declarations: `tsconfig.build.json` starts them at `src/index.ts`. +- **Keep `exports["."].default` pointing at `./dist/index.js`.** +- `pnpm size` (`.size-limit.mjs`): what a host ships, bundled and minified by esbuild. `Player` (JS + CSS) within 35 KB, and the tooltip geometry alone within 2 KB, which fails if the player stops tree-shaking away. +- `pnpm test`: Vitest projects `unit` (Node, for `core/`) and `component` (covers `__test__/component` + `__test__/integration` in real Chromium via Playwright, not jsdom). Run it with `--browser.headless`. ## Code structure - `src/core/*.ts`: pure orchestration and timing logic (state machines, clip watching, overlay choreography), unit-tested with fake timers and no DOM. -- `src/components/*.svelte`: markup + wiring only. Once a component's script logic grows past ~100 lines, move the decision-making into `core/` with tests. +- `src/dom/`: the DOM layer. `h()`/`svg()` create elements; a function prop or child stays bound to the signals it reads (one effect per binding, nothing re-renders). `show()` is `{#if}` (with an optional exit animation), `each()` is a keyed list, `mount()` owns a scope whose dispose stops every binding. Views created by `show()`/`each()` live in scopes detached from the effect that creates them: alien-signals disposes an effect's child effects on every re-run. +- `src/ui//`: one folder per component, `.ts` (the component) + `.styles.ts` (its CSS, when it has any), markup + wiring only. Props are `ViewProps

`: data as getters, `on*` callbacks as is. Once a component's logic grows past ~100 lines, move the decision-making into `core/` with tests. +- Signal writes apply at once. Group writes that must land together (a step render, the photo/video swap) in `batch()`. +- Tests: `renderView()` (`__test__/render-view.ts`) mounts a component with plain props, each one a signal that `rerender()` sets. ## Styling: the player lives in other people's pages - `app.css` imports only Tailwind's theme + utilities, **never full `tailwindcss`** (its preflight resets the host page). Required resets are scoped under `.openshowcase-player`. -- Host CSS is unlayered and beats Tailwind's layered utilities, so visuals that must survive any site (hotspot, tooltip, navbar, spotlight) are styled in scoped ` diff --git a/packages/player-core/src/components/Navbar.svelte b/packages/player-core/src/components/Navbar.svelte deleted file mode 100644 index 3723fd0..0000000 --- a/packages/player-core/src/components/Navbar.svelte +++ /dev/null @@ -1,209 +0,0 @@ - - -

- - diff --git a/packages/player-core/src/components/PhotoLayer.svelte b/packages/player-core/src/components/PhotoLayer.svelte deleted file mode 100644 index 8e6ac30..0000000 --- a/packages/player-core/src/components/PhotoLayer.svelte +++ /dev/null @@ -1,341 +0,0 @@ - - -{#if previous} - -{/if} - - - -{#each lights as light (light.id)} -
-{/each} - -{#if visible && hotspot} - (hovered = value)} - /> -{/if} - -{#each bursts as burst (burst.id)} - -{/each} - -{#if visible && tooltip} - (hovered = value)} - /> -{/if} - - diff --git a/packages/player-core/src/components/Player.svelte b/packages/player-core/src/components/Player.svelte deleted file mode 100644 index 9b54039..0000000 --- a/packages/player-core/src/components/Player.svelte +++ /dev/null @@ -1,538 +0,0 @@ - - - - -
-
- {#if demo.theme.wrapper === 'browser'} - goTo(0)} /> - {/if} - - -
-
- - diff --git a/packages/player-core/src/components/Tooltip.svelte b/packages/player-core/src/components/Tooltip.svelte deleted file mode 100644 index 3544630..0000000 --- a/packages/player-core/src/components/Tooltip.svelte +++ /dev/null @@ -1,253 +0,0 @@ - - -
onclick?.()} - onkeydown={(event) => (event.key === 'Enter' || event.key === ' ') && onclick?.()} - onmouseenter={() => onhoverchange?.(true)} - onmouseleave={() => onhoverchange?.(false)} - out:vanish ->{shown.text}
- - diff --git a/packages/player-core/src/components/VideoLayer.svelte b/packages/player-core/src/components/VideoLayer.svelte deleted file mode 100644 index dfd71f6..0000000 --- a/packages/player-core/src/components/VideoLayer.svelte +++ /dev/null @@ -1,42 +0,0 @@ - - - - - diff --git a/packages/player-core/src/components/types.ts b/packages/player-core/src/components/types.ts deleted file mode 100644 index 727c2f0..0000000 --- a/packages/player-core/src/components/types.ts +++ /dev/null @@ -1,13 +0,0 @@ -/** - * Shared prop/data shapes for components. Kept in a plain .ts module rather than exported - * from a .svelte file — TypeScript's ambient `*.svelte` module shim only recognizes the - * default export, not named exports from the component's `