@joewinke/jatui 0.13.0 → 0.15.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.
- package/dist/components/VideoPlayer.svelte +779 -16
- package/dist/components/VideoPlayer.svelte.d.ts +108 -0
- package/dist/index.d.ts +3 -1
- package/dist/index.js +9 -0
- package/dist/video/README.md +3 -3
- package/dist/video/presence/flip.d.ts +145 -0
- package/dist/video/presence/flip.js +253 -0
- package/dist/video/presence/idle.d.ts +82 -0
- package/dist/video/presence/idle.js +145 -0
- package/dist/video/presence/resume.d.ts +76 -0
- package/dist/video/presence/resume.js +139 -0
- package/dist/video/presence/winddown.d.ts +106 -0
- package/dist/video/presence/winddown.js +104 -0
- package/dist/video/presence.d.ts +25 -21
- package/dist/video/presence.js +25 -21
- package/dist/video/rate/ads.d.ts +36 -0
- package/dist/video/rate/ads.js +59 -0
- package/dist/video/rate/compose.d.ts +82 -0
- package/dist/video/rate/compose.js +114 -0
- package/dist/video/rate/silence.d.ts +27 -0
- package/dist/video/rate/silence.js +48 -0
- package/dist/video/rate/speaker.d.ts +54 -0
- package/dist/video/rate/speaker.js +94 -0
- package/dist/video/rate/tick.d.ts +38 -0
- package/dist/video/rate/tick.js +15 -0
- package/dist/video/rate.d.ts +20 -63
- package/dist/video/rate.js +20 -82
- package/dist/video/settings.js +25 -2
- package/package.json +1 -1
package/dist/video/rate.d.ts
CHANGED
|
@@ -1,69 +1,26 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* Rate module (mos-5lzns.32) — the rate composer and its advisors: smart
|
|
3
|
+
* speed, per-speaker pace, skip ad reads. Ported from extension-library
|
|
4
|
+
* FEATURES.md §The rate composer.
|
|
3
5
|
*
|
|
4
|
-
*
|
|
5
|
-
* composer") — this is the one non-obvious rule, stated up front because it
|
|
6
|
-
* looks like a bug from the outside:
|
|
6
|
+
* rate = base × speaker × silence (clamp [0.0625, 16], 0.001 deadband)
|
|
7
7
|
*
|
|
8
|
-
*
|
|
9
|
-
* · you — the speed keys (−/=/Backspace, alt+wheel)
|
|
10
|
-
* · speaker — "this person talks fast" (mos-5lzns.32 fills)
|
|
11
|
-
* · silence — "nothing is being said here" (mos-5lzns.32 fills)
|
|
8
|
+
* `base` is the only factor a human chose and the only one the UI reports.
|
|
12
9
|
*
|
|
13
|
-
*
|
|
10
|
+
* Layout (every file pure and node-testable — `npm run test:unit`):
|
|
14
11
|
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
* staircase) — it returns early, before any multiplication, because no
|
|
25
|
-
* advisor gets to un-pause the video by multiplying its way out of zero.
|
|
26
|
-
* 3. Only real changes are written. `playbackRate` is a live audio
|
|
27
|
-
* parameter: writing a *slightly* different value is audible as a wobble.
|
|
28
|
-
* Hence the 0.001 deadband.
|
|
29
|
-
* 4. The clamp is [0.0625, 16] — the range HTML media elements actually
|
|
30
|
-
* support. A product of three multipliers can leave it; a single one
|
|
31
|
-
* cannot.
|
|
32
|
-
*
|
|
33
|
-
* The SPEED_STEPS staircase and formatSpeedLabel are ported from the
|
|
34
|
-
* extension's theater (linear 0.1 steps below 1×, all the way down to 0 —
|
|
35
|
-
* playbackRate=0 is a genuine frozen frame; above 1× the familiar jumps).
|
|
36
|
-
*/
|
|
37
|
-
/** The speed staircase — one step per press of −/=, Backspace resets to 1. */
|
|
38
|
-
export declare const SPEED_STEPS: number[];
|
|
39
|
-
/**
|
|
40
|
-
* "A quarter speed" reads faster as "−.75" than "0.25×" — below 1× the label
|
|
41
|
-
* is the delta, not the multiplier. The 0 step is the frozen-frame end of the
|
|
42
|
-
* staircase — a state, not a level — and the label says so ("0×"), because a
|
|
43
|
-
* frozen frame labeled "1×" lies. Garbage degrades to `1×`.
|
|
44
|
-
*/
|
|
45
|
-
export declare function formatSpeedLabel(rate: number): string;
|
|
46
|
-
/**
|
|
47
|
-
* One step along the staircase. Unknown current rate snaps to 1 first (a
|
|
48
|
-
* hand-set rate off the staircase still steps from where the user expects).
|
|
49
|
-
*/
|
|
50
|
-
export declare function stepRate(current: number, direction: 1 | -1): number;
|
|
51
|
-
/** The clamp the composer applies — the range HTML media elements actually support. */
|
|
52
|
-
export declare const RATE_MIN = 0.0625;
|
|
53
|
-
export declare const RATE_MAX = 16;
|
|
54
|
-
/** Writes only on real change — a slightly-different write is audible as a wobble. */
|
|
55
|
-
export declare const RATE_DEADBAND = 0.001;
|
|
56
|
-
export interface ComposedRate {
|
|
57
|
-
rate: number;
|
|
58
|
-
/** False when the deadband swallowed the write (keep the previous rate). */
|
|
59
|
-
changed: boolean;
|
|
60
|
-
}
|
|
61
|
-
/**
|
|
62
|
-
* The whole arbitration. `speaker` and `silence` are advisor products in
|
|
63
|
-
* [0.0625, 16] that COLLAPSE TO 1 when their feature is off or its data has
|
|
64
|
-
* not arrived — mos-5lzns.32 fills both; until then they are always 1 and
|
|
65
|
-
* this is exactly `base`.
|
|
66
|
-
*
|
|
67
|
-
* `base === 0` returns early: a frozen frame is a state, not a level.
|
|
12
|
+
* · rate/compose.ts — the contract: SPEED_STEPS staircase, formatSpeedLabel,
|
|
13
|
+
* composeRate (base 0 is a state, advisors collapse to 1, clamp), and
|
|
14
|
+
* shouldWriteRate (deadband, except an exact return to base).
|
|
15
|
+
* · rate/speaker.ts — props → advisors/speaker-rate; manual rates keyed by
|
|
16
|
+
* NAME always beat measured ones.
|
|
17
|
+
* · rate/silence.ts — waveform → advisors/smart-speed map + boost factor.
|
|
18
|
+
* · rate/ads.ts — adSpans ∪ `ad: true` turns; skip only when PLAYBACK
|
|
19
|
+
* runs into an ad, never when a seek lands in one.
|
|
20
|
+
* · rate/tick.ts — the 120ms loop's one-tick decision.
|
|
68
21
|
*/
|
|
69
|
-
export
|
|
22
|
+
export * from './rate/compose';
|
|
23
|
+
export * from './rate/speaker';
|
|
24
|
+
export * from './rate/silence';
|
|
25
|
+
export * from './rate/ads';
|
|
26
|
+
export * from './rate/tick';
|
package/dist/video/rate.js
CHANGED
|
@@ -1,88 +1,26 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* Rate module (mos-5lzns.32) — the rate composer and its advisors: smart
|
|
3
|
+
* speed, per-speaker pace, skip ad reads. Ported from extension-library
|
|
4
|
+
* FEATURES.md §The rate composer.
|
|
3
5
|
*
|
|
4
|
-
*
|
|
5
|
-
* composer") — this is the one non-obvious rule, stated up front because it
|
|
6
|
-
* looks like a bug from the outside:
|
|
6
|
+
* rate = base × speaker × silence (clamp [0.0625, 16], 0.001 deadband)
|
|
7
7
|
*
|
|
8
|
-
*
|
|
9
|
-
* · you — the speed keys (−/=/Backspace, alt+wheel)
|
|
10
|
-
* · speaker — "this person talks fast" (mos-5lzns.32 fills)
|
|
11
|
-
* · silence — "nothing is being said here" (mos-5lzns.32 fills)
|
|
8
|
+
* `base` is the only factor a human chose and the only one the UI reports.
|
|
12
9
|
*
|
|
13
|
-
*
|
|
10
|
+
* Layout (every file pure and node-testable — `npm run test:unit`):
|
|
14
11
|
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
* staircase) — it returns early, before any multiplication, because no
|
|
25
|
-
* advisor gets to un-pause the video by multiplying its way out of zero.
|
|
26
|
-
* 3. Only real changes are written. `playbackRate` is a live audio
|
|
27
|
-
* parameter: writing a *slightly* different value is audible as a wobble.
|
|
28
|
-
* Hence the 0.001 deadband.
|
|
29
|
-
* 4. The clamp is [0.0625, 16] — the range HTML media elements actually
|
|
30
|
-
* support. A product of three multipliers can leave it; a single one
|
|
31
|
-
* cannot.
|
|
32
|
-
*
|
|
33
|
-
* The SPEED_STEPS staircase and formatSpeedLabel are ported from the
|
|
34
|
-
* extension's theater (linear 0.1 steps below 1×, all the way down to 0 —
|
|
35
|
-
* playbackRate=0 is a genuine frozen frame; above 1× the familiar jumps).
|
|
36
|
-
*/
|
|
37
|
-
/** The speed staircase — one step per press of −/=, Backspace resets to 1. */
|
|
38
|
-
export const SPEED_STEPS = [
|
|
39
|
-
0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1, 1.1, 1.2, 1.3, 1.4, 1.5, 1.75, 2, 2.5, 5, 10
|
|
40
|
-
];
|
|
41
|
-
/**
|
|
42
|
-
* "A quarter speed" reads faster as "−.75" than "0.25×" — below 1× the label
|
|
43
|
-
* is the delta, not the multiplier. The 0 step is the frozen-frame end of the
|
|
44
|
-
* staircase — a state, not a level — and the label says so ("0×"), because a
|
|
45
|
-
* frozen frame labeled "1×" lies. Garbage degrades to `1×`.
|
|
46
|
-
*/
|
|
47
|
-
export function formatSpeedLabel(rate) {
|
|
48
|
-
if (!Number.isFinite(rate) || rate < 0)
|
|
49
|
-
return '1×';
|
|
50
|
-
if (rate === 0)
|
|
51
|
-
return '0×';
|
|
52
|
-
if (rate < 1) {
|
|
53
|
-
return (rate - 1).toFixed(2).replace(/\.?0+$/, '').replace(/^-0\./, '-.') + '×';
|
|
54
|
-
}
|
|
55
|
-
return rate.toFixed(2).replace(/\.?0+$/, '') + '×';
|
|
56
|
-
}
|
|
57
|
-
/**
|
|
58
|
-
* One step along the staircase. Unknown current rate snaps to 1 first (a
|
|
59
|
-
* hand-set rate off the staircase still steps from where the user expects).
|
|
60
|
-
*/
|
|
61
|
-
export function stepRate(current, direction) {
|
|
62
|
-
const i = SPEED_STEPS.indexOf(current);
|
|
63
|
-
const cur = i === -1 ? SPEED_STEPS.indexOf(1) : i;
|
|
64
|
-
return SPEED_STEPS[Math.min(SPEED_STEPS.length - 1, Math.max(0, cur + direction))];
|
|
65
|
-
}
|
|
66
|
-
/** The clamp the composer applies — the range HTML media elements actually support. */
|
|
67
|
-
export const RATE_MIN = 0.0625;
|
|
68
|
-
export const RATE_MAX = 16;
|
|
69
|
-
/** Writes only on real change — a slightly-different write is audible as a wobble. */
|
|
70
|
-
export const RATE_DEADBAND = 0.001;
|
|
71
|
-
/**
|
|
72
|
-
* The whole arbitration. `speaker` and `silence` are advisor products in
|
|
73
|
-
* [0.0625, 16] that COLLAPSE TO 1 when their feature is off or its data has
|
|
74
|
-
* not arrived — mos-5lzns.32 fills both; until then they are always 1 and
|
|
75
|
-
* this is exactly `base`.
|
|
76
|
-
*
|
|
77
|
-
* `base === 0` returns early: a frozen frame is a state, not a level.
|
|
12
|
+
* · rate/compose.ts — the contract: SPEED_STEPS staircase, formatSpeedLabel,
|
|
13
|
+
* composeRate (base 0 is a state, advisors collapse to 1, clamp), and
|
|
14
|
+
* shouldWriteRate (deadband, except an exact return to base).
|
|
15
|
+
* · rate/speaker.ts — props → advisors/speaker-rate; manual rates keyed by
|
|
16
|
+
* NAME always beat measured ones.
|
|
17
|
+
* · rate/silence.ts — waveform → advisors/smart-speed map + boost factor.
|
|
18
|
+
* · rate/ads.ts — adSpans ∪ `ad: true` turns; skip only when PLAYBACK
|
|
19
|
+
* runs into an ad, never when a seek lands in one.
|
|
20
|
+
* · rate/tick.ts — the 120ms loop's one-tick decision.
|
|
78
21
|
*/
|
|
79
|
-
export
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
const si = Number.isFinite(silence) && silence > 0 ? silence : 1;
|
|
85
|
-
const rate = Math.min(RATE_MAX, Math.max(RATE_MIN, base * sp * si));
|
|
86
|
-
const changed = Math.abs(rate - base) > RATE_DEADBAND;
|
|
87
|
-
return { rate: changed ? rate : base, changed };
|
|
88
|
-
}
|
|
22
|
+
export * from './rate/compose';
|
|
23
|
+
export * from './rate/speaker';
|
|
24
|
+
export * from './rate/silence';
|
|
25
|
+
export * from './rate/ads';
|
|
26
|
+
export * from './rate/tick';
|
package/dist/video/settings.js
CHANGED
|
@@ -40,7 +40,14 @@ export const VIDEO_SETTINGS = [
|
|
|
40
40
|
{ id: 'audio.target', type: 'range', default: -20, min: -30, max: -12, step: 2, owner: 'mos-5lzns.31', wired: true },
|
|
41
41
|
{ id: 'audio.quiet', type: 'bool', default: true, owner: 'mos-5lzns.31', wired: true },
|
|
42
42
|
{ id: 'audio.limiter', type: 'bool', default: true, owner: 'mos-5lzns.31', wired: true },
|
|
43
|
-
//
|
|
43
|
+
// Read by VideoPlayer's `smartSpeed` / `speakerPace` (+ `speakerRates`) /
|
|
44
|
+
// `skipAds` (+ `adSpans`) props → video/rate/* (silenceMapFor + silenceFactor,
|
|
45
|
+
// speakerRateMap + speakerFactor, normalizeAdSpans + adSkipTarget), composed
|
|
46
|
+
// by rate/compose.ts composeRate. All default off: an automatic rate change
|
|
47
|
+
// is the host's opt-in.
|
|
48
|
+
{ id: 'player.smartSpeed', type: 'bool', default: false, owner: 'mos-5lzns.32', wired: true },
|
|
49
|
+
{ id: 'player.speakerRate', type: 'bool', default: false, owner: 'mos-5lzns.32', wired: true },
|
|
50
|
+
{ id: 'player.skipAds', type: 'bool', default: false, owner: 'mos-5lzns.32', wired: true },
|
|
44
51
|
// Read by VideoPlayer's `night` / `nightDepth` / `biasLight` / `predictive` /
|
|
45
52
|
// `strobeGuard` props → video/night/* (clock.nightArmed, levels.nightLevels,
|
|
46
53
|
// meter.biasCells, track.lumaAhead / inFlash / composeNight). Unlike the
|
|
@@ -51,7 +58,23 @@ export const VIDEO_SETTINGS = [
|
|
|
51
58
|
{ id: 'night.bias', type: 'bool', default: true, owner: 'mos-5lzns.33', wired: true },
|
|
52
59
|
{ id: 'player.predictive', type: 'bool', default: true, owner: 'mos-5lzns.33', wired: true },
|
|
53
60
|
{ id: 'player.strobeGuard', type: 'bool', default: true, owner: 'mos-5lzns.33', wired: true },
|
|
54
|
-
//
|
|
61
|
+
// Read by VideoPlayer's `windDown` / `windDownAfter` / `windDownNightOnly` /
|
|
62
|
+
// `idleDetection` props → video/presence/winddown.ts (shouldBeginWindDown,
|
|
63
|
+
// windDownAfterMs) + presence/idle.ts (startDesktopWatch). As with night,
|
|
64
|
+
// the DEFAULT is the host's opt-in: an absent `windDown` prop means the
|
|
65
|
+
// feature does not exist on that player. `sleep.desktopIdle` defaults OFF
|
|
66
|
+
// because turning it on is what asks the browser for a permission — the
|
|
67
|
+
// host calls `requestIdleDetection()` from the click that turns it on.
|
|
68
|
+
{ id: 'sleep.enabled', type: 'bool', default: true, owner: 'mos-5lzns.34', wired: true },
|
|
69
|
+
{ id: 'sleep.after', type: 'range', default: 30, min: 10, max: 90, step: 5, owner: 'mos-5lzns.34', wired: true },
|
|
70
|
+
{ id: 'sleep.nightOnly', type: 'bool', default: true, owner: 'mos-5lzns.34', wired: true },
|
|
71
|
+
{ id: 'sleep.desktopIdle', type: 'bool', default: false, owner: 'mos-5lzns.34', wired: true },
|
|
72
|
+
// Read by VideoPlayer's `resumeSnap` prop (with `resumeKey` present) →
|
|
73
|
+
// video/presence/resume.ts planResumeSnap → advisors/resume-point snapResume.
|
|
74
|
+
{ id: 'player.resumeSnap', type: 'bool', default: true, owner: 'mos-5lzns.34', wired: true },
|
|
75
|
+
// Read by VideoPlayer's `openMotion` prop (with `openFrom` present) →
|
|
76
|
+
// video/presence/flip.ts flipOpen. Off ⇒ the poster still paints.
|
|
77
|
+
{ id: 'player.openMotion', type: 'bool', default: true, owner: 'mos-5lzns.34', wired: true },
|
|
55
78
|
];
|
|
56
79
|
/** Coerce a raw stored value against a spec — never throws, never returns junk. */
|
|
57
80
|
export function coerce(spec, raw) {
|