diff --git a/public/wallpapers/thumbs/wallpaper1.jpg b/public/wallpapers/thumbs/wallpaper1.jpg deleted file mode 100644 index 3b807fdfd..000000000 Binary files a/public/wallpapers/thumbs/wallpaper1.jpg and /dev/null differ diff --git a/public/wallpapers/thumbs/wallpaper10.jpg b/public/wallpapers/thumbs/wallpaper10.jpg deleted file mode 100644 index 67f011b61..000000000 Binary files a/public/wallpapers/thumbs/wallpaper10.jpg and /dev/null differ diff --git a/public/wallpapers/thumbs/wallpaper11.jpg b/public/wallpapers/thumbs/wallpaper11.jpg deleted file mode 100644 index 3ddae52c0..000000000 Binary files a/public/wallpapers/thumbs/wallpaper11.jpg and /dev/null differ diff --git a/public/wallpapers/thumbs/wallpaper12.jpg b/public/wallpapers/thumbs/wallpaper12.jpg deleted file mode 100644 index fcb82f393..000000000 Binary files a/public/wallpapers/thumbs/wallpaper12.jpg and /dev/null differ diff --git a/public/wallpapers/thumbs/wallpaper13.jpg b/public/wallpapers/thumbs/wallpaper13.jpg deleted file mode 100644 index cfeb50f66..000000000 Binary files a/public/wallpapers/thumbs/wallpaper13.jpg and /dev/null differ diff --git a/public/wallpapers/thumbs/wallpaper14.jpg b/public/wallpapers/thumbs/wallpaper14.jpg deleted file mode 100644 index c4b8e0a6b..000000000 Binary files a/public/wallpapers/thumbs/wallpaper14.jpg and /dev/null differ diff --git a/public/wallpapers/thumbs/wallpaper15.jpg b/public/wallpapers/thumbs/wallpaper15.jpg deleted file mode 100644 index ea949b1d9..000000000 Binary files a/public/wallpapers/thumbs/wallpaper15.jpg and /dev/null differ diff --git a/public/wallpapers/thumbs/wallpaper16.jpg b/public/wallpapers/thumbs/wallpaper16.jpg deleted file mode 100644 index 7a3182474..000000000 Binary files a/public/wallpapers/thumbs/wallpaper16.jpg and /dev/null differ diff --git a/public/wallpapers/thumbs/wallpaper17.jpg b/public/wallpapers/thumbs/wallpaper17.jpg deleted file mode 100644 index effce8113..000000000 Binary files a/public/wallpapers/thumbs/wallpaper17.jpg and /dev/null differ diff --git a/public/wallpapers/thumbs/wallpaper18.jpg b/public/wallpapers/thumbs/wallpaper18.jpg deleted file mode 100644 index 5dfc629db..000000000 Binary files a/public/wallpapers/thumbs/wallpaper18.jpg and /dev/null differ diff --git a/public/wallpapers/thumbs/wallpaper2.jpg b/public/wallpapers/thumbs/wallpaper2.jpg deleted file mode 100644 index 371cc69a6..000000000 Binary files a/public/wallpapers/thumbs/wallpaper2.jpg and /dev/null differ diff --git a/public/wallpapers/thumbs/wallpaper3.jpg b/public/wallpapers/thumbs/wallpaper3.jpg deleted file mode 100644 index 49d9191e5..000000000 Binary files a/public/wallpapers/thumbs/wallpaper3.jpg and /dev/null differ diff --git a/public/wallpapers/thumbs/wallpaper4.jpg b/public/wallpapers/thumbs/wallpaper4.jpg deleted file mode 100644 index 169dd84b8..000000000 Binary files a/public/wallpapers/thumbs/wallpaper4.jpg and /dev/null differ diff --git a/public/wallpapers/thumbs/wallpaper5.jpg b/public/wallpapers/thumbs/wallpaper5.jpg deleted file mode 100644 index bc4e93b4a..000000000 Binary files a/public/wallpapers/thumbs/wallpaper5.jpg and /dev/null differ diff --git a/public/wallpapers/thumbs/wallpaper6.jpg b/public/wallpapers/thumbs/wallpaper6.jpg deleted file mode 100644 index b11145bf4..000000000 Binary files a/public/wallpapers/thumbs/wallpaper6.jpg and /dev/null differ diff --git a/public/wallpapers/thumbs/wallpaper7.jpg b/public/wallpapers/thumbs/wallpaper7.jpg deleted file mode 100644 index 0fd5b38bf..000000000 Binary files a/public/wallpapers/thumbs/wallpaper7.jpg and /dev/null differ diff --git a/public/wallpapers/thumbs/wallpaper8.jpg b/public/wallpapers/thumbs/wallpaper8.jpg deleted file mode 100644 index 7380ffbb9..000000000 Binary files a/public/wallpapers/thumbs/wallpaper8.jpg and /dev/null differ diff --git a/public/wallpapers/thumbs/wallpaper9.jpg b/public/wallpapers/thumbs/wallpaper9.jpg deleted file mode 100644 index baa49c974..000000000 Binary files a/public/wallpapers/thumbs/wallpaper9.jpg and /dev/null differ diff --git a/public/wallpapers/wallpaper1.jpg b/public/wallpapers/wallpaper1.jpg deleted file mode 100644 index dbd8afb8b..000000000 Binary files a/public/wallpapers/wallpaper1.jpg and /dev/null differ diff --git a/public/wallpapers/wallpaper10.jpg b/public/wallpapers/wallpaper10.jpg deleted file mode 100644 index 49da791cb..000000000 Binary files a/public/wallpapers/wallpaper10.jpg and /dev/null differ diff --git a/public/wallpapers/wallpaper11.jpg b/public/wallpapers/wallpaper11.jpg deleted file mode 100644 index b20004068..000000000 Binary files a/public/wallpapers/wallpaper11.jpg and /dev/null differ diff --git a/public/wallpapers/wallpaper12.jpg b/public/wallpapers/wallpaper12.jpg deleted file mode 100644 index 264357dd5..000000000 Binary files a/public/wallpapers/wallpaper12.jpg and /dev/null differ diff --git a/public/wallpapers/wallpaper13.jpg b/public/wallpapers/wallpaper13.jpg deleted file mode 100644 index 052f0ff7f..000000000 Binary files a/public/wallpapers/wallpaper13.jpg and /dev/null differ diff --git a/public/wallpapers/wallpaper14.jpg b/public/wallpapers/wallpaper14.jpg deleted file mode 100644 index 233238a45..000000000 Binary files a/public/wallpapers/wallpaper14.jpg and /dev/null differ diff --git a/public/wallpapers/wallpaper15.jpg b/public/wallpapers/wallpaper15.jpg deleted file mode 100644 index 5742aab45..000000000 Binary files a/public/wallpapers/wallpaper15.jpg and /dev/null differ diff --git a/public/wallpapers/wallpaper16.jpg b/public/wallpapers/wallpaper16.jpg deleted file mode 100644 index 1f9efcea1..000000000 Binary files a/public/wallpapers/wallpaper16.jpg and /dev/null differ diff --git a/public/wallpapers/wallpaper17.jpg b/public/wallpapers/wallpaper17.jpg deleted file mode 100644 index d7188a473..000000000 Binary files a/public/wallpapers/wallpaper17.jpg and /dev/null differ diff --git a/public/wallpapers/wallpaper18.jpg b/public/wallpapers/wallpaper18.jpg deleted file mode 100644 index 9976c8cef..000000000 Binary files a/public/wallpapers/wallpaper18.jpg and /dev/null differ diff --git a/public/wallpapers/wallpaper2.jpg b/public/wallpapers/wallpaper2.jpg deleted file mode 100644 index 6a5640c7e..000000000 Binary files a/public/wallpapers/wallpaper2.jpg and /dev/null differ diff --git a/public/wallpapers/wallpaper3.jpg b/public/wallpapers/wallpaper3.jpg deleted file mode 100644 index 73d60c55d..000000000 Binary files a/public/wallpapers/wallpaper3.jpg and /dev/null differ diff --git a/public/wallpapers/wallpaper4.jpg b/public/wallpapers/wallpaper4.jpg deleted file mode 100644 index 49f281643..000000000 Binary files a/public/wallpapers/wallpaper4.jpg and /dev/null differ diff --git a/public/wallpapers/wallpaper5.jpg b/public/wallpapers/wallpaper5.jpg deleted file mode 100644 index 294ca329c..000000000 Binary files a/public/wallpapers/wallpaper5.jpg and /dev/null differ diff --git a/public/wallpapers/wallpaper6.jpg b/public/wallpapers/wallpaper6.jpg deleted file mode 100644 index 419569d68..000000000 Binary files a/public/wallpapers/wallpaper6.jpg and /dev/null differ diff --git a/public/wallpapers/wallpaper7.jpg b/public/wallpapers/wallpaper7.jpg deleted file mode 100644 index aa9d818d8..000000000 Binary files a/public/wallpapers/wallpaper7.jpg and /dev/null differ diff --git a/public/wallpapers/wallpaper8.jpg b/public/wallpapers/wallpaper8.jpg deleted file mode 100644 index 14e5ca595..000000000 Binary files a/public/wallpapers/wallpaper8.jpg and /dev/null differ diff --git a/public/wallpapers/wallpaper9.jpg b/public/wallpapers/wallpaper9.jpg deleted file mode 100644 index be273b486..000000000 Binary files a/public/wallpapers/wallpaper9.jpg and /dev/null differ diff --git a/src/components/video-editor/projectPersistence.test.ts b/src/components/video-editor/projectPersistence.test.ts index cbc0d89f7..d38c8df98 100644 --- a/src/components/video-editor/projectPersistence.test.ts +++ b/src/components/video-editor/projectPersistence.test.ts @@ -1,6 +1,6 @@ import { describe, expect, it } from "vitest"; import { DEFAULT_CURSOR_THEME_ID } from "@/lib/cursor/cursorThemes"; -import { DEFAULT_WALLPAPER } from "@/lib/wallpaper"; +import { DEFAULT_WALLPAPER, WALLPAPER_PATHS } from "@/lib/wallpaper"; import { createProjectData, createProjectSnapshot, @@ -32,7 +32,7 @@ describe("projectPersistence media compatibility", () => { webcamVideoPath: "/tmp/webcam.webm", }, { - wallpaper: "/wallpapers/wallpaper1.jpg", + wallpaper: "/wallpapers/brand/rm-dark-dotgrid.jpg", shadowIntensity: 0, showBlur: false, motionBlurAmount: 0, @@ -183,7 +183,7 @@ it("creates stable snapshots for identical project state", () => { webcamVideoPath: "/tmp/webcam.webm", }; const editor = normalizeProjectEditor({ - wallpaper: "/wallpapers/wallpaper1.jpg", + wallpaper: "/wallpapers/brand/rm-dark-dotgrid.jpg", shadowIntensity: 0, showBlur: false, motionBlurAmount: 0, @@ -216,35 +216,47 @@ it("detects unsaved changes from differing snapshots", () => { describe("wallpaper legacy normalization", () => { it("rewrites pre-fix packaged paths (resources/assets/wallpapers/…)", () => { const normalized = normalizeProjectEditor({ - wallpaper: "file:///opt/Openscreen/resources/assets/wallpapers/wallpaper5.jpg", + wallpaper: "file:///opt/Openscreen/resources/assets/wallpapers/brand/rm-grid.jpg", }); - expect(normalized.wallpaper).toBe("/wallpapers/wallpaper5.jpg"); + expect(normalized.wallpaper).toBe("/wallpapers/brand/rm-grid.jpg"); }); it("rewrites new packaged layout (resources/wallpapers/…)", () => { const normalized = normalizeProjectEditor({ - wallpaper: "file:///opt/Openscreen/resources/wallpapers/wallpaper3.jpg", + wallpaper: "file:///opt/Openscreen/resources/wallpapers/brand/rm-framed.jpg", }); - expect(normalized.wallpaper).toBe("/wallpapers/wallpaper3.jpg"); + expect(normalized.wallpaper).toBe("/wallpapers/brand/rm-framed.jpg"); }); it("rewrites unpackaged dev layout (public/wallpapers/…)", () => { const normalized = normalizeProjectEditor({ - wallpaper: "file:///home/user/project/public/wallpapers/wallpaper1.jpg", + wallpaper: "file:///home/user/project/public/wallpapers/brand/rm-dark-dotgrid.jpg", }); - expect(normalized.wallpaper).toBe("/wallpapers/wallpaper1.jpg"); + expect(normalized.wallpaper).toBe("/wallpapers/brand/rm-dark-dotgrid.jpg"); }); it("rewrites Windows-style file URLs with drive letter", () => { const normalized = normalizeProjectEditor({ - wallpaper: "file:///C:/Users/me/openscreen/resources/wallpapers/wallpaper2.jpg", + wallpaper: "file:///C:/Users/me/openscreen/resources/wallpapers/brand/rm-grid.jpg", }); - expect(normalized.wallpaper).toBe("/wallpapers/wallpaper2.jpg"); + expect(normalized.wallpaper).toBe("/wallpapers/brand/rm-grid.jpg"); }); it("leaves canonical relative paths untouched", () => { + const normalized = normalizeProjectEditor({ wallpaper: "/wallpapers/brand/rm-grid.jpg" }); + expect(normalized.wallpaper).toBe("/wallpapers/brand/rm-grid.jpg"); + }); + + /* + * And a project naming a wallpaper that is no longer bundled falls back. + * + * The eighteen stock gradients were removed, so an older project can name one + * that is not there any more. Left as-is it would be a broken image behind + * somebody's recording; DEFAULT_WALLPAPER is a brand board. + */ + it("falls back when a project names a wallpaper that is gone", () => { const normalized = normalizeProjectEditor({ wallpaper: "/wallpapers/wallpaper2.jpg" }); - expect(normalized.wallpaper).toBe("/wallpapers/wallpaper2.jpg"); + expect(normalized.wallpaper).toBe(WALLPAPER_PATHS[0]); }); it("leaves data URIs untouched", () => { diff --git a/src/components/video-editor/projectPersistence.ts b/src/components/video-editor/projectPersistence.ts index 627402844..257a07b7a 100644 --- a/src/components/video-editor/projectPersistence.ts +++ b/src/components/video-editor/projectPersistence.ts @@ -49,19 +49,47 @@ import { const VALID_BLUR_SHAPES = new Set(["rectangle", "oval", "freehand"] as const); -// Old projects persisted machine-specific file:// URLs for bundled wallpapers. -// Match only the known install layouts (packaged resources/[assets/]wallpapers, -// dev public/wallpapers) so a user's own file under some "wallpapers" folder isn't -// silently replaced. +/* + * Old projects persisted machine-specific file:// URLs for bundled wallpapers. + * + * Only the known install layouts are matched — packaged + * `resources/[assets/]wallpapers`, dev `public/wallpapers` — so a user's own file + * under some folder called "wallpapers" is not silently replaced. + * + * The tail allows one directory, because the bundled set moved into + * `wallpapers/brand/`. It used to be `wallpaper\d+\.jpg` and nothing else, which + * matched the stock run and no brand board: a packaged project whose wallpaper was + * one of ours came back as an unrewritten file:// URL pointing at the machine it + * was saved on. Now that the brand set is the ONLY set, that was every packaged + * project. Still one segment and still `.jpg`, so it cannot walk anywhere. + */ const LEGACY_FILE_WALLPAPER_RE = - /^file:\/\/.*?\/(?:resources\/(?:assets\/)?|public\/)wallpapers\/(wallpaper\d+\.jpg)$/i; + /^file:\/\/.*?\/(?:resources\/(?:assets\/)?|public\/)wallpapers\/((?:[\w-]+\/)?[\w-]+\.jpg)$/i; const CANONICAL_WALLPAPERS = new Set(WALLPAPER_PATHS); function normalizeWallpaperValue(value: string): string { const match = LEGACY_FILE_WALLPAPER_RE.exec(value); - if (!match) return value; - const canonical = `/wallpapers/${match[1]}`; - return CANONICAL_WALLPAPERS.has(canonical) ? canonical : DEFAULT_WALLPAPER; + if (match) { + const canonical = `/wallpapers/${match[1]}`; + return CANONICAL_WALLPAPERS.has(canonical) ? canonical : DEFAULT_WALLPAPER; + } + /* + * A bundled path that is no longer bundled also falls back. + * + * Only file:// URLs used to be checked against the canonical set, so an + * already-relative `/wallpapers/…` was passed through whatever it named. That was + * harmless while the bundled set only ever grew. It stopped being harmless when + * the eighteen stock gradients were removed: every project that used one now + * names a file that is not there, and passing it through puts a broken image + * behind somebody's recording instead of a board. + * + * Scoped to `/wallpapers/` — a data: URI or a user's own file:// path is theirs + * and is left exactly as it is, which the tests above pin. + */ + if (value.startsWith("/wallpapers/") && !CANONICAL_WALLPAPERS.has(value)) { + return DEFAULT_WALLPAPER; + } + return value; } export const PROJECT_VERSION = 2; diff --git a/src/lib/wallpaper.test.ts b/src/lib/wallpaper.test.ts index 1347bf40b..018fde6ea 100644 --- a/src/lib/wallpaper.test.ts +++ b/src/lib/wallpaper.test.ts @@ -7,17 +7,18 @@ import { DEFAULT_WALLPAPER, resolveImageWallpaperUrl, UnsafeImagePrefixError, - WALLPAPER_COUNT, WALLPAPER_PATHS, WALLPAPER_THUMB_PATHS, wallpaperLabel, } from "./wallpaper"; describe("WALLPAPER_PATHS", () => { - // The list is the brand set followed by the stock run, not a count on its own — - // WALLPAPER_COUNT still describes the stock half and nothing else. - it("is the brand set plus the stock set", () => { - expect(WALLPAPER_PATHS).toHaveLength(BRAND_WALLPAPERS.length + WALLPAPER_COUNT); + // The brand set and nothing else. This is a branded build, and a picker offering + // eighteen stock gradients beside the boards invites a video that is off-brand by + // one click. + it("is the brand set, and only the brand set", () => { + expect(WALLPAPER_PATHS).toHaveLength(BRAND_WALLPAPERS.length); + expect(WALLPAPER_PATHS.every((p) => p.startsWith("/wallpapers/brand/"))).toBe(true); }); it("puts the brand set first", () => { diff --git a/src/lib/wallpaper.ts b/src/lib/wallpaper.ts index f4b693cd9..3c5450670 100644 --- a/src/lib/wallpaper.ts +++ b/src/lib/wallpaper.ts @@ -1,48 +1,36 @@ import { getAssetPath } from "@/lib/assetPath"; import { BRAND_WALLPAPERS } from "@/lib/brandWallpapers"; -/** The stock set, which is still a count and a naming convention. */ -export const WALLPAPER_COUNT = 18; - -const STOCK_PATHS: readonly string[] = Array.from( - { length: WALLPAPER_COUNT }, - (_, i) => `/wallpapers/wallpaper${i + 1}.jpg`, -); - /* - * Brand wallpapers first, then the stock set. + * The brand boards, and only those. * - * The list used to be derived entirely from WALLPAPER_COUNT, so a wallpaper that was - * not called `wallpaperN.jpg` did not exist as far as the picker was concerned — which - * is why the RoleModel set never appeared in it however many times the branding was - * redone. They live under /wallpapers/brand/ with their own names rather than being - * renumbered into the stock run: 19 upward would put them last, lose the names, and - * collide the moment upstream adds one. + * The list used to be derived from a count and a naming convention — eighteen + * `wallpaperN.jpg` — so a wallpaper not called that did not exist as far as the + * picker was concerned, which is why the RoleModel set never appeared in it however + * many times the branding was redone. Then it was both sets, ours first. It is now + * ours alone: this is a branded build, and a picker offering eighteen stock + * gradients alongside the boards invites a video that is off-brand by one click. * - * First on purpose. These are the default look for this build, and DEFAULT_WALLPAPER - * is still index 0 — which now means the brand board rather than a stock gradient. + * They live under /wallpapers/brand/ with their own names rather than being + * renumbered into the old run, which would lose the names and collide the moment + * upstream adds one. * - * projectPersistence keys its canonical set off WALLPAPER_PATHS, so being in this - * array is also what stops a saved project's brand wallpaper being replaced by the - * default on load. + * projectPersistence keys its canonical set off this array, so a saved project that + * still names a stock gradient now falls back to DEFAULT_WALLPAPER — index 0, which + * is a brand board. That is the intended migration and the only visible effect on + * existing projects. */ -export const WALLPAPER_PATHS: readonly string[] = [ - ...BRAND_WALLPAPERS.map((w) => w.path), - ...STOCK_PATHS, -]; +export const WALLPAPER_PATHS: readonly string[] = BRAND_WALLPAPERS.map((w) => w.path); // Small (240x240, ~3-8KB) pre-generated copies used ONLY for the picker grid's swatches — the // full-res originals (up to 4+MB, up to 7680px) are what `settings.wallpaper` still stores and // what actually gets rendered/exported. Without this the grid was decoding all 18 originals // (~20MB combined) simultaneously just to paint a few dozen px each (reported: picker felt slow // to load). -export const WALLPAPER_THUMB_PATHS: readonly string[] = [ - ...BRAND_WALLPAPERS.map((w) => w.thumb), - ...Array.from({ length: WALLPAPER_COUNT }, (_, i) => `/wallpapers/thumbs/wallpaper${i + 1}.jpg`), -]; +export const WALLPAPER_THUMB_PATHS: readonly string[] = BRAND_WALLPAPERS.map((w) => w.thumb); /** - * A label for a bundled wallpaper, or null for the stock set, which has none. + * A label for a bundled wallpaper, or null for anything not in the set. * * The picker shows a bare grid of swatches; ours have names worth reading and a * `title` is the cheapest place to put them.