From 66eb93044d5f08c269201deee545de8450e98836 Mon Sep 17 00:00:00 2001 From: git-chad Date: Wed, 16 Sep 2026 22:30:25 -0300 Subject: [PATCH 1/7] test: establish V3 composition and alpha compatibility baselines --- .github/workflows/ci.yml | 6 + V3-ROADMAP.md | 4 + bun.lock | 9 +- package.json | 2 + tests/composition/README.md | 59 + .../baselines/contained-image-halftone.png | Bin 0 -> 146482 bytes .../composition/baselines/legacy-blends.json | 1538 +++++++++++++++++ .../baselines/legacy-text-mask.png | Bin 0 -> 8940 bytes .../baselines/solid-text-background.png | Bin 0 -> 16171 bytes .../baselines/transparent-text-screen.png | Bin 0 -> 16878 bytes tests/composition/browser.mjs | 242 +++ tests/composition/fixtures/alpha-sample.svg | 8 + .../fixtures/contained-image-halftone.json | 204 +++ .../fixtures/existing-default-project.json | 473 +++++ .../fixtures/legacy-text-mask.json | 177 ++ .../fixtures/solid-text-background.json | 177 ++ .../fixtures/transparent-text-screen.json | 177 ++ tests/composition/run.mjs | 147 ++ tests/composition/tsconfig.json | 10 + 19 files changed, 3231 insertions(+), 2 deletions(-) create mode 100644 tests/composition/README.md create mode 100644 tests/composition/baselines/contained-image-halftone.png create mode 100644 tests/composition/baselines/legacy-blends.json create mode 100644 tests/composition/baselines/legacy-text-mask.png create mode 100644 tests/composition/baselines/solid-text-background.png create mode 100644 tests/composition/baselines/transparent-text-screen.png create mode 100644 tests/composition/browser.mjs create mode 100644 tests/composition/fixtures/alpha-sample.svg create mode 100644 tests/composition/fixtures/contained-image-halftone.json create mode 100644 tests/composition/fixtures/existing-default-project.json create mode 100644 tests/composition/fixtures/legacy-text-mask.json create mode 100644 tests/composition/fixtures/solid-text-background.json create mode 100644 tests/composition/fixtures/transparent-text-screen.json create mode 100644 tests/composition/run.mjs create mode 100644 tests/composition/tsconfig.json diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a7a0c800..c3df8c56 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -47,6 +47,12 @@ jobs: - name: Type check app run: bun run typecheck:tsc + - name: Install composition test browser + run: bunx playwright install --with-deps chromium + + - name: Check composition baselines + run: bun run test:composition + - name: Ensure changeset exists for PR changes if: github.event_name == 'pull_request' run: bunx changeset status --since=origin/${{ github.base_ref }} diff --git a/V3-ROADMAP.md b/V3-ROADMAP.md index d7a7ac6b..537b02a1 100644 --- a/V3-ROADMAP.md +++ b/V3-ROADMAP.md @@ -14,6 +14,10 @@ Los PRs pequeños pueden integrarse progresivamente en la rama de V3. Ningún ca La rama de integración es `git-chad/shader-lab-v3-plan`. Todos los PRs pequeños de V3 deben usarla como base; únicamente el PR principal apunta a `main` y permanece en borrador hasta completar la validación obligatoria. +PR principal: [#150 — V3: designer-focused composition and experimental graphics](https://github.com/basementstudio/shader-lab/pull/150). + +Primer paso de la fase 1: [baselines de composición y mapa del canal alfa](tests/composition/README.md). Esta cobertura inicial no cierra la fase ni sustituye la validación visual con las catorce referencias elegidas. + ## Fase 1 — Resolver la base de composición y proteger proyectos existentes **Prioridad máxima:** transparencia, grupos y máscaras sostienen la composición. La preparación inicial debe ser breve y servir a la ejecución. diff --git a/bun.lock b/bun.lock index 5860ee77..0b577af4 100644 --- a/bun.lock +++ b/bun.lock @@ -51,6 +51,7 @@ "babel-plugin-react-compiler": "1.0.0", "cross-env": "^10.1.0", "drizzle-kit": "^0.31.10", + "playwright": "^1.63.0", "postcss-preset-env": "^10.6.1", "tailwindcss": "^4.1.18", "typescript": "^5.9.3", @@ -58,7 +59,7 @@ }, "packages/shader-lab-mcp": { "name": "@basementstudio/shader-lab-mcp", - "version": "0.1.0", + "version": "0.1.1", "bin": { "shader-lab-mcp": "dist/stdio.js", }, @@ -78,7 +79,7 @@ }, "packages/shader-lab-react": { "name": "@basementstudio/shader-lab", - "version": "3.0.0", + "version": "3.0.2", "dependencies": { "typescript": "^5.9.3", }, @@ -1912,6 +1913,10 @@ "pkce-challenge": ["pkce-challenge@5.0.1", "", {}, "sha512-wQ0b/W4Fr01qtpHlqSqspcj3EhBvimsdh0KlHhH8HRZnMsEa0ea2fTULOXOS9ccQr3om+GcGRk4e+isrZWV8qQ=="], + "playwright": ["playwright@1.63.0", "", { "dependencies": { "playwright-core": "1.63.0" }, "bin": { "playwright": "cli.js" } }, "sha512-+7ziBLidS4NaNCdt57SUDT+wYmmd5fmiQejUic/kb+YsYSCPyOOE9sebzMjNmQrsnNpDJqd4WHvV/8lfKfUDUg=="], + + "playwright-core": ["playwright-core@1.63.0", "", { "bin": { "playwright-core": "cli.js" } }, "sha512-rYCsBF/M5HjUch52bbtVONEFjv6Xu8sm8h72dNlR5bzIE1fvC/bxgspzkjSfU+MweEMmPM8KJebG6nnyxo5mCg=="], + "postcss": ["postcss@8.5.8", "", { "dependencies": { "nanoid": "^3.3.11", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" } }, "sha512-OW/rX8O/jXnm82Ey1k44pObPtdblfiuWnrd8X7GJ7emImCOstunGbXUpp7HdBrFQX6rJzn3sPT397Wp5aCwCHg=="], "postcss-attribute-case-insensitive": ["postcss-attribute-case-insensitive@7.0.1", "", { "dependencies": { "postcss-selector-parser": "^7.0.0" }, "peerDependencies": { "postcss": "^8.4" } }, "sha512-Uai+SupNSqzlschRyNx3kbCTWgY/2hcwtHEI/ej2LJWc9JJ77qKgGptd8DHwY1mXtZ7Aoh4z4yxfwMBue9eNgw=="], diff --git a/package.json b/package.json index fc2897ef..efc1b5be 100644 --- a/package.json +++ b/package.json @@ -31,6 +31,7 @@ "version-canary": "changeset version --snapshot canary", "version-packages": "changeset version", "start": "next start", + "test:composition": "bun tests/composition/run.mjs", "typecheck": "tsgo --noEmit", "typecheck:runtime": "bun run --cwd packages/shader-lab-react typecheck", "typecheck:compare": "bun run typecheck:tsc && bun run typecheck", @@ -84,6 +85,7 @@ "babel-plugin-react-compiler": "1.0.0", "cross-env": "^10.1.0", "drizzle-kit": "^0.31.10", + "playwright": "^1.63.0", "postcss-preset-env": "^10.6.1", "tailwindcss": "^4.1.18", "typescript": "^5.9.3" diff --git a/tests/composition/README.md b/tests/composition/README.md new file mode 100644 index 00000000..1966c5e5 --- /dev/null +++ b/tests/composition/README.md @@ -0,0 +1,59 @@ +# V3 composition baselines + +First slice of roadmap steps 1.1–1.2. This PR establishes regression checks before changing alpha behavior; it does not implement transparent composition, groups, or new masks. + +Integration branch: `git-chad/shader-lab-v3-plan`. Parent PR: [#150](https://github.com/basementstudio/shader-lab/pull/150). Child PRs target that branch, never `main`. + +## Run + +```sh +bun install --frozen-lockfile +bunx playwright install chromium +bun run test:composition +``` + +Linux requires `bunx playwright install --with-deps chromium`. The runner serves a bundled harness on an ephemeral loopback port and launches the locked Playwright Chromium with WebGPU over SwiftShader. No app server, account, or external services are required. Missing WebGPU, browser errors, shader compilation errors, missing baselines, and mismatches fail the command; tests do not silently skip or fall back to WebGL. + +Actual PNGs are saved in `.context/composition-test/`. Run `bun run test:composition --update` only when deliberately capturing a reviewed baseline. Never refresh existing legacy expectations just to make an alpha change pass. + +## Frozen references + +Captured before renderer changes, from the renderer at `6f39a88` (the pre-V3 `origin/main` revision). Fixture JSON files retain explicit version-6 settings instead of regenerating from layer defaults. The four render fixtures are synthetic saved projects created for regression coverage, not user-supplied artworks. They use a local SVG with a transparent cutout and soft alpha edge, and the bundled Geist Mono font. + +| Fixture | What it protects | +| --- | --- | +| `legacy-text-mask` | Existing text in luminance-mask mode, including its opaque black surroundings | +| `solid-text-background` | Deliberate solid text backgrounds and partial layer opacity | +| `transparent-text-screen` | Existing transparent text with an explicitly selected Screen blend | +| `contained-image-halftone` | Contained media, current black letterboxing, and partial-strength halftone | + +Each fixture renders through the editor renderer, compares preview with PNG export, and reopens serialized JSON into a new renderer/device. PNG comparisons allow at most two byte values per channel for backend rounding; no pixels may exceed that tolerance. Reopen and preview/export comparisons are exact within a run. Images are also checked for opaque alpha and nontrivial content. + +`legacy-blends.json` freezes 136 GPU samples across the editor and exported runtime: all 16 blend modes at three opacities, plus five mask sources, two mask modes, and inversion. The shaders are evaluated into float render targets; both implementations must match, and reference values have a tolerance of `0.00001`. These are compatibility expectations, not endorsements of the old alpha semantics. + +`existing-default-project.json` is an unmodified copy of the repository's existing saved project. Parsing, serialization, reopening, and hydration must retain its nine layers, two bundled assets, blend modes, masks, opacity, and parameter values. Its video/audio and full effect stack are **not** rendered by this initial suite. + +## Confirmed alpha boundaries + +These findings come from source inspection and the limited GPU checks above, not a completed end-to-end alpha audit. + +| Boundary | Current behavior | Required follow-up | +| --- | --- | --- | +| `blend-modes.ts` in editor and runtime | Filter mixes RGB using source alpha but returns alpha 1; masks multiply RGB or threshold to black and return alpha 1 | Distinguish source-over composition from effect interpolation; introduce true coverage masks with a compatibility path for saved masks | +| `pass-node.ts` in both renderers | Source and effect passes share composition; default opaque node materials can force alpha 1 independently of shader output | Define straight/premultiplied alpha conventions and material settings together with separate source/effect semantics | +| `media-pass.ts` | Contain mode fills out-of-bounds samples with opaque black | Preserve previous saved appearances while allowing transparent bounds in new composition behavior | +| `pipeline-manager.ts` | A single global ping-pong chain begins over an opaque base and finishes through an opaque blit | Introduce isolated group targets and their own effect scope; keep the scene background a deliberate choice | +| `scene-post-process.ts` | Scene color adjustments return alpha 1 | Preserve coverage through color grading | +| Canvas renderer creation | Editor and runtime use `alpha: false`; editor clears to alpha 1 | Carry alpha through preview/export where supported, including texture output | +| Text creation | New text defaults to mask mode and background alpha 1 | Change only new-layer defaults in phase 2; preserve saved text settings | + +Changing the shared mix formula alone is insufficient: source-over applied to a filtered copy of the same translucent input can increase its coverage. True masks also change the visual meaning of existing saved masks. Resolve both before switching the pipeline to transparent targets. + +## Next implementation slice + +1. Define source versus effect composition, alpha representation, and a persisted compatibility strategy for saved projects and exported runtime configs. +2. Add expected-output GPU tests for empty pixels next to opaque content, partial coverage, source-over blending, effect opacity, and soft masks over colored lower layers. +3. Implement alpha behavior across render targets, materials, postprocessing, preview, and supported exports while keeping these legacy fixtures stable. +4. Extend into isolated groups, scoped masks, reordering, undo, and save/reopen tests. + +Still outstanding for phase 1: the fourteen selected artistic references, broader photographs/portraits/objects and video captures, complete runtime scene/export coverage, group/mask behavior, and the short 3D feasibility checks. This suite is a starting point, not phase-1 acceptance. diff --git a/tests/composition/baselines/contained-image-halftone.png b/tests/composition/baselines/contained-image-halftone.png new file mode 100644 index 0000000000000000000000000000000000000000..7f2640e0d504ab12bd3c15da09335b3165630472 GIT binary patch literal 146482 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%0A}8&1gGpF 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%0A8SS%XX$js!pUe8qNZ86j{p z6EnFD3kKF@+80e&(K?hpdk@j%&3WlM51!pdaoY%%8FkC6EO;Pw5@3#Qydh3);>}x? zm?Hcwkk)5o9L!m`3SFRymcyDe@#7|ZTgS@#)eM|He+k3!Kj6`Ip_xpiRTal5VCK2| z9KppOS(kbG>@{9b9@g#&DDA6Y7}Nyc{|z{G`bQFN;rXqonvO_QE3=C4lJ0zJn6#Cw04+GkXff#l>{5 z0fXxq@pG=hmbVhTb~gPzmtB7z#8a?@;_P`SN)bxM5Dbw)Z2xBgnVCQ1w7~2S z9cJ%T+{F{v`|l=-i;CzG|AL0WKjJMJhR1mqgGXWO>V4#_{1$BAVbt!SmJ7%Feif{p zw{bUZ5V^T$W$Yg5>ypqKgR^ijs^=V~wh{^o4iN4bj@LGt(t_RiPBXj@PT;+z+b+CiGxr>LL{(^ zNoCPZg}+{0y=>^1j>D1tlX3|xp@R~$Pv6-MbPu3RA&5IkMG@SWR4Kr z=Aut;4!=Hd(||OFO6%_?Kw?m;JT(;X(S;@|tga+=?Sdgl54~bIWQt*HN(s%=4g7sF zgF2GJzqjcoB{}&lIi4@LUIF3P1NF1SF>3oblNWsTUL0N{8{!k-%X$J0m{G3=Z`G~N z*=G(;Wxb^Hrc12fe2w>yT%$>OJ?59=dL6YJwc#_~UY+Uq=Qd9K0-(oZe7 zM6%kH21RiDjhB8m|6yeMaZbF*z*|yE?f7aWB|hed-N*R+N(OUxUXU5bNhR}s;pK^d z8GWPyryLJ1c)6D1_fyGwSDZDlGEEyLQB*XWBlqW$_cDX1$1lYoom8lBjOLAPbV|$O zi{u=VUOmU?Sxia9K`#;fM0(BeYVAbae zoj8V}eEY`+gGKu({%gbc< zBJ3|jBa|0=HhR}eMg%(V7Bm&~I&j)HVYcY77VSpA9ZD}ry}ApX=0dG50p%l5BEfFk ziK>)fFFAntGDd^cdkp4aKc@bx_v{TNIp@}_Pv-$tO z;9LwzBaC(zri&IQ~Zl4b5rt_J3E3JgCf%k-8T0 zSazk6Ek0Va<{erIzu#Hl!je058n}aMLB95oAnnu#gJC`}90xn0%pJ<*!r$`TnNR31 zrO1J1QSvZHV0IEn5DVxHQ=S7NG<>H54*2yowAv0i@4*i^c_g1d6tD|S8woK4$P)+! z#w?OYoj|o9=vEm{WujcY&73SR6upGU4tAmN=#^VGuO2faOiv9wtP~h55b1BAS;Ly} zUL@4_r{dQQDOF7(VGp=P8#`py`};aC4nJd>ob}(`_>4W$-2{Ywaxr-}C&Qxj%#*rB zXbh+xNQ-D4)QXc}R1rRjqLsnK?w7*7rokIGY|Uox;r*h=a+vH9DRMMOfi~Kc~l^26Ypdd;|7~JuUv@Dz_yIvF%DG zRzxdHZt6(eszOnV3PdtvhQvXI&aLU#svXrL&DiX4UjS9*rB|bzpM@SDz@;~^_+mb9 zER=cpr2!R)-UOhfH4S?XKv~F1D)4IE;ei z_Iaubg{wrxLenQ+olcJ-TejNQSWP^=j%gOQ)PeV zEZyJ|Uvz8(tq43`55C}HY6X5@2odQ!#8?Wo<@uNYK_58%S_WX2_a6k#z?s+3Wu=Ae z(a=k(b_n=%>BdcSap*pNQXyBEz}C;Ai1xj|D=)JIg2AZuV1!MceY(9OrCh5q5d0qq zYzDqCpdvfCAfv>?KP2!>8Z{Fp`p%AL&sWhj9~@8q-*9q)WFaPL_n%wD%&*1Dg%I(* zG`9QV$Z2_qM|8yqd7^=@PERgzOqKUbZDB-aBClq2Vbc0|=Jy1hO#ZER*8*89v+^!H zFQvnAi99#uL#{{^5r*Ktl);Y3b@IGHBKN|K3=nHGG!EohOdxN``!9{-SXnESMTc)u z|LJqetn}(lC~zU+fJ>(((#mllVPZi-?}?b_eWBUsqK(<@8#AU?C0_NZhToVb)QPn) zwTem`eJF$WW%G?JIqC-%3YJ_)#5+-`kH)->Vz~w*gqzE_JSCrVTUVj4@V}sH6M}}e zB>wxB=*7bN#1_eRNP8@gqxf28^_W@GTGsctMN^(Y!StfaebS9w9+iGhTAPOaWYu`n zqb3EmQppwu(z@axhBd22s98ZTo;4uyBNS~2rUMt~yWo4O_hl5M32oFz0MlPF! zrFVz%!_y%wl}$ju3GI1MoQvByh8X{03{5i8u8Ikd1SQoxgm#v$C>{r`_MN17-bL)C z-?0Bxf3lPawh4#c@}WTX<#%l!zwSa-(FfEFPohVn8LO=!E;`^< zI}jgI7ytZ+7*D&&+0;ntn)2(_w)|eN1xl-Wc3MX+~^F9TKC$P#=Kb1X!^!frxKz3j>J)|98c)*!TD%!FMl%5hSn&m0_i|SUU;Y z%S5{E$9MvQG@_2i!xP{;f!sJ2WhwBz;L3a|HF72JLhhdnjmOR8K`xaL2|?3;fFP&5 zzGChNT|oakxaLBrA7hub<8t5OvhEFG=cZsjmJOTLv>}>NOhXcUT`%B~fK%Q_N;w?7 z!uG5-FrXJ{p&?AU5yG>Q8ItamFtt|)9&H%LlO;pAC8=)6-bYCA<%l>|pkN1Fw?Wlv z^5hZl;wOWpb`?-mc(*q6u1{v|aC+Y=WI=i<6COU}?+uSpCC&G)eavc879Y!bP#+Z5 z0g0kISrkIMx=_xD(NAGbuNt5#;M1ftl-~;MJXv;$54Ig+(tQWXJCkW)^HAb(^6u}+ zG}p_T$W%x(q4hp4%oY3)?F-FD&@GA6fiL*(g$}2t!#5>vd{e^X@rNj$d7AOFHWH$_ znRPXf1PMIFLUXw7DQE`J-KUfA>GjjZ31sxXV?9eOwvNr1xn(Dlu9dRvK`AqD6>x0z zX>!KzBX9K?R{!}A-&e?EJRXA4VV7yGp4kP8@TH|uqg5qJ-%sLEkx!>y3dHE1%7)_K zoBrYag=;KHG4UYBjcxJ)@+R*_eWP)5$GPF79PO9qy!8t$v?LRPcM} zJT5yfw~OJ4m{LImi-pD*MhyMC-)vVW!vV}q8>LzTdv|fUK7{T?l|3n zbS_uSrGST6dW}IJ@+&%XHMXXeNDzo5yZ8q-tdAAhRtFUH=DN5GC*n>24!07|whfCZ zE{(&T))sGaYtT0YnVtLAZ^ePgIv85d#^~Rk{K7)6rZ>UnnT_6mAtz7%cM@=G?_&yH zOv&DlC`zk=-eBO??P#33xhQ)17SaZjS;pY`7!0$>iXIQfzWDYJFnoK?^n&Y6_)^~tlflwyWnk+m}X)H`%3WH`t=quKSuH!cILAQn@ zbBD5QdK(-oUUGWpYeKe%u$&&H%Mn;7!pMCj^@mAgF<-EhoT6xQdbglI3SRl*hmIBPLl_>c z@YTr1Y@ZNM^@Wl*Vt`UHDoulRH#ocMF|5BMJPO^1`J6_h01qFb((g_-J6b1@AQasK zwPG}Sg@;I6jfx%LX34nvMEL1Ij1aE}vL6$?>p2r|iIX2!knm5I_|hg3luqca61Z1t zX4H_541Ft@facMB+oJ)vBuf#84cGjc-Ml&8yrc zS2*+vrwReF0sIoLuzL0wKAqZ*z)9_?Zx#utDsqlQOTRZv4oalBK=Lskk9s2qlXFqz zzqPWKcfZq*Wv@c8R1c96da-;^lb-Q&+t-uR+7@yn@B9Y#JivL5plXP zwylF&=`LEuEz*A$F|pY|k_NN1W%^KQCc07Zc=s$y^zhKQ1BQfjwf3HOt8} z{DD$dQdP1AOiYwxLv2QFX0}UWeSylmfku{uXJMRtiEmcifvq>e7Xk+t;5ramQldMFvx^<&{YuRHxHi)YqnMDqlf(DdO4@6{b>;yBlq@FI-pbTE8+mu_ zElk-m#^WzQTPrlz(7@m&8#lKM!lz+1`L4xWkR^<1YI|-+mt)1Pg`^k#hRLME{UnQ0 z2|_a~Enr}+#Yl#T{ZtwbCjJdOJ2mTdqr5vMPQ9`WALm* zv9G|OWDpb-jN{-foLkp1uKs5F#bxl8UikA!&?>x$!@FG!{|>p~5d@A7A)x0RBA0Wxi~kj;bK`!qmBLxcXy;PtU2{7<;`Erp&S2vyIet&sbZ-;a zGj(`_S7GUtho63ao9^FxGW}rj|b-p4`eK+YZb3J^9tw$ zeyza48m^@~(Yzbc3rm^;iu+ISI;Gr-yo${s8Ojz^#f96kmC{ndlljoKYZo3*F+~Oc zVm3jD_zul>VYg+Wauii!Y)J`}79S8ki_xjaQG}qx5p1c4apq@A-8p1S2a|}+TW}Jk z@HM&aY^?JI51G$M=fpcSSt3nEed?KcFkv$s zzw5v%xG@646QKuXpdo8%A@7X@%C6dSFBil!nNXh!a8KTauulR<#qotdBsMXA7aYs- z5(J2>*(znCK){AYgoc7%p3AN&ayQ7EK7h;?CeT4#GY@ zMLm_h$r7>Tw0rqX5F?s&6N=m_?z|$no`L-iWWR*9zwf{vVnzQ^d4j%zk0s`QP*sm+ z&t=|{Gu+J+1I~oqPbBN{B0Kid^GTSy1oCViJZ=xV0v#^-=8!dTtjK-qhLse{DN67N zh)#qSikUA6i%gKPm4{>Hl&xU-5d>7fOnzRwJ#ed2BAK>xo@x@A?v+KHm?j!Je+yse( z2=P5v zKqm7f_%j%2ZH5dfZ8Fxs;a{gofkcRdY3ZQ!#}lH-!+s~#Ni`6N*ZMQi!`M) z{vOZtpGC<+D24>aS4gBng*eEOk7)uw)q+wt73A9mdHwGd%-u)XJg*&($dqnUnH-bA zJC!Tr^#&6p0jF0Jsr*Ceh$9RL)l)h{tji~LhZk0hB@1i+pm0n|q|6l_L<6o$R6kb86CW)f%}hImu6SN_ zEze&f^rYasi;y#g zaMuj`YlCSdg*F#1MPst?xy6!%v2q>B3IYfo_bx$G-zPSH5FgeYNkl}r(2S;HP%zD- zM~fr|@_98gnj)66;T}#`d7So7xs?@;*Uy9&7si#C=49x)6B8YS(P+e&SQk%tS8B+H zSe?k)=wxb*jjcdraXTspbriayWLd%(O4{)9Rzr%5-(vUUR=CBP+?75=-@6umU&N!c z^rUi?TA0jVfKmaMyF5)ReT@zm9_=flV}mds4k1ka0=)*Nz!9jqX7pY&{=r`o5*m(2 zHxR0;=)P2ODTDDH7e+)5!cWY?U;u+*F!6Hgqv-qM3j%?nhU`@>xtHm|VD2MX1c>?L ztkey&#e&(;4c|_`E($DBp9+pu0#;`UUh*z9ou2my4+unWd>4~Ra20U<{SN6H&!IE6 zDZ}-spi02D%JGMywGtjc(?Dks8Bkqh944{=F+oCdgW-he^0#=zAZR54b1?}**yo2K za11ufBzul{I->BmlyVx4%q{rIru@Qz;gBo1#n4K|8@tkn>$89HF$tguX+`L*7OCPJ ws8C)V3;z!Q0RR7y&ynT;000I_L_t&o07$BT_$Tb#9RL6T07*qoM6N<$g8FWNasU7T literal 0 HcmV?d00001 diff --git a/tests/composition/baselines/legacy-blends.json b/tests/composition/baselines/legacy-blends.json new file mode 100644 index 00000000..d8c1a9f8 --- /dev/null +++ b/tests/composition/baselines/legacy-blends.json @@ -0,0 +1,1538 @@ +[ + { + "implementation": "editor", + "mode": "normal", + "opacity": 0, + "rgba": [ + 0.20000000298023224, + 0.6000000238418579, + 0.8999999761581421, + 1 + ] + }, + { + "implementation": "editor", + "mode": "normal", + "opacity": 0.35, + "rgba": [ + 0.3050000071525574, + 0.5475000143051147, + 0.7599999308586121, + 1 + ] + }, + { + "implementation": "editor", + "mode": "normal", + "opacity": 1, + "rgba": [ + 0.5, + 0.45000001788139343, + 0.5, + 1 + ] + }, + { + "implementation": "editor", + "mode": "multiply", + "opacity": 0, + "rgba": [ + 0.20000000298023224, + 0.6000000238418579, + 0.8999999761581421, + 1 + ] + }, + { + "implementation": "editor", + "mode": "multiply", + "opacity": 0.35, + "rgba": [ + 0.19300000369548798, + 0.5264999866485596, + 0.7582499384880066, + 1 + ] + }, + { + "implementation": "editor", + "mode": "multiply", + "opacity": 1, + "rgba": [ + 0.18000000715255737, + 0.39000001549720764, + 0.4949999749660492, + 1 + ] + }, + { + "implementation": "editor", + "mode": "screen", + "opacity": 0, + "rgba": [ + 0.20000000298023224, + 0.6000000238418579, + 0.8999999761581421, + 1 + ] + }, + { + "implementation": "editor", + "mode": "screen", + "opacity": 0.35, + "rgba": [ + 0.31200000643730164, + 0.6209999918937683, + 0.9017499685287476, + 1 + ] + }, + { + "implementation": "editor", + "mode": "screen", + "opacity": 1, + "rgba": [ + 0.5200000405311584, + 0.6600000262260437, + 0.9049999713897705, + 1 + ] + }, + { + "implementation": "editor", + "mode": "overlay", + "opacity": 0, + "rgba": [ + 0.20000000298023224, + 0.6000000238418579, + 0.8999999761581421, + 1 + ] + }, + { + "implementation": "editor", + "mode": "overlay", + "opacity": 0.35, + "rgba": [ + 0.2840000092983246, + 0.5720000267028809, + 0.8859999179840088, + 1 + ] + }, + { + "implementation": "editor", + "mode": "overlay", + "opacity": 1, + "rgba": [ + 0.4399999976158142, + 0.5200000405311584, + 0.85999995470047, + 1 + ] + }, + { + "implementation": "editor", + "mode": "darken", + "opacity": 0, + "rgba": [ + 0.20000000298023224, + 0.6000000238418579, + 0.8999999761581421, + 1 + ] + }, + { + "implementation": "editor", + "mode": "darken", + "opacity": 0.35, + "rgba": [ + 0.20000000298023224, + 0.5475000143051147, + 0.7599999308586121, + 1 + ] + }, + { + "implementation": "editor", + "mode": "darken", + "opacity": 1, + "rgba": [ + 0.20000000298023224, + 0.45000001788139343, + 0.5, + 1 + ] + }, + { + "implementation": "editor", + "mode": "lighten", + "opacity": 0, + "rgba": [ + 0.20000000298023224, + 0.6000000238418579, + 0.8999999761581421, + 1 + ] + }, + { + "implementation": "editor", + "mode": "lighten", + "opacity": 0.35, + "rgba": [ + 0.3050000071525574, + 0.6000000238418579, + 0.8999999761581421, + 1 + ] + }, + { + "implementation": "editor", + "mode": "lighten", + "opacity": 1, + "rgba": [ + 0.5, + 0.6000000238418579, + 0.8999999761581421, + 1 + ] + }, + { + "implementation": "editor", + "mode": "color-dodge", + "opacity": 0, + "rgba": [ + 0.20000000298023224, + 0.6000000238418579, + 0.8999999761581421, + 1 + ] + }, + { + "implementation": "editor", + "mode": "color-dodge", + "opacity": 0.35, + "rgba": [ + 0.3400000035762787, + 0.6449999809265137, + 0.9174999594688416, + 1 + ] + }, + { + "implementation": "editor", + "mode": "color-dodge", + "opacity": 1, + "rgba": [ + 0.6000000238418579, + 0.7285714745521545, + 0.949999988079071, + 1 + ] + }, + { + "implementation": "editor", + "mode": "color-burn", + "opacity": 0, + "rgba": [ + 0.20000000298023224, + 0.6000000238418579, + 0.8999999761581421, + 1 + ] + }, + { + "implementation": "editor", + "mode": "color-burn", + "opacity": 0.35, + "rgba": [ + 0.16500000655651093, + 0.4950000047683716, + 0.7424999475479126, + 1 + ] + }, + { + "implementation": "editor", + "mode": "color-burn", + "opacity": 1, + "rgba": [ + 0.10000000149011612, + 0.30000001192092896, + 0.44999998807907104, + 1 + ] + }, + { + "implementation": "editor", + "mode": "hard-light", + "opacity": 0, + "rgba": [ + 0.20000000298023224, + 0.6000000238418579, + 0.8999999761581421, + 1 + ] + }, + { + "implementation": "editor", + "mode": "hard-light", + "opacity": 0.35, + "rgba": [ + 0.2840000092983246, + 0.5720000267028809, + 0.8859999179840088, + 1 + ] + }, + { + "implementation": "editor", + "mode": "hard-light", + "opacity": 1, + "rgba": [ + 0.4399999976158142, + 0.5200000405311584, + 0.85999995470047, + 1 + ] + }, + { + "implementation": "editor", + "mode": "soft-light", + "opacity": 0, + "rgba": [ + 0.20000000298023224, + 0.6000000238418579, + 0.8999999761581421, + 1 + ] + }, + { + "implementation": "editor", + "mode": "soft-light", + "opacity": 0.35, + "rgba": [ + 0.22595743834972382, + 0.5877782702445984, + 0.8931843042373657, + 1 + ] + }, + { + "implementation": "editor", + "mode": "soft-light", + "opacity": 1, + "rgba": [ + 0.274164080619812, + 0.5650807023048401, + 0.8805266618728638, + 1 + ] + }, + { + "implementation": "editor", + "mode": "difference", + "opacity": 0, + "rgba": [ + 0.20000000298023224, + 0.6000000238418579, + 0.8999999761581421, + 1 + ] + }, + { + "implementation": "editor", + "mode": "difference", + "opacity": 0.35, + "rgba": [ + 0.27000001072883606, + 0.5475000143051147, + 0.8824999332427979, + 1 + ] + }, + { + "implementation": "editor", + "mode": "difference", + "opacity": 1, + "rgba": [ + 0.4000000059604645, + 0.45000001788139343, + 0.8499999642372131, + 1 + ] + }, + { + "implementation": "editor", + "mode": "exclusion", + "opacity": 0, + "rgba": [ + 0.20000000298023224, + 0.6000000238418579, + 0.8999999761581421, + 1 + ] + }, + { + "implementation": "editor", + "mode": "exclusion", + "opacity": 0.35, + "rgba": [ + 0.2839999794960022, + 0.5895000100135803, + 0.8859999179840088, + 1 + ] + }, + { + "implementation": "editor", + "mode": "exclusion", + "opacity": 1, + "rgba": [ + 0.4399999678134918, + 0.5700000524520874, + 0.8600000143051147, + 1 + ] + }, + { + "implementation": "editor", + "mode": "hue", + "opacity": 0, + "rgba": [ + 0.20000000298023224, + 0.6000000238418579, + 0.8999999761581421, + 1 + ] + }, + { + "implementation": "editor", + "mode": "hue", + "opacity": 0.35, + "rgba": [ + 0.33033299446105957, + 0.5728330016136169, + 0.785332977771759, + 1 + ] + }, + { + "implementation": "editor", + "mode": "hue", + "opacity": 1, + "rgba": [ + 0.572380006313324, + 0.522379994392395, + 0.572380006313324, + 1 + ] + }, + { + "implementation": "editor", + "mode": "saturation", + "opacity": 0, + "rgba": [ + 0.20000000298023224, + 0.6000000238418579, + 0.8999999761581421, + 1 + ] + }, + { + "implementation": "editor", + "mode": "saturation", + "opacity": 0.35, + "rgba": [ + 0.20000000298023224, + 0.6000000238418579, + 0.8999999761581421, + 1 + ] + }, + { + "implementation": "editor", + "mode": "saturation", + "opacity": 1, + "rgba": [ + 0.19999998807907104, + 0.6000000238418579, + 0.8999999761581421, + 1 + ] + }, + { + "implementation": "editor", + "mode": "color", + "opacity": 0, + "rgba": [ + 0.20000000298023224, + 0.6000000238418579, + 0.8999999761581421, + 1 + ] + }, + { + "implementation": "editor", + "mode": "color", + "opacity": 0.35, + "rgba": [ + 0.33033299446105957, + 0.5728330016136169, + 0.785332977771759, + 1 + ] + }, + { + "implementation": "editor", + "mode": "color", + "opacity": 1, + "rgba": [ + 0.572380006313324, + 0.522379994392395, + 0.572380006313324, + 1 + ] + }, + { + "implementation": "editor", + "mode": "luminosity", + "opacity": 0, + "rgba": [ + 0.20000000298023224, + 0.6000000238418579, + 0.8999999761581421, + 1 + ] + }, + { + "implementation": "editor", + "mode": "luminosity", + "opacity": 0.35, + "rgba": [ + 0.17466700077056885, + 0.5746670365333557, + 0.8746669888496399, + 1 + ] + }, + { + "implementation": "editor", + "mode": "luminosity", + "opacity": 1, + "rgba": [ + 0.12761999666690826, + 0.5276200175285339, + 0.8276199698448181, + 1 + ] + }, + { + "implementation": "editor", + "source": "alpha", + "mode": "multiply", + "invert": false, + "rgba": [ + 0.10000000149011612, + 0.30000001192092896, + 0.44999998807907104, + 1 + ] + }, + { + "implementation": "editor", + "source": "alpha", + "mode": "multiply", + "invert": true, + "rgba": [ + 0.10000000149011612, + 0.30000001192092896, + 0.44999998807907104, + 1 + ] + }, + { + "implementation": "editor", + "source": "alpha", + "mode": "stencil", + "invert": false, + "rgba": [ + 0.20000000298023224, + 0.6000000238418579, + 0.8999999761581421, + 1 + ] + }, + { + "implementation": "editor", + "source": "alpha", + "mode": "stencil", + "invert": true, + "rgba": [ + 0.20000000298023224, + 0.6000000238418579, + 0.8999999761581421, + 1 + ] + }, + { + "implementation": "editor", + "source": "red", + "mode": "multiply", + "invert": false, + "rgba": [ + 0.1600000113248825, + 0.48000001907348633, + 0.7199999690055847, + 1 + ] + }, + { + "implementation": "editor", + "source": "red", + "mode": "multiply", + "invert": true, + "rgba": [ + 0.03999999910593033, + 0.11999999731779099, + 0.17999997735023499, + 1 + ] + }, + { + "implementation": "editor", + "source": "red", + "mode": "stencil", + "invert": false, + "rgba": [ + 0.20000000298023224, + 0.6000000238418579, + 0.8999999761581421, + 1 + ] + }, + { + "implementation": "editor", + "source": "red", + "mode": "stencil", + "invert": true, + "rgba": [ + 0, + 0, + 0, + 1 + ] + }, + { + "implementation": "editor", + "source": "green", + "mode": "multiply", + "invert": false, + "rgba": [ + 0.06000000238418579, + 0.18000000715255737, + 0.27000001072883606, + 1 + ] + }, + { + "implementation": "editor", + "source": "green", + "mode": "multiply", + "invert": true, + "rgba": [ + 0.14000000059604645, + 0.42000001668930054, + 0.6299999952316284, + 1 + ] + }, + { + "implementation": "editor", + "source": "green", + "mode": "stencil", + "invert": false, + "rgba": [ + 0, + 0, + 0, + 1 + ] + }, + { + "implementation": "editor", + "source": "green", + "mode": "stencil", + "invert": true, + "rgba": [ + 0.20000000298023224, + 0.6000000238418579, + 0.8999999761581421, + 1 + ] + }, + { + "implementation": "editor", + "source": "blue", + "mode": "multiply", + "invert": false, + "rgba": [ + 0.020000001415610313, + 0.06000000238418579, + 0.08999999612569809, + 1 + ] + }, + { + "implementation": "editor", + "source": "blue", + "mode": "multiply", + "invert": true, + "rgba": [ + 0.17999999225139618, + 0.5400000214576721, + 0.809999942779541, + 1 + ] + }, + { + "implementation": "editor", + "source": "blue", + "mode": "stencil", + "invert": false, + "rgba": [ + 0, + 0, + 0, + 1 + ] + }, + { + "implementation": "editor", + "source": "blue", + "mode": "stencil", + "invert": true, + "rgba": [ + 0.20000000298023224, + 0.6000000238418579, + 0.8999999761581421, + 1 + ] + }, + { + "implementation": "editor", + "source": "luminance", + "mode": "multiply", + "invert": false, + "rgba": [ + 0.07837200164794922, + 0.23511601984500885, + 0.3526740074157715, + 1 + ] + }, + { + "implementation": "editor", + "source": "luminance", + "mode": "multiply", + "invert": true, + "rgba": [ + 0.12162800133228302, + 0.36488401889801025, + 0.5473259687423706, + 1 + ] + }, + { + "implementation": "editor", + "source": "luminance", + "mode": "stencil", + "invert": false, + "rgba": [ + 0, + 0, + 0, + 1 + ] + }, + { + "implementation": "editor", + "source": "luminance", + "mode": "stencil", + "invert": true, + "rgba": [ + 0.20000000298023224, + 0.6000000238418579, + 0.8999999761581421, + 1 + ] + }, + { + "implementation": "runtime", + "mode": "normal", + "opacity": 0, + "rgba": [ + 0.20000000298023224, + 0.6000000238418579, + 0.8999999761581421, + 1 + ] + }, + { + "implementation": "runtime", + "mode": "normal", + "opacity": 0.35, + "rgba": [ + 0.3050000071525574, + 0.5475000143051147, + 0.7599999308586121, + 1 + ] + }, + { + "implementation": "runtime", + "mode": "normal", + "opacity": 1, + "rgba": [ + 0.5, + 0.45000001788139343, + 0.5, + 1 + ] + }, + { + "implementation": "runtime", + "mode": "multiply", + "opacity": 0, + "rgba": [ + 0.20000000298023224, + 0.6000000238418579, + 0.8999999761581421, + 1 + ] + }, + { + "implementation": "runtime", + "mode": "multiply", + "opacity": 0.35, + "rgba": [ + 0.19300000369548798, + 0.5264999866485596, + 0.7582499384880066, + 1 + ] + }, + { + "implementation": "runtime", + "mode": "multiply", + "opacity": 1, + "rgba": [ + 0.18000000715255737, + 0.39000001549720764, + 0.4949999749660492, + 1 + ] + }, + { + "implementation": "runtime", + "mode": "screen", + "opacity": 0, + "rgba": [ + 0.20000000298023224, + 0.6000000238418579, + 0.8999999761581421, + 1 + ] + }, + { + "implementation": "runtime", + "mode": "screen", + "opacity": 0.35, + "rgba": [ + 0.31200000643730164, + 0.6209999918937683, + 0.9017499685287476, + 1 + ] + }, + { + "implementation": "runtime", + "mode": "screen", + "opacity": 1, + "rgba": [ + 0.5200000405311584, + 0.6600000262260437, + 0.9049999713897705, + 1 + ] + }, + { + "implementation": "runtime", + "mode": "overlay", + "opacity": 0, + "rgba": [ + 0.20000000298023224, + 0.6000000238418579, + 0.8999999761581421, + 1 + ] + }, + { + "implementation": "runtime", + "mode": "overlay", + "opacity": 0.35, + "rgba": [ + 0.2840000092983246, + 0.5720000267028809, + 0.8859999179840088, + 1 + ] + }, + { + "implementation": "runtime", + "mode": "overlay", + "opacity": 1, + "rgba": [ + 0.4399999976158142, + 0.5200000405311584, + 0.85999995470047, + 1 + ] + }, + { + "implementation": "runtime", + "mode": "darken", + "opacity": 0, + "rgba": [ + 0.20000000298023224, + 0.6000000238418579, + 0.8999999761581421, + 1 + ] + }, + { + "implementation": "runtime", + "mode": "darken", + "opacity": 0.35, + "rgba": [ + 0.20000000298023224, + 0.5475000143051147, + 0.7599999308586121, + 1 + ] + }, + { + "implementation": "runtime", + "mode": "darken", + "opacity": 1, + "rgba": [ + 0.20000000298023224, + 0.45000001788139343, + 0.5, + 1 + ] + }, + { + "implementation": "runtime", + "mode": "lighten", + "opacity": 0, + "rgba": [ + 0.20000000298023224, + 0.6000000238418579, + 0.8999999761581421, + 1 + ] + }, + { + "implementation": "runtime", + "mode": "lighten", + "opacity": 0.35, + "rgba": [ + 0.3050000071525574, + 0.6000000238418579, + 0.8999999761581421, + 1 + ] + }, + { + "implementation": "runtime", + "mode": "lighten", + "opacity": 1, + "rgba": [ + 0.5, + 0.6000000238418579, + 0.8999999761581421, + 1 + ] + }, + { + "implementation": "runtime", + "mode": "color-dodge", + "opacity": 0, + "rgba": [ + 0.20000000298023224, + 0.6000000238418579, + 0.8999999761581421, + 1 + ] + }, + { + "implementation": "runtime", + "mode": "color-dodge", + "opacity": 0.35, + "rgba": [ + 0.3400000035762787, + 0.6449999809265137, + 0.9174999594688416, + 1 + ] + }, + { + "implementation": "runtime", + "mode": "color-dodge", + "opacity": 1, + "rgba": [ + 0.6000000238418579, + 0.7285714745521545, + 0.949999988079071, + 1 + ] + }, + { + "implementation": "runtime", + "mode": "color-burn", + "opacity": 0, + "rgba": [ + 0.20000000298023224, + 0.6000000238418579, + 0.8999999761581421, + 1 + ] + }, + { + "implementation": "runtime", + "mode": "color-burn", + "opacity": 0.35, + "rgba": [ + 0.16500000655651093, + 0.4950000047683716, + 0.7424999475479126, + 1 + ] + }, + { + "implementation": "runtime", + "mode": "color-burn", + "opacity": 1, + "rgba": [ + 0.10000000149011612, + 0.30000001192092896, + 0.44999998807907104, + 1 + ] + }, + { + "implementation": "runtime", + "mode": "hard-light", + "opacity": 0, + "rgba": [ + 0.20000000298023224, + 0.6000000238418579, + 0.8999999761581421, + 1 + ] + }, + { + "implementation": "runtime", + "mode": "hard-light", + "opacity": 0.35, + "rgba": [ + 0.2840000092983246, + 0.5720000267028809, + 0.8859999179840088, + 1 + ] + }, + { + "implementation": "runtime", + "mode": "hard-light", + "opacity": 1, + "rgba": [ + 0.4399999976158142, + 0.5200000405311584, + 0.85999995470047, + 1 + ] + }, + { + "implementation": "runtime", + "mode": "soft-light", + "opacity": 0, + "rgba": [ + 0.20000000298023224, + 0.6000000238418579, + 0.8999999761581421, + 1 + ] + }, + { + "implementation": "runtime", + "mode": "soft-light", + "opacity": 0.35, + "rgba": [ + 0.22595743834972382, + 0.5877782702445984, + 0.8931843042373657, + 1 + ] + }, + { + "implementation": "runtime", + "mode": "soft-light", + "opacity": 1, + "rgba": [ + 0.274164080619812, + 0.5650807023048401, + 0.8805266618728638, + 1 + ] + }, + { + "implementation": "runtime", + "mode": "difference", + "opacity": 0, + "rgba": [ + 0.20000000298023224, + 0.6000000238418579, + 0.8999999761581421, + 1 + ] + }, + { + "implementation": "runtime", + "mode": "difference", + "opacity": 0.35, + "rgba": [ + 0.27000001072883606, + 0.5475000143051147, + 0.8824999332427979, + 1 + ] + }, + { + "implementation": "runtime", + "mode": "difference", + "opacity": 1, + "rgba": [ + 0.4000000059604645, + 0.45000001788139343, + 0.8499999642372131, + 1 + ] + }, + { + "implementation": "runtime", + "mode": "exclusion", + "opacity": 0, + "rgba": [ + 0.20000000298023224, + 0.6000000238418579, + 0.8999999761581421, + 1 + ] + }, + { + "implementation": "runtime", + "mode": "exclusion", + "opacity": 0.35, + "rgba": [ + 0.2839999794960022, + 0.5895000100135803, + 0.8859999179840088, + 1 + ] + }, + { + "implementation": "runtime", + "mode": "exclusion", + "opacity": 1, + "rgba": [ + 0.4399999678134918, + 0.5700000524520874, + 0.8600000143051147, + 1 + ] + }, + { + "implementation": "runtime", + "mode": "hue", + "opacity": 0, + "rgba": [ + 0.20000000298023224, + 0.6000000238418579, + 0.8999999761581421, + 1 + ] + }, + { + "implementation": "runtime", + "mode": "hue", + "opacity": 0.35, + "rgba": [ + 0.33033299446105957, + 0.5728330016136169, + 0.785332977771759, + 1 + ] + }, + { + "implementation": "runtime", + "mode": "hue", + "opacity": 1, + "rgba": [ + 0.572380006313324, + 0.522379994392395, + 0.572380006313324, + 1 + ] + }, + { + "implementation": "runtime", + "mode": "saturation", + "opacity": 0, + "rgba": [ + 0.20000000298023224, + 0.6000000238418579, + 0.8999999761581421, + 1 + ] + }, + { + "implementation": "runtime", + "mode": "saturation", + "opacity": 0.35, + "rgba": [ + 0.20000000298023224, + 0.6000000238418579, + 0.8999999761581421, + 1 + ] + }, + { + "implementation": "runtime", + "mode": "saturation", + "opacity": 1, + "rgba": [ + 0.19999998807907104, + 0.6000000238418579, + 0.8999999761581421, + 1 + ] + }, + { + "implementation": "runtime", + "mode": "color", + "opacity": 0, + "rgba": [ + 0.20000000298023224, + 0.6000000238418579, + 0.8999999761581421, + 1 + ] + }, + { + "implementation": "runtime", + "mode": "color", + "opacity": 0.35, + "rgba": [ + 0.33033299446105957, + 0.5728330016136169, + 0.785332977771759, + 1 + ] + }, + { + "implementation": "runtime", + "mode": "color", + "opacity": 1, + "rgba": [ + 0.572380006313324, + 0.522379994392395, + 0.572380006313324, + 1 + ] + }, + { + "implementation": "runtime", + "mode": "luminosity", + "opacity": 0, + "rgba": [ + 0.20000000298023224, + 0.6000000238418579, + 0.8999999761581421, + 1 + ] + }, + { + "implementation": "runtime", + "mode": "luminosity", + "opacity": 0.35, + "rgba": [ + 0.17466700077056885, + 0.5746670365333557, + 0.8746669888496399, + 1 + ] + }, + { + "implementation": "runtime", + "mode": "luminosity", + "opacity": 1, + "rgba": [ + 0.12761999666690826, + 0.5276200175285339, + 0.8276199698448181, + 1 + ] + }, + { + "implementation": "runtime", + "source": "alpha", + "mode": "multiply", + "invert": false, + "rgba": [ + 0.10000000149011612, + 0.30000001192092896, + 0.44999998807907104, + 1 + ] + }, + { + "implementation": "runtime", + "source": "alpha", + "mode": "multiply", + "invert": true, + "rgba": [ + 0.10000000149011612, + 0.30000001192092896, + 0.44999998807907104, + 1 + ] + }, + { + "implementation": "runtime", + "source": "alpha", + "mode": "stencil", + "invert": false, + "rgba": [ + 0.20000000298023224, + 0.6000000238418579, + 0.8999999761581421, + 1 + ] + }, + { + "implementation": "runtime", + "source": "alpha", + "mode": "stencil", + "invert": true, + "rgba": [ + 0.20000000298023224, + 0.6000000238418579, + 0.8999999761581421, + 1 + ] + }, + { + "implementation": "runtime", + "source": "red", + "mode": "multiply", + "invert": false, + "rgba": [ + 0.1600000113248825, + 0.48000001907348633, + 0.7199999690055847, + 1 + ] + }, + { + "implementation": "runtime", + "source": "red", + "mode": "multiply", + "invert": true, + "rgba": [ + 0.03999999910593033, + 0.11999999731779099, + 0.17999997735023499, + 1 + ] + }, + { + "implementation": "runtime", + "source": "red", + "mode": "stencil", + "invert": false, + "rgba": [ + 0.20000000298023224, + 0.6000000238418579, + 0.8999999761581421, + 1 + ] + }, + { + "implementation": "runtime", + "source": "red", + "mode": "stencil", + "invert": true, + "rgba": [ + 0, + 0, + 0, + 1 + ] + }, + { + "implementation": "runtime", + "source": "green", + "mode": "multiply", + "invert": false, + "rgba": [ + 0.06000000238418579, + 0.18000000715255737, + 0.27000001072883606, + 1 + ] + }, + { + "implementation": "runtime", + "source": "green", + "mode": "multiply", + "invert": true, + "rgba": [ + 0.14000000059604645, + 0.42000001668930054, + 0.6299999952316284, + 1 + ] + }, + { + "implementation": "runtime", + "source": "green", + "mode": "stencil", + "invert": false, + "rgba": [ + 0, + 0, + 0, + 1 + ] + }, + { + "implementation": "runtime", + "source": "green", + "mode": "stencil", + "invert": true, + "rgba": [ + 0.20000000298023224, + 0.6000000238418579, + 0.8999999761581421, + 1 + ] + }, + { + "implementation": "runtime", + "source": "blue", + "mode": "multiply", + "invert": false, + "rgba": [ + 0.020000001415610313, + 0.06000000238418579, + 0.08999999612569809, + 1 + ] + }, + { + "implementation": "runtime", + "source": "blue", + "mode": "multiply", + "invert": true, + "rgba": [ + 0.17999999225139618, + 0.5400000214576721, + 0.809999942779541, + 1 + ] + }, + { + "implementation": "runtime", + "source": "blue", + "mode": "stencil", + "invert": false, + "rgba": [ + 0, + 0, + 0, + 1 + ] + }, + { + "implementation": "runtime", + "source": "blue", + "mode": "stencil", + "invert": true, + "rgba": [ + 0.20000000298023224, + 0.6000000238418579, + 0.8999999761581421, + 1 + ] + }, + { + "implementation": "runtime", + "source": "luminance", + "mode": "multiply", + "invert": false, + "rgba": [ + 0.07837200164794922, + 0.23511601984500885, + 0.3526740074157715, + 1 + ] + }, + { + "implementation": "runtime", + "source": "luminance", + "mode": "multiply", + "invert": true, + "rgba": [ + 0.12162800133228302, + 0.36488401889801025, + 0.5473259687423706, + 1 + ] + }, + { + "implementation": "runtime", + "source": "luminance", + "mode": "stencil", + "invert": false, + "rgba": [ + 0, + 0, + 0, + 1 + ] + }, + { + "implementation": "runtime", + "source": "luminance", + "mode": "stencil", + "invert": true, + "rgba": [ + 0.20000000298023224, + 0.6000000238418579, + 0.8999999761581421, + 1 + ] + } +] diff --git a/tests/composition/baselines/legacy-text-mask.png b/tests/composition/baselines/legacy-text-mask.png new file mode 100644 index 0000000000000000000000000000000000000000..bb1c40ec487f75cead898c1caffac855b91e7abb GIT binary patch literal 8940 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 literal 0 HcmV?d00001 diff --git a/tests/composition/baselines/solid-text-background.png b/tests/composition/baselines/solid-text-background.png new file mode 100644 index 0000000000000000000000000000000000000000..8645a06bf3128b5e34767720d1c230b59908693e GIT binary patch literal 16171 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 literal 0 HcmV?d00001 diff --git a/tests/composition/baselines/transparent-text-screen.png b/tests/composition/baselines/transparent-text-screen.png new file mode 100644 index 0000000000000000000000000000000000000000..bd1d17c05fc9d2f6a796343b5158a902e33e0c79 GIT binary patch literal 16878 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 ( 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 literal 0 HcmV?d00001 diff --git a/tests/composition/browser.mjs b/tests/composition/browser.mjs new file mode 100644 index 00000000..95070168 --- /dev/null +++ b/tests/composition/browser.mjs @@ -0,0 +1,242 @@ +import { buildBlendNode as buildRuntimeBlendNode } from "@runtime/renderer/blend-modes" +import { float, vec4 } from "three/tsl" +import * as THREE from "three/webgpu" +import { + buildViewerProjectState, + parseLabProjectFileValue, +} from "@/lib/editor/project-file" +import { buildBlendNode } from "@/renderer/blend-modes" +import { buildRendererFrame } from "@/renderer/contracts" +import { createWebGPURenderer } from "@/renderer/create-webgpu-renderer" +import { BLEND_MODES } from "@/types/editor" + +function pixels(canvas) { + const copy = document.createElement("canvas") + copy.width = canvas.width + copy.height = canvas.height + const context = copy.getContext("2d", { willReadFrequently: true }) + context.drawImage(canvas, 0, 0) + return context.getImageData(0, 0, copy.width, copy.height) +} + +function compare(actual, expected, tolerance = 0) { + if (actual.width !== expected.width || actual.height !== expected.height) { + throw new Error("Image dimensions changed") + } + let changedPixels = 0 + let maxDelta = 0 + for (let index = 0; index < actual.data.length; index += 4) { + let delta = 0 + for (let channel = 0; channel < 4; channel++) { + delta = Math.max( + delta, + Math.abs(actual.data[index + channel] - expected.data[index + channel]) + ) + } + if (delta > tolerance) changedPixels++ + maxDelta = Math.max(maxDelta, delta) + } + return { changedPixels, maxDelta } +} + +async function settle(renderer, frame) { + renderer.render(frame) + const deadline = performance.now() + 30_000 + while (renderer.hasPendingResources()) { + if (performance.now() > deadline) + throw new Error("Timed out loading or compiling a fixture") + await new Promise((resolve) => setTimeout(resolve, 20)) + } + await renderer.prepareForExportFrame(frame.clock.timelineTime, true) + renderer.render(frame) + await renderer.waitForGpuIdle() +} + +async function renderProject(value) { + const project = parseLabProjectFileValue(value) + const state = buildViewerProjectState(project) + const size = project.composition + const canvas = document.createElement("canvas") + const renderer = await createWebGPURenderer(canvas, { + strictPassFailures: true, + }) + try { + await renderer.initialize() + renderer.resize(size, 1) + const frame = buildRendererFrame({ + ...state, + outputSize: size, + viewportSize: size, + delta: 0, + clockTime: 0, + pixelRatio: 1, + timeline: { ...state.timeline, currentTime: 0, isPlaying: false }, + }) + await settle(renderer, frame) + const preview = pixels(canvas) + const exported = renderer.exportFrame(frame, size) + const exportDiff = compare(preview, pixels(exported)) + if (exportDiff.changedPixels) + throw new Error(`Preview/export mismatch: ${JSON.stringify(exportDiff)}`) + return { image: preview, png: exported.toDataURL("image/png") } + } finally { + renderer.dispose() + await renderer.destroyDevice() + } +} + +window.checkProject = async (name, update) => { + const file = await (await fetch(`/fixtures/${name}.json`)).json() + const first = await renderProject(file) + // Reopen a serialized project in a new renderer/device, with fresh textures. + const reopened = await renderProject( + JSON.parse(JSON.stringify(parseLabProjectFileValue(file))) + ) + const reopenDiff = compare(first.image, reopened.image) + if (reopenDiff.changedPixels) + throw new Error(`Reopen mismatch: ${JSON.stringify(reopenDiff)}`) + const colors = new Set() + for (let i = 0; i < first.image.data.length; i += 4) { + colors.add( + `${first.image.data[i]},${first.image.data[i + 1]},${first.image.data[i + 2]}` + ) + if (first.image.data[i + 3] !== 255) + throw new Error("Legacy fixture unexpectedly became transparent") + } + if (colors.size < 8) + throw new Error("Fixture is blank or has lost its content") + let baselineDiff = null + if (!update) { + const response = await fetch(`/baselines/${name}.png`) + if (!response.ok) throw new Error(`Missing baseline: ${name}`) + const bitmap = await createImageBitmap(await response.blob()) + const reference = document.createElement("canvas") + reference.width = bitmap.width + reference.height = bitmap.height + reference.getContext("2d").drawImage(bitmap, 0, 0) + bitmap.close() + baselineDiff = compare(first.image, pixels(reference), 2) + } + return { png: first.png, baselineDiff, reopenDiff, colors: colors.size } +} + +window.checkLegacyBlendContract = async () => { + const renderer = new THREE.WebGPURenderer({ antialias: false }) + await renderer.init() + renderer.toneMapping = THREE.NoToneMapping + const target = new THREE.RenderTarget(1, 1, { + type: THREE.FloatType, + depthBuffer: false, + }) + const geometry = new THREE.PlaneGeometry(2, 2) + const camera = new THREE.OrthographicCamera(-1, 1, 1, -1, 0, 1) + const material = new THREE.MeshBasicNodeMaterial({ + transparent: true, + blending: THREE.NoBlending, + }) + const mesh = new THREE.Mesh(geometry, material) + const scene = new THREE.Scene() + scene.add(mesh) + const results = [] + try { + for (const [implementation, build] of [ + ["editor", buildBlendNode], + ["runtime", buildRuntimeBlendNode], + ]) { + for (const mode of BLEND_MODES) { + for (const opacity of [0, 0.35, 1]) { + material.colorNode = build( + mode, + vec4(0.2, 0.6, 0.9, 1), + vec4(0.8, 0.3, 0.1, 0.5), + float(opacity) + ) + material.needsUpdate = true + renderer.setRenderTarget(target) + renderer.render(scene, camera) + const data = await renderer.readRenderTargetPixelsAsync( + target, + 0, + 0, + 1, + 1 + ) + results.push({ + implementation, + mode, + opacity, + rgba: Array.from(data), + }) + } + } + for (const source of ["alpha", "red", "green", "blue", "luminance"]) { + for (const mode of ["multiply", "stencil"]) { + for (const invert of [false, true]) { + material.colorNode = build( + "normal", + vec4(0.2, 0.6, 0.9, 1), + vec4(0.8, 0.3, 0.1, 0.5), + float(1), + "mask", + { source, mode, invert } + ) + material.needsUpdate = true + renderer.render(scene, camera) + const data = await renderer.readRenderTargetPixelsAsync( + target, + 0, + 0, + 1, + 1 + ) + results.push({ + implementation, + source, + mode, + invert, + rgba: Array.from(data), + }) + } + } + } + } + return results + } finally { + target.dispose() + material.dispose() + geometry.dispose() + renderer.dispose() + renderer.backend.device.destroy() + } +} + +window.checkExistingProject = async () => { + const original = await ( + await fetch("/fixtures/existing-default-project.json") + ).json() + const parsed = parseLabProjectFileValue(original) + const reopened = parseLabProjectFileValue(JSON.parse(JSON.stringify(parsed))) + if (JSON.stringify(parsed) !== JSON.stringify(reopened)) + throw new Error("Saved project is not stable across parse/serialize/reopen") + const state = buildViewerProjectState(reopened) + if ( + state.layers.length !== original.layers.length || + state.assets.length !== original.assets.length + ) { + throw new Error("Existing project lost layers or bundled assets") + } + for (const [index, layer] of state.layers.entries()) { + const saved = original.layers[index] + for (const key of [ + "blendMode", + "compositeMode", + "maskConfig", + "opacity", + "params", + ]) { + if (JSON.stringify(layer[key]) !== JSON.stringify(saved[key])) + throw new Error(`Existing ${layer.type} layer changed ${key}`) + } + } + return { layers: state.layers.length, assets: state.assets.length } +} diff --git a/tests/composition/fixtures/alpha-sample.svg b/tests/composition/fixtures/alpha-sample.svg new file mode 100644 index 00000000..7be9db5a --- /dev/null +++ b/tests/composition/fixtures/alpha-sample.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/tests/composition/fixtures/contained-image-halftone.json b/tests/composition/fixtures/contained-image-halftone.json new file mode 100644 index 00000000..5b66ba46 --- /dev/null +++ b/tests/composition/fixtures/contained-image-halftone.json @@ -0,0 +1,204 @@ +{ + "format": "shader-lab", + "version": 6, + "composition": { + "width": 256, + "height": 192 + }, + "assets": [ + { + "id": "sample", + "kind": "image", + "fileName": "alpha-sample.svg", + "url": "/scenes/default/alpha-sample.svg", + "mimeType": "image/svg+xml", + "width": 160, + "height": 160, + "duration": null, + "sizeBytes": 570 + } + ], + "layers": [ + { + "assetId": null, + "blendMode": "normal", + "compositeMode": "filter", + "expanded": true, + "hue": 0, + "id": "halftone", + "kind": "effect", + "locked": false, + "maskConfig": { + "invert": false, + "mode": "multiply", + "source": "luminance" + }, + "name": "Halftone", + "opacity": 0.65, + "params": { + "colorMode": "cmyk", + "shape": "circle", + "spacing": 5, + "dotSize": 1, + "dotMin": 0, + "angle": 28, + "contrast": 1, + "softness": 0.25, + "dotGain": 0, + "dotMorph": 0, + "invertLuma": false, + "customColorCount": 4, + "customLuminanceBias": 0, + "bloomEnabled": false, + "bloomIntensity": 1.25, + "bloomThreshold": 0.6, + "bloomRadius": 6, + "bloomSoftness": 0.35, + "customBgColor": "#F5F5F0", + "customColor1": "#0d1014", + "customColor2": "#4d5057", + "customColor3": "#969aa2", + "customColor4": "#e1e2de", + "ink": "#0d1014", + "duotoneLight": "#F5F5F0", + "duotoneDark": "#1d1d1c", + "preset": "process", + "gcr": 0.5, + "cmykBlend": "subtractive", + "cyanAngle": 15, + "magentaAngle": 75, + "yellowAngle": 0, + "keyAngle": 45, + "paperColor": "#F5F5F0", + "paperGrain": 0.15, + "registration": 0, + "inkCyan": "#00AEEF", + "inkMagenta": "#EC008C", + "inkYellow": "#FFF200", + "inkKey": "#1a1a1a" + }, + "runtimeError": null, + "saturation": 1, + "type": "halftone", + "visible": true + }, + { + "assetId": "sample", + "blendMode": "normal", + "compositeMode": "filter", + "expanded": true, + "hue": 0, + "id": "image", + "kind": "source", + "locked": false, + "maskConfig": { + "invert": false, + "mode": "multiply", + "source": "luminance" + }, + "name": "Image", + "opacity": 1, + "params": { + "fitMode": "contain", + "scale": 1, + "offset": [ + 0, + 0 + ], + "svgRasterResolution": "2048" + }, + "runtimeError": null, + "saturation": 1, + "type": "image", + "visible": true + } + ], + "selectedLayerId": "halftone", + "sceneConfig": { + "backgroundColor": "#080808", + "compositionAspect": "screen", + "compositionWidth": 1920, + "compositionHeight": 1080, + "exposure": 0, + "brightness": 0, + "contrast": 0, + "saturation": 1, + "vibrance": 0, + "hue": 0, + "temperature": 0, + "tint": 0, + "invert": false, + "channelMixer": { + "rr": 1, + "rg": 0, + "rb": 0, + "gr": 0, + "gg": 1, + "gb": 0, + "br": 0, + "bg": 0, + "bb": 1 + }, + "colorCurves": { + "blue": { + "points": [ + { + "x": 0, + "y": 0 + }, + { + "x": 1, + "y": 1 + } + ] + }, + "green": { + "points": [ + { + "x": 0, + "y": 0 + }, + { + "x": 1, + "y": 1 + } + ] + }, + "red": { + "points": [ + { + "x": 0, + "y": 0 + }, + { + "x": 1, + "y": 1 + } + ] + }, + "rgb": { + "points": [ + { + "x": 0, + "y": 0 + }, + { + "x": 1, + "y": 1 + } + ] + } + }, + "clampMin": 0, + "clampGamma": 1, + "clampMax": 1, + "quantizeEnabled": false, + "quantizeLevels": 256, + "colorMap": null + }, + "timeline": { + "duration": 5, + "loop": true, + "tracks": [] + } +} diff --git a/tests/composition/fixtures/existing-default-project.json b/tests/composition/fixtures/existing-default-project.json new file mode 100644 index 00000000..33dfad0a --- /dev/null +++ b/tests/composition/fixtures/existing-default-project.json @@ -0,0 +1,473 @@ +{ + "assets": [ + { + "duration": 5.041667, + "fileName": "aura.mp4", + "height": 720, + "id": "efb4eebe-d991-44c8-8f08-8fac18281a9b", + "kind": "video", + "mimeType": "video/mp4", + "sizeBytes": 629868, + "url": "/scenes/default/aura.mp4", + "width": 578 + }, + { + "duration": 59.996, + "fileName": "aura.ogg", + "height": null, + "id": "f4a5f106-8d90-46a2-b86f-b68a7a1cd5fb", + "kind": "audio", + "mimeType": "audio/ogg", + "sizeBytes": 779577, + "url": "/scenes/default/aura.ogg", + "width": null + } + ], + "audio": { + "bands": { + "bass": { + "attackMs": 219, + "gainDb": 0, + "highHz": 140, + "lowHz": 20, + "releaseMs": 560 + }, + "mid": { + "attackMs": 246, + "gainDb": 0, + "highHz": 2000, + "lowHz": 140, + "releaseMs": 493 + }, + "high": { + "attackMs": 202, + "gainDb": 0, + "highHz": 16000, + "lowHz": 2000, + "releaseMs": 424 + }, + "level": { + "attackMs": 264, + "gainDb": 0, + "highHz": 20000, + "lowHz": 20, + "releaseMs": 577 + } + }, + "links": [], + "offsetSeconds": 0, + "source": { + "assetId": "f4a5f106-8d90-46a2-b86f-b68a7a1cd5fb", + "kind": "asset" + } + }, + "composition": { + "height": 949, + "width": 1512 + }, + "exportedAt": "2026-08-14T15:16:56.006Z", + "format": "shader-lab", + "layers": [ + { + "assetId": null, + "blendMode": "normal", + "compositeMode": "filter", + "expanded": true, + "hue": 4, + "id": "eb6dda3c-1632-44c5-9a29-d4f382a09b8d", + "kind": "effect", + "locked": false, + "maskConfig": { + "invert": false, + "mode": "multiply", + "source": "luminance" + }, + "name": "Displacement Map", + "opacity": 1, + "params": { + "channel": "luminance", + "direction": "both", + "midpoint": 0.23, + "strength": 82 + }, + "runtimeError": null, + "saturation": 2, + "type": "displacement-map", + "visible": true + }, + { + "assetId": null, + "blendMode": "screen", + "compositeMode": "filter", + "expanded": true, + "hue": 0, + "id": "83cd9b9f-7584-4779-96e1-c387bfbf55e6", + "kind": "effect", + "locked": false, + "maskConfig": { + "invert": false, + "mode": "multiply", + "source": "luminance" + }, + "name": "Bloom", + "opacity": 1, + "params": { + "bloomIntensity": 1.66, + "bloomKnee": 0.22, + "bloomRadius": 13.25, + "bloomSoftness": 0.92, + "bloomThreshold": 0.29, + "highlightDrive": 1.95 + }, + "runtimeError": null, + "saturation": 1, + "type": "bloom", + "visible": true + }, + { + "assetId": null, + "blendMode": "normal", + "compositeMode": "filter", + "expanded": true, + "hue": 0, + "id": "a349a6a1-31db-45bc-bc48-f11a696eb206", + "kind": "effect", + "locked": false, + "maskConfig": { + "invert": false, + "mode": "multiply", + "source": "luminance" + }, + "name": "Progressive Blur", + "opacity": 1, + "params": { + "angle": 0, + "end": 0.73, + "samples": 9, + "start": 0.59, + "strength": 20 + }, + "runtimeError": null, + "saturation": 1, + "type": "smear", + "visible": true + }, + { + "assetId": null, + "blendMode": "normal", + "compositeMode": "filter", + "expanded": true, + "hue": 2, + "id": "40c39149-a3e6-4abc-a5c2-f0f4c7e2e67b", + "kind": "effect", + "locked": false, + "maskConfig": { + "invert": false, + "mode": "multiply", + "source": "luminance" + }, + "name": "ASCII", + "opacity": 1, + "params": { + "bgOpacity": 0.18, + "boldness": 0.26, + "breakGrid": "off", + "breakThreshold": 0.06, + "charset": "light", + "colorMode": "source", + "columns": 358, + "customChars": " .:-=+*#%@", + "fontFamily": "mono", + "fontWeight": 400, + "invert": false, + "monoColor": "#f5f5f0", + "rowWarp": 0, + "signalBlackPoint": 0, + "signalWhitePoint": 1 + }, + "runtimeError": null, + "saturation": 1.35, + "type": "ascii", + "visible": true + }, + { + "assetId": null, + "blendMode": "lighten", + "compositeMode": "filter", + "expanded": true, + "hue": 0, + "id": "d6b5aa25-7379-4ce9-9b1b-048aff0a0f81", + "kind": "source", + "locked": false, + "maskConfig": { + "invert": false, + "mode": "multiply", + "source": "luminance" + }, + "name": "Pixel Trail", + "opacity": 1, + "params": { + "cellSize": 24, + "decay": 0.862, + "displaceAmount": 0.183, + "intensity": 1.9, + "radius": 0.07 + }, + "runtimeError": null, + "saturation": 1, + "type": "pixel-trail", + "visible": true + }, + { + "assetId": null, + "blendMode": "normal", + "compositeMode": "filter", + "expanded": true, + "hue": 0, + "id": "89ce5095-45f8-46c7-86cb-bc6bb3ad7fff", + "kind": "effect", + "locked": false, + "maskConfig": { + "invert": false, + "mode": "multiply", + "source": "luminance" + }, + "name": "Blob Tracking", + "opacity": 1, + "params": { + "blobAmount": 4, + "centerShape": "cross", + "connectLines": true, + "connectorArrows": false, + "connectorDashed": false, + "curvedLines": false, + "detectionMode": "luminance", + "innerEffectParams": "", + "innerEffectType": "none", + "invert": false, + "minBlobSize": 6, + "motionMaskThreshold": 0.08, + "motionPersistence": 0.82, + "motionThreshold": 0.36, + "outputMode": "decorated", + "persistentTracking": true, + "sensitivity": 0.72, + "shapeScale": 1, + "shapeType": "square", + "showLabels": true, + "showOutline": true, + "smoothing": 0.52, + "strokeColor": "#E6E6E6", + "strokeWidth": 2, + "trailDecay": 0.35 + }, + "runtimeError": null, + "saturation": 1, + "type": "blob-tracking", + "visible": true + }, + { + "assetId": null, + "blendMode": "normal", + "compositeMode": "filter", + "expanded": true, + "hue": 0, + "id": "6bfa2084-cf57-4f8a-bb49-57cfa1c74b1c", + "kind": "effect", + "locked": false, + "maskConfig": { + "invert": false, + "mode": "multiply", + "source": "luminance" + }, + "name": "Dithering", + "opacity": 1, + "params": { + "algorithm": "bayer-4x4", + "animateDither": false, + "chromaticSplit": false, + "colorMode": "source", + "ditherSpeed": 1, + "dotScale": 1, + "highlightColor": "#f5f2e8", + "levels": 3, + "monoColor": "#f5f5f0", + "pixelSize": 1, + "preset": "custom", + "shadowColor": "#101010", + "spread": 0.5 + }, + "runtimeError": null, + "saturation": 1, + "type": "dithering", + "visible": true + }, + { + "assetId": null, + "blendMode": "normal", + "compositeMode": "mask", + "expanded": true, + "hue": 0, + "id": "0e3136ed-a783-4527-888d-269caeb49a9f", + "kind": "source", + "locked": false, + "maskConfig": { + "invert": false, + "mode": "multiply", + "source": "luminance" + }, + "name": "Text", + "opacity": 1, + "params": { + "anchor": "center", + "backgroundAlpha": 1, + "backgroundColor": "#000000", + "fontFamily": "sans", + "fontSize": 201, + "fontWeight": 800, + "letterSpacing": -0.1, + "offset": [ + 0, + 0 + ], + "text": "ShaderLab", + "textColor": "#ffffff" + }, + "runtimeError": null, + "saturation": 1, + "type": "text", + "visible": true + }, + { + "assetId": "efb4eebe-d991-44c8-8f08-8fac18281a9b", + "blendMode": "normal", + "compositeMode": "filter", + "expanded": true, + "hue": 0, + "id": "cd60ee67-6fbe-41f2-9281-547a12823cc1", + "kind": "source", + "locked": false, + "maskConfig": { + "invert": false, + "mode": "multiply", + "source": "luminance" + }, + "name": "Video", + "opacity": 1, + "params": { + "fitMode": "cover", + "offset": [ + 0, + 0 + ], + "playbackRate": 1, + "scale": 1.23 + }, + "runtimeError": null, + "saturation": 1, + "type": "video", + "visible": true + } + ], + "sceneConfig": { + "backgroundColor": "#080808", + "compositionAspect": "screen", + "compositionWidth": 1920, + "compositionHeight": 1080, + "exposure": 2.42, + "brightness": 0, + "contrast": 0.05, + "saturation": 1.12, + "vibrance": 0.1, + "hue": 9, + "temperature": 0, + "tint": 0, + "invert": false, + "channelMixer": { + "rr": 1, + "rg": 0, + "rb": 0, + "gr": 0, + "gg": 1, + "gb": 0, + "br": 0, + "bg": 0, + "bb": 1 + }, + "colorCurves": { + "blue": { + "points": [ + { + "x": 0, + "y": 0 + }, + { + "x": 1, + "y": 1 + } + ] + }, + "green": { + "points": [ + { + "x": 0, + "y": 0 + }, + { + "x": 1, + "y": 1 + } + ] + }, + "red": { + "points": [ + { + "x": 0, + "y": 0 + }, + { + "x": 1, + "y": 1 + } + ] + }, + "rgb": { + "points": [ + { + "x": 0, + "y": 0.01213968211206895 + }, + { + "x": 0.2680158943965517, + "y": 0.23698477909482762 + }, + { + "x": 0.4523504849137931, + "y": 0.5597218480603448 + }, + { + "x": 0.7020979256465517, + "y": 0.798760775862069 + }, + { + "x": 1, + "y": 1 + } + ] + } + }, + "clampMin": 0, + "clampGamma": 1, + "clampMax": 1, + "quantizeEnabled": false, + "quantizeLevels": 256, + "colorMap": null + }, + "selectedLayerId": "cd60ee67-6fbe-41f2-9281-547a12823cc1", + "timeline": { + "duration": 59.996, + "loop": true, + "tracks": [] + }, + "version": 6 +} diff --git a/tests/composition/fixtures/legacy-text-mask.json b/tests/composition/fixtures/legacy-text-mask.json new file mode 100644 index 00000000..d4134be9 --- /dev/null +++ b/tests/composition/fixtures/legacy-text-mask.json @@ -0,0 +1,177 @@ +{ + "format": "shader-lab", + "version": 6, + "composition": { + "width": 256, + "height": 192 + }, + "assets": [ + { + "id": "sample", + "kind": "image", + "fileName": "alpha-sample.svg", + "url": "/scenes/default/alpha-sample.svg", + "mimeType": "image/svg+xml", + "width": 160, + "height": 160, + "duration": null, + "sizeBytes": 570 + } + ], + "layers": [ + { + "assetId": null, + "blendMode": "normal", + "compositeMode": "mask", + "expanded": true, + "hue": 0, + "id": "text", + "kind": "source", + "locked": false, + "maskConfig": { + "invert": false, + "mode": "multiply", + "source": "luminance" + }, + "name": "Text", + "opacity": 1, + "params": { + "text": "V3", + "anchor": "center", + "offset": [ + 0, + 0 + ], + "fontSize": 96, + "fontFamily": "mono", + "fontWeight": 400, + "letterSpacing": 0, + "textColor": "#ffffff", + "backgroundColor": "#000000", + "backgroundAlpha": 1 + }, + "runtimeError": null, + "saturation": 1, + "type": "text", + "visible": true + }, + { + "assetId": "sample", + "blendMode": "normal", + "compositeMode": "filter", + "expanded": true, + "hue": 0, + "id": "image", + "kind": "source", + "locked": false, + "maskConfig": { + "invert": false, + "mode": "multiply", + "source": "luminance" + }, + "name": "Image", + "opacity": 1, + "params": { + "fitMode": "contain", + "scale": 1, + "offset": [ + 0, + 0 + ], + "svgRasterResolution": "2048" + }, + "runtimeError": null, + "saturation": 1, + "type": "image", + "visible": true + } + ], + "selectedLayerId": "text", + "sceneConfig": { + "backgroundColor": "#080808", + "compositionAspect": "screen", + "compositionWidth": 1920, + "compositionHeight": 1080, + "exposure": 0, + "brightness": 0, + "contrast": 0, + "saturation": 1, + "vibrance": 0, + "hue": 0, + "temperature": 0, + "tint": 0, + "invert": false, + "channelMixer": { + "rr": 1, + "rg": 0, + "rb": 0, + "gr": 0, + "gg": 1, + "gb": 0, + "br": 0, + "bg": 0, + "bb": 1 + }, + "colorCurves": { + "blue": { + "points": [ + { + "x": 0, + "y": 0 + }, + { + "x": 1, + "y": 1 + } + ] + }, + "green": { + "points": [ + { + "x": 0, + "y": 0 + }, + { + "x": 1, + "y": 1 + } + ] + }, + "red": { + "points": [ + { + "x": 0, + "y": 0 + }, + { + "x": 1, + "y": 1 + } + ] + }, + "rgb": { + "points": [ + { + "x": 0, + "y": 0 + }, + { + "x": 1, + "y": 1 + } + ] + } + }, + "clampMin": 0, + "clampGamma": 1, + "clampMax": 1, + "quantizeEnabled": false, + "quantizeLevels": 256, + "colorMap": null + }, + "timeline": { + "duration": 5, + "loop": true, + "tracks": [] + } +} diff --git a/tests/composition/fixtures/solid-text-background.json b/tests/composition/fixtures/solid-text-background.json new file mode 100644 index 00000000..2cf18469 --- /dev/null +++ b/tests/composition/fixtures/solid-text-background.json @@ -0,0 +1,177 @@ +{ + "format": "shader-lab", + "version": 6, + "composition": { + "width": 256, + "height": 192 + }, + "assets": [ + { + "id": "sample", + "kind": "image", + "fileName": "alpha-sample.svg", + "url": "/scenes/default/alpha-sample.svg", + "mimeType": "image/svg+xml", + "width": 160, + "height": 160, + "duration": null, + "sizeBytes": 570 + } + ], + "layers": [ + { + "assetId": null, + "blendMode": "normal", + "compositeMode": "filter", + "expanded": true, + "hue": 0, + "id": "text", + "kind": "source", + "locked": false, + "maskConfig": { + "invert": false, + "mode": "multiply", + "source": "luminance" + }, + "name": "Text", + "opacity": 0.75, + "params": { + "text": "V3", + "anchor": "center", + "offset": [ + 0, + 0 + ], + "fontSize": 96, + "fontFamily": "mono", + "fontWeight": 400, + "letterSpacing": 0, + "textColor": "#ffffff", + "backgroundColor": "#000000", + "backgroundAlpha": 1 + }, + "runtimeError": null, + "saturation": 1, + "type": "text", + "visible": true + }, + { + "assetId": "sample", + "blendMode": "normal", + "compositeMode": "filter", + "expanded": true, + "hue": 0, + "id": "image", + "kind": "source", + "locked": false, + "maskConfig": { + "invert": false, + "mode": "multiply", + "source": "luminance" + }, + "name": "Image", + "opacity": 1, + "params": { + "fitMode": "contain", + "scale": 1, + "offset": [ + 0, + 0 + ], + "svgRasterResolution": "2048" + }, + "runtimeError": null, + "saturation": 1, + "type": "image", + "visible": true + } + ], + "selectedLayerId": "text", + "sceneConfig": { + "backgroundColor": "#080808", + "compositionAspect": "screen", + "compositionWidth": 1920, + "compositionHeight": 1080, + "exposure": 0, + "brightness": 0, + "contrast": 0, + "saturation": 1, + "vibrance": 0, + "hue": 0, + "temperature": 0, + "tint": 0, + "invert": false, + "channelMixer": { + "rr": 1, + "rg": 0, + "rb": 0, + "gr": 0, + "gg": 1, + "gb": 0, + "br": 0, + "bg": 0, + "bb": 1 + }, + "colorCurves": { + "blue": { + "points": [ + { + "x": 0, + "y": 0 + }, + { + "x": 1, + "y": 1 + } + ] + }, + "green": { + "points": [ + { + "x": 0, + "y": 0 + }, + { + "x": 1, + "y": 1 + } + ] + }, + "red": { + "points": [ + { + "x": 0, + "y": 0 + }, + { + "x": 1, + "y": 1 + } + ] + }, + "rgb": { + "points": [ + { + "x": 0, + "y": 0 + }, + { + "x": 1, + "y": 1 + } + ] + } + }, + "clampMin": 0, + "clampGamma": 1, + "clampMax": 1, + "quantizeEnabled": false, + "quantizeLevels": 256, + "colorMap": null + }, + "timeline": { + "duration": 5, + "loop": true, + "tracks": [] + } +} diff --git a/tests/composition/fixtures/transparent-text-screen.json b/tests/composition/fixtures/transparent-text-screen.json new file mode 100644 index 00000000..96d0c2de --- /dev/null +++ b/tests/composition/fixtures/transparent-text-screen.json @@ -0,0 +1,177 @@ +{ + "format": "shader-lab", + "version": 6, + "composition": { + "width": 256, + "height": 192 + }, + "assets": [ + { + "id": "sample", + "kind": "image", + "fileName": "alpha-sample.svg", + "url": "/scenes/default/alpha-sample.svg", + "mimeType": "image/svg+xml", + "width": 160, + "height": 160, + "duration": null, + "sizeBytes": 570 + } + ], + "layers": [ + { + "assetId": null, + "blendMode": "screen", + "compositeMode": "filter", + "expanded": true, + "hue": 0, + "id": "text", + "kind": "source", + "locked": false, + "maskConfig": { + "invert": false, + "mode": "multiply", + "source": "luminance" + }, + "name": "Text", + "opacity": 1, + "params": { + "text": "V3", + "anchor": "center", + "offset": [ + 0, + 0 + ], + "fontSize": 96, + "fontFamily": "mono", + "fontWeight": 400, + "letterSpacing": 0, + "textColor": "#ff713d", + "backgroundColor": "#000000", + "backgroundAlpha": 0 + }, + "runtimeError": null, + "saturation": 1, + "type": "text", + "visible": true + }, + { + "assetId": "sample", + "blendMode": "normal", + "compositeMode": "filter", + "expanded": true, + "hue": 0, + "id": "image", + "kind": "source", + "locked": false, + "maskConfig": { + "invert": false, + "mode": "multiply", + "source": "luminance" + }, + "name": "Image", + "opacity": 1, + "params": { + "fitMode": "contain", + "scale": 1, + "offset": [ + 0, + 0 + ], + "svgRasterResolution": "2048" + }, + "runtimeError": null, + "saturation": 1, + "type": "image", + "visible": true + } + ], + "selectedLayerId": "text", + "sceneConfig": { + "backgroundColor": "#080808", + "compositionAspect": "screen", + "compositionWidth": 1920, + "compositionHeight": 1080, + "exposure": 0, + "brightness": 0, + "contrast": 0, + "saturation": 1, + "vibrance": 0, + "hue": 0, + "temperature": 0, + "tint": 0, + "invert": false, + "channelMixer": { + "rr": 1, + "rg": 0, + "rb": 0, + "gr": 0, + "gg": 1, + "gb": 0, + "br": 0, + "bg": 0, + "bb": 1 + }, + "colorCurves": { + "blue": { + "points": [ + { + "x": 0, + "y": 0 + }, + { + "x": 1, + "y": 1 + } + ] + }, + "green": { + "points": [ + { + "x": 0, + "y": 0 + }, + { + "x": 1, + "y": 1 + } + ] + }, + "red": { + "points": [ + { + "x": 0, + "y": 0 + }, + { + "x": 1, + "y": 1 + } + ] + }, + "rgb": { + "points": [ + { + "x": 0, + "y": 0 + }, + { + "x": 1, + "y": 1 + } + ] + } + }, + "clampMin": 0, + "clampGamma": 1, + "clampMax": 1, + "quantizeEnabled": false, + "quantizeLevels": 256, + "colorMap": null + }, + "timeline": { + "duration": 5, + "loop": true, + "tracks": [] + } +} diff --git a/tests/composition/run.mjs b/tests/composition/run.mjs new file mode 100644 index 00000000..10eed70d --- /dev/null +++ b/tests/composition/run.mjs @@ -0,0 +1,147 @@ +import assert from "node:assert/strict" +import { mkdir } from "node:fs/promises" +import { resolve, sep } from "node:path" +import { chromium } from "playwright" + +const root = resolve(import.meta.dir, "../..") +const directory = resolve(import.meta.dir) +const update = process.argv.includes("--update") +const artifacts = resolve(root, ".context/composition-test") +await mkdir(artifacts, { recursive: true }) +const bundle = await Bun.build({ + entrypoints: [resolve(directory, "browser.mjs")], + target: "browser", + define: { "process.env": "{}" }, +}) +if (!bundle.success) + throw new AggregateError(bundle.logs, "Composition harness failed to bundle") + +const server = Bun.serve({ + hostname: "127.0.0.1", + port: 0, + async fetch(request) { + const path = new URL(request.url).pathname + if (path === "/") + return new Response( + ``, + { headers: { "Content-Type": "text/html" } } + ) + if (path === "/browser.js") + return new Response(bundle.outputs[0], { + headers: { "Content-Type": "text/javascript" }, + }) + if (path === "/scenes/default/alpha-sample.svg") + return new Response( + Bun.file(resolve(directory, "fixtures/alpha-sample.svg")) + ) + const base = + path.startsWith("/fixtures/") || path.startsWith("/baselines/") + ? directory + : resolve(root, "public") + const file = resolve(base, `.${path}`) + if (!(file.startsWith(`${base}${sep}`) && (await Bun.file(file).exists()))) + return new Response("Not found", { status: 404 }) + return new Response(Bun.file(file)) + }, +}) + +let browser +try { + browser = await chromium.launch({ + headless: true, + args: [ + "--enable-unsafe-webgpu", + "--use-angle=swiftshader", + "--enable-unsafe-swiftshader", + ], + }) + const page = await browser.newPage() + page.setDefaultTimeout(120_000) + const errors = [] + page.on("pageerror", (error) => errors.push(error.message)) + page.on("console", (message) => { + if (message.type() === "error") errors.push(message.text()) + }) + await page.goto(server.url.href) + await page.waitForFunction(() => typeof window.checkProject === "function") + await page.evaluate(() => document.fonts.load('400 96px "Fixture Mono"')) + assert.ok( + await page.evaluate(async () => !!(await navigator.gpu?.requestAdapter())), + "WebGPU is required; no fallback or skipped tests" + ) + + console.log( + "Existing project:", + await page.evaluate(() => window.checkExistingProject()) + ) + const blends = await page.evaluate(() => window.checkLegacyBlendContract()) + const blendPath = resolve(directory, "baselines/legacy-blends.json") + for (const sample of blends) { + assert.ok( + sample.rgba.every(Number.isFinite), + `Non-finite pixel: ${JSON.stringify(sample)}` + ) + assert.equal(sample.rgba[3], 1, "Legacy compositor is opaque") + } + const half = blends.length / 2 + for (let i = 0; i < half; i++) { + assert.deepEqual( + blends[i].rgba, + blends[i + half].rgba, + "Editor/runtime blend mismatch" + ) + } + if (update) { + await Bun.write(blendPath, `${JSON.stringify(blends, null, 2)}\n`) + } else { + const expected = await Bun.file(blendPath).json() + assert.equal(blends.length, expected.length) + for (const [index, sample] of blends.entries()) { + const { rgba, ...identity } = sample + const { rgba: expectedRgba, ...expectedIdentity } = expected[index] + assert.deepEqual(identity, expectedIdentity) + for (let channel = 0; channel < 4; channel++) { + assert.ok( + Math.abs(rgba[channel] - expectedRgba[channel]) < 0.00001, + `Legacy blend changed: ${JSON.stringify(sample)}` + ) + } + } + } + console.log(`PASS ${blends.length} editor/runtime blend and mask samples`) + for (const name of [ + "legacy-text-mask", + "solid-text-background", + "transparent-text-screen", + "contained-image-halftone", + ]) { + const result = await page.evaluate( + ({ name, update }) => window.checkProject(name, update), + { name, update } + ) + const output = update + ? resolve(directory, `baselines/${name}.png`) + : resolve(artifacts, `${name}.png`) + await Bun.write(output, Buffer.from(result.png.split(",")[1], "base64")) + assert.equal( + result.baselineDiff?.changedPixels ?? 0, + 0, + `${name}: ${JSON.stringify(result.baselineDiff)}; actual image: ${output}` + ) + console.log( + `PASS ${name}: preview/export and reopen match; ${result.colors} colors` + ) + } + assert.deepEqual(errors, [], "Browser or GPU errors occurred") + console.log( + update + ? "Baseline capture complete. Review images before committing." + : "Composition baselines passed." + ) +} finally { + await browser?.close() + server.stop(true) +} diff --git a/tests/composition/tsconfig.json b/tests/composition/tsconfig.json new file mode 100644 index 00000000..f5e2740b --- /dev/null +++ b/tests/composition/tsconfig.json @@ -0,0 +1,10 @@ +{ + "extends": "../../tsconfig.json", + "compilerOptions": { + "baseUrl": ".", + "paths": { + "@/*": ["../../src/*"], + "@runtime/*": ["../../packages/shader-lab-react/src/*"] + } + } +} From 6915fac3454ec092dc858828e647b417a33312f8 Mon Sep 17 00:00:00 2001 From: git-chad Date: Wed, 16 Sep 2026 22:33:09 -0300 Subject: [PATCH 2/7] test: surface GPU and resource failures in composition checks --- tests/composition/browser.mjs | 4 +++- tests/composition/run.mjs | 15 +++++++++++++-- 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/tests/composition/browser.mjs b/tests/composition/browser.mjs index 95070168..aa4f6d2d 100644 --- a/tests/composition/browser.mjs +++ b/tests/composition/browser.mjs @@ -44,7 +44,9 @@ async function settle(renderer, frame) { const deadline = performance.now() + 30_000 while (renderer.hasPendingResources()) { if (performance.now() > deadline) - throw new Error("Timed out loading or compiling a fixture") + throw new Error( + `Timed out loading or compiling a fixture (compilation pending: ${renderer.hasPendingCompilations()})` + ) await new Promise((resolve) => setTimeout(resolve, 20)) } await renderer.prepareForExportFrame(frame.clock.timelineTime, true) diff --git a/tests/composition/run.mjs b/tests/composition/run.mjs index 10eed70d..251c5e1b 100644 --- a/tests/composition/run.mjs +++ b/tests/composition/run.mjs @@ -61,9 +61,20 @@ try { const page = await browser.newPage() page.setDefaultTimeout(120_000) const errors = [] - page.on("pageerror", (error) => errors.push(error.message)) + page.on("pageerror", (error) => { + errors.push(error.message) + console.error(error.message) + }) page.on("console", (message) => { - if (message.type() === "error") errors.push(message.text()) + if (message.type() === "error") { + errors.push(message.text()) + console.error(message.text()) + } + }) + page.on("requestfailed", (request) => { + const message = `${request.url()}: ${request.failure()?.errorText}` + errors.push(message) + console.error(message) }) await page.goto(server.url.href) await page.waitForFunction(() => typeof window.checkProject === "function") From 5aebd215e97f3bef58f36821078a286766ba4abe Mon Sep 17 00:00:00 2001 From: git-chad Date: Wed, 16 Sep 2026 22:53:22 -0300 Subject: [PATCH 3/7] test: select software WebGPU adapter explicitly --- tests/composition/run.mjs | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/tests/composition/run.mjs b/tests/composition/run.mjs index 251c5e1b..7aaabf08 100644 --- a/tests/composition/run.mjs +++ b/tests/composition/run.mjs @@ -54,6 +54,7 @@ try { headless: true, args: [ "--enable-unsafe-webgpu", + "--use-webgpu-adapter=swiftshader", "--use-angle=swiftshader", "--enable-unsafe-swiftshader", ], @@ -83,6 +84,20 @@ try { await page.evaluate(async () => !!(await navigator.gpu?.requestAdapter())), "WebGPU is required; no fallback or skipped tests" ) + console.log( + "GPU adapter:", + await page.evaluate(async () => { + const adapter = await navigator.gpu.requestAdapter() + return adapter + ? { + vendor: adapter.info.vendor, + architecture: adapter.info.architecture, + device: adapter.info.device, + description: adapter.info.description, + } + : null + }) + ) console.log( "Existing project:", From fa9be06479e4d2f33156f0c25e25f72af1c80b54 Mon Sep 17 00:00:00 2001 From: git-chad Date: Wed, 16 Sep 2026 22:54:38 -0300 Subject: [PATCH 4/7] test: cover actual editor hydration and project resaving --- tests/composition/README.md | 2 +- tests/composition/browser.mjs | 34 ++++++++++++++++++++++++++++++++++ 2 files changed, 35 insertions(+), 1 deletion(-) diff --git a/tests/composition/README.md b/tests/composition/README.md index 1966c5e5..0101cce7 100644 --- a/tests/composition/README.md +++ b/tests/composition/README.md @@ -31,7 +31,7 @@ Each fixture renders through the editor renderer, compares preview with PNG expo `legacy-blends.json` freezes 136 GPU samples across the editor and exported runtime: all 16 blend modes at three opacities, plus five mask sources, two mask modes, and inversion. The shaders are evaluated into float render targets; both implementations must match, and reference values have a tolerance of `0.00001`. These are compatibility expectations, not endorsements of the old alpha semantics. -`existing-default-project.json` is an unmodified copy of the repository's existing saved project. Parsing, serialization, reopening, and hydration must retain its nine layers, two bundled assets, blend modes, masks, opacity, and parameter values. Its video/audio and full effect stack are **not** rendered by this initial suite. +`existing-default-project.json` is an unmodified copy of the repository's existing saved project. Parsing, serialization, reopening, viewer hydration, and the actual editor hydration/save path must retain its nine layers, two bundled assets, blend modes, masks, opacity, and parameter values. The editor check also verifies scene settings, composition dimensions, selection, timeline, audio, and the scene-replacement signal. Its video/audio and full effect stack are **not** rendered by this initial suite. ## Confirmed alpha boundaries diff --git a/tests/composition/browser.mjs b/tests/composition/browser.mjs index aa4f6d2d..03d83c75 100644 --- a/tests/composition/browser.mjs +++ b/tests/composition/browser.mjs @@ -2,12 +2,18 @@ import { buildBlendNode as buildRuntimeBlendNode } from "@runtime/renderer/blend import { float, vec4 } from "three/tsl" import * as THREE from "three/webgpu" import { + applyLabProjectFile, + buildLabProjectFile, buildViewerProjectState, parseLabProjectFileValue, } from "@/lib/editor/project-file" import { buildBlendNode } from "@/renderer/blend-modes" import { buildRendererFrame } from "@/renderer/contracts" import { createWebGPURenderer } from "@/renderer/create-webgpu-renderer" +import { useAssetStore } from "@/store/asset-store" +import { useEditorStore } from "@/store/editor-store" +import { useLayerStore } from "@/store/layer-store" +import { useTimelineStore } from "@/store/timeline-store" import { BLEND_MODES } from "@/types/editor" function pixels(canvas) { @@ -221,6 +227,34 @@ window.checkExistingProject = async () => { if (JSON.stringify(parsed) !== JSON.stringify(reopened)) throw new Error("Saved project is not stable across parse/serialize/reopen") const state = buildViewerProjectState(reopened) + const revision = useEditorStore.getState().sceneRevision + const missing = applyLabProjectFile(reopened, []) + if (missing.missingAssetCount || missing.missingAudioSource) { + throw new Error("Editor hydration lost bundled media") + } + if (useEditorStore.getState().sceneRevision !== revision + 1) { + throw new Error("Editor did not signal scene replacement") + } + const stored = buildLabProjectFile() + for (const key of [ + "layers", + "sceneConfig", + "composition", + "selectedLayerId", + "timeline", + "audio", + ]) { + if (JSON.stringify(stored[key]) !== JSON.stringify(reopened[key])) { + throw new Error(`Editor hydration/save changed ${key}`) + } + } + if ( + useAssetStore.getState().assets.length !== original.assets.length || + useLayerStore.getState().layers.length !== original.layers.length || + useTimelineStore.getState().currentTime !== 0 + ) { + throw new Error("Editor stores were not restored") + } if ( state.layers.length !== original.layers.length || state.assets.length !== original.assets.length From e3a9f7dfa24844482b4820d63d3a5bd5f62af7e7 Mon Sep 17 00:00:00 2001 From: git-chad Date: Wed, 16 Sep 2026 22:55:47 -0300 Subject: [PATCH 5/7] ci: run composition GPU regressions on macOS --- .github/workflows/ci.yml | 27 +++++++++++++++++++++------ tests/composition/README.md | 4 +++- 2 files changed, 24 insertions(+), 7 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c3df8c56..8c894539 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -47,12 +47,27 @@ jobs: - name: Type check app run: bun run typecheck:tsc - - name: Install composition test browser - run: bunx playwright install --with-deps chromium - - - name: Check composition baselines - run: bun run test:composition - - name: Ensure changeset exists for PR changes if: github.event_name == 'pull_request' run: bunx changeset status --since=origin/${{ github.base_ref }} + + composition: + # Linux Chromium/SwiftShader currently drops its GPU instance during these + # texture-backed shader compilations. Keep the full GPU checks on macOS. + runs-on: macos-14 + timeout-minutes: 10 + steps: + - uses: actions/checkout@v4 + - uses: oven-sh/setup-bun@v2 + with: + bun-version: latest + - run: bun install --frozen-lockfile + - run: bunx playwright install chromium + - run: bun run test:composition + - name: Upload rendered compositions + if: always() + uses: actions/upload-artifact@v4 + with: + name: composition-actuals + path: .context/composition-test/ + if-no-files-found: ignore diff --git a/tests/composition/README.md b/tests/composition/README.md index 0101cce7..c661eb9d 100644 --- a/tests/composition/README.md +++ b/tests/composition/README.md @@ -12,7 +12,9 @@ bunx playwright install chromium bun run test:composition ``` -Linux requires `bunx playwright install --with-deps chromium`. The runner serves a bundled harness on an ephemeral loopback port and launches the locked Playwright Chromium with WebGPU over SwiftShader. No app server, account, or external services are required. Missing WebGPU, browser errors, shader compilation errors, missing baselines, and mismatches fail the command; tests do not silently skip or fall back to WebGL. +The supported baseline runner is macOS, including the dedicated `macos-14` CI job. Linux Chromium/SwiftShader currently drops its GPU instance during texture-backed shader compilation (`Instance dropped in popErrorScope`); Linux support is not verified. The existing build, lint, and type checks remain on Linux. + +The runner serves a bundled harness on an ephemeral loopback port and launches the locked Playwright Chromium with an explicitly selected SwiftShader WebGPU adapter. No app server, account, or external services are required. Missing WebGPU, browser errors, shader compilation errors, missing baselines, and mismatches fail the command; tests do not silently skip or fall back to WebGL. Actual PNGs are saved in `.context/composition-test/`. Run `bun run test:composition --update` only when deliberately capturing a reviewed baseline. Never refresh existing legacy expectations just to make an alpha change pass. From bdab0b7bf6ad1ae03369bf3ee678d21ca314740e Mon Sep 17 00:00:00 2001 From: git-chad Date: Wed, 16 Sep 2026 23:05:14 -0300 Subject: [PATCH 6/7] test: verify hydration replaces stale state and prunes tracks --- tests/composition/README.md | 2 + tests/composition/browser.mjs | 93 +++++++++++++++++++++++++++++++++++ 2 files changed, 95 insertions(+) diff --git a/tests/composition/README.md b/tests/composition/README.md index c661eb9d..c382b789 100644 --- a/tests/composition/README.md +++ b/tests/composition/README.md @@ -35,6 +35,8 @@ Each fixture renders through the editor renderer, compares preview with PNG expo `existing-default-project.json` is an unmodified copy of the repository's existing saved project. Parsing, serialization, reopening, viewer hydration, and the actual editor hydration/save path must retain its nine layers, two bundled assets, blend modes, masks, opacity, and parameter values. The editor check also verifies scene settings, composition dimensions, selection, timeline, audio, and the scene-replacement signal. Its video/audio and full effect stack are **not** rendered by this initial suite. +Editor hydration starts from deliberately different store state. A separate in-memory variant adds an opacity track with keyframes, tracks targeting a missing layer and parameter, and an invalid layer selection. It verifies that hydration preserves valid animation, prunes invalid tracks, clears previous timeline selection/playhead state, and saves only the surviving track. The frozen project fixture remains unchanged. + ## Confirmed alpha boundaries These findings come from source inspection and the limited GPU checks above, not a completed end-to-end alpha audit. diff --git a/tests/composition/browser.mjs b/tests/composition/browser.mjs index 03d83c75..aed845f3 100644 --- a/tests/composition/browser.mjs +++ b/tests/composition/browser.mjs @@ -25,6 +25,17 @@ function pixels(canvas) { return context.getImageData(0, 0, copy.width, copy.height) } +function canonicalJson(value) { + return JSON.stringify(value, (_key, entry) => { + if (entry && typeof entry === "object" && !Array.isArray(entry)) { + return Object.fromEntries( + Object.entries(entry).sort(([a], [b]) => a.localeCompare(b)) + ) + } + return entry + }) +} + function compare(actual, expected, tolerance = 0) { if (actual.width !== expected.width || actual.height !== expected.height) { throw new Error("Image dimensions changed") @@ -227,6 +238,13 @@ window.checkExistingProject = async () => { if (JSON.stringify(parsed) !== JSON.stringify(reopened)) throw new Error("Saved project is not stable across parse/serialize/reopen") const state = buildViewerProjectState(reopened) + // Start from a different editor session so no-op restoration cannot pass + // merely because the stores already contain their default values. + useLayerStore.getState().replaceState([], null, null) + useAssetStore.getState().replaceAssets([]) + useEditorStore.getState().updateSceneConfig({ exposure: 2 }) + useEditorStore.getState().setOutputSize(320, 240) + useTimelineStore.setState({ currentTime: 3, isPlaying: false, loop: false }) const revision = useEditorStore.getState().sceneRevision const missing = applyLabProjectFile(reopened, []) if (missing.missingAssetCount || missing.missingAudioSource) { @@ -274,5 +292,80 @@ window.checkExistingProject = async () => { throw new Error(`Existing ${layer.type} layer changed ${key}`) } } + const validTrack = { + id: "hydration-opacity", + layerId: reopened.layers[0].id, + binding: { + kind: "layer", + property: "opacity", + label: "Opacity", + valueType: "number", + }, + enabled: true, + keyframes: [ + { + id: "opacity-start", + time: 0, + value: 0.25, + easing: { type: "bezier", controlPoints: [0, 0, 1, 1] }, + }, + { + id: "opacity-end", + time: 1, + value: 1, + easing: { type: "bezier", controlPoints: [0, 0, 1, 1] }, + }, + ], + } + const tracks = [ + validTrack, + { ...validTrack, id: "missing-layer", layerId: "deleted-layer" }, + { + ...validTrack, + id: "missing-parameter", + binding: { + kind: "param", + key: "removed-parameter", + label: "Removed", + valueType: "number", + }, + }, + ] + const withTracks = structuredClone(reopened) + withTracks.timeline.tracks = tracks + withTracks.selectedLayerId = "deleted-layer" + useTimelineStore.setState({ + tracks: [{ ...validTrack, id: "previous-session-track" }], + currentTime: 3, + isPlaying: false, + selectedTrackId: "previous-session-track", + selectedKeyframeId: "previous-session-keyframe", + selectedKeyframeIds: ["previous-session-keyframe"], + }) + applyLabProjectFile(withTracks, useAssetStore.getState().assets) + const timeline = useTimelineStore.getState() + if (canonicalJson(timeline.tracks) !== canonicalJson([validTrack])) { + throw new Error( + `Hydration must retain valid tracks and prune missing layers/parameters: ${JSON.stringify(timeline.tracks)}` + ) + } + if ( + timeline.currentTime !== 0 || + !timeline.isPlaying || + timeline.selectedTrackId !== null || + timeline.selectedKeyframeId !== null || + timeline.selectedKeyframeIds.length !== 0 || + useLayerStore.getState().selectedLayerId !== null + ) { + throw new Error( + "Hydration retained stale timeline state or an invalid layer selection" + ) + } + if ( + canonicalJson(buildLabProjectFile().timeline.tracks) !== + canonicalJson([validTrack]) + ) { + throw new Error("Saving restored pruned timeline tracks") + } return { layers: state.layers.length, assets: state.assets.length } } From c69bafdefbf7dadce5ffd13267030c381761fe77 Mon Sep 17 00:00:00 2001 From: git-chad Date: Wed, 16 Sep 2026 23:12:45 -0300 Subject: [PATCH 7/7] fix: reveal lower content around newly contained media --- .changeset/transparent-media-bounds.md | 5 + .github/workflows/ci.yml | 1 + V3-ROADMAP.md | 6 +- packages/shader-lab-react/README.md | 5 + .../src/renderer/media-pass.ts | 9 +- src/lib/editor/config/layer-registry.ts | 10 + src/lib/editor/project-file.ts | 9 + src/renderer/media-pass.ts | 9 +- tests/composition/README.md | 14 +- tests/composition/browser.mjs | 13 +- tests/composition/media-bounds.mjs | 222 ++++++++++++++++++ tests/composition/run.mjs | 12 + 12 files changed, 305 insertions(+), 10 deletions(-) create mode 100644 .changeset/transparent-media-bounds.md create mode 100644 tests/composition/media-bounds.mjs diff --git a/.changeset/transparent-media-bounds.md b/.changeset/transparent-media-bounds.md new file mode 100644 index 00000000..931e9dab --- /dev/null +++ b/.changeset/transparent-media-bounds.md @@ -0,0 +1,5 @@ +--- +"@basementstudio/shader-lab": patch +--- + +Support transparent borders for contained image and video layers with `params.transparentBounds: true`. Existing runtime configs without the setting retain black borders. diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 8c894539..056c78ba 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -5,6 +5,7 @@ on: branches: - main - git-chad/shader-lab-v3-plan + - git-chad/v3-* push: branches: - main diff --git a/V3-ROADMAP.md b/V3-ROADMAP.md index 537b02a1..3fe5a670 100644 --- a/V3-ROADMAP.md +++ b/V3-ROADMAP.md @@ -6,13 +6,13 @@ El orden es una **propuesta de ejecución**; las prioridades de producto son rev ## Flujo de integración y entrega -Todo el trabajo de V3 se entrega mediante PRs pequeños dirigidos a una rama de integración de V3. Un PR principal reúne esa rama y tiene como destino `main`. +Todo el trabajo de V3 se entrega mediante PRs pequeños apilados. Cada nuevo PR parte de la rama del PR anterior y la usa como base. El primer PR de la pila apunta a la rama de integración de V3; un PR principal reúne esa rama y tiene como destino `main`. -**PRs pequeños → rama de integración de V3 → PR principal → `main`.** +**PR nuevo → PR anterior → rama de integración de V3 → PR principal → `main`.** Los PRs pequeños pueden integrarse progresivamente en la rama de V3. Ningún cambio de V3 se integra en `main` hasta completar el alcance obligatorio del plan y su validación global de la fase 7. La fase 8 sigue siendo opcional y no bloquea esa entrega. -La rama de integración es `git-chad/shader-lab-v3-plan`. Todos los PRs pequeños de V3 deben usarla como base; únicamente el PR principal apunta a `main` y permanece en borrador hasta completar la validación obligatoria. +La rama de integración es `git-chad/shader-lab-v3-plan`. La pila comienza con [#151](https://github.com/basementstudio/shader-lab/pull/151), en `git-chad/v3-composition-alpha`. El siguiente PR usa esa rama como base. Al integrar PRs, actualizar las bases de los descendientes para conservar la pila; únicamente el PR principal apunta a `main` y permanece en borrador hasta completar la validación obligatoria. PR principal: [#150 — V3: designer-focused composition and experimental graphics](https://github.com/basementstudio/shader-lab/pull/150). diff --git a/packages/shader-lab-react/README.md b/packages/shader-lab-react/README.md index 3136c719..93d786e2 100644 --- a/packages/shader-lab-react/README.md +++ b/packages/shader-lab-react/README.md @@ -653,6 +653,11 @@ export const sketch = Fn(() => { ## Included Runtime Support +Image and video layers in Contain mode support `params.transparentBounds: true` +to reveal the content beneath their empty borders. Omit the setting or use +`false` to retain black borders. This option does not affect Cover mode or make +the composition's canvas background transparent. + - Gradient - Text - Custom shader (source and effect modes) diff --git a/packages/shader-lab-react/src/renderer/media-pass.ts b/packages/shader-lab-react/src/renderer/media-pass.ts index 6296bf00..8cca8590 100644 --- a/packages/shader-lab-react/src/renderer/media-pass.ts +++ b/packages/shader-lab-react/src/renderer/media-pass.ts @@ -22,6 +22,7 @@ type Node = TSLNode export class MediaPass extends PassNode { private readonly canvasAspectUniform: Node private readonly fitModeUniform: Node + private readonly boundsAlphaUniform: Node private readonly offsetXUniform: Node private readonly offsetYUniform: Node private readonly scaleUniform: Node @@ -40,6 +41,7 @@ export class MediaPass extends PassNode { this.placeholder = new THREE.Texture() this.canvasAspectUniform = uniform(1) this.fitModeUniform = uniform(0) + this.boundsAlphaUniform = uniform(1) this.offsetXUniform = uniform(0) this.offsetYUniform = uniform(0) this.scaleUniform = uniform(1) @@ -101,6 +103,7 @@ export class MediaPass extends PassNode { override updateParams(params: LayerParameterValues): void { this.fitModeUniform.value = params.fitMode === "contain" ? 1 : 0 + this.boundsAlphaUniform.value = params.transparentBounds === true ? 0 : 1 this.scaleUniform.value = typeof params.scale === "number" ? 1 / Math.max(params.scale, 0.01) : 1 @@ -180,7 +183,11 @@ export class MediaPass extends PassNode { .and(sampledUv.x.lessThanEqual(1)) .and(sampledUv.y.greaterThanEqual(0)) .and(sampledUv.y.lessThanEqual(1)) - const contained = select(inBounds, this.mediaTextureNode, vec4(0, 0, 0, 1)) + const contained = select( + inBounds, + this.mediaTextureNode, + vec4(0, 0, 0, this.boundsAlphaUniform) + ) return mix(this.mediaTextureNode, contained, useContain) } diff --git a/src/lib/editor/config/layer-registry.ts b/src/lib/editor/config/layer-registry.ts index 908a9490..a9227a2f 100644 --- a/src/lib/editor/config/layer-registry.ts +++ b/src/lib/editor/config/layer-registry.ts @@ -26,6 +26,16 @@ const mediaPlacementParams = [ ], type: "select", }, + { + defaultValue: true, + key: "transparentBounds", + label: "Transparent Borders", + type: "boolean", + visibleWhen: { + equals: "contain", + key: "fitMode", + }, + }, { defaultValue: 1, key: "scale", diff --git a/src/lib/editor/project-file.ts b/src/lib/editor/project-file.ts index 82937213..60a0350d 100644 --- a/src/lib/editor/project-file.ts +++ b/src/lib/editor/project-file.ts @@ -603,6 +603,15 @@ export function migrateLayerParams( ): LayerParameterValues { const params: LayerParameterValues = { ...layer.params } + // Files without this setting predate transparent contain bounds. Preserve + // their black borders before filling missing parameters with new defaults. + if ( + (layer.type === "image" || layer.type === "video") && + params.transparentBounds === undefined + ) { + params.transparentBounds = false + } + if (layer.type === "ascii" && typeof params.fontWeight === "string") { params.fontWeight = LEGACY_ASCII_FONT_WEIGHTS[params.fontWeight] ?? 400 } diff --git a/src/renderer/media-pass.ts b/src/renderer/media-pass.ts index 73e3255c..e250ee8e 100644 --- a/src/renderer/media-pass.ts +++ b/src/renderer/media-pass.ts @@ -28,6 +28,7 @@ type Node = TSLNode export class MediaPass extends PassNode { private readonly canvasAspectUniform: Node private readonly fitModeUniform: Node + private readonly boundsAlphaUniform: Node private readonly offsetXUniform: Node private readonly offsetYUniform: Node private readonly scaleUniform: Node @@ -47,6 +48,7 @@ export class MediaPass extends PassNode { this.placeholder = new THREE.Texture() this.canvasAspectUniform = uniform(1) this.fitModeUniform = uniform(0) + this.boundsAlphaUniform = uniform(1) this.offsetXUniform = uniform(0) this.offsetYUniform = uniform(0) this.scaleUniform = uniform(1) @@ -114,6 +116,7 @@ export class MediaPass extends PassNode { override updateParams(params: LayerParameterValues): void { this.fitModeUniform.value = params.fitMode === "contain" ? 1 : 0 + this.boundsAlphaUniform.value = params.transparentBounds === true ? 0 : 1 this.scaleUniform.value = typeof params.scale === "number" ? 1 / Math.max(params.scale, 0.01) : 1 @@ -212,7 +215,11 @@ export class MediaPass extends PassNode { .and(sampledUv.x.lessThanEqual(1)) .and(sampledUv.y.greaterThanEqual(0)) .and(sampledUv.y.lessThanEqual(1)) - const contained = select(inBounds, this.mediaTextureNode, vec4(0, 0, 0, 1)) + const contained = select( + inBounds, + this.mediaTextureNode, + vec4(0, 0, 0, this.boundsAlphaUniform) + ) return mix(this.mediaTextureNode, contained, useContain) } diff --git a/tests/composition/README.md b/tests/composition/README.md index c382b789..ed695725 100644 --- a/tests/composition/README.md +++ b/tests/composition/README.md @@ -1,8 +1,8 @@ # V3 composition baselines -First slice of roadmap steps 1.1–1.2. This PR establishes regression checks before changing alpha behavior; it does not implement transparent composition, groups, or new masks. +Regression coverage for roadmap steps 1.1–1.2. The first PR establishes legacy baselines; its stacked successor adds transparent media bounds. Full transparent composition, groups, and new masks remain outstanding. -Integration branch: `git-chad/shader-lab-v3-plan`. Parent PR: [#150](https://github.com/basementstudio/shader-lab/pull/150). Child PRs target that branch, never `main`. +Integration branch: `git-chad/shader-lab-v3-plan`. Parent PR: [#150](https://github.com/basementstudio/shader-lab/pull/150). The first child, [#151](https://github.com/basementstudio/shader-lab/pull/151), targets integration. Each subsequent stacked PR targets the preceding feature branch, never `main`. ## Run @@ -37,6 +37,14 @@ Each fixture renders through the editor renderer, compares preview with PNG expo Editor hydration starts from deliberately different store state. A separate in-memory variant adds an opacity track with keyframes, tracks targeting a missing layer and parameter, and an invalid layer selection. It verifies that hydration preserves valid animation, prunes invalid tracks, clears previous timeline selection/playhead state, and saves only the surviving track. The frozen project fixture remains unchanged. +## Transparent media bounds + +New image and video layers expose **Transparent Borders** when Fit is **Contain**. It defaults on; disabling it restores black borders. Saved layers without `transparentBounds` are migrated to `false` before new defaults are applied. Runtime configs that omit it also keep black borders. Cover mode is unchanged, including its existing edge sampling. No saved fixture or visual baseline is refreshed for this change. + +`media-bounds.mjs` renders the editor and runtime MediaPass with both the SVG and bundled video over a colored input texture. It checks legacy/missing, explicit solid, transparent, partial-opacity, scaled/offset, and Cover cases. It also checks new-layer defaults, migration, save/reopen, shader-config export, and preview/PNG export against explicit pixel expectations. Rendered transparent/solid examples are saved alongside the baseline artifacts. + +This change reveals lower content at empty media bounds; it does not make the scene canvas or exported PNG background transparent. The existing scene background, mask semantics, and global effect scope remain unchanged. + ## Confirmed alpha boundaries These findings come from source inspection and the limited GPU checks above, not a completed end-to-end alpha audit. @@ -45,7 +53,7 @@ These findings come from source inspection and the limited GPU checks above, not | --- | --- | --- | | `blend-modes.ts` in editor and runtime | Filter mixes RGB using source alpha but returns alpha 1; masks multiply RGB or threshold to black and return alpha 1 | Distinguish source-over composition from effect interpolation; introduce true coverage masks with a compatibility path for saved masks | | `pass-node.ts` in both renderers | Source and effect passes share composition; default opaque node materials can force alpha 1 independently of shader output | Define straight/premultiplied alpha conventions and material settings together with separate source/effect semantics | -| `media-pass.ts` | Contain mode fills out-of-bounds samples with opaque black | Preserve previous saved appearances while allowing transparent bounds in new composition behavior | +| `media-pass.ts` | Contain mode now supports transparent out-of-bounds samples, defaulting on for new layers; absent settings retain black | Broader alpha composition remains separate from this source-boundary fix | | `pipeline-manager.ts` | A single global ping-pong chain begins over an opaque base and finishes through an opaque blit | Introduce isolated group targets and their own effect scope; keep the scene background a deliberate choice | | `scene-post-process.ts` | Scene color adjustments return alpha 1 | Preserve coverage through color grading | | Canvas renderer creation | Editor and runtime use `alpha: false`; editor clears to alpha 1 | Carry alpha through preview/export where supported, including texture output | diff --git a/tests/composition/browser.mjs b/tests/composition/browser.mjs index aed845f3..3ec42f04 100644 --- a/tests/composition/browser.mjs +++ b/tests/composition/browser.mjs @@ -15,6 +15,7 @@ import { useEditorStore } from "@/store/editor-store" import { useLayerStore } from "@/store/layer-store" import { useTimelineStore } from "@/store/timeline-store" import { BLEND_MODES } from "@/types/editor" +import { checkMediaBounds } from "./media-bounds.mjs" function pixels(canvas) { const copy = document.createElement("canvas") @@ -238,6 +239,12 @@ window.checkExistingProject = async () => { if (JSON.stringify(parsed) !== JSON.stringify(reopened)) throw new Error("Saved project is not stable across parse/serialize/reopen") const state = buildViewerProjectState(reopened) + const expectedRestored = structuredClone(reopened) + for (const layer of expectedRestored.layers) { + if (layer.type === "image" || layer.type === "video") { + layer.params.transparentBounds = false + } + } // Start from a different editor session so no-op restoration cannot pass // merely because the stores already contain their default values. useLayerStore.getState().replaceState([], null, null) @@ -262,7 +269,7 @@ window.checkExistingProject = async () => { "timeline", "audio", ]) { - if (JSON.stringify(stored[key]) !== JSON.stringify(reopened[key])) { + if (JSON.stringify(stored[key]) !== JSON.stringify(expectedRestored[key])) { throw new Error(`Editor hydration/save changed ${key}`) } } @@ -280,7 +287,7 @@ window.checkExistingProject = async () => { throw new Error("Existing project lost layers or bundled assets") } for (const [index, layer] of state.layers.entries()) { - const saved = original.layers[index] + const saved = expectedRestored.layers[index] for (const key of [ "blendMode", "compositeMode", @@ -369,3 +376,5 @@ window.checkExistingProject = async () => { } return { layers: state.layers.length, assets: state.assets.length } } + +window.checkMediaBounds = () => checkMediaBounds(renderProject) diff --git a/tests/composition/media-bounds.mjs b/tests/composition/media-bounds.mjs new file mode 100644 index 00000000..21bbab2b --- /dev/null +++ b/tests/composition/media-bounds.mjs @@ -0,0 +1,222 @@ +import { MediaPass as RuntimeMediaPass } from "@runtime/renderer/media-pass" +import * as THREE from "three/webgpu" +import { createLayer } from "@/lib/editor/layers" +import { + applyLabProjectFile, + buildLabProjectFile, + buildViewerProjectState, + migrateLayerParams, + parseLabProjectFileValue, +} from "@/lib/editor/project-file" +import { buildShaderExportConfig } from "@/lib/editor/shader-export" +import { MediaPass } from "@/renderer/media-pass" + +function assertPixel(actual, expected, label) { + if ( + actual.length !== expected.length || + actual.some( + (value, index) => + !Number.isFinite(value) || Math.abs(value - expected[index]) > 0.0001 + ) + ) { + throw new Error(`${label}: expected ${expected}, received ${actual}`) + } +} + +async function checkMediaPasses() { + const renderer = new THREE.WebGPURenderer({ antialias: false }) + await renderer.init() + renderer.toneMapping = THREE.NoToneMapping + const backdrop = [0.2, 0.4, 0.8, 1] + const input = new THREE.DataTexture( + new Float32Array(backdrop), + 1, + 1, + THREE.RGBAFormat, + THREE.FloatType + ) + input.needsUpdate = true + const target = new THREE.RenderTarget(64, 48, { + type: THREE.FloatType, + depthBuffer: false, + }) + let count = 0 + try { + for (const [name, Pass] of [ + ["editor", MediaPass], + ["runtime", RuntimeMediaPass], + ]) { + for (const kind of ["image", "video"]) { + const pass = new Pass(`${name}-${kind}`) + try { + pass.resize(64, 48) + const url = + kind === "image" + ? "/scenes/default/alpha-sample.svg" + : "/scenes/default/aura.mp4" + if (name === "editor") { + await pass.setMedia({ + url, + kind, + isSvg: kind === "image", + width: kind === "image" ? 160 : 578, + height: kind === "image" ? 160 : 720, + }) + pass.setPreviewFrozen(true) + await pass.prepareForExportFrame(0) + } else { + await pass.setMedia(url, kind) + } + const render = async (params, opacity = 1) => { + pass.updateParams(params) + pass.updateOpacity(opacity) + pass.render(renderer, input, target, 0, 0) + return Array.from( + await renderer.readRenderTargetPixelsAsync(target, 0, 24, 64, 1) + ) + } + for (const placement of [ + { scale: 1, offset: [0, 0] }, + { scale: 0.5, offset: [0.2, 0] }, + ]) { + const params = { ...placement, fitMode: "contain" } + const legacy = await render(params) + const solid = await render({ ...params, transparentBounds: false }) + const transparent = await render({ + ...params, + transparentBounds: true, + }) + const faded = await render( + { ...params, transparentBounds: true }, + 0.35 + ) + assertPixel( + legacy.slice(0, 4), + [0, 0, 0, 1], + `${name}/${kind}: absent flag keeps black borders` + ) + assertPixel( + solid.slice(0, 4), + [0, 0, 0, 1], + `${name}/${kind}: explicit solid borders` + ) + assertPixel( + transparent.slice(0, 4), + backdrop, + `${name}/${kind}: empty border reveals lower layer` + ) + assertPixel( + faded.slice(0, 4), + backdrop, + `${name}/${kind}: empty border stays clear at partial opacity` + ) + if (kind === "image") { + // The square SVG center remains opaque; its hue/coverage must + // not change when only the out-of-bounds behavior changes. + const center = placement.scale === 1 ? 32 : 37 + assertPixel( + transparent.slice(center * 4, center * 4 + 4), + solid.slice(center * 4, center * 4 + 4), + `${name}: in-bounds content is unchanged` + ) + if (transparent[center * 4] < 0.5) + throw new Error(`${name}: opaque center lost its color`) + } + count += 4 + } + if (kind === "image") { + const params = { fitMode: "cover", scale: 0.5, offset: [0.2, 0] } + assertPixel( + await render({ ...params, transparentBounds: true }), + await render({ ...params, transparentBounds: false }), + `${name}: cover mode is unchanged` + ) + count++ + } + } finally { + pass.dispose() + } + } + } + return count + } finally { + input.dispose() + target.dispose() + renderer.dispose() + } +} + +export async function checkMediaBounds(renderProject) { + for (const type of ["image", "video"]) { + const layer = createLayer(type) + if (layer.params.transparentBounds !== true) + throw new Error(`New ${type} layer has opaque borders`) + for (const value of [undefined, false, true]) { + const params = { ...layer.params } + if (value === undefined) delete params.transparentBounds + else params.transparentBounds = value + for (const version of [1, 5, 6]) { + if ( + migrateLayerParams({ ...layer, params }, version) + .transparentBounds !== (value ?? false) + ) { + throw new Error( + `${type} migration changed the explicit or legacy border setting` + ) + } + } + } + } + + const project = parseLabProjectFileValue( + await (await fetch("/fixtures/contained-image-halftone.json")).json() + ) + project.layers = project.layers.filter((layer) => layer.type === "image") + project.selectedLayerId = project.layers[0].id + project.layers[0].params.transparentBounds = true + project.sceneConfig.backgroundColor = "#2468cc" + applyLabProjectFile(project, []) + const saved = buildLabProjectFile() + const state = buildViewerProjectState( + parseLabProjectFileValue(JSON.parse(JSON.stringify(saved))) + ) + if (state.layers[0].params.transparentBounds !== true) + throw new Error("Save/reopen lost transparent borders") + const config = buildShaderExportConfig({ + ...state, + composition: project.composition, + }) + if (config.layers[0].params.transparentBounds !== true) + throw new Error("Shader export lost transparent borders") + + const transparent = await renderProject(saved) + project.layers[0].params.transparentBounds = false + const solid = await renderProject(project) + const pixel = (result, x, y) => + Array.from( + result.image.data.slice( + (y * result.image.width + x) * 4, + (y * result.image.width + x) * 4 + 4 + ) + ) + assertPixel( + pixel(transparent, 4, 96), + [36, 104, 204, 255], + "PNG export reveals scene background" + ) + assertPixel( + pixel(solid, 4, 96), + [0, 0, 0, 255], + "PNG export preserves solid borders" + ) + assertPixel( + pixel(transparent, 128, 96), + pixel(solid, 128, 96), + "PNG export preserves opaque image content" + ) + return { + samples: await checkMediaPasses(), + transparentPng: transparent.png, + solidPng: solid.png, + } +} diff --git a/tests/composition/run.mjs b/tests/composition/run.mjs index 7aaabf08..b1660542 100644 --- a/tests/composition/run.mjs +++ b/tests/composition/run.mjs @@ -161,6 +161,18 @@ try { `PASS ${name}: preview/export and reopen match; ${result.colors} colors` ) } + const mediaBounds = await page.evaluate(() => window.checkMediaBounds()) + await Bun.write( + resolve(artifacts, "transparent-media-bounds.png"), + Buffer.from(mediaBounds.transparentPng.split(",")[1], "base64") + ) + await Bun.write( + resolve(artifacts, "solid-media-bounds.png"), + Buffer.from(mediaBounds.solidPng.split(",")[1], "base64") + ) + console.log( + `PASS media bounds: ${mediaBounds.samples} editor/runtime image/video samples, migration, save/reopen, shader export, and PNG export` + ) assert.deepEqual(errors, [], "Browser or GPU errors occurred") console.log( update