@ksp-gonogo/kerbcast-react 1.6.3 → 1.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (43) hide show
  1. package/CHANGELOG.md +54 -0
  2. package/README.md +19 -0
  3. package/dist/CameraFeed.d.ts +63 -19
  4. package/dist/CameraFeed.js +329 -202
  5. package/dist/FeedActionBar.d.ts +133 -0
  6. package/dist/FeedActionBar.js +225 -0
  7. package/dist/KerbalFaceFeed.d.ts +82 -0
  8. package/dist/KerbalFaceFeed.js +111 -0
  9. package/dist/RecordingsTray.d.ts +37 -0
  10. package/dist/RecordingsTray.js +279 -0
  11. package/dist/context.d.ts +27 -1
  12. package/dist/context.js +68 -2
  13. package/dist/hooks/useRecordings.d.ts +35 -0
  14. package/dist/hooks/useRecordings.js +33 -0
  15. package/dist/hooks/useReportDisplaySize.d.ts +23 -0
  16. package/dist/hooks/useReportDisplaySize.js +71 -0
  17. package/dist/index.d.ts +12 -2
  18. package/dist/index.js +13 -1
  19. package/dist/menuPositioning.d.ts +20 -0
  20. package/dist/menuPositioning.js +98 -0
  21. package/dist/timing.d.ts +4 -0
  22. package/dist/timing.js +19 -0
  23. package/package.json +2 -2
  24. package/src/CameraFeed.test.tsx +719 -10
  25. package/src/CameraFeed.tsx +586 -334
  26. package/src/FeedActionBar.test.ts +196 -0
  27. package/src/FeedActionBar.test.tsx +215 -0
  28. package/src/FeedActionBar.tsx +391 -0
  29. package/src/KerbalFaceFeed.test.tsx +203 -0
  30. package/src/KerbalFaceFeed.tsx +214 -0
  31. package/src/RecordingsTray.test.tsx +288 -0
  32. package/src/RecordingsTray.tsx +475 -0
  33. package/src/context.test.tsx +94 -0
  34. package/src/context.tsx +98 -1
  35. package/src/hooks/useRecordings.sharedState.test.tsx +117 -0
  36. package/src/hooks/useRecordings.test.tsx +217 -0
  37. package/src/hooks/useRecordings.ts +110 -0
  38. package/src/hooks/useReportDisplaySize.test.tsx +166 -0
  39. package/src/hooks/useReportDisplaySize.ts +91 -0
  40. package/src/index.ts +27 -1
  41. package/src/menuPositioning.ts +126 -0
  42. package/src/timing.test.ts +34 -0
  43. package/src/timing.ts +21 -0
package/CHANGELOG.md CHANGED
@@ -1,5 +1,59 @@
1
1
  # Changelog
2
2
 
3
+ ## Unreleased (next minor)
4
+
5
+ ### Added
6
+
7
+ - `useRecordings`: a reactive recordings store over the SDK's
8
+ `client.recording` controller. Exposes finished standalone clips
9
+ (`recordings`), synchronised sets (`groups`), and in-progress recordings
10
+ (`active`, for a REC dot + elapsed timer), plus `start` / `stop` /
11
+ `startGroup` / `stopGroup` / `discard` / `discardGroup` / `isRecording`. This
12
+ is the headless data layer the recordings tray + REC controls sit on; it owns
13
+ no chrome and keeps grouped clips out of the singles list
14
+ - `RecordingsStore` and `ActiveRecordingInfo` types
15
+
16
+ ## 1.7.0 - 2026-07-24
17
+
18
+ Crew face cameras, auto-resolution, and camera targeting.
19
+
20
+ ### Added
21
+
22
+ - `KerbalFaceFeed`: a single-kerbal face-camera primitive. Renders one crew
23
+ face in a square frame, keyed by `flightId`, and never remounts its `<video>`
24
+ on re-layout. Composable via `children` (name label, badge, custom overlays)
25
+ and an `actions` bar.
26
+ - Low-level auto-resolution primitives, for CUSTOM feed surfaces only (not
27
+ needed for normal use, since the feed components self-measure):
28
+ `useReportDisplaySize`, `createClientDisplaySizes`, `useKerbcastDisplaySizes`,
29
+ the `KerbcastDisplaySizes` type, and a `displaySizes` override on
30
+ `KerbcastProvider`.
31
+ - `showActions?: boolean` (default true) on `CameraFeed` and `KerbalFaceFeed` to
32
+ suppress the hover action bar without affecting resolution reporting.
33
+ - `reportSize?: boolean` (default true) on `KerbalFaceFeed` to opt a
34
+ fixed-resolution face out of auto-resolution.
35
+ - `enableTracking?: boolean` (default false) on `CameraFeed`: a tri-state
36
+ auto-track control (off / active-vessel / target) on pan+zoom cameras,
37
+ highlighted from the server-published `CameraState.trackMode`.
38
+ - `cameraFilter?: (camera) => boolean` on `CameraFeed` to narrow the selectable
39
+ set (picker menu, stepper, auto-latch). Omit to consider every camera.
40
+ - `--kerbcast-action-active` theme token: the fill for every active action-row
41
+ toggle (tracking, quality, PiP, fullscreen, custom). Defaults to
42
+ `var(--kerbcast-accent, #00ff88)`, so one knob recolours them all.
43
+
44
+ ### Changed
45
+
46
+ - `KerbalFaceFeed` `size` is now LAYOUT-ONLY. It sets the element's size but no
47
+ longer requests a stream resolution: the primitive always self-measures its
48
+ rendered box and reports that (auto-resolution), so resolution follows how
49
+ large the feed is actually shown.
50
+ - `CameraFeed` with `renderSize="auto"` (the default) now reports its measured
51
+ display size for auto-resolution instead of writing a 16:9 operator render
52
+ size. `renderSize="none"` opts out.
53
+ - `CameraFeed` auto-disables its manual pan/zoom controls while the camera's
54
+ published `trackMode` is not `none` (they no-op against a live track and the
55
+ rate/drag path otherwise jitters).
56
+
3
57
  ## 0.12.0 - 2026-06-07
4
58
 
5
59
  Initial release. Versioned in lockstep with `@jonpepler/kerbcast` and the
package/README.md CHANGED
@@ -73,8 +73,27 @@ An imperative `CameraFeedHandle` (via `ref`) exposes `stepCamera`,
73
73
  `setPanAxis`, `setZoomRate`, `nudgePan`, and `nudgeZoom` for wiring feeds
74
74
  to a gamepad or keyboard.
75
75
 
76
+ `enableTracking` shows a tri-state auto-track control (off / active-vessel /
77
+ target) on pan+zoom cameras, and `CameraFeed` disables its manual pan/zoom
78
+ while a camera is tracking. `cameraFilter` narrows the selectable cameras
79
+ (picker, stepper, auto-latch). `showActions={false}` hides the whole action
80
+ bar without affecting resolution reporting.
81
+
82
+ ## `KerbalFaceFeed`
83
+
84
+ A single-kerbal face-camera primitive: one crew face in a square frame, keyed
85
+ by `flightId`, never remounting its `<video>` on re-layout. Compose a name
86
+ label, badge, or overlay via `children`. `size` is LAYOUT-ONLY: the feed always
87
+ self-measures its rendered box and reports that for auto-resolution, so stream
88
+ quality follows how large it is shown (pass `reportSize={false}` to opt out).
89
+
76
90
  ## Hooks
77
91
 
92
+ - `useReportDisplaySize(flightId, ref)`. Self-measure an element and drive the
93
+ client's per-consumer `reportDisplaySize` (auto-resolution). The feed
94
+ primitives use it internally; multiple views of one camera from a client
95
+ collapse to a single MAX report.
96
+
78
97
  - `useKerbcastCameras(): CameraState[]`. The live camera registry,
79
98
  re-rendering as cameras appear, change, or are destroyed.
80
99
  - `useKerbcastStream(flightId): MediaStream | null`. The video stream
@@ -1,20 +1,11 @@
1
- import type { KerbcastClient } from "@ksp-gonogo/kerbcast";
1
+ import type { CameraState, KerbcastClient } from "@ksp-gonogo/kerbcast";
2
+ import { type FeedAction } from "./FeedActionBar";
2
3
  /**
3
- * A consumer-supplied action rendered into the feed's top-right action bar.
4
- * Lets a host page (e.g. the sidecar's spotlight toggle) inject controls
5
- * without the library knowing what they do.
4
+ * The consumer-supplied action shape, and the shared top-right action bar
5
+ * both `CameraFeed` and `KerbalFaceFeed` render, live in `FeedActionBar`.
6
+ * Re-exported here since existing imports reference `./CameraFeed`.
6
7
  */
7
- export interface FeedAction {
8
- /** Stable identity for the React key. */
9
- id: string;
10
- /** Accessible label; used for aria-label and the native tooltip. */
11
- label: string;
12
- /** Icon node, sized by the action bar (~14px). */
13
- icon: React.ReactNode;
14
- /** Toggle state: renders the button highlighted and sets aria-pressed. */
15
- active?: boolean;
16
- onClick: () => void;
17
- }
8
+ export type { FeedAction } from "./FeedActionBar";
18
9
  /**
19
10
  * A hook that yields the live `MediaStream` for a resolved flightId. Must be
20
11
  * a stable reference (the same function identity every render) and called
@@ -43,6 +34,13 @@ export interface CameraFeedProps {
43
34
  * buttons). Never called on auto-latch.
44
35
  */
45
36
  onSelectCamera?: (flightId: number) => void;
37
+ /**
38
+ * Restrict the cameras this feed can select / step through / auto-latch onto
39
+ * (the picker menu + stepper + fallback). Omit to consider every camera (the
40
+ * default). A host uses it to scope the selectable set — e.g. a part-grid tile
41
+ * offering only part cameras so crew cams stay in the crew bar.
42
+ */
43
+ cameraFilter?: (camera: CameraState) => boolean;
46
44
  /**
47
45
  * Called whenever the camera this feed actually displays changes — including
48
46
  * auto-latch and fallback picks, not just explicit selection. The argument
@@ -76,8 +74,12 @@ export interface CameraFeedProps {
76
74
  */
77
75
  showStandbyIcon?: boolean;
78
76
  /**
79
- * "auto" (default): ResizeObserver drives `setRenderSize` at a 16:9 crop,
80
- * debounced 500 ms. "none": no render-size feedback.
77
+ * "auto" (default): the feed self-measures its rendered pixel box and reports
78
+ * it to the sidecar via the per-consumer `reportDisplaySize` (auto-resolution;
79
+ * the sidecar maxes across consumers). "none": no reporting, for a
80
+ * fixed-resolution feed. This drives the AUTO signal, not the operator
81
+ * `setRenderSize` (which, with the quality presets, is the manual cap:
82
+ * effective = min(auto, cap)).
81
83
  */
82
84
  renderSize?: "auto" | "none";
83
85
  /** Message shown when no cameras are available. */
@@ -104,6 +106,39 @@ export interface CameraFeedProps {
104
106
  * false.
105
107
  */
106
108
  enableQualityControl?: boolean;
109
+ /**
110
+ * Show a built-in auto-track (crosshair) control, only on pan+zoom cameras.
111
+ * A tri-state toggle group (off / track active vessel / track target): the
112
+ * camera aims itself at the chosen moving vessel (and auto-zooms) with no kOS.
113
+ * State is SERVER-authoritative: the highlight reflects `CameraState.trackMode`
114
+ * published by the sidecar, never the local click, so two browsers agree.
115
+ * While tracking, the manual pan/zoom controls are disabled (the aim loop owns
116
+ * the gimbal + FoV). Default false.
117
+ */
118
+ enableTracking?: boolean;
119
+ /**
120
+ * Show a built-in REC control in the action bar: a STATEFUL toggle (never
121
+ * overflow-eligible, per the #6 spec) that starts/stops a client-side
122
+ * recording of this feed via `useRecordings()`. Idle -> click starts
123
+ * (`start(flightId)`); active shows a red dot + a live elapsed timer on the
124
+ * tile -> click stops (`stop(recordingId)`) and the clip lands in the
125
+ * recordings store. Recording is purely client-local (this browser's own
126
+ * MediaRecorder, nothing server-authoritative) and read from the store
127
+ * (`isRecording(flightId)`), so it stays correct if toggled elsewhere (e.g.
128
+ * a REC+ grouped recording). Default false.
129
+ */
130
+ enableRecording?: boolean;
131
+ /**
132
+ * Record this feed at the operator's full render size for the duration of
133
+ * the built-in REC control's recording (overrides only the display-size
134
+ * demand; still yields to the adaptive framerate shed). Off by default.
135
+ * Threaded straight into `start(flightId, { forceFullResolution })`; has
136
+ * no effect unless `enableRecording` is also set. While the feed is armed
137
+ * (force sent, waiting for the resolution bump) the tile shows an
138
+ * "ARMING" pill under the title in place of the REC badge, then switches
139
+ * to the normal REC badge + elapsed timer once recording actually starts.
140
+ */
141
+ recordFullResolution?: boolean;
107
142
  /**
108
143
  * Consumer-injected action buttons, rendered left of the built-in
109
144
  * fullscreen/PiP controls in the top-right action bar.
@@ -111,10 +146,19 @@ export interface CameraFeedProps {
111
146
  actions?: FeedAction[];
112
147
  /**
113
148
  * Consumer-injected action buttons rendered at the far end of the action
114
- * bar, right of the built-in controls — the natural home for a close/remove
115
- * button so it sits in the corner.
149
+ * bar: the natural home for a close/remove button. Always pinned trailing
150
+ * (never overflow-eligible, never counted toward the overflow threshold),
151
+ * so it sits in the corner as a persistent, single-click control, right of
152
+ * the ⋮ overflow trigger when one is present.
116
153
  */
117
154
  trailingActions?: FeedAction[];
155
+ /**
156
+ * Render the feed's action UI (the top-right action bar: camera stepper,
157
+ * custom actions, quality / fullscreen / PiP). Default true. Set false to
158
+ * suppress the whole bar (e.g. a small tile where hover controls add
159
+ * nothing). Does not affect display-size reporting.
160
+ */
161
+ showActions?: boolean;
118
162
  /**
119
163
  * Override how the displayed video stream is sourced for the resolved
120
164
  * flightId. Omit (the default) to use the built-in `useKerbcastStream` —