@streamlayer/web-os 0.1.2 → 0.2.1

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/README.md CHANGED
@@ -1,3 +1,231 @@
1
- # web-os
1
+ # StreamLayerSDKTv Pause Ad Integration
2
2
 
3
- This library was generated with [Nx](https://nx.dev).
3
+ > **Alpha Version**: This feature is currently in alpha. Expect potential instability, including occasional freezes.
4
+
5
+ ## Prerequisites
6
+
7
+ ### 1. PAL SDK
8
+
9
+ Add the Google PAL SDK to your HTML `<head>`:
10
+
11
+ ```html
12
+ <script type="text/javascript" src="https://imasdk.googleapis.com/pal/sdkloader/pal.js"></script>
13
+ ```
14
+
15
+ ### 2. Spatial Navigation
16
+
17
+ This feature uses [@noriginmedia/norigin-spatial-navigation](https://github.com/nicetechnologies/norigin-spatial-navigation) with `shouldFocusDOMNode: true` mode for remote control support.
18
+
19
+ ---
20
+
21
+ ## Integration
22
+
23
+ ### Props
24
+
25
+ | Prop | Type | Description |
26
+ |------|------|-------------|
27
+ | `showPauseAd` | `boolean` | Controls pause ad visibility. Set to `true` when video pauses. |
28
+ | `onRenderPauseAd` | `(params: { rendered: boolean }) => void` | Called when pause ad overlay renders. Use to hide your UI elements. |
29
+ | `onClosePauseAd` | `() => void` | Called when pause ad closes without resuming video (user dismissed overlay). |
30
+ | `videoPlayerController` | `VideoPlayerCallback` | Called when user resumes video via the pause ad overlay button. |
31
+ | `pauseAdVastUrl` | `Array<{ template: string; url: string }>` | VAST tag configuration. |
32
+
33
+ ### pauseAdVastUrl Configuration
34
+
35
+ ```typescript
36
+ pauseAdVastUrl={[
37
+ {
38
+ template: 'default', // Currently only 'default' template is supported
39
+ url: 'https://your-vast-tag-url.com/vast.xml',
40
+ },
41
+ ]}
42
+ ```
43
+
44
+ > **Note**: Only the first item in the array is used. Multi-item rotation is not yet supported.
45
+
46
+ ---
47
+
48
+ ## Understanding `showPauseAd` vs `pauseAdRendered`
49
+
50
+ These two flags serve different purposes and are controlled by different parties:
51
+
52
+ | Flag | Controlled By | Purpose |
53
+ |------|---------------|---------|
54
+ | `showPauseAd` | **You (integrator)** | Request to show/hide pause ad |
55
+ | `pauseAdRendered` | **SDK (via callback)** | Actual visibility state on screen |
56
+
57
+ ### Why two flags?
58
+
59
+ **`showPauseAd`** is your *intent* — "I want the pause ad to appear/disappear."
60
+
61
+ **`pauseAdRendered`** is the *actual state* — "The pause ad is currently visible on screen."
62
+
63
+ These values don't always match due to **animation delays**:
64
+
65
+ - **Opening delay (5 seconds)**: SDK waits before showing the overlay
66
+ - **Closing delay (400ms)**: SDK animates the overlay before removing it
67
+
68
+ ### State combinations
69
+
70
+ | `showPauseAd` | `pauseAdRendered` | State |
71
+ |---------------|-------------------|-------|
72
+ | `false` | `false` | Video playing or paused without ad |
73
+ | `true` | `false` | Video paused, SDK preparing overlay (5s delay) |
74
+ | `true` | `true` | Pause ad visible on screen |
75
+ | `false` | `true` | **Closing animation in progress (400ms)** |
76
+
77
+ ### Timeline
78
+
79
+ ```
80
+ Video pauses
81
+
82
+
83
+ showPauseAd = true ← You set this on video pause
84
+ pauseAdRendered = false
85
+
86
+ │ ← 5 second delay (SDK loads ad, prepares overlay)
87
+
88
+ showPauseAd = true
89
+ pauseAdRendered = true ← SDK calls onRenderPauseAd({ rendered: true })
90
+ Hide your UI controls now
91
+
92
+ │ ← User resumes video or closes overlay
93
+
94
+ showPauseAd = false ← You set this on play/close
95
+ pauseAdRendered = true ← Still true! Closing animation playing
96
+
97
+ │ ← 400ms closing animation
98
+
99
+ showPauseAd = false
100
+ pauseAdRendered = false ← SDK calls onRenderPauseAd({ rendered: false })
101
+ Safe to show your UI controls
102
+ ```
103
+
104
+ ### Why this matters
105
+
106
+ Always use `pauseAdRendered` to control your UI visibility:
107
+
108
+ ```tsx
109
+ // Correct: hide UI based on actual render state
110
+ const showControls = !pauseAdRendered
111
+
112
+ // This ensures:
113
+ // 1. Your controls don't disappear 5s before the ad appears
114
+ // 2. Your controls don't reappear during the 400ms closing animation
115
+ ```
116
+
117
+ If you used `showPauseAd` instead, your controls would:
118
+ - Disappear immediately on pause (5s before the ad shows)
119
+ - Reappear during the closing animation (overlapping with the ad)
120
+
121
+ ---
122
+
123
+ ## Implementation Example
124
+
125
+ ```tsx
126
+ import { useState, useCallback, useRef } from 'react'
127
+ import { StreamLayerSDKTv, type VideoPlayerCallback } from '@streamlayer/sdk-web-os'
128
+
129
+ export const VideoView = () => {
130
+ const [showPauseAd, setShowPauseAd] = useState(false)
131
+ const [pauseAdRendered, setPauseAdRendered] = useState(false)
132
+ const videoRef = useRef<HTMLVideoElement>(null)
133
+
134
+ // Called when pause ad overlay renders/hides
135
+ const onRenderPauseAd = useCallback((params: { rendered: boolean }) => {
136
+ setPauseAdRendered(params.rendered)
137
+ }, [])
138
+
139
+ // Called when pause ad closes without video resumption
140
+ const onClosePauseAd = useCallback(() => {
141
+ setShowPauseAd(false)
142
+ }, [])
143
+
144
+ // Called when user clicks resume on pause ad overlay
145
+ const videoPlayerController: VideoPlayerCallback = useCallback((data) => {
146
+ if (data.play === true) {
147
+ videoRef.current?.play()
148
+ }
149
+ }, [])
150
+
151
+ // Video event handlers
152
+ const onVideoPause = useCallback(() => {
153
+ setShowPauseAd(true)
154
+ }, [])
155
+
156
+ const onVideoPlay = useCallback(() => {
157
+ setShowPauseAd(false)
158
+ }, [])
159
+
160
+ // Hide your UI controls when pause ad is rendered
161
+ const showControls = !pauseAdRendered
162
+
163
+ return (
164
+ <StreamLayerSDKTv
165
+ showPauseAd={showPauseAd}
166
+ onRenderPauseAd={onRenderPauseAd}
167
+ onClosePauseAd={onClosePauseAd}
168
+ videoPlayerController={videoPlayerController}
169
+ pauseAdVastUrl={[
170
+ {
171
+ template: 'default',
172
+ url: 'https://your-vast-tag-url.com',
173
+ },
174
+ ]}
175
+ >
176
+ {/* Your video container */}
177
+ <div>
178
+ <video
179
+ ref={videoRef}
180
+ onPause={onVideoPause}
181
+ onPlay={onVideoPlay}
182
+ />
183
+
184
+ {/* Hide controls when pause ad is displayed */}
185
+ {showControls && (
186
+ <div className="video-controls">
187
+ {/* Play button, timeline, etc. */}
188
+ </div>
189
+ )}
190
+ </div>
191
+ </StreamLayerSDKTv>
192
+ )
193
+ }
194
+ ```
195
+
196
+ ---
197
+
198
+ ## Lifecycle Flow
199
+
200
+ ```
201
+ Video Pauses
202
+
203
+
204
+ setShowPauseAd(true) ──► StreamLayerSDKTv receives showPauseAd=true
205
+
206
+
207
+ onRenderPauseAd({ rendered: true })
208
+
209
+
210
+ Hide your UI (controls, timeline, etc.)
211
+
212
+ ┌───────────────────────┴───────────────────────┐
213
+ ▼ ▼
214
+ User clicks RESUME User closes overlay
215
+ │ │
216
+ ▼ ▼
217
+ videoPlayerController({ play: true }) onClosePauseAd()
218
+ │ │
219
+ ▼ ▼
220
+ Resume video playback setShowPauseAd(false)
221
+ setShowPauseAd(false) (video stays paused)
222
+ ```
223
+
224
+ ---
225
+
226
+ ## Key Points
227
+
228
+ 1. **You control `showPauseAd`**: Set it to `true` on video pause, `false` on play/resume.
229
+ 2. **Hide UI on render**: When `onRenderPauseAd` fires with `rendered: true`, hide your video controls (play button, timeline, etc.).
230
+ 3. **Handle both exit paths**: User can either resume video (via `videoPlayerController`) or dismiss the overlay (via `onClosePauseAd`).
231
+ 4. **Single VAST tag**: Only one item in `pauseAdVastUrl` is processed; additional items are ignored.