diff --git a/.woodpecker.yml b/.woodpecker.yml
index 36fb5f0..ddfa5ab 100644
--- a/.woodpecker.yml
+++ b/.woodpecker.yml
@@ -9,7 +9,7 @@ steps:
- /var/run/docker.sock:/var/run/docker.sock
environment:
FORCE_COLOR: 1
- EARTHLY_EXEC_CMD: "/bin/sh"
+ EARTHLY_EXEC_CMD: '/bin/sh'
EARTHLY_CONFIGURATION:
from_secret: EARTHLY_CONFIGURATION
SSH_CONFIG:
@@ -25,4 +25,4 @@ steps:
- earthly bootstrap
- earthly --secret SSH_CONFIG --secret SSH_UPLOAD_KEY --secret SSH_KNOWN_HOSTS --secret SSH_TARGET --push +deploy
when:
- branch: ["main"]
+ branch: ['main']
diff --git a/av-sync/index.html b/av-sync/index.html
index 0e8c387..8585a5a 100644
--- a/av-sync/index.html
+++ b/av-sync/index.html
@@ -1,11 +1,11 @@
-
-
- AV SYNC
-
-
-
-
-
+
+
+ AV SYNC
+
+
+
+
+
diff --git a/av-sync/src/app.css b/av-sync/src/app.css
index 05ecf59..495c559 100644
--- a/av-sync/src/app.css
+++ b/av-sync/src/app.css
@@ -1,3 +1,4 @@
-html, body {
- margin: 0;
-}
\ No newline at end of file
+html,
+body {
+ margin: 0;
+}
diff --git a/av-sync/svelte.config.js b/av-sync/svelte.config.js
index b0683fd..c6e1140 100644
--- a/av-sync/svelte.config.js
+++ b/av-sync/svelte.config.js
@@ -1,7 +1,7 @@
-import { vitePreprocess } from '@sveltejs/vite-plugin-svelte'
+import { vitePreprocess } from '@sveltejs/vite-plugin-svelte';
export default {
- // Consult https://svelte.dev/docs#compile-time-svelte-preprocess
- // for more information about preprocessors
- preprocess: vitePreprocess(),
-}
+ // Consult https://svelte.dev/docs#compile-time-svelte-preprocess
+ // for more information about preprocessors
+ preprocess: vitePreprocess()
+};
diff --git a/av-sync/tsconfig.json b/av-sync/tsconfig.json
index 5fb548f..ff8fdff 100644
--- a/av-sync/tsconfig.json
+++ b/av-sync/tsconfig.json
@@ -1,20 +1,20 @@
{
- "extends": "@tsconfig/svelte/tsconfig.json",
- "compilerOptions": {
- "target": "ESNext",
- "useDefineForClassFields": true,
- "module": "ESNext",
- "resolveJsonModule": true,
- /**
- * Typecheck JS in `.svelte` and `.js` files by default.
- * Disable checkJs if you'd like to use dynamic types in JS.
- * Note that setting allowJs false does not prevent the use
- * of JS in `.svelte` files.
- */
- "allowJs": true,
- "checkJs": true,
- "isolatedModules": true
- },
- "include": ["src/**/*.ts", "src/**/*.js", "src/**/*.svelte"],
- "references": [{ "path": "./tsconfig.node.json" }]
+ "extends": "@tsconfig/svelte/tsconfig.json",
+ "compilerOptions": {
+ "target": "ESNext",
+ "useDefineForClassFields": true,
+ "module": "ESNext",
+ "resolveJsonModule": true,
+ /**
+ * Typecheck JS in `.svelte` and `.js` files by default.
+ * Disable checkJs if you'd like to use dynamic types in JS.
+ * Note that setting allowJs false does not prevent the use
+ * of JS in `.svelte` files.
+ */
+ "allowJs": true,
+ "checkJs": true,
+ "isolatedModules": true
+ },
+ "include": ["src/**/*.ts", "src/**/*.js", "src/**/*.svelte"],
+ "references": [{ "path": "./tsconfig.node.json" }]
}
diff --git a/av-sync/tsconfig.node.json b/av-sync/tsconfig.node.json
index d02c37d..e07d022 100644
--- a/av-sync/tsconfig.node.json
+++ b/av-sync/tsconfig.node.json
@@ -1,10 +1,10 @@
{
- "compilerOptions": {
- "composite": true,
- "skipLibCheck": true,
- "module": "ESNext",
- "moduleResolution": "bundler",
- "strict": true
- },
- "include": ["vite.config.ts"]
+ "compilerOptions": {
+ "composite": true,
+ "skipLibCheck": true,
+ "module": "ESNext",
+ "moduleResolution": "bundler",
+ "strict": true
+ },
+ "include": ["vite.config.ts"]
}
diff --git a/av-sync/vite.config.ts b/av-sync/vite.config.ts
index d701969..5e75b6c 100644
--- a/av-sync/vite.config.ts
+++ b/av-sync/vite.config.ts
@@ -1,7 +1,7 @@
-import { defineConfig } from 'vite'
-import { svelte } from '@sveltejs/vite-plugin-svelte'
+import { defineConfig } from 'vite';
+import { svelte } from '@sveltejs/vite-plugin-svelte';
// https://vitejs.dev/config/
export default defineConfig({
- plugins: [svelte()],
-})
+ plugins: [svelte()]
+});
diff --git a/package.json b/package.json
index 5dc7ef0..b3d2b6c 100644
--- a/package.json
+++ b/package.json
@@ -1,61 +1,61 @@
{
- "name": "testcard",
- "version": "0.0.0",
- "private": true,
- "scripts": {
- "dev": "vite dev",
- "build": "vite build",
- "preview": "vite preview",
- "check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
- "check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch",
- "lint": "prettier --check . && eslint .",
- "format": "prettier --write .",
- "generate-assets": "earthly +assets-generated",
- "av:dev": "cd av-sync && vite",
- "av:render:video": "cd av-sync && concurrently -P -k -s command-1 \"vite --port 8626\" \"wait-on http://localhost:8626 && node render-video.js --url http://localhost:8626 {@}\" --",
- "av:render:audio": "cd av-sync && node render-audio.js"
- },
- "devDependencies": {
- "@tsconfig/svelte": "^5.0.4",
- "@types/debug": "^4.1.12",
- "@types/eslint": "8.56.0",
- "@types/lodash": "^4.17.15",
- "@typescript-eslint/eslint-plugin": "^6.21.0",
- "@typescript-eslint/parser": "^6.21.0",
- "commander": "^12.1.0",
- "concurrently": "^8.2.2",
- "eslint": "^8.57.1",
- "eslint-config-prettier": "^9.1.0",
- "eslint-plugin-svelte": "^2.46.1",
- "node-wav": "^0.0.2",
- "prettier": "^3.5.0",
- "prettier-plugin-svelte": "^3.3.3",
- "puppeteer": "^22.15.0",
- "svelte-check": "^4.0.0",
- "wait-on": "^7.2.0"
- },
- "type": "module",
- "dependencies": {
- "@fontsource/atkinson-hyperlegible": "^5.1.1",
- "@fontsource/b612": "^5.1.1",
- "@sveltejs/adapter-auto": "^3.3.1",
- "@sveltejs/adapter-static": "^3.0.8",
- "@sveltejs/kit": "^2.17.1",
- "@sveltejs/vite-plugin-svelte": "^4.0.0",
- "@tabler/icons-webfont": "^2.47.0",
- "debug": "^4.4.0",
- "i18next": "^23.16.8",
- "lodash": "^4.17.21",
- "normalize.css": "^8.0.1",
- "svelte": "^5.0.0",
- "svelte-i18next": "^2.2.2",
- "tslib": "^2.8.1",
- "typescript": "^5.7.3",
- "vite": "^5.4.14"
- },
- "trustedDependencies": [
- "esbuild",
- "puppeteer",
- "svelte-preprocess"
- ]
+ "name": "testcard",
+ "version": "0.0.0",
+ "private": true,
+ "scripts": {
+ "dev": "vite dev",
+ "build": "vite build",
+ "preview": "vite preview",
+ "check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
+ "check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch",
+ "lint": "prettier --check . && eslint .",
+ "format": "prettier --write .",
+ "generate-assets": "earthly +assets-generated",
+ "av:dev": "cd av-sync && vite",
+ "av:render:video": "cd av-sync && concurrently -P -k -s command-1 \"vite --port 8626\" \"wait-on http://localhost:8626 && node render-video.js --url http://localhost:8626 {@}\" --",
+ "av:render:audio": "cd av-sync && node render-audio.js"
+ },
+ "devDependencies": {
+ "@tsconfig/svelte": "^5.0.4",
+ "@types/debug": "^4.1.12",
+ "@types/eslint": "8.56.0",
+ "@types/lodash": "^4.17.15",
+ "@typescript-eslint/eslint-plugin": "^6.21.0",
+ "@typescript-eslint/parser": "^6.21.0",
+ "commander": "^12.1.0",
+ "concurrently": "^8.2.2",
+ "eslint": "^8.57.1",
+ "eslint-config-prettier": "^9.1.0",
+ "eslint-plugin-svelte": "^2.46.1",
+ "node-wav": "^0.0.2",
+ "prettier": "^3.5.0",
+ "prettier-plugin-svelte": "^3.3.3",
+ "puppeteer": "^22.15.0",
+ "svelte-check": "^4.0.0",
+ "wait-on": "^7.2.0"
+ },
+ "type": "module",
+ "dependencies": {
+ "@fontsource/atkinson-hyperlegible": "^5.1.1",
+ "@fontsource/b612": "^5.1.1",
+ "@sveltejs/adapter-auto": "^3.3.1",
+ "@sveltejs/adapter-static": "^3.0.8",
+ "@sveltejs/kit": "^2.17.1",
+ "@sveltejs/vite-plugin-svelte": "^4.0.0",
+ "@tabler/icons-webfont": "^2.47.0",
+ "debug": "^4.4.0",
+ "i18next": "^23.16.8",
+ "lodash": "^4.17.21",
+ "normalize.css": "^8.0.1",
+ "svelte": "^5.0.0",
+ "svelte-i18next": "^2.2.2",
+ "tslib": "^2.8.1",
+ "typescript": "^5.7.3",
+ "vite": "^5.4.14"
+ },
+ "trustedDependencies": [
+ "esbuild",
+ "puppeteer",
+ "svelte-preprocess"
+ ]
}
diff --git a/src/index.css b/src/index.css
index c805adc..f7f7f19 100644
--- a/src/index.css
+++ b/src/index.css
@@ -1,75 +1,81 @@
-body, html {
- height: 100%;
- margin: 0;
- display: flex;
- justify-content: center;
- align-items: center;
+body,
+html {
+ height: 100%;
+ margin: 0;
+ display: flex;
+ justify-content: center;
+ align-items: center;
- color: white;
- background-color: black;
+ color: white;
+ background-color: black;
- font-family: 'Atkinson Hyperlegible', 'B612', 'IBM Plex Sans', 'Helvetica Neue', Arial, sans-serif;
- font-size: 20px;
+ font-family:
+ 'Atkinson Hyperlegible', 'B612', 'IBM Plex Sans', 'Helvetica Neue', Arial, sans-serif;
+ font-size: 20px;
}
* {
- box-sizing: border-box;
+ box-sizing: border-box;
}
a {
- color: white;
+ color: white;
}
-
-h1, h2, h3, h4 {
- margin-top: 0;
+h1,
+h2,
+h3,
+h4 {
+ margin-top: 0;
}
-button, .button {
- display: inline-flex;
- align-items: center;
- gap: 0.25em;
- text-decoration: none;
- border: 1px solid white;
- cursor: pointer;
+button,
+.button {
+ display: inline-flex;
+ align-items: center;
+ gap: 0.25em;
+ text-decoration: none;
+ border: 1px solid white;
+ cursor: pointer;
- padding: 0.25em 0.5em;
- border-radius: 0.25em;
+ padding: 0.25em 0.5em;
+ border-radius: 0.25em;
- background: black;
- color: white;
+ background: black;
+ color: white;
- &:disabled {
- opacity: 0.7;
- }
+ &:disabled {
+ opacity: 0.7;
+ }
}
-input[type="number"], input[type="search"], input[type="text"] {
- background: transparent;
- color: white;
- border: 1px solid white;
- border-radius: 4px;
- padding: 0.2em;
+input[type='number'],
+input[type='search'],
+input[type='text'] {
+ background: transparent;
+ color: white;
+ border: 1px solid white;
+ border-radius: 4px;
+ padding: 0.2em;
+ &:focus {
+ outline: solid rgba(255, 255, 255, 0.66);
+ }
- &:focus {
- outline: solid rgba(255, 255, 255, 0.66);
- }
-
- &:disabled {
- opacity: 0.7;
- pointer-events: none;
- }
+ &:disabled {
+ opacity: 0.7;
+ pointer-events: none;
+ }
}
select {
- background: black;
- color: white;
- padding: 0.25em 0.5em;
- border-radius: 0.25em;
- border: 1px solid white;
+ background: black;
+ color: white;
+ padding: 0.25em 0.5em;
+ border-radius: 0.25em;
+ border: 1px solid white;
- &:disabled {
- opacity: 0.7;
- }
-}
\ No newline at end of file
+ &:disabled {
+ opacity: 0.7;
+ }
+}
diff --git a/src/lib/BackgroundGrid.svelte b/src/lib/BackgroundGrid.svelte
index 94b8aca..97b9fb0 100644
--- a/src/lib/BackgroundGrid.svelte
+++ b/src/lib/BackgroundGrid.svelte
@@ -115,9 +115,9 @@
{#each [...Array(verticalCount).keys()] as x}
-
+
{#each [...Array(horizontalCount).keys()] as y}
-
+
{/each}
{/each}
diff --git a/src/lib/Clock.svelte b/src/lib/Clock.svelte
index 8b69c7e..45f8cfc 100644
--- a/src/lib/Clock.svelte
+++ b/src/lib/Clock.svelte
@@ -20,15 +20,15 @@
diff --git a/src/lib/ScreenInfo.svelte b/src/lib/ScreenInfo.svelte
index 52b5936..b28ba27 100644
--- a/src/lib/ScreenInfo.svelte
+++ b/src/lib/ScreenInfo.svelte
@@ -5,7 +5,7 @@
let screenResolution = $state('... x ...');
let windowResolution = $state('');
- let dpr = $state("1");
+ let dpr = $state('1');
function updateResolution() {
const realWidth = Math.round(screen.width) * window.devicePixelRatio;
@@ -35,8 +35,8 @@
{windowResolution}
{/if}
- {#if dpr !== "1"}
-
{$i18n.t("Device Pixel Ratio")}: {dpr}
+ {#if dpr !== '1'}
+
{$i18n.t('Device Pixel Ratio')}: {dpr}
{/if}
@@ -51,7 +51,8 @@
font-weight: bold;
}
- .window, .dpr {
+ .window,
+ .dpr {
margin-top: calc(1em / 0.8);
font-size: 0.8em;
}
diff --git a/src/lib/locales/en.json b/src/lib/locales/en.json
index a6c370a..6814048 100644
--- a/src/lib/locales/en.json
+++ b/src/lib/locales/en.json
@@ -1,49 +1,48 @@
{
- "tests": {
- "audio": {
- "label": "Audio",
- "description": "Check your stereo channels or surround audio output, verify if your speakers are in phase."
- },
- "av-sync": {
- "label": "Audio/Video Sync",
- "description": "Check if your audio and video are in sync, and measure the delay."
- },
- "card": {
- "label": "Card",
- "description": "Test card for your display or projector, check colors, resolution and geometry."
- },
- "camera": {
- "label": "Camera",
- "description": "Check whether your webcam or capture device is working, its image quality, resolution and frame rate. Take a snapshot."
- },
- "gamepad": {
- "label": "Gamepad",
- "description": "Test your gamepad, check if it's working, all the buttons and joysticks, stick drift, dead zones and calibration."
- },
- "keyboard": {
- "label": "Keyboard",
- "description": "Check if all keys are working and what key codes they send."
- },
- "microphone": {
- "label": "Microphone",
- "description": "Check if your microphone is working, its quality, volume and noise."
- },
- "mouse": {
- "label": "Mouse",
- "description": "Check if your mouse or touch device works properly, if there are dead zones or jitter."
- },
- "sensors": {
- "label": "Sensors",
- "description": "See the output of your device's sensors, e.g. GPS, accelerometer, gyroscope, compass, etc."
-
- },
- "internet": {
- "label": "Internet speed",
- "description": "Measure your internet speed, ping and jitter."
- },
- "timer": {
- "label": "High resolution timer",
- "description": "Display a millisecond resolution timer on screen, useful for measuring video pipeline latency."
- }
- }
+ "tests": {
+ "audio": {
+ "label": "Audio",
+ "description": "Check your stereo channels or surround audio output, verify if your speakers are in phase."
+ },
+ "av-sync": {
+ "label": "Audio/Video Sync",
+ "description": "Check if your audio and video are in sync, and measure the delay."
+ },
+ "card": {
+ "label": "Card",
+ "description": "Test card for your display or projector, check colors, resolution and geometry."
+ },
+ "camera": {
+ "label": "Camera",
+ "description": "Check whether your webcam or capture device is working, its image quality, resolution and frame rate. Take a snapshot."
+ },
+ "gamepad": {
+ "label": "Gamepad",
+ "description": "Test your gamepad, check if it's working, all the buttons and joysticks, stick drift, dead zones and calibration."
+ },
+ "keyboard": {
+ "label": "Keyboard",
+ "description": "Check if all keys are working and what key codes they send."
+ },
+ "microphone": {
+ "label": "Microphone",
+ "description": "Check if your microphone is working, its quality, volume and noise."
+ },
+ "mouse": {
+ "label": "Mouse",
+ "description": "Check if your mouse or touch device works properly, if there are dead zones or jitter."
+ },
+ "sensors": {
+ "label": "Sensors",
+ "description": "See the output of your device's sensors, e.g. GPS, accelerometer, gyroscope, compass, etc."
+ },
+ "internet": {
+ "label": "Internet speed",
+ "description": "Measure your internet speed, ping and jitter."
+ },
+ "timer": {
+ "label": "High resolution timer",
+ "description": "Display a millisecond resolution timer on screen, useful for measuring video pipeline latency."
+ }
+ }
}
diff --git a/src/routes/(pages)/+page.svelte b/src/routes/(pages)/+page.svelte
index dd19aea..86a1ff6 100644
--- a/src/routes/(pages)/+page.svelte
+++ b/src/routes/(pages)/+page.svelte
@@ -4,7 +4,7 @@
import { version } from '../../../package.json';
import { i18n } from '$lib/i18n';
import type { Snapshot } from '@sveltejs/kit';
- const buildDate = import.meta.env.VITE_BUILD_DATE || "???";
+ const buildDate = import.meta.env.VITE_BUILD_DATE || '???';
let search = $state('');
@@ -155,13 +155,15 @@
}
}
- let nonEmptyCategories = $derived(categories.filter((category) => {
- const categoryTests = filteredTests.filter((test) => test.categories.includes(category.id));
- return categoryTests.some(
- (test) =>
- !filteredCategories.length || filteredCategories.every((f) => test.categories.includes(f))
- );
- }));
+ let nonEmptyCategories = $derived(
+ categories.filter((category) => {
+ const categoryTests = filteredTests.filter((test) => test.categories.includes(category.id));
+ return categoryTests.some(
+ (test) =>
+ !filteredCategories.length || filteredCategories.every((f) => test.categories.includes(f))
+ );
+ })
+ );
export const snapshot: Snapshot = {
capture: () => JSON.stringify({ filtered: filteredCategories, search }),
@@ -224,7 +226,12 @@
{/each}
-
+