diff --git a/lib/.gitattributes b/lib/.gitattributes index 8ec8526..c7f813d 100644 --- a/lib/.gitattributes +++ b/lib/.gitattributes @@ -38,3 +38,13 @@ tests/__screenshots__/particles/particles-chromium.png filter=lfs diff=lfs merge tests/__screenshots__/particles/particles-firefox.png filter=lfs diff=lfs merge=lfs -text tests/__screenshots__/particles/particles-iphone.png filter=lfs diff=lfs merge=lfs -text tests/__screenshots__/pointer/pointer-chromium.png filter=lfs diff=lfs merge=lfs -text +tests/__screenshots__/play-pause-controls---global/play-pause-controls---global-android.png filter=lfs diff=lfs merge=lfs -text +tests/__screenshots__/play-pause-controls---global/play-pause-controls---global-firefox.png filter=lfs diff=lfs merge=lfs -text +tests/__screenshots__/play-pause-controls---global/play-pause-controls---global-iphone.png filter=lfs diff=lfs merge=lfs -text +tests/__screenshots__/play-pause-controls---global/play-pause-controls---global-safari.png filter=lfs diff=lfs merge=lfs -text +tests/__screenshots__/play-pause-controls---local/play-pause-controls---local-chromium.png filter=lfs diff=lfs merge=lfs -text +tests/__screenshots__/play-pause-controls---local/play-pause-controls---local-firefox.png filter=lfs diff=lfs merge=lfs -text +tests/__screenshots__/play-pause-controls---local/play-pause-controls---local-iphone.png filter=lfs diff=lfs merge=lfs -text +tests/__screenshots__/play-pause-controls---local/play-pause-controls---local-safari.png filter=lfs diff=lfs merge=lfs -text +tests/__screenshots__/play-pause-controls---global/play-pause-controls---global-chromium.png filter=lfs diff=lfs merge=lfs -text +tests/__screenshots__/play-pause-controls---local/play-pause-controls---local-android.png filter=lfs diff=lfs merge=lfs -text diff --git a/lib/package.json b/lib/package.json index cf44fc6..13c6832 100644 --- a/lib/package.json +++ b/lib/package.json @@ -29,9 +29,10 @@ "prepack": "pnpm build", "release": "changelogen --release --clean", "test": "playwright test", + "test:local": "docker build -t usegl . && docker run --rm -v $(pwd)/test-results:/app/test-results usegl /bin/sh -c 'xvfb-run pnpm run test'", "test:ui": "playwright test --ui", - "typecheck": "tsc --noEmit && astro check", - "updateScreenshots": "docker build -t usegl . && docker run --rm -v $(pwd)/test-results:/app/test-results -v $(pwd)/tests/__screenshots__:/app/tests/__screenshots__ usegl" + "test:update": "docker build -t usegl . && docker run --rm -v $(pwd)/test-results:/app/test-results -v $(pwd)/tests/__screenshots__:/app/tests/__screenshots__ usegl", + "typecheck": "tsc --noEmit && astro check" }, "devDependencies": { "@astrojs/check": "0.9.4", diff --git a/lib/playground/src/components/GlobalPlayPause.astro b/lib/playground/src/components/GlobalPlayPause.astro new file mode 100644 index 0000000..b449060 --- /dev/null +++ b/lib/playground/src/components/GlobalPlayPause.astro @@ -0,0 +1,25 @@ +--- +import PlayPause from "./PlayPause.astro"; +--- + + + + + + diff --git a/lib/playground/src/components/PlayPause.astro b/lib/playground/src/components/PlayPause.astro new file mode 100644 index 0000000..3cbf8ea --- /dev/null +++ b/lib/playground/src/components/PlayPause.astro @@ -0,0 +1,73 @@ + + + diff --git a/lib/playground/src/components/RenderCount.astro b/lib/playground/src/components/RenderCount.astro index af66013..a6519fe 100644 --- a/lib/playground/src/components/RenderCount.astro +++ b/lib/playground/src/components/RenderCount.astro @@ -4,7 +4,7 @@ #renders { color: white; position: absolute; - bottom: 1.5em; - right: 1.5em; + bottom: 1.5rem; + right: 1.5rem; } diff --git a/lib/playground/src/layouts/Layout.astro b/lib/playground/src/layouts/Layout.astro index 40edce9..a6cf2f7 100644 --- a/lib/playground/src/layouts/Layout.astro +++ b/lib/playground/src/layouts/Layout.astro @@ -37,6 +37,7 @@ import RenderCount from "../components/RenderCount.astro"; grid-template-columns: auto 1fr; font-family: Verdana, Geneva, Tahoma, sans-serif; background: black; + color: white; color-scheme: dark; } diff --git a/lib/playground/src/pages/blob.astro b/lib/playground/src/pages/blob.astro index cf21047..474d712 100644 --- a/lib/playground/src/pages/blob.astro +++ b/lib/playground/src/pages/blob.astro @@ -1,9 +1,10 @@ --- +import GlobalPlayPause from "../components/GlobalPlayPause.astro"; import Layout from "../layouts/Layout.astro"; --- + diff --git a/lib/playground/src/pages/gradient.astro b/lib/playground/src/pages/gradient.astro index 95ccfd1..45ec521 100644 --- a/lib/playground/src/pages/gradient.astro +++ b/lib/playground/src/pages/gradient.astro @@ -1,36 +1,57 @@ --- +import GlobalPlayPause from "../components/GlobalPlayPause.astro"; import Layout from "../layouts/Layout.astro"; --- + diff --git a/lib/playground/src/pages/particles.astro b/lib/playground/src/pages/particles.astro index 7f1eaa8..042afc5 100644 --- a/lib/playground/src/pages/particles.astro +++ b/lib/playground/src/pages/particles.astro @@ -1,9 +1,10 @@ --- +import GlobalPlayPause from "../components/GlobalPlayPause.astro"; import Layout from "../layouts/Layout.astro"; --- + diff --git a/lib/playground/src/pages/pause.astro b/lib/playground/src/pages/pause.astro new file mode 100644 index 0000000..bb3b3ec --- /dev/null +++ b/lib/playground/src/pages/pause.astro @@ -0,0 +1,158 @@ +--- +import PlayPause from "../components/PlayPause.astro"; +import Layout from "../layouts/Layout.astro"; +--- + + + + +
+
+ Global : +
+
+ + + +
+ +
+
+ + diff --git a/lib/playwright.config.ts b/lib/playwright.config.ts index b7bd284..8fef492 100644 --- a/lib/playwright.config.ts +++ b/lib/playwright.config.ts @@ -3,6 +3,8 @@ import { defineConfig, devices } from "@playwright/test"; const desktopViewport = { width: 800, height: 400 }; const mobileViewport = { width: 360, height: 640 }; +const serverUrl = "http://localhost:4321"; + /** * See https://playwright.dev/docs/test-configuration. */ @@ -12,12 +14,12 @@ export default defineConfig({ fullyParallel: true, /* Fail the build on CI if you accidentally left test.only in the source code. */ forbidOnly: !!process.env.CI, - /* Retry on CI only */ - retries: process.env.CI ? 2 : 0, + retries: 3, /* Reporter to use. See https://playwright.dev/docs/test-reporters */ reporter: "html", use: { trace: "on-first-retry", + baseURL: serverUrl, }, snapshotPathTemplate: "{testDir}/__screenshots__/{testName}/{testName}-{projectName}{ext}", expect: { @@ -32,7 +34,7 @@ export default defineConfig({ ...devices["Desktop Chrome"], viewport: desktopViewport, launchOptions: { - args: ["--use-gl=egl", "--ignore-gpu-blocklist", "--use-gl=angle"], + args: ["--use-angle=gl"], }, }, }, @@ -67,7 +69,7 @@ export default defineConfig({ ], webServer: { command: "pnpm dev", - url: "http://localhost:4321", + url: serverUrl, reuseExistingServer: !process.env.CI, }, }); diff --git a/lib/src/helpers/loop.ts b/lib/src/helpers/loop.ts deleted file mode 100644 index 4f71b69..0000000 --- a/lib/src/helpers/loop.ts +++ /dev/null @@ -1,9 +0,0 @@ -export function loop(callback: ({ time, deltaTime }: { time: number; deltaTime: number }) => void) { - const startTime = performance.now(); - - requestAnimationFrame((time) => { - const deltaTime = time - startTime; - callback({ time, deltaTime }); - loop(callback); - }); -} diff --git a/lib/src/hooks/useLoop.ts b/lib/src/hooks/useLoop.ts new file mode 100644 index 0000000..0053d7f --- /dev/null +++ b/lib/src/hooks/useLoop.ts @@ -0,0 +1,115 @@ +interface LoopData { + /** + * time elapsed in milliseconds since the loop started, excluding pauses. + * + * This timer is paused when the loop is paused, to avoid jumps in animations. If you want to get the time elapsed including pauses, use `elapsedTime` instead. + */ + time: number; + /** + * Δt in milliseconds since the previous loop iteration. + */ + deltaTime: number; + /** + * time elapsed in milliseconds since the loop started, including pauses. + * + * This timer is NOT paused when the loop is paused, which can cause jumps in animations. If you want to get the time elapsed excluding pauses, use `time` instead. + */ + elapsedTime: number; +} + +export interface LoopOptions { + /** + * If true, the loop will start immediately. + * + * If false, the loop will start when the `play` method is called. + * @default true + */ + immediate?: boolean; +} + +interface LoopObj { + play: () => void; + pause: () => void; +} + +const allLoops: Array = []; + +/** + * A custom hook that creates an animation loop. + * @param callback A function that will be called on every animation frame. + * @param options Options for the loop. + * @returns An object with `play` and `pause` methods to control the animation loop. + */ +export function useLoop(callback: ({ time, deltaTime }: LoopData) => void, options?: LoopOptions) { + let animationFrameHandle: number; + let pauseTime: number | null; + let loopStartTime: number; + let delay = 0; + + const { immediate = true } = options || {}; + + function loopFn(previousTime: number, delay = 0) { + const currentTime = performance.now(); + const elapsedTime = currentTime - loopStartTime; + const time = elapsedTime - delay; + const deltaTime = currentTime - previousTime; + callback({ time, elapsedTime, deltaTime }); + + animationFrameHandle = requestAnimationFrame(() => loopFn(currentTime, delay)); + } + + function play() { + const currentTime = performance.now(); + if (loopStartTime === undefined) { + loopStartTime = performance.now(); + } + delay += currentTime - (pauseTime || currentTime); + cancelAnimationFrame(animationFrameHandle); + animationFrameHandle = requestAnimationFrame(() => loopFn(currentTime, delay)); + pauseTime = null; + } + + function pause() { + if (pauseTime == null) { + pauseTime = performance.now(); + } + cancelAnimationFrame(animationFrameHandle); + } + + if (immediate) { + play(); + } + + const loop = { + /** + * Play the animation loop. + */ + play, + /** + * Pause the animation loop. + */ + pause, + }; + + allLoops.push(loop); + + return loop; +} + +/** + * Play all loops that have been registered with `useLoop`. + */ +export function playAllLoops() { + for (const loop of allLoops) { + loop.play(); + } +} + +/** + * Pause all loops that have been registered with `useLoop`. + */ +export function pauseAllLoops() { + for (const loop of allLoops) { + loop.pause(); + } +} diff --git a/lib/src/hooks/useWebGLCanvas.ts b/lib/src/hooks/useWebGLCanvas.ts index dd2eea3..cfc055a 100644 --- a/lib/src/hooks/useWebGLCanvas.ts +++ b/lib/src/hooks/useWebGLCanvas.ts @@ -1,12 +1,13 @@ import { onCanvasResize } from "../helpers/resize"; -import { loop } from "../helpers/loop"; import type { Attribute, DrawMode, PostEffect, Uniforms } from "../types"; import { useWebGLContext } from "./useWebGLContext"; import { useQuadRenderPass } from "./useQuadRenderPass"; import { useCompositor } from "./useCompositor"; import { findUniformName } from "../internal/findName"; +import type { LoopOptions } from "./useLoop"; +import { useLoop } from "./useLoop"; -interface Props { +interface Props extends LoopOptions { canvas: HTMLCanvasElement | OffscreenCanvas | string; fragment: string; vertex?: string; @@ -25,6 +26,7 @@ export const useWebGLCanvas = (props: Props) => { vertex, dpr = window.devicePixelRatio, postEffects = [], + immediate, } = props; const { gl, canvas, setSize: setCanvasSize } = useWebGLContext(canvasProp); @@ -32,6 +34,27 @@ export const useWebGLCanvas = (props: Props) => { const primaryPass = useQuadRenderPass(gl, props); const compositor = useCompositor(gl, primaryPass, postEffects); + function render() { + compositor.render(); + } + + let requestedRender = false; + + /** + * Request a render to be executed on the next animation frame. + * If this function is called multiple times before the next animation frame, + * the render will only be executed once. + */ + function requestRender() { + if (requestedRender) return; + requestedRender = true; + + requestAnimationFrame(() => { + requestedRender = false; + render(); + }); + } + for (const pass of compositor.allPasses) { pass.onUpdated(requestRender); } @@ -43,11 +66,21 @@ export const useWebGLCanvas = (props: Props) => { } const timeUniformName = findUniformName(fragment + vertex, "time"); + let play = () => {}; + let pause = () => {}; if (timeUniformName && primaryPass.uniforms[timeUniformName] === undefined) { - loop(({ time }) => { - (primaryPass.uniforms as Record)[timeUniformName] = time / 500; + requestAnimationFrame(() => { + // use RAF to avoid triggering an extra render for the initialization of the time uniform + (primaryPass.uniforms as Record)[timeUniformName] = 0; }); + + ({ play, pause } = useLoop( + ({ deltaTime }) => { + (primaryPass.uniforms as Record)[timeUniformName] += deltaTime / 500; + }, + { immediate }, + )); } if (canvas instanceof HTMLCanvasElement) { @@ -57,32 +90,13 @@ export const useWebGLCanvas = (props: Props) => { }); } - function render() { - compositor.render(); - } - - let requestedRender = false; - - /** - * Request a render to be executed on the next animation frame. - * If this function is called multiple times before the next animation frame, - * the render will only be executed once. - */ - function requestRender() { - if (requestedRender) return; - requestedRender = true; - - requestAnimationFrame(() => { - requestedRender = false; - render(); - }); - } - return { gl, render, canvas, setSize, + play, + pause, dpr, uniforms: primaryPass.uniforms, onUpdated: primaryPass.onUpdated, diff --git a/lib/src/index.ts b/lib/src/index.ts index 23a1b2a..9ed6ff8 100644 --- a/lib/src/index.ts +++ b/lib/src/index.ts @@ -1,17 +1,17 @@ -export * from "./core/attribute"; -export * from "./core/buffer"; -export * from "./core/program"; -export * from "./core/renderTarget"; -export * from "./core/shader"; -export * from "./core/texture"; +export { setAttribute } from "./core/attribute"; +export { createAndBindBuffer } from "./core/buffer"; +export { createProgram } from "./core/program"; +export { createRenderTarget, setRenderTarget } from "./core/renderTarget"; +export { createShader } from "./core/shader"; +export { createTexture, loadTexture } from "./core/texture"; -export * from "./hooks/useCompositor"; -export * from "./hooks/useEffectPass"; -export * from "./hooks/useQuadRenderPass"; -export * from "./hooks/useRenderPass"; -export * from "./hooks/useWebGLCanvas"; -export * from "./hooks/useWebGLContext"; +export { useCompositor } from "./hooks/useCompositor"; +export { useEffectPass } from "./hooks/useEffectPass"; +export { useQuadRenderPass } from "./hooks/useQuadRenderPass"; +export { useRenderPass } from "./hooks/useRenderPass"; +export { useWebGLCanvas } from "./hooks/useWebGLCanvas"; +export { useWebGLContext } from "./hooks/useWebGLContext"; +export { useLoop, playAllLoops, pauseAllLoops } from "./hooks/useLoop"; -export * from "./helpers/loop"; -export * from "./helpers/pointer"; -export * from "./helpers/resize"; +export { onPointerEvents } from "./helpers/pointer"; +export { onCanvasResize } from "./helpers/resize"; diff --git a/lib/tests/__screenshots__/blob/blob-android.png b/lib/tests/__screenshots__/blob/blob-android.png index c285550..2b53d87 100644 --- a/lib/tests/__screenshots__/blob/blob-android.png +++ b/lib/tests/__screenshots__/blob/blob-android.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:0b610ef8a7295a49952f06715aaef5470e1386905a88cb7b73f5841c180bca10 -size 7598 +oid sha256:3c96b566b1d817cf63c7ee21541e6f4cc5ccfeeb4d438bf8fdf81cdcae1eb12a +size 7772 diff --git a/lib/tests/__screenshots__/blob/blob-chromium.png b/lib/tests/__screenshots__/blob/blob-chromium.png index 449e685..a16ac22 100644 --- a/lib/tests/__screenshots__/blob/blob-chromium.png +++ b/lib/tests/__screenshots__/blob/blob-chromium.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:d353071f7164c0513d35814e18050824c171a9c36f427fb00198e5fd0830164d -size 9911 +oid sha256:692a9842b4875c7939a1d1e4e935f8e1c28362ac2ebec569233eaacc168d9ded +size 10251 diff --git a/lib/tests/__screenshots__/blob/blob-firefox.png b/lib/tests/__screenshots__/blob/blob-firefox.png index a7b5e6e..9ccc556 100644 --- a/lib/tests/__screenshots__/blob/blob-firefox.png +++ b/lib/tests/__screenshots__/blob/blob-firefox.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:127c173ec0faa0fcaf8db5c89f3b6f06ccc01cb2b0144f0c3c3215b1dd5cdd38 -size 18014 +oid sha256:f262c7bafdc8910ffd906b101b7546c2c17237c53087cc2d89ded4f30f4b220b +size 18245 diff --git a/lib/tests/__screenshots__/blob/blob-iphone.png b/lib/tests/__screenshots__/blob/blob-iphone.png index 701f662..29d95b1 100644 --- a/lib/tests/__screenshots__/blob/blob-iphone.png +++ b/lib/tests/__screenshots__/blob/blob-iphone.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:4433e30c6876711dfc1612b739484cf31cd3bc5adf9afdba00bc1644b4e16f20 -size 8381 +oid sha256:3749ea2b949bda42f1f645112e3ab975df2125c34bd73046e83e5202a83ec6af +size 8650 diff --git a/lib/tests/__screenshots__/blob/blob-safari.png b/lib/tests/__screenshots__/blob/blob-safari.png index 85878ce..59fbc74 100644 --- a/lib/tests/__screenshots__/blob/blob-safari.png +++ b/lib/tests/__screenshots__/blob/blob-safari.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:271d6d5747638c8676ee5e3c53878a01ee13b612f4e49b9723dff91a2f7430c2 -size 9912 +oid sha256:a75c383cc946096dd285b3e7e71d7dbe7ab949c9405eb91a66b9084633e77f77 +size 10232 diff --git a/lib/tests/__screenshots__/bloom/bloom-chromium.png b/lib/tests/__screenshots__/bloom/bloom-chromium.png index 6481846..8469981 100644 --- a/lib/tests/__screenshots__/bloom/bloom-chromium.png +++ b/lib/tests/__screenshots__/bloom/bloom-chromium.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:ccf76bb2c29d489913fb5b9241201035589223fbd12a1330db8a89be56c50b1c -size 59900 +oid sha256:11ae1193336f44872d71ea920c3f009929f9ed502eecca9c3403d780eda56591 +size 67477 diff --git a/lib/tests/__screenshots__/circle/circle-chromium.png b/lib/tests/__screenshots__/circle/circle-chromium.png index 5954d91..3414c05 100644 --- a/lib/tests/__screenshots__/circle/circle-chromium.png +++ b/lib/tests/__screenshots__/circle/circle-chromium.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:8c36b9493974a29bcaa5edf50a67c1399f4f00b2332ffc0a7ade7561722d7335 -size 8432 +oid sha256:48520f38f70e635dc6c6341e0a18dd6c2fce45cb4c29b0df17fc2bbbe4e0d8ba +size 8444 diff --git a/lib/tests/__screenshots__/gradient/gradient-android.png b/lib/tests/__screenshots__/gradient/gradient-android.png index b26b163..9a4b8c5 100644 --- a/lib/tests/__screenshots__/gradient/gradient-android.png +++ b/lib/tests/__screenshots__/gradient/gradient-android.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:791383d82f62fd90f03136c5ce39fa2a28bc64668bff698f7caeda5b06651f6f -size 4301 +oid sha256:ddb41d9b5273c312a92c540acab7cdaf3d585c1ede0877daaba174c9b0003fb8 +size 4424 diff --git a/lib/tests/__screenshots__/gradient/gradient-chromium.png b/lib/tests/__screenshots__/gradient/gradient-chromium.png index 37b2a47..aec8af7 100644 --- a/lib/tests/__screenshots__/gradient/gradient-chromium.png +++ b/lib/tests/__screenshots__/gradient/gradient-chromium.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:84f53c7d58fac6962fbb186ae7bbf5edb7a8940ab3672c213237957180d259fb -size 5339 +oid sha256:ce4544d48409d7447cd3e26eb0c40fe48d75f50e54a1a920f5c2832cb4754850 +size 5799 diff --git a/lib/tests/__screenshots__/gradient/gradient-firefox.png b/lib/tests/__screenshots__/gradient/gradient-firefox.png index 6a56ffb..128ca62 100644 --- a/lib/tests/__screenshots__/gradient/gradient-firefox.png +++ b/lib/tests/__screenshots__/gradient/gradient-firefox.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:19485231f760a922c245613f8862998447b00d665e8c2089fa859c36f1ea29dd -size 13737 +oid sha256:b83da802f944d5592764ac1b09865facb40da2304cd8ed2a36c3c34650504164 +size 17086 diff --git a/lib/tests/__screenshots__/gradient/gradient-iphone.png b/lib/tests/__screenshots__/gradient/gradient-iphone.png index 7c1f037..c6d4613 100644 --- a/lib/tests/__screenshots__/gradient/gradient-iphone.png +++ b/lib/tests/__screenshots__/gradient/gradient-iphone.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:49325d0de76beec1d134e4b67bb55319c06d217e52c70dbdfef31969ce93c06d -size 4330 +oid sha256:8aa63fb71876451a71db2655e256eaabf8a000962a82aac9f62560103f65ede8 +size 4525 diff --git a/lib/tests/__screenshots__/gradient/gradient-safari.png b/lib/tests/__screenshots__/gradient/gradient-safari.png index 23cb057..c981c1e 100644 --- a/lib/tests/__screenshots__/gradient/gradient-safari.png +++ b/lib/tests/__screenshots__/gradient/gradient-safari.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:62e0463b064c93be45caeccbcfd0079d59badecb09b02c6d1d703afeff6c820c -size 4980 +oid sha256:fd91e153b712447d8d46aa07b6407bb061361b3d3ec9d2c62d7c0000f5a666a3 +size 5394 diff --git a/lib/tests/__screenshots__/particles/particles-android.png b/lib/tests/__screenshots__/particles/particles-android.png index cc7306f..d8f0ee5 100644 --- a/lib/tests/__screenshots__/particles/particles-android.png +++ b/lib/tests/__screenshots__/particles/particles-android.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:bc1c49878bf2e89a8c0c9c0f1103ca383ce40f416ce9d52fc507507a2f03d3a0 -size 23267 +oid sha256:9d213060ded3a71a7cbc27b88c7c2b78db468fee00f304362fb1369e4bad1fd0 +size 23613 diff --git a/lib/tests/__screenshots__/particles/particles-chromium.png b/lib/tests/__screenshots__/particles/particles-chromium.png index 4eb256c..67800b2 100644 --- a/lib/tests/__screenshots__/particles/particles-chromium.png +++ b/lib/tests/__screenshots__/particles/particles-chromium.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:fa4a67d177681dace771b4a8de1f17be8503c61edc3d6e7f4f8194cf14f06a3f -size 12380 +oid sha256:1eacbb04ca299aa82e827c32c6c4dc8011407279b46b6c06e63364bc7772b616 +size 12449 diff --git a/lib/tests/__screenshots__/particles/particles-firefox.png b/lib/tests/__screenshots__/particles/particles-firefox.png index 7ccbc10..db79a4f 100644 --- a/lib/tests/__screenshots__/particles/particles-firefox.png +++ b/lib/tests/__screenshots__/particles/particles-firefox.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:151369f10a2c3be4537ca3a664ac6ea49c305767046b7706041dad89301c4a91 -size 21963 +oid sha256:8ad021479867f9bd28af8934317b4583862e3581da71f8f0b30f4b15c4240f23 +size 22016 diff --git a/lib/tests/__screenshots__/particles/particles-iphone.png b/lib/tests/__screenshots__/particles/particles-iphone.png index 86f2a60..b2ecf52 100644 --- a/lib/tests/__screenshots__/particles/particles-iphone.png +++ b/lib/tests/__screenshots__/particles/particles-iphone.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:4f676971e200d49c6771f1ba958d2fd762419108b344af7e6141fa12791f481b -size 26791 +oid sha256:8960229e06812b4be67f65f9d3377d1569aa7a4174343d7227a411aa73942a5d +size 26860 diff --git a/lib/tests/__screenshots__/particles/particles-safari.png b/lib/tests/__screenshots__/particles/particles-safari.png index d280bed..46a2ccd 100644 --- a/lib/tests/__screenshots__/particles/particles-safari.png +++ b/lib/tests/__screenshots__/particles/particles-safari.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:cf891879e69978edd001c038a9364e0261cadb513447a8c6865e8dae424f088e -size 24970 +oid sha256:9b7a5031b71ac3a114599f84c8a865b1f952c34356d07104a46d4f48ab9e84d5 +size 24966 diff --git a/lib/tests/__screenshots__/play-pause-controls---global/play-pause-controls---global-android.png b/lib/tests/__screenshots__/play-pause-controls---global/play-pause-controls---global-android.png new file mode 100644 index 0000000..a605b82 --- /dev/null +++ b/lib/tests/__screenshots__/play-pause-controls---global/play-pause-controls---global-android.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:4e58a4d1f17ee9164664cab1ebea19ad00198cfdc8e3e7a5aeb429ba4de96a3f +size 6338 diff --git a/lib/tests/__screenshots__/play-pause-controls---global/play-pause-controls---global-chromium.png b/lib/tests/__screenshots__/play-pause-controls---global/play-pause-controls---global-chromium.png new file mode 100644 index 0000000..63a19b6 --- /dev/null +++ b/lib/tests/__screenshots__/play-pause-controls---global/play-pause-controls---global-chromium.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:f1d3f93803709744810eea3b3cfbc80610c882ae053d8c7909b9bb3eb96e7f9c +size 7516 diff --git a/lib/tests/__screenshots__/play-pause-controls---global/play-pause-controls---global-firefox.png b/lib/tests/__screenshots__/play-pause-controls---global/play-pause-controls---global-firefox.png new file mode 100644 index 0000000..d2cd521 --- /dev/null +++ b/lib/tests/__screenshots__/play-pause-controls---global/play-pause-controls---global-firefox.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:5ce4325d78887fbfe5f843b637b72311701537a6053d240a3c53214ea4d040e1 +size 13952 diff --git a/lib/tests/__screenshots__/play-pause-controls---global/play-pause-controls---global-iphone.png b/lib/tests/__screenshots__/play-pause-controls---global/play-pause-controls---global-iphone.png new file mode 100644 index 0000000..d3540cb --- /dev/null +++ b/lib/tests/__screenshots__/play-pause-controls---global/play-pause-controls---global-iphone.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:d33d1b46f6256c27bc237af7412fb528ea2b7c0e231912dd530533c68bab480c +size 6181 diff --git a/lib/tests/__screenshots__/play-pause-controls---global/play-pause-controls---global-safari.png b/lib/tests/__screenshots__/play-pause-controls---global/play-pause-controls---global-safari.png new file mode 100644 index 0000000..d5a7488 --- /dev/null +++ b/lib/tests/__screenshots__/play-pause-controls---global/play-pause-controls---global-safari.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:eb4bbd913bebcbde36c59a8fb092a15f8b48da7ee1687a4ae0c07908d443898c +size 7288 diff --git a/lib/tests/__screenshots__/play-pause-controls---local/play-pause-controls---local-android.png b/lib/tests/__screenshots__/play-pause-controls---local/play-pause-controls---local-android.png new file mode 100644 index 0000000..389d06f --- /dev/null +++ b/lib/tests/__screenshots__/play-pause-controls---local/play-pause-controls---local-android.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:8c978064a8f2a8aa0f21f17f1df6fbc58f64c0d09dceef29a97bcd41cfc852ee +size 6355 diff --git a/lib/tests/__screenshots__/play-pause-controls---local/play-pause-controls---local-chromium.png b/lib/tests/__screenshots__/play-pause-controls---local/play-pause-controls---local-chromium.png new file mode 100644 index 0000000..546ca5b --- /dev/null +++ b/lib/tests/__screenshots__/play-pause-controls---local/play-pause-controls---local-chromium.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:96109fbb821d76ae6ff9e7628dd561bb751dbe974d6598a1c84e0f2527c356fc +size 7612 diff --git a/lib/tests/__screenshots__/play-pause-controls---local/play-pause-controls---local-firefox.png b/lib/tests/__screenshots__/play-pause-controls---local/play-pause-controls---local-firefox.png new file mode 100644 index 0000000..f2241e3 --- /dev/null +++ b/lib/tests/__screenshots__/play-pause-controls---local/play-pause-controls---local-firefox.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a8a71d8531290393f17118049e925bd9749570f02b81969d2088adf841fc0f92 +size 14541 diff --git a/lib/tests/__screenshots__/play-pause-controls---local/play-pause-controls---local-iphone.png b/lib/tests/__screenshots__/play-pause-controls---local/play-pause-controls---local-iphone.png new file mode 100644 index 0000000..5949bf3 --- /dev/null +++ b/lib/tests/__screenshots__/play-pause-controls---local/play-pause-controls---local-iphone.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:714840f1a03b4fe1c270550db1237b85555736658ba6a2a53914896857216305 +size 6961 diff --git a/lib/tests/__screenshots__/play-pause-controls---local/play-pause-controls---local-safari.png b/lib/tests/__screenshots__/play-pause-controls---local/play-pause-controls---local-safari.png new file mode 100644 index 0000000..df2bc5c --- /dev/null +++ b/lib/tests/__screenshots__/play-pause-controls---local/play-pause-controls---local-safari.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:0eb9062bf89e59d8f8c9fd7fbefb9822cf909e66596d14dfeaf68592f53ff1c5 +size 8289 diff --git a/lib/tests/__screenshots__/pointer-move/pointer-move-android.png b/lib/tests/__screenshots__/pointer-move/pointer-move-android.png index 9c84536..2431439 100644 --- a/lib/tests/__screenshots__/pointer-move/pointer-move-android.png +++ b/lib/tests/__screenshots__/pointer-move/pointer-move-android.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:5b2d0981aa3adee2bb4e76748422ae9d81aef8ef9fe24ce4132df3fc7a0443c8 -size 4311 +oid sha256:467a7ebfae8341992b8233ad976953ca666ffa69d35e8992c18a38e4d51b3bfc +size 4455 diff --git a/lib/tests/__screenshots__/pointer/pointer-chromium.png b/lib/tests/__screenshots__/pointer/pointer-chromium.png index 4e0948f..2dc71e3 100644 --- a/lib/tests/__screenshots__/pointer/pointer-chromium.png +++ b/lib/tests/__screenshots__/pointer/pointer-chromium.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:411fa8c905f9b0f414b5490d34ad3d15e835d7861d7a5c8f8cf3d8bbd448a476 -size 4772 +oid sha256:c82b9367203ac73af41a68e5734bb14fe2b6fe6f5c219fff0ed9911c2db37c20 +size 4722 diff --git a/lib/tests/__screenshots__/texture/texture-chromium.png b/lib/tests/__screenshots__/texture/texture-chromium.png index 630a036..03a4328 100644 --- a/lib/tests/__screenshots__/texture/texture-chromium.png +++ b/lib/tests/__screenshots__/texture/texture-chromium.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:e36532389e9c5009aa0dcef936e761caafc4b79ce74493e398ea20a660a61356 -size 176766 +oid sha256:be3daa26a69c64387037937904cc83e98b1509e8e600ebd79e3a4b5a20d0bb39 +size 176782 diff --git a/lib/tests/screenshots.spec.ts b/lib/tests/screenshots.spec.ts index 6d221a8..a642975 100644 --- a/lib/tests/screenshots.spec.ts +++ b/lib/tests/screenshots.spec.ts @@ -2,23 +2,91 @@ import { test, expect } from "@playwright/test"; import { routes } from "../playground/src/components/routes"; -for (const route of routes) { - test(route, async ({ page }) => { - await page.goto(`http://localhost:4321/${route}`); +const ignoreRoutes = new Set(["pause"]); + +const routesToTest = routes.filter((route) => !ignoreRoutes.has(route)); + +for (const route of routesToTest) { + test(route, async ({ page, baseURL }) => { + await page.goto(`${baseURL}/${route}`); await expect(page.locator("main")).toHaveScreenshot(); }); } -test("pointer move", async ({ page, viewport }) => { - await page.goto(`http://localhost:4321/pointer`); +test("pointer move", async ({ page, viewport, baseURL }) => { + await page.goto(`${baseURL}/pointer`); await expect(page.getByText("Renders: 1")).toBeVisible(); await page.mouse.move((viewport?.width || 0) * 0.5, (viewport?.height || 0) * 0.45); await expect(page.getByText("Renders: 2")).toBeVisible(); - await page.waitForTimeout(200); + await page.waitForTimeout(100); + + await expect(page.locator("main")).toHaveScreenshot(); +}); + +test("play / pause controls - local", async ({ page, baseURL }) => { + await page.goto(`${baseURL}/pause`); + + await expect(page.getByText("Renders: 1")).toBeVisible(); + + await page.evaluate(() => { + return new Promise((resolve) => { + const playPauseBtn = document.querySelector( + ".controls.local button:nth-of-type(1)", + )!; + + playPauseBtn.click(); + + requestAnimationFrame(() => { + requestAnimationFrame(() => { + requestAnimationFrame(() => { + requestAnimationFrame(() => { + playPauseBtn.click(); + resolve(); + }); + }); + }); + }); + }); + }); + + await expect(page.getByText("Renders: 5")).toBeVisible(); + + await page.waitForTimeout(100); + + await expect(page.locator("main")).toHaveScreenshot(); +}); + +test("play / pause controls - global", async ({ page, baseURL }) => { + await page.goto(`${baseURL}/pause`); + + await expect(page.getByText("Renders: 1")).toBeVisible(); + + await page.evaluate(() => { + return new Promise((resolve) => { + const playPauseBtn = document.querySelector(".controls.global button")!; + + playPauseBtn.click(); + + requestAnimationFrame(() => { + requestAnimationFrame(() => { + requestAnimationFrame(() => { + requestAnimationFrame(() => { + playPauseBtn.click(); + resolve(); + }); + }); + }); + }); + }); + }); + + await expect(page.getByText("Renders: 5")).toBeVisible(); + + await page.waitForTimeout(100); await expect(page.locator("main")).toHaveScreenshot(); });