Compare commits

...

2 Commits

Author SHA1 Message Date
7498d9066e Add modal confirmation to mode change 2025-03-07 15:40:42 +01:00
b974ac8936 readme 2025-03-07 15:29:26 +01:00
5 changed files with 51 additions and 9 deletions

15
README.md Normal file
View File

@@ -0,0 +1,15 @@
# followspot-psn
Solution for controlling followspots, and sending the position data to ma3 over [posistagenet (PSN)](https://posistage.net/). It uses [psn-py](https://github.com/vyv/psn-py) to do PSN stuff.
### Deployment
**TLDR**: `docker compose up --build` on a Linux machine.
> [!NOTE]
Why Linux? This is because PSN uses multicast to transmit positional data to ma3. On linux this is done using host networking driver. However the host networking driver on macOS or windows will only allow broadcasting on the docker linux VM. It could probably be done using some fancy routing/bridge setup with the docker VM.
This opens a webserver on port 8000 where you can control the PSN trackers. PSN data is multicasted on `236.10.10.10:56565`. Tracker positions can also be updated using OSC, by default OSC listens on port 9000. The OSC endpoint expects data on `/Tracker/{trackerid}` with three floats specifying x, y and z value.
Currently all configuration is done in the source files, most notably in [psn_server.py](backend/psn_server.py).
The rest of the functionality is documented in the code.

View File

@@ -15,7 +15,7 @@ PSN_DEFAULT_UDP_PORT = 56565
PSN_DEFAULT_UDP_MCAST_ADDRESS = "236.10.10.10" PSN_DEFAULT_UDP_MCAST_ADDRESS = "236.10.10.10"
WEB_SERVER_PORT = 8000 WEB_SERVER_PORT = 8000
IP = "0.0.0.0" IP = "0.0.0.0"
OSC_SERVER_PORT = 6969 OSC_SERVER_PORT = 9000
NUM_TRACKERS = 3 NUM_TRACKERS = 3
class SceneDimensions: class SceneDimensions:

View File

@@ -63,6 +63,8 @@
width = image?.getBoundingClientRect().width ?? 0; width = image?.getBoundingClientRect().width ?? 0;
height = image?.getBoundingClientRect().height ?? 0; height = image?.getBoundingClientRect().height ?? 0;
}); });
</script> </script>
<svelte:window onresize={resize} /> <svelte:window onresize={resize} />

View File

@@ -1,10 +1,38 @@
<script lang="ts"> <script lang="ts">
type Props = { type Props = {
open: boolean; action: () => void;
onClose: () => void; };
let { action }: Props = $props();
let dialog: HTMLDialogElement;
const openModal = () => {
dialog.showModal();
}; };
</script> </script>
<dialog> <button class="mb-24 rounded-md bg-red-400 p-2" onclick={openModal}>
<div></div> Change mode
</button>
<dialog
open={false}
bind:this={dialog}
class="absolute left-0 top-0 z-50 m-0 h-full max-h-full w-full max-w-full p-0 open:bg-black/80"
>
<div class="flex h-full w-full flex-col items-center justify-center">
<h1 class="text-red-600 text-8xl">THIS GONNA FUCK THINGS UP</h1>
<div class="flex items-center justify-center gap-6">
<button class="rounded-md bg-gray-400 p-4" onclick={() => dialog.close()}
>Close</button
>
<button
class="rounded-md bg-red-400 p-4"
onclick={() => {
action();
dialog.close();
}}>Change mode</button
>
</div>
</div>
</dialog> </dialog>

View File

@@ -1,6 +1,5 @@
<script lang="ts"> <script lang="ts">
import type { TrackerData } from "$lib/utils/types"; import type { TrackerData } from "$lib/utils/types";
import { onMount } from "svelte";
import Modal from "./Modal.svelte"; import Modal from "./Modal.svelte";
type Props = { type Props = {
@@ -56,10 +55,8 @@
let z_viz = $derived(trackers[selected].z.toFixed(2)); let z_viz = $derived(trackers[selected].z.toFixed(2));
</script> </script>
<Modal />
<div class="slider-container ml-auto"> <div class="slider-container ml-auto">
<button class="bg-red-400 rounded-md p-2 mb-24" <Modal action={buttonAction} />
onclick={buttonAction}>Change mode</button>
<input <input
type="range" type="range"
id="z" id="z"