diff --git a/netvr-cpp/README.md b/netvr-cpp/README.md new file mode 100644 index 0000000..9fcc877 --- /dev/null +++ b/netvr-cpp/README.md @@ -0,0 +1,4 @@ +# netvr-cpp + +Not actually needed, the rust code supersedes everything here. But useful as +a point of reference. diff --git a/netvr-dashboard/README.md b/netvr-dashboard/README.md index 054e6a4..2835edb 100644 --- a/netvr-dashboard/README.md +++ b/netvr-dashboard/README.md @@ -4,7 +4,7 @@ This folder contains simple dashboard application for managing devices connected ## Compiling -To compile the dashboard you'll need latest [nodejs 16](https://nodejs.org/en/). +To compile the dashboard you'll need latest [nodejs 20](https://nodejs.org/en/). If you have not done so, I recommend running `corepack enable yarn` as admin (do not run any other commands as admin). This will make sure that you have correct yarn version for this project. Once you have the correct system-wide dependencies you can run `yarn` to download and install this projects dependencies. The run `yarn build` to build the project. diff --git a/netvr-dashboard/src/components/design.tsx b/netvr-dashboard/src/components/design.tsx index 4c2d8c1..1844587 100644 --- a/netvr-dashboard/src/components/design.tsx +++ b/netvr-dashboard/src/components/design.tsx @@ -3,12 +3,18 @@ import { css } from '@emotion/react' import React, { PropsWithChildren, useId, useState } from 'react' import { ErrorBoundary } from './error-boundary' +/** + * Styles to be applied to all focusable elements. + */ export const focusableStyles = css({ ':focus-visible': { outline: '2px solid var(--base-e)', }, }) +/** + * Styles to be applied to the root so that selection follows the theme. + */ export const selectionStyle = css({ '::selection': { background: 'var(--base-d)', @@ -16,6 +22,13 @@ export const selectionStyle = css({ }, }) +/** + * How a Pane should look and work. Stores its open state in local storage based + * on the id. + * + * @param param0 + * @returns + */ export function Pane({ children, title, @@ -170,6 +183,13 @@ export function Pane({ ) } +/** + * A button that follows the theme. This is here so that I don't have to style + * every damn button manually. + * + * @param props + * @returns + */ export function Button( props: React.DetailedHTMLProps< React.ButtonHTMLAttributes, @@ -204,6 +224,11 @@ export function Button( ) } +/** + * Select element that follows the theme. + * @param props + * @returns + */ export function Select( props: React.DetailedHTMLProps< React.SelectHTMLAttributes, @@ -240,6 +265,11 @@ export function Select( ) } +/** + * Input element that follows the theme. + * @param props + * @returns + */ export function Input( props: React.DetailedHTMLProps< React.InputHTMLAttributes, diff --git a/netvr-dashboard/src/components/error-boundary.tsx b/netvr-dashboard/src/components/error-boundary.tsx index 2f2ac52..30b2f7d 100644 --- a/netvr-dashboard/src/components/error-boundary.tsx +++ b/netvr-dashboard/src/components/error-boundary.tsx @@ -23,6 +23,10 @@ const showErrorOverlay = (err: Error) => { document.body.appendChild(overlay) } +/** + * Just an error boundary with the added twist that it can trigger a display of + * vites overlay and also that it can recover from errors in certain cases. + */ type State = { hasError: boolean; key: number } export class ErrorBoundary extends Component< { children: React.ReactNode; fallback?: React.ReactNode }, diff --git a/netvr-dashboard/src/components/json-view.tsx b/netvr-dashboard/src/components/json-view.tsx index 7168095..152683a 100644 --- a/netvr-dashboard/src/components/json-view.tsx +++ b/netvr-dashboard/src/components/json-view.tsx @@ -18,6 +18,11 @@ const theme = [...'0123456789ABCDEF'].reduce((object, l) => { return object }, {} as any) +/** + * Component for displaying JSON data in a tree view. + * @param param0 + * @returns + */ export function JSONView({ data, shouldExpandNode, name }: Props) { return ( void) { } const ctx = createContext(null) +/** + * Put this in the root so that you can use `useSocket` anywhere in the app. + * @param param0 + * @returns + */ export function SocketProvider({ children, url, @@ -161,6 +170,10 @@ export function SocketProvider({ return null } +/** + * Use this to get the websocket anywhere in the app. + * @returns + */ export function useSocket() { const value = useContext(ctx) if (!value) throw new Error('Missing SocketProvider') diff --git a/netvr-dashboard/src/components/theme.tsx b/netvr-dashboard/src/components/theme.tsx index c3281d7..29abafa 100644 --- a/netvr-dashboard/src/components/theme.tsx +++ b/netvr-dashboard/src/components/theme.tsx @@ -75,6 +75,11 @@ function useThemeData() { ]) } +/** + * Sets the basic styles according to the set theme. + * @param param0 + * @returns + */ export function ThemeRoot({ children }: PropsWithChildren<{}>) { const data = useThemeData() return ( @@ -105,11 +110,21 @@ export function ThemeRoot({ children }: PropsWithChildren<{}>) { const opaque = Symbol() +/** + * Used for passing the theme to the `ReprovideTheme` component. Usefull for + * react-three-fiber. + * @returns + */ export function useReprovideTheme() { const theme = useThemeInternal() return { [opaque]: theme } } +/** + * Useful for react-three-fiber. Use in conjunction with `useReprovideTheme`. + * @param props + * @returns + */ export function ReprovideTheme(props: { children: React.ReactNode value: ReturnType @@ -125,10 +140,17 @@ function useThemeInternal() { return theme } +/** + * use this hook to get the theme anywhere in the app. + * @returns + */ export function useTheme() { return useThemeInternal().resolved } +/** + * UI for selecting the theme. + */ export const ThemeSelector = memo(function ThemeSelector() { const theme = useThemeInternal() return ( diff --git a/netvr-dashboard/src/dashboard/calibration-pane.tsx b/netvr-dashboard/src/dashboard/calibration-pane.tsx index 066bdab..314579e 100644 --- a/netvr-dashboard/src/dashboard/calibration-pane.tsx +++ b/netvr-dashboard/src/dashboard/calibration-pane.tsx @@ -11,6 +11,12 @@ import { JSONView } from '../components/json-view' import { useLocalStorage } from '../utils' import { useDropzone } from 'react-dropzone' +/** + * Pane for triggering calibration and choosing target and reference devices. + * + * @param param0 + * @returns + */ export function CalibrationPane({ sendMessage, serverState, diff --git a/netvr-dashboard/src/dashboard/client-pane.tsx b/netvr-dashboard/src/dashboard/client-pane.tsx index e802de2..b81a9fe 100644 --- a/netvr-dashboard/src/dashboard/client-pane.tsx +++ b/netvr-dashboard/src/dashboard/client-pane.tsx @@ -5,6 +5,13 @@ import { RemoteConfigurationSnapshot, StateSnapshot } from '../protocol/data' import * as sentMessages from '../protocol/sent-messages' import { ClientId } from '../protocol/recieved-messages' +/** + * Shows information about a client which is connected to the server. + * + * + * @param param0 + * @returns + */ export function ClientPane({ client, clientId, diff --git a/netvr-dashboard/src/dashboard/dashboard.tsx b/netvr-dashboard/src/dashboard/dashboard.tsx index 9df0b4e..5eb240e 100644 --- a/netvr-dashboard/src/dashboard/dashboard.tsx +++ b/netvr-dashboard/src/dashboard/dashboard.tsx @@ -36,6 +36,12 @@ function useSendKeepAlive(socket: WebSocket) { }, [socket]) } +/** + * Main component representing the dashboard. Connects to the server via websocket + * on socketUrl. + * @param param0 + * @returns + */ export function Dashboard({ socketUrl }: { socketUrl: string }) { const [key, setKey] = useState(0) return ( diff --git a/netvr-dashboard/src/dashboard/fullscreen-button.tsx b/netvr-dashboard/src/dashboard/fullscreen-button.tsx index cc43582..1b11c1d 100644 --- a/netvr-dashboard/src/dashboard/fullscreen-button.tsx +++ b/netvr-dashboard/src/dashboard/fullscreen-button.tsx @@ -23,6 +23,11 @@ function useFullscreen() { } } +/** + * Button which switches you to fullscreen. Also detects if you are already in + * fullscreen so that it can change the icon accordingly. + * @returns + */ export function FullscreenButton() { const fullscreen = useFullscreen() return ( diff --git a/netvr-dashboard/src/dashboard/merge-data.tsx b/netvr-dashboard/src/dashboard/merge-data.tsx index bf7cc85..d76a12c 100644 --- a/netvr-dashboard/src/dashboard/merge-data.tsx +++ b/netvr-dashboard/src/dashboard/merge-data.tsx @@ -1,5 +1,9 @@ import { ConfigurationSnapshotSet, StateSnapshot } from '../protocol/data' +/** + * State communicated via UDP to the server (dashboard gets it from the server + * via websocket in either case) + */ export type DatagramState = { [key: number]: { id: number @@ -8,6 +12,14 @@ export type DatagramState = { } } +/** + * Merges datagram data with configuration snapshot, so that the dashboard can + * show it all in one place. + * + * @param datagramData + * @param configurationSnapshot + * @returns + */ export function mergeData( datagramData: DatagramState, configurationSnapshot: ConfigurationSnapshotSet | null, @@ -44,4 +56,7 @@ export function mergeData( .map(({ id, ...rest }) => [id, rest]), ) } +/** + * Type representing the merged data. This describes the full state. + */ export type MergedData = ReturnType diff --git a/netvr-dashboard/src/dashboard/message-log.tsx b/netvr-dashboard/src/dashboard/message-log.tsx index 135378c..ad28407 100644 --- a/netvr-dashboard/src/dashboard/message-log.tsx +++ b/netvr-dashboard/src/dashboard/message-log.tsx @@ -60,6 +60,10 @@ const defaultState: State = { keyGen: 1, } +/** + * controls how the message log works, and returns the log and a dispatch function + * to add messages to the log. Does not render anything. + */ export function useLog({ showDatagrams }: { showDatagrams: boolean }) { const [log, dispatch] = useReducer(logReducer, defaultState) return [ @@ -71,6 +75,9 @@ export function useLog({ showDatagrams }: { showDatagrams: boolean }) { ] as const } +/** + * Renders a single message in the log. + */ export const Message = memo(function Message({ message, timestamp, diff --git a/netvr-dashboard/src/dashboard/quick-actions-pane.tsx b/netvr-dashboard/src/dashboard/quick-actions-pane.tsx index 164a808..ced4802 100644 --- a/netvr-dashboard/src/dashboard/quick-actions-pane.tsx +++ b/netvr-dashboard/src/dashboard/quick-actions-pane.tsx @@ -2,6 +2,12 @@ import { Pane, Button, Input } from '../components/design' import * as sentMessages from '../protocol/sent-messages' +/** + * A pane that contains quick actions that can be performed by pushing a single + * button without having to select anything. + * @param props + * @returns + */ export function QuickActionsPane(props: { sendMessage: sentMessages.SendMessage closeSocket: () => void diff --git a/netvr-dashboard/src/dashboard/use-sync-clients-by-headset.tsx b/netvr-dashboard/src/dashboard/use-sync-clients-by-headset.tsx index 3cd2ade..0f66ad2 100644 --- a/netvr-dashboard/src/dashboard/use-sync-clients-by-headset.tsx +++ b/netvr-dashboard/src/dashboard/use-sync-clients-by-headset.tsx @@ -9,6 +9,11 @@ type Props = { sendMessage: sentMessages.SendMessage } +/** + * Triggers the simple calibration algorithm which uses the headset position. + * @param param0 + * @returns + */ export function useSyncClientsByHeadset({ state, sendMessage }: Props) { const [message, setMessage] = useState('') return { onClick: syncClientsByHeadset, message } diff --git a/netvr-dashboard/src/index.tsx b/netvr-dashboard/src/index.tsx index 60ac420..243be02 100644 --- a/netvr-dashboard/src/index.tsx +++ b/netvr-dashboard/src/index.tsx @@ -9,6 +9,9 @@ import { lazy } from 'react' const SampleViz = lazy(() => import('./other/sample-viz')) const DelayViz = lazy(() => import('./other/delay-viz')) +/** + * Entry point for the dashboard mounting it to the DOM. + */ export async function run() { const events = document.querySelector('#events')! if (!events) throw new Error('Cant find #events') diff --git a/netvr-dashboard/src/other/delay-viz.tsx b/netvr-dashboard/src/other/delay-viz.tsx index db6dac5..8275ee0 100644 --- a/netvr-dashboard/src/other/delay-viz.tsx +++ b/netvr-dashboard/src/other/delay-viz.tsx @@ -14,7 +14,6 @@ import { CameraControls, Connections, PolyLine, - Segment, SpinningCube, dist, mul, @@ -26,6 +25,10 @@ type FileData = { text: string } +/** + * Vizualizes the delay data from .txt file. Data for this route is generated + * by Logger.cs. + */ export default function DelayVizRoute() { const [fileData, setFileData] = useState(null) const dropzone = useDropzone({ diff --git a/netvr-dashboard/src/other/sample-viz.tsx b/netvr-dashboard/src/other/sample-viz.tsx index 2a31e1a..427623e 100644 --- a/netvr-dashboard/src/other/sample-viz.tsx +++ b/netvr-dashboard/src/other/sample-viz.tsx @@ -45,6 +45,10 @@ type Sample = { now_nanos: number } +/** + * Vizualizes the calibration data from .json file. Or the server-based data + * collection in the same format. + */ export default function SampleVizRoute() { const [savedCalibration, setSavedCalibration] = useState(null) diff --git a/netvr-dashboard/src/other/shared.tsx b/netvr-dashboard/src/other/shared.tsx index 62cb27a..e73e5c5 100644 --- a/netvr-dashboard/src/other/shared.tsx +++ b/netvr-dashboard/src/other/shared.tsx @@ -8,6 +8,9 @@ import { ErrorBoundary } from '../components/error-boundary' import { InstancedMesh } from 'three' import { button, useControls } from 'leva' +/** + * Model of a spinning cube to be displayed as a loading indicator. + */ export function SpinningCube() { const theme = useTheme() const boxRef = useRef(null) @@ -35,6 +38,9 @@ export function SpinningCube() { ) } +/** + * Line from point A to point B. + */ export function Segment({ from, to, @@ -49,6 +55,9 @@ export function Segment({ return } +/** + * A string of lines. More efficient than using multiple s. + */ export function PolyLine(props: { points: readonly (readonly [number, number, number])[] color: any @@ -97,6 +106,9 @@ function PolyLineInner({ ) } +/** + * Axis of a coordinate system. Also draws ticks and distance labels. + */ export function Axes({ pos }: { pos?: readonly [number, number, number] }) { const tickLength = 0.05 return ( @@ -219,6 +231,9 @@ function AxisTicks({ ) } +/** + * Function adding multiple 3d vectors + */ export function plus( ...a: readonly (readonly [number, number, number] | undefined)[] ): [number, number, number] { @@ -229,6 +244,9 @@ export function plus( ] } +/** + * Multiply 3d vector by a scalar + */ export function mul( k: number, v: readonly [number, number, number] | undefined, @@ -236,6 +254,9 @@ export function mul( return [(v?.[0] ?? 0) * k, (v?.[1] ?? 0) * k, (v?.[2] ?? 0) * k] } +/** + * Adds camera control buttons to the leva panel + */ export function CameraControls() { const position = useRef(null) useFrame((state) => { @@ -263,6 +284,12 @@ export function CameraControls() { return null } +/** + * Shows connections between two sets of points. Way more efficient than using + * multiple components. As in, if you tried to draw it with segments + * you would get very low FPS and this draws at 60 FPS no problem (at least in + * my tests). + */ export function Connections({ points1, points2, @@ -297,6 +324,9 @@ export function Connections({ ) } +/** + * Distance between two 3d points + */ export function dist( a: readonly [number, number, number], b: readonly [number, number, number], diff --git a/netvr-dashboard/src/protocol/data.tsx b/netvr-dashboard/src/protocol/data.tsx index 9aa6793..a49bf4b 100644 --- a/netvr-dashboard/src/protocol/data.tsx +++ b/netvr-dashboard/src/protocol/data.tsx @@ -1,3 +1,6 @@ +/** + * Definition of a specification of OpenXR action as passed to the dashboard. + */ export type RemoteAction = { type: | 'Boolean' @@ -11,6 +14,9 @@ export type RemoteAction = { binding: string } +/** + * Snapshot of configuration of single remote client. + */ export type RemoteConfigurationSnapshot = { version: number user_paths: readonly string[] @@ -21,16 +27,29 @@ export type RemoteConfigurationSnapshot = { name: string } +/** + * Snapshot of configuration of all remote clients. + */ export type ConfigurationSnapshotSet = { clients: { [key: number]: RemoteConfigurationSnapshot } } +/** + * 3d vector. + */ export type Vec3 = { x: number; y: number; z: number } +/** + * Pose. Position and orientation. + */ export type Pose = { position: Vec3 orientation: { x: number; y: number; z: number; w: number } } +/** + * Snapshot of state of single remote client. As oposed to configuration, this + * data changes often and as such is transfered via UDP. + */ export type StateSnapshot = { controllers: readonly { interaction_profile: number diff --git a/netvr-dashboard/src/protocol/location-map.tsx b/netvr-dashboard/src/protocol/location-map.tsx index 3a8f896..c10da07 100644 --- a/netvr-dashboard/src/protocol/location-map.tsx +++ b/netvr-dashboard/src/protocol/location-map.tsx @@ -1,3 +1,6 @@ +/** + * unused + */ export const locationMap = { isTracked: 'bool', devicePosition: 'vector3', diff --git a/netvr-dashboard/src/protocol/recieved-messages.tsx b/netvr-dashboard/src/protocol/recieved-messages.tsx index c22e72c..a152ab5 100644 --- a/netvr-dashboard/src/protocol/recieved-messages.tsx +++ b/netvr-dashboard/src/protocol/recieved-messages.tsx @@ -1,33 +1,58 @@ import type { ConfigurationSnapshotSet, StateSnapshot } from './data' +/** + * Corresponds with SocketAddr in Rust. + */ export type SocketAddr = string +/** + * Corresponds with ClientId in Rust. + */ export type ClientId = number +/** + * Message semt from, server to dashboard when a new client starts connecting. + */ export type ConnectionEstablished = { type: 'ConnectionEstablished' id: ClientId addr: SocketAddr } +/** + * Message sent from server to dashboard when a client is fully connected. + */ export type FullyConnected = { type: 'FullyConnected' id: ClientId } +/** + * Message sent from server to dashboard when a client disconnects. + */ export type ConnectionClosed = { type: 'ConnectionClosed' id: ClientId } +/** + * Server forwards datagrams from clients to dashboard as this message. + */ export type DatagramUp = { type: 'DatagramUp' id: ClientId message: StateSnapshot } +/** + * Message sent from server to dashboard when configuration changes. + * + */ export type ConfigurationSnapshotChanged = { type: 'ConfigurationSnapshotChanged' value: ConfigurationSnapshotSet } +/** + * Message sent from server to dashboard. + */ export type DashboardMessageDown = | ConfigurationSnapshotChanged | DatagramUp diff --git a/netvr-dashboard/src/protocol/sent-messages.tsx b/netvr-dashboard/src/protocol/sent-messages.tsx index 5b70551..084e490 100644 --- a/netvr-dashboard/src/protocol/sent-messages.tsx +++ b/netvr-dashboard/src/protocol/sent-messages.tsx @@ -1,7 +1,13 @@ import type { ClientId } from './recieved-messages' +/** + * Signature of function that sends messages to server. + */ export type SendMessage = (message: DashboardMessageUp) => void +/** + * Messages that dashboard can send to server. + */ export type DashboardMessageUp = | { type: diff --git a/netvr-dashboard/src/utils.ts b/netvr-dashboard/src/utils.ts index 0289eae..0a1bf95 100644 --- a/netvr-dashboard/src/utils.ts +++ b/netvr-dashboard/src/utils.ts @@ -1,5 +1,8 @@ import { useCallback, useEffect, useState } from 'react' +/** + * like useState, but the state is stored in localStorage + */ export function useLocalStorage( key: string, defaultValue: Value, diff --git a/netvr-dashboard/src/wasm/wasm-wrapper.ts b/netvr-dashboard/src/wasm/wasm-wrapper.ts index 8d65ac6..39f47fc 100644 --- a/netvr-dashboard/src/wasm/wasm-wrapper.ts +++ b/netvr-dashboard/src/wasm/wasm-wrapper.ts @@ -29,6 +29,11 @@ function loadWasm(): return { status: 'loading', value: cachePromise } } +/** + * Loads C++ wasm module and returns its exported functions. Suspends react tree + * until the module is loaded, so you probably want to wrap it in . + * @returns + */ export function useWasmSuspending() { const wasm = loadWasm() if (wasm.status === 'loading') throw wasm.value