Compare commits

...

3 commits

Author SHA1 Message Date
8394c19c2c wip nav
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
2024-02-19 00:36:00 +01:00
88e7d4a9b6 wip nav 2024-02-18 23:38:55 +01:00
11a2c56fb7 wip av scale 2024-02-18 23:38:54 +01:00
18 changed files with 332 additions and 14 deletions

View file

@ -1,8 +1,12 @@
<script lang="ts">
// time in seconds
import '@fontsource/b612';
import '@fontsource/b612/700.css';
import 'normalize.css/normalize.css';
import { onMount, tick } from 'svelte';
import SectorIndicator from './components/SectorIndicator.svelte';
import FlashIndicator from './components/FlashIndicator.svelte';
import Scale from './components/Scale.svelte';
export let frame = 0;
export let fps = 60;
@ -50,6 +54,10 @@
</div>
</div>
<div class="scale">
<Scale {frame} {fps} />
</div>
{#if debug}
<div class="controls">
<input type="range" min="0" max={fps * 4} bind:value={frame} />
@ -66,6 +74,13 @@
color: white;
--color-active: red;
--color-inactive: white;
display: flex;
flex-direction: column;
justify-content: space-evenly;
align-items: center;
font-family: 'B612', 'IBM Plex Sans', 'Helvetica Neue', Arial, sans-serif;
}
.circular {
@ -74,16 +89,16 @@
}
.cyclic {
position: absolute;
top: 25%;
left: 50%;
transform: translate(-50%, -50%);
width: 100vw;
display: flex;
justify-content: space-evenly;
}
.scale {
width: 80vw;
}
main.debug {
background: black;
}

View file

@ -0,0 +1,59 @@
<script lang="ts">
export let frame: number;
export let fps: number;
</script>
<div class="scale">
<div class="labels">
<div>Video Late</div>
<div>Audio Late</div>
</div>
<div class="indicator"></div>
<div class="ticks">
{#each Array.from({ length: fps }, (_, i) => i) as i}
<div class="tick"></div>
{/each}
</div>
<div class="axis"></div>
</div>
<style>
.scale {
position: relative;
}
.labels {
position: absolute;
top: -3vw;
width: 100%;
display: flex;
font-size: 2vw;
}
.labels > div {
flex-grow: 1;
text-align: center;
}
.axis {
position: absolute;
top: 50%;
left: 0;
transform: translateY(-50%);
width: 100%;
background: white;
height: 2px;
}
.ticks {
display: flex;
justify-content: space-between;
}
.tick {
width: 2px;
height: 3vh;
background: white;
}
</style>

View file

@ -39,6 +39,7 @@
"@sveltejs/adapter-static": "^3.0.1",
"@sveltejs/kit": "^2.0.0",
"@sveltejs/vite-plugin-svelte": "^3.0.0",
"@tabler/icons-svelte": "^2.47.0",
"lodash": "^4.17.21",
"normalize.css": "^8.0.1",
"svelte": "^4.2.7",

View file

@ -20,6 +20,9 @@ dependencies:
'@sveltejs/vite-plugin-svelte':
specifier: ^3.0.0
version: 3.0.2(svelte@4.2.9)(vite@5.0.12)
'@tabler/icons-svelte':
specifier: ^2.47.0
version: 2.47.0(svelte@4.2.9)
lodash:
specifier: ^4.17.21
version: 4.17.21
@ -674,6 +677,19 @@ packages:
- supports-color
dev: false
/@tabler/icons-svelte@2.47.0(svelte@4.2.9):
resolution: {integrity: sha512-xL2NyCUUhBQv0lXylgNCpfHtMW4Ihu0hCacaYXeX+NiS1LO0geqXk/0lkrBH+u/ZLX6vyqUYNFjawjzmxthFjw==}
peerDependencies:
svelte: '>=3 <5'
dependencies:
'@tabler/icons': 2.47.0
svelte: 4.2.9
dev: false
/@tabler/icons@2.47.0:
resolution: {integrity: sha512-4w5evLh+7FUUiA1GucvGj2ReX2TvOjEr4ejXdwL/bsjoSkof6r1gQmzqI+VHrE2CpJpB3al7bCTulOkFa/RcyA==}
dev: false
/@tootallnate/quickjs-emscripten@0.23.0:
resolution: {integrity: sha512-C5Mc6rdnsaJDjO3UpGW/CQTHtCKaYlScZTly4JIu97Jxo/odCiH0ITnDXSJPTOrEKk/ycSZ0AOgTmkDtkOsvIA==}
dev: true

View file

@ -14,4 +14,8 @@ body, html {
* {
box-sizing: border-box;
}
a {
color: white;
}

View file

@ -16,7 +16,8 @@
let verticalMargin = MARGIN_SIZE;
let unloaded = true;
let transparent = false;
export let transparent = false;
export let subdued = false;
function updateCounts() {
const gridWidth = window.innerWidth - MARGIN_SIZE;
@ -72,6 +73,7 @@
class="background"
class:unloaded
class:transparent
class:subdued
class:even-vertical={verticalCount % 2 === 0}
style="--horizontal-count: {horizontalCount};
--vertical-count: {verticalCount};
@ -266,6 +268,13 @@
}
}
.background.subdued {
& .edge,
& .corner {
opacity: 0.33;
}
}
.grid {
display: grid;
grid-template-columns: repeat(var(--horizontal-count), var(--block-size));

View file

@ -6,6 +6,8 @@
import BrightnessGradient from '$lib/BrightnessGradient.svelte';
import { onMount } from 'svelte';
export let full = false;
let sizes = {
blockSize: 64,
horizontalCount: 16,
@ -30,6 +32,7 @@
<div
class="test-card"
class:full
style="--block-size: {sizes.blockSize}px;
--horizontal-margin: {sizes.horizontalMargin}px;
--vertical-margin: {sizes.verticalMargin}px;
@ -38,8 +41,11 @@
--column-height: {columnHeight};
--left-column: {leftColumn};"
>
<BackgroundGrid on:change={(ev) => (sizes = ev.detail)} />
<Axes />
<BackgroundGrid on:change={(ev) => (sizes = ev.detail)} subdued={!full} />
<div class="axes">
<Axes />
</div>
<div class="outer"></div>
<div class="inner"></div>
@ -137,4 +143,13 @@
flex-grow: 1;
}
}
.test-card:not(.full) {
& .info,
& .column,
& .axes,
& .inner {
display: none;
}
}
</style>

52
src/routes/+layout.svelte Normal file
View file

@ -0,0 +1,52 @@
<script lang="ts">
import 'normalize.css/normalize.css';
import '@fontsource/b612';
import '@fontsource/b612/700.css';
import '../index.css';
import TestCard from '$lib/TestCard.svelte';
import { page } from '$app/stores';
import { onMount } from 'svelte';
let idleTimeout: NodeJS.Timeout | undefined;
onMount(() => {
window.addEventListener('mousemove', () => {
clearTimeout(idleTimeout);
document.body.classList.remove('idle');
idleTimeout = setTimeout(() => {
document.body.classList.add('idle');
}, 3000);
});
});
$: onlyCard = $page.url.pathname === '/card';
</script>
<TestCard full={onlyCard} />
<main class:content={!onlyCard}>
<slot />
</main>
<style>
main.content {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
max-height: 90vh;
max-width: 90vw;
background: rgba(0, 0, 0, 0.8);
border-radius: 0.5rem;
border: 1px solid white;
padding: 1rem;
}
:global(.hide-idle) {
transition: opacity 1s;
opacity: 1;
}
:global(body.idle .hide-idle) {
opacity: 0;
}
</style>

View file

@ -1,9 +1,70 @@
<script>
import 'normalize.css/normalize.css';
import '@fontsource/b612';
import '@fontsource/b612/700.css';
import '../index.css';
import TestCard from '$lib/TestCard.svelte';
import {
IconCamera,
IconCpu2,
IconDeviceGamepad,
IconKeyboard,
IconMicrophone,
IconMouse,
IconVideo,
IconVolume
} from '@tabler/icons-svelte';
</script>
<TestCard />
<nav>
<h1>Universal Test Card</h1>
<div class="options">
<a href="card">
<div class="icon"><IconVideo size={72} /></div>
Video
</a>
<a href="audio">
<div class="icon"><IconVolume size={72} /></div>
Audio
</a>
<a href="keyboard">
<div class="icon"><IconKeyboard size={72} /></div>
Keyboard
</a>
<a href="mouse">
<div class="icon"><IconMouse size={72} /></div>
Mouse
</a>
<a href="gamepad">
<div class="icon"><IconDeviceGamepad size={72} /></div>
Gamepad
</a>
<a href="camera">
<div class="icon"><IconCamera size={72} /></div>
Camera
</a>
<a href="microphone">
<div class="icon"><IconMicrophone size={72} /></div>
Microphone
</a>
<a href="sensors">
<div class="icon"><IconCpu2 size={72} /></div>
Sensors
</a>
</div>
</nav>
<style>
h1 {
text-align: center;
font-size: 2.5rem;
margin: 1rem;
}
.options {
display: flex;
justify-content: space-evenly;
gap: 2em;
& a {
text-align: center;
text-decoration: none;
}
}
</style>

View file

View file

View file

@ -0,0 +1,26 @@
<script>
import { IconArrowBack } from '@tabler/icons-svelte';
</script>
<a href="/" class="hide-idle"><IconArrowBack /> Back</a>
<style>
a {
position: absolute;
top: 2rem;
right: 2rem;
background: black;
border: 1px solid white;
border-radius: 0.2em;
padding: 0.5em 1em;
box-shadow: 0 0 0.5em rgba(255, 255, 255, 0.5);
display: flex;
gap: 0.5em;
align-items: center;
text-decoration: none;
}
</style>

View file

View file

@ -0,0 +1,60 @@
<script lang="ts">
import { onMount } from 'svelte';
let key: string;
let code: string;
let pressedKeys: string[] = [];
onMount(() => {
document.addEventListener('keydown', (event) => {
key = event.key;
code = event.code;
pressedKeys = [...pressedKeys, event.key];
pressedKeys = pressedKeys.slice(-50);
});
});
</script>
<h2>Keyboard testing</h2>
<p>Press a key on the keyboard to see the event object and the key code.</p>
<div class="current">
{#if key}
<span>{key}</span>
{/if}
{#if code}
<span class="code">({code})</span>
{/if}
</div>
<p>Pressed keys:</p>
<ul>
{#each pressedKeys as key}
<li>{key}</li>
{/each}
</ul>
<style>
.current {
display: flex;
}
.code {
margin-left: 1em;
opacity: 0.8;
}
ul {
list-style: none;
padding: 0;
display: flex;
flex-wrap: wrap;
justify-content: safe space-evenly;
gap: 0.2em;
}
li {
margin: 0;
padding: 0;
display: inline-block;
}
</style>

View file

View file

View file

View file