@ume-group/contracts 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.
Files changed (57) hide show
  1. package/README.md +37 -0
  2. package/dist/adserving.d.ts +150 -0
  3. package/dist/adserving.d.ts.map +1 -0
  4. package/dist/adserving.js +8 -0
  5. package/dist/campaigns.d.ts +37 -0
  6. package/dist/campaigns.d.ts.map +1 -0
  7. package/dist/campaigns.js +8 -0
  8. package/dist/gausst.d.ts +236 -0
  9. package/dist/gausst.d.ts.map +1 -0
  10. package/dist/gausst.js +307 -0
  11. package/dist/gausst.test.d.ts +2 -0
  12. package/dist/gausst.test.d.ts.map +1 -0
  13. package/dist/gausst.test.js +71 -0
  14. package/dist/index.d.ts +1531 -0
  15. package/dist/index.d.ts.map +1 -0
  16. package/dist/index.js +1112 -0
  17. package/dist/layer2/index.d.ts +9 -0
  18. package/dist/layer2/index.d.ts.map +1 -0
  19. package/dist/layer2/index.js +10 -0
  20. package/dist/layer2/shaders.d.ts +185 -0
  21. package/dist/layer2/shaders.d.ts.map +1 -0
  22. package/dist/layer2/shaders.js +604 -0
  23. package/dist/layer2/webcam-utils.d.ts +113 -0
  24. package/dist/layer2/webcam-utils.d.ts.map +1 -0
  25. package/dist/layer2/webcam-utils.js +147 -0
  26. package/dist/layer2/webcam-utils.test.d.ts +2 -0
  27. package/dist/layer2/webcam-utils.test.d.ts.map +1 -0
  28. package/dist/layer2/webcam-utils.test.js +18 -0
  29. package/dist/layer2.d.ts +558 -0
  30. package/dist/layer2.d.ts.map +1 -0
  31. package/dist/layer2.js +376 -0
  32. package/dist/layer2.test.d.ts +2 -0
  33. package/dist/layer2.test.d.ts.map +1 -0
  34. package/dist/layer2.test.js +65 -0
  35. package/dist/perspective.d.ts +28 -0
  36. package/dist/perspective.d.ts.map +1 -0
  37. package/dist/perspective.js +157 -0
  38. package/dist/segmentation/MediaPipeSegmenter.d.ts +201 -0
  39. package/dist/segmentation/MediaPipeSegmenter.d.ts.map +1 -0
  40. package/dist/segmentation/MediaPipeSegmenter.js +434 -0
  41. package/dist/segmentation/index.d.ts +5 -0
  42. package/dist/segmentation/index.d.ts.map +1 -0
  43. package/dist/segmentation/index.js +4 -0
  44. package/dist/webcam/GarbageMatteDragManager.d.ts +63 -0
  45. package/dist/webcam/GarbageMatteDragManager.d.ts.map +1 -0
  46. package/dist/webcam/GarbageMatteDragManager.js +183 -0
  47. package/dist/webcam/WebcamStreamManager.d.ts +103 -0
  48. package/dist/webcam/WebcamStreamManager.d.ts.map +1 -0
  49. package/dist/webcam/WebcamStreamManager.js +356 -0
  50. package/dist/webcam/index.d.ts +5 -0
  51. package/dist/webcam/index.d.ts.map +1 -0
  52. package/dist/webcam/index.js +2 -0
  53. package/openapi/admetise.yaml +632 -0
  54. package/openapi/includu.yaml +621 -0
  55. package/openapi/integration.yaml +372 -0
  56. package/openapi/shared/schemas.yaml +227 -0
  57. package/package.json +53 -0
@@ -0,0 +1,1531 @@
1
+ /**
2
+ * Shared types for Includu Platform
3
+ *
4
+ * Used by:
5
+ * - @includu/editor (timeline editor)
6
+ * - @includu/cms (video library)
7
+ */
8
+ /**
9
+ * Debug flag - true in Vite dev mode, false in production builds.
10
+ * Can also be set manually for testing.
11
+ */
12
+ export declare let DEBUG: boolean;
13
+ /** Override the DEBUG flag (useful for testing or manual control) */
14
+ export declare function setDebug(value: boolean): void;
15
+ /** Debug logger - only outputs when DEBUG is true (dev mode by default) */
16
+ export declare function debug(...args: unknown[]): void;
17
+ /**
18
+ * A video clip from any source (CMS, YouTube, etc.)
19
+ */
20
+ export interface VideoClip {
21
+ /** Unique identifier */
22
+ id: string;
23
+ /** Display title */
24
+ title: string;
25
+ /** Optional description */
26
+ description?: string;
27
+ /** Duration in seconds */
28
+ duration: number;
29
+ /** Thumbnail URL */
30
+ thumbnail?: string;
31
+ /** HLS manifest URL for playback */
32
+ hlsUrl: string;
33
+ /** Original source type */
34
+ sourceType: 'cms' | 'youtube' | 'vimeo' | 'url';
35
+ /** Source-specific identifier (e.g., Cloudflare Stream UID) */
36
+ sourceId?: string;
37
+ /** Creation timestamp */
38
+ createdAt: string;
39
+ /** Last updated timestamp */
40
+ updatedAt: string;
41
+ }
42
+ /**
43
+ * Video clip with CMS-specific metadata
44
+ */
45
+ export interface CMSVideoClip extends VideoClip {
46
+ sourceType: 'cms';
47
+ /** Cloudflare Stream video UID */
48
+ streamUid: string;
49
+ /** Processing status */
50
+ status: 'uploading' | 'processing' | 'ready' | 'error';
51
+ /** Upload progress (0-100) */
52
+ uploadProgress?: number;
53
+ /** Tags for organization */
54
+ tags: string[];
55
+ /** Original filename */
56
+ originalFilename?: string;
57
+ /** File size in bytes */
58
+ fileSize?: number;
59
+ }
60
+ /**
61
+ * Live stream input
62
+ */
63
+ export interface LiveStream {
64
+ id: string;
65
+ title: string;
66
+ description?: string;
67
+ /** SRT ingest URL */
68
+ srtUrl: string;
69
+ /** HLS playback URL (when live) */
70
+ hlsUrl?: string;
71
+ /** Stream status */
72
+ status: 'idle' | 'connecting' | 'live' | 'ended';
73
+ /** Cloudflare Stream live input ID */
74
+ streamInputId: string;
75
+ createdAt: string;
76
+ }
77
+ export type OverlayType = 'text' | 'emoji' | 'shape' | 'image' | 'cta' | 'sprite-sequence' | 'video';
78
+ /** Track type for overlays - determines which timeline track they appear on */
79
+ export type OverlayTrack = 'overlays' | 'branding' | 'motion-gfx';
80
+ export interface TextContent {
81
+ text: string;
82
+ fontSize: number;
83
+ fontFamily: string;
84
+ fontWeight: 'normal' | 'bold';
85
+ color: string;
86
+ textAlign: 'left' | 'center' | 'right';
87
+ /**
88
+ * Background plane properties (independent from text transform)
89
+ * When present, background is rendered as a separate layer that can be scaled independently
90
+ */
91
+ background?: {
92
+ /** Background color (hex or rgba) */
93
+ color: string;
94
+ /** Background opacity (0-1), default 1 */
95
+ opacity?: number;
96
+ /** Padding around text as percentage of overlay size */
97
+ padding?: {
98
+ x: number;
99
+ y: number;
100
+ };
101
+ /** Independent scale multiplier for background plane (default 1.0) */
102
+ scale?: number;
103
+ /** Corner radius in pixels */
104
+ borderRadius?: number;
105
+ };
106
+ /**
107
+ * Text offset within the background plane
108
+ * Allows positioning text independently from its background
109
+ */
110
+ textOffset?: {
111
+ /** Horizontal offset as percentage of background width (-50 to 50) */
112
+ x: number;
113
+ /** Vertical offset as percentage of background height (-50 to 50) */
114
+ y: number;
115
+ };
116
+ /** @deprecated Use background.color instead */
117
+ backgroundColor?: string;
118
+ }
119
+ export interface EmojiContent {
120
+ emoji: string;
121
+ size: number;
122
+ }
123
+ export interface ShapeContent {
124
+ shape: 'rectangle' | 'circle' | 'arrow';
125
+ fillColor: string;
126
+ fillOpacity: number;
127
+ strokeColor: string;
128
+ strokeWidth: number;
129
+ cornerRadius?: number;
130
+ }
131
+ export interface ImageContent {
132
+ src: string;
133
+ alt?: string;
134
+ fit: 'contain' | 'cover' | 'fill';
135
+ opacity?: number;
136
+ borderRadius?: number;
137
+ /** Optional click URL to make the image clickable */
138
+ clickUrl?: string;
139
+ }
140
+ export interface CTAContent {
141
+ text: string;
142
+ url: string;
143
+ newTab: boolean;
144
+ style: {
145
+ backgroundColor: string;
146
+ textColor: string;
147
+ borderRadius: number;
148
+ fontSize: number;
149
+ fontWeight: 'normal' | 'bold';
150
+ padding: {
151
+ x: number;
152
+ y: number;
153
+ };
154
+ };
155
+ hoverStyle?: {
156
+ backgroundColor?: string;
157
+ textColor?: string;
158
+ };
159
+ }
160
+ /**
161
+ * Sprite sequence overlay content for animated image sequences
162
+ *
163
+ * Renders pre-rendered image sequences (sprite sheets) as animated overlays.
164
+ * Supports both grid layouts (columns × rows) and horizontal strips.
165
+ *
166
+ * Animation is driven by CSS background-position, independent of video FPS.
167
+ *
168
+ * @example Grid layout (4×4 = 16 frames):
169
+ * { frameWidth: 256, frameHeight: 256, frameCount: 16, columns: 4 }
170
+ *
171
+ * @example Horizontal strip (12 frames in a row):
172
+ * { frameWidth: 128, frameHeight: 128, frameCount: 12, columns: 12 }
173
+ */
174
+ export interface SpriteSequenceContent {
175
+ /**
176
+ * URL to the sprite sheet image
177
+ * Supports R2 upload URLs or external URLs
178
+ */
179
+ spritesheetUrl: string;
180
+ /** Width of a single frame in pixels */
181
+ frameWidth: number;
182
+ /** Height of a single frame in pixels */
183
+ frameHeight: number;
184
+ /** Total number of frames in the sprite sheet */
185
+ frameCount: number;
186
+ /**
187
+ * Number of frames per row (columns)
188
+ * - For grid layout: columns × rows = frameCount
189
+ * - For horizontal strip: columns = frameCount
190
+ */
191
+ columns: number;
192
+ /**
193
+ * Sprite animation frames per second
194
+ * Independent of video FPS - sprite animates at its own rate
195
+ */
196
+ framesPerSecond: number;
197
+ /** Loop the animation (default: true) */
198
+ loop: boolean;
199
+ /**
200
+ * Play forward then backward (ping-pong)
201
+ * When true: 0,1,2,3,2,1,0,1,2...
202
+ */
203
+ pingPong?: boolean;
204
+ /**
205
+ * Which frame to start on (0-indexed, default: 0)
206
+ */
207
+ startFrame?: number;
208
+ /** Opacity 0-1 (default: 1) */
209
+ opacity?: number;
210
+ /**
211
+ * CSS filter for color tinting
212
+ * Example: "hue-rotate(90deg)" or "sepia(1) saturate(5) hue-rotate(300deg)"
213
+ */
214
+ tintFilter?: string;
215
+ }
216
+ /**
217
+ * Video overlay content - for WebM/MP4 with alpha channel support
218
+ * Used for motion graphics, animated effects, and video compositing
219
+ */
220
+ export interface VideoContent {
221
+ /**
222
+ * URL to the video file
223
+ * Supports WebM (VP9 with alpha), MP4, or any browser-supported format
224
+ */
225
+ videoUrl: string;
226
+ /** Loop the video (default: true) */
227
+ loop: boolean;
228
+ /** Mute the video audio (default: true for motion graphics) */
229
+ muted: boolean;
230
+ /**
231
+ * Playback rate (1.0 = normal speed)
232
+ * Range: 0.25 to 4.0
233
+ */
234
+ playbackRate?: number;
235
+ /**
236
+ * Start time offset in seconds
237
+ * Use to skip to a specific part of the video
238
+ */
239
+ startTime?: number;
240
+ /** Opacity 0-1 (default: 1) */
241
+ opacity?: number;
242
+ /** Object fit mode for video within container */
243
+ fit?: 'contain' | 'cover' | 'fill';
244
+ /**
245
+ * CSS filter for color effects
246
+ * Example: "brightness(1.2)" or "hue-rotate(90deg)"
247
+ */
248
+ filter?: string;
249
+ }
250
+ export type OverlayContent = TextContent | EmojiContent | ShapeContent | ImageContent | CTAContent | SpriteSequenceContent | VideoContent;
251
+ export interface OverlayPosition {
252
+ x: number;
253
+ y: number;
254
+ width: number;
255
+ height: number;
256
+ }
257
+ /**
258
+ * Animation entrance/exit type
259
+ * - 'none': No animation (instant appear/disappear)
260
+ * - 'fade': Opacity fade (current default)
261
+ * - 'slide-left': Slide in from left / out to left
262
+ * - 'slide-right': Slide in from right / out to right
263
+ * - 'slide-top': Slide in from top / out to top
264
+ * - 'slide-bottom': Slide in from bottom / out to bottom
265
+ */
266
+ export type AnimationType = 'none' | 'fade' | 'scale' | 'slide-left' | 'slide-right' | 'slide-top' | 'slide-bottom';
267
+ export interface OverlayAnimation {
268
+ opacity: number;
269
+ fadeIn: number;
270
+ fadeOut: number;
271
+ /** Entrance animation type (default: 'fade') */
272
+ entranceType?: AnimationType;
273
+ /** Exit animation type (default: 'fade') */
274
+ exitType?: AnimationType;
275
+ }
276
+ /**
277
+ * Corner point in normalized coordinates (0-1 range)
278
+ * Relative to the video content area
279
+ */
280
+ export interface CornerPoint {
281
+ x: number;
282
+ y: number;
283
+ }
284
+ /**
285
+ * Corner offset - relative adjustment from the natural corner position
286
+ * Values are in percentage of the overlay's dimensions
287
+ */
288
+ export interface CornerOffset {
289
+ dx: number;
290
+ dy: number;
291
+ }
292
+ /**
293
+ * Four corner offsets for perspective fine-tuning
294
+ * These are RELATIVE adjustments on top of the overlay's position/size
295
+ */
296
+ export interface CornerOffsets {
297
+ tl: CornerOffset;
298
+ tr: CornerOffset;
299
+ br: CornerOffset;
300
+ bl: CornerOffset;
301
+ }
302
+ /**
303
+ * Four corners defining perspective quad (absolute positions)
304
+ * Order: top-left, top-right, bottom-right, bottom-left (clockwise)
305
+ * @deprecated Use CornerOffsets for new code - corners are computed from position + offsets
306
+ */
307
+ export interface CornerPoints {
308
+ tl: CornerPoint;
309
+ tr: CornerPoint;
310
+ br: CornerPoint;
311
+ bl: CornerPoint;
312
+ }
313
+ /**
314
+ * Perspective transform configuration for corner pinning
315
+ *
316
+ * Corner pinning is a FINE-TUNING layer on top of regular transforms:
317
+ * 1. Position/scale/rotate sets the base overlay bounds
318
+ * 2. Corner offsets apply small perspective adjustments
319
+ *
320
+ * @see https://github.com/uMe-Group/Includu/issues/58
321
+ */
322
+ export interface PerspectiveTransform {
323
+ /** Whether perspective transform is enabled */
324
+ enabled: boolean;
325
+ /**
326
+ * Corner offsets - relative adjustments from natural corner positions
327
+ * Values are percentages of the overlay's dimensions
328
+ * Default: all zeros (no perspective adjustment)
329
+ * Optional for backward compatibility - if missing, use corners or default to zeros
330
+ */
331
+ cornerOffsets?: CornerOffsets;
332
+ /**
333
+ * @deprecated Use cornerOffsets instead
334
+ * Kept for backward compatibility with existing saved projects
335
+ */
336
+ corners?: CornerPoints;
337
+ }
338
+ /**
339
+ * Creates default corner offsets (no perspective adjustment)
340
+ */
341
+ export declare function createDefaultCornerOffsets(): CornerOffsets;
342
+ /**
343
+ * Computes absolute corner positions from overlay position and corner offsets
344
+ * This is how corners are calculated for rendering
345
+ */
346
+ export declare function computeCornersFromOffsets(position: OverlayPosition, offsets: CornerOffsets): CornerPoints;
347
+ /**
348
+ * @deprecated Use createDefaultCornerOffsets instead
349
+ * Creates default corner points for a rectangular overlay
350
+ * Uses the overlay's position to calculate initial corner positions
351
+ */
352
+ export declare function createDefaultCornerPoints(position: OverlayPosition): CornerPoints;
353
+ /**
354
+ * Migrate old absolute corners to new offset-based format
355
+ * Call this when loading projects with old corner format
356
+ */
357
+ export declare function migrateToCornerOffsets(position: OverlayPosition, corners: CornerPoints): CornerOffsets;
358
+ export interface Overlay {
359
+ id: string;
360
+ /** Display name in the timeline */
361
+ label: string;
362
+ type: OverlayType;
363
+ /** Which timeline track this overlay belongs to (default: 'overlays') */
364
+ track?: OverlayTrack;
365
+ /** First frame where overlay is visible (inclusive) */
366
+ startFrame: number;
367
+ /** First frame where overlay is NOT visible (exclusive) */
368
+ endFrame: number;
369
+ /** Timeline bar color */
370
+ color?: string;
371
+ position: OverlayPosition;
372
+ animation: OverlayAnimation;
373
+ content: OverlayContent;
374
+ /** Optional perspective transform for corner pinning */
375
+ perspective?: PerspectiveTransform;
376
+ /**
377
+ * Z-axis rotation in degrees (0-360)
378
+ * Only applied when rotationEnabled is true
379
+ */
380
+ rotation?: number;
381
+ /**
382
+ * X-axis rotation in degrees (-60 to +60)
383
+ * Tilts forward/backward (CSS rotateX)
384
+ * Only applied when rotationEnabled is true
385
+ */
386
+ rotationX?: number;
387
+ /**
388
+ * Y-axis rotation in degrees (-60 to +60)
389
+ * Tilts left/right (CSS rotateY)
390
+ * Only applied when rotationEnabled is true
391
+ */
392
+ rotationY?: number;
393
+ /**
394
+ * Whether rotation is enabled (opt-in toggle)
395
+ * Default: false
396
+ */
397
+ rotationEnabled?: boolean;
398
+ }
399
+ /**
400
+ * Video source reference stored with a project.
401
+ * Supports VMS (Cloudflare Stream), local, and R2 sources.
402
+ */
403
+ export interface VideoSource {
404
+ type: 'vms' | 'local' | 'r2';
405
+ vmsClipId?: string;
406
+ vmsStreamUid?: string;
407
+ vmsHlsUrl?: string;
408
+ vmsTitle?: string;
409
+ vmsThumbnail?: string;
410
+ vmsWidth?: number;
411
+ vmsHeight?: number;
412
+ r2Key?: string;
413
+ }
414
+ /**
415
+ * Per-project monetization settings (creator-defined).
416
+ * Distinct from MonetizationConfig which is the published version.
417
+ */
418
+ export interface MonetizationSettings {
419
+ enabled: boolean;
420
+ revenueShare?: number;
421
+ restrictions?: AdRestrictions;
422
+ /** Whether 3D ads (Layer 2) are enabled */
423
+ layer2Enabled?: boolean;
424
+ /** Whether 2D ads are enabled */
425
+ layer2DEnabled?: boolean;
426
+ }
427
+ /**
428
+ * Metadata for multipart upload requests
429
+ */
430
+ export interface UploadMetadata {
431
+ projectId: string;
432
+ filename: string;
433
+ contentType: string;
434
+ size: number;
435
+ type: 'video' | 'proxy';
436
+ }
437
+ /** Subscription/access tier for a creator */
438
+ export type CreatorTier = 'free' | 'pro' | 'enterprise';
439
+ /**
440
+ * A creator account — the unified identity across Includu and Admetise.
441
+ *
442
+ * Auth-agnostic: the account stores profile data only.
443
+ * Authentication is handled externally (Cloudflare Access today, social login later).
444
+ *
445
+ * KV key patterns:
446
+ * - `creator:{id}` — primary record
447
+ * - `creator-email:{email}` — email → id index
448
+ * - `creator-slug:{slug}` — slug → id index
449
+ */
450
+ export interface CreatorAccount {
451
+ /** Unique creator ID (generated, URL-safe) */
452
+ id: string;
453
+ /** Email address (from auth provider, used as identity key) */
454
+ email: string;
455
+ /** Display name shown on channel pages and in the editor */
456
+ displayName: string;
457
+ /** URL-friendly slug for public channel (e.g., "jorgen" → play.includu.com/@jorgen) */
458
+ slug: string;
459
+ /** Avatar/profile image URL (R2 or external) */
460
+ avatarUrl?: string;
461
+ /** Short bio for channel pages */
462
+ bio?: string;
463
+ /** Subscription tier */
464
+ tier: CreatorTier;
465
+ /** Branding settings for published content */
466
+ branding?: CreatorBranding;
467
+ /** ISO 8601 */
468
+ createdAt: string;
469
+ /** ISO 8601 */
470
+ updatedAt: string;
471
+ }
472
+ /**
473
+ * Per-creator branding for published content.
474
+ * Stored on CreatorAccount, applied during publish.
475
+ */
476
+ export interface CreatorBranding {
477
+ /** Logo URL (R2 or external) — shown on player */
478
+ logoUrl?: string;
479
+ /** Watermark URL (R2 or external) — overlaid on recordings */
480
+ watermarkUrl?: string;
481
+ /** Primary brand color (hex, e.g. "#E53935") */
482
+ brandColor?: string;
483
+ /** Whether to show branding on published content */
484
+ enabled: boolean;
485
+ }
486
+ /**
487
+ * An Includu project - a set of overlay events for a video clip.
488
+ * This is the runtime storage format used by the API worker and KV store.
489
+ */
490
+ export interface Project {
491
+ id: string;
492
+ name: string;
493
+ /** Creator who owns this project (absent on legacy projects) */
494
+ creatorId?: string;
495
+ createdAt: string;
496
+ updatedAt: string;
497
+ /** R2 key for uploaded video (legacy) */
498
+ videoKey?: string;
499
+ /** R2 key for proxy video (legacy) */
500
+ proxyKey?: string;
501
+ /** Frames per second for timeline */
502
+ fps: number;
503
+ /** Video duration in seconds */
504
+ duration: number;
505
+ /** Overlay events */
506
+ overlays: Overlay[];
507
+ /** Video source reference */
508
+ videoSource?: VideoSource;
509
+ /** Ad slot placements (template-based, preferred) */
510
+ adPlacements?: AdSlotPlacement[];
511
+ /** @deprecated Use adPlacements instead - kept for backwards compatibility */
512
+ adSlots?: AdSlot[];
513
+ /** Monetization settings */
514
+ monetization?: MonetizationSettings;
515
+ /** Layer 2: 3D Composite scene. null explicitly clears the field. */
516
+ layer2Scene?: import('./layer2').Layer2Scene | null;
517
+ }
518
+ export interface PaginatedResponse<T> {
519
+ items: T[];
520
+ total: number;
521
+ page: number;
522
+ pageSize: number;
523
+ hasMore: boolean;
524
+ }
525
+ export interface ApiError {
526
+ error: string;
527
+ message: string;
528
+ status: number;
529
+ }
530
+ /**
531
+ * An overlay as stored in a published project
532
+ */
533
+ export interface PublishedOverlay {
534
+ id: string;
535
+ type: OverlayType;
536
+ /** First frame where overlay is visible (inclusive) */
537
+ startFrame: number;
538
+ /** First frame where overlay is NOT visible (exclusive) */
539
+ endFrame: number;
540
+ position: OverlayPosition;
541
+ animation: OverlayAnimation;
542
+ content: OverlayContent;
543
+ /** Optional perspective transform for corner pinning */
544
+ perspective?: PerspectiveTransform;
545
+ /** Z-axis rotation in degrees (0-360) */
546
+ rotation?: number;
547
+ /** X-axis rotation in degrees (-60 to +60) */
548
+ rotationX?: number;
549
+ /** Y-axis rotation in degrees (-60 to +60) */
550
+ rotationY?: number;
551
+ /** Whether rotation is enabled */
552
+ rotationEnabled?: boolean;
553
+ }
554
+ /**
555
+ * A published (immutable) version of a project for end-user playback
556
+ */
557
+ export interface PublishedProject {
558
+ /** Unique publish ID (nanoid, 10 chars) */
559
+ publishId: string;
560
+ /** Source project UUID */
561
+ projectId: string;
562
+ /** Display name */
563
+ name: string;
564
+ /** Video source information */
565
+ video: {
566
+ hlsUrl: string;
567
+ duration: number;
568
+ thumbnail?: string;
569
+ aspectRatio?: string;
570
+ };
571
+ /** Frames per second */
572
+ fps: number;
573
+ /** Overlay events */
574
+ overlays: PublishedOverlay[];
575
+ /** Publication timestamp (ISO 8601) */
576
+ publishedAt: string;
577
+ /** Publisher identifier (email or user ID) */
578
+ publishedBy: string;
579
+ /** Version number for tracking republishes */
580
+ version: number;
581
+ /** Optional branding configuration */
582
+ branding?: {
583
+ logo?: string;
584
+ accentColor?: string;
585
+ showPoweredBy?: boolean;
586
+ };
587
+ /** Monetization configuration (optional, for Admetise integration) */
588
+ monetization?: MonetizationConfig;
589
+ /** Layer 2 (3D composite) scene data */
590
+ layer2Scene?: import('./layer2').Layer2Scene;
591
+ }
592
+ /**
593
+ * Public manifest returned by the API for player consumption
594
+ */
595
+ export interface PublishedManifest {
596
+ publishId: string;
597
+ name: string;
598
+ video: {
599
+ hlsUrl: string;
600
+ duration: number;
601
+ thumbnail?: string;
602
+ aspectRatio?: string;
603
+ };
604
+ fps: number;
605
+ overlays: PublishedOverlay[];
606
+ branding?: {
607
+ logo?: string;
608
+ accentColor?: string;
609
+ showPoweredBy?: boolean;
610
+ };
611
+ links: {
612
+ player: string;
613
+ embed: string;
614
+ embedCode: string;
615
+ /** Participation URL (only if participation is enabled) */
616
+ participate?: string;
617
+ };
618
+ /** Monetization configuration (optional, for Admetise integration) */
619
+ monetization?: MonetizationConfig;
620
+ /** Layer 2 (3D composite) scene data */
621
+ layer2Scene?: import('./layer2').Layer2Scene;
622
+ /** Layer 2 player options */
623
+ layer2Options?: {
624
+ /** Show 3D ads in view-only mode (when not participating) */
625
+ show3DAdsInViewMode?: boolean;
626
+ /** Show participation preview silhouette for non-participants */
627
+ showParticipationPreview?: boolean;
628
+ };
629
+ /**
630
+ * Creator's webcam runtime settings for preview mode.
631
+ * When present, the player pre-loads these settings so the creator
632
+ * can instantly see their work without reconfiguring from scratch.
633
+ * Only set during preview, never during publish.
634
+ */
635
+ previewWebcamSettings?: import('./layer2').PreviewWebcamSettings;
636
+ }
637
+ /**
638
+ * Session metadata for a recorded participation.
639
+ *
640
+ * Captures everything needed to re-publish the participant's recording
641
+ * as a new monetizable version with dynamic overlays and ads.
642
+ *
643
+ * Classify an overlay for recording: should it be burned into the video
644
+ * (static visual) or kept as dynamic metadata (interactive/monetizable)?
645
+ *
646
+ * Some overlays (e.g., clickable images) are BOTH — burned visually into
647
+ * the recording but also preserved as dynamic metadata so their click URL
648
+ * can be restored when re-publishing.
649
+ */
650
+ export declare function classifyOverlayForRecording(overlay: PublishedOverlay): {
651
+ burnable: boolean;
652
+ dynamic: boolean;
653
+ };
654
+ /**
655
+ * Session metadata for a participation recording.
656
+ *
657
+ * PRINCIPLES:
658
+ * - Static visual overlays (text, images, shapes) are BURNED into the recording
659
+ * - Interactive/monetizable overlays (CTAs) are stored as DYNAMIC REFERENCES
660
+ * - This preserves the content creator's ability to:
661
+ * - Update CTA links, ad content, and text after the fact
662
+ * - Serve different ads to different viewers
663
+ * - Monetize derivative content through revenue sharing
664
+ * - Keep interactive elements (clickable CTAs) working
665
+ */
666
+ export interface SessionMetadata {
667
+ /** Schema version for forward compatibility */
668
+ version: 1;
669
+ /** When the recording was made (ISO 8601) */
670
+ recordedAt: string;
671
+ /** Recording duration in ms */
672
+ durationMs: number;
673
+ /** Output format */
674
+ format: {
675
+ mimeType: string;
676
+ codec: string;
677
+ };
678
+ /** Output resolution */
679
+ resolution: {
680
+ width: number;
681
+ height: number;
682
+ };
683
+ /** Recording FPS (matches source video) */
684
+ fps: number;
685
+ /** Background video reference (for re-compositing) */
686
+ background: {
687
+ hlsUrl: string;
688
+ startTimeMs: number;
689
+ durationMs: number;
690
+ aspectRatio: string;
691
+ };
692
+ /** Webcam composite settings (Gausst coordinates) */
693
+ participation: {
694
+ position: [number, number, number];
695
+ rotation: [number, number, number];
696
+ scale: number;
697
+ framingType: string;
698
+ backgroundMethod: string;
699
+ };
700
+ /**
701
+ * Overlay definitions — stored as REFERENCES, not burned in.
702
+ * These enable re-publishing with dynamic, editable, monetizable overlays.
703
+ */
704
+ overlayDefinitions: Array<{
705
+ id: string;
706
+ type: string;
707
+ startFrame: number;
708
+ endFrame: number;
709
+ position: {
710
+ x: number;
711
+ y: number;
712
+ width: number;
713
+ height: number;
714
+ };
715
+ content: unknown;
716
+ }>;
717
+ /** 3D ad placement references — dynamic, can be swapped/updated */
718
+ adPlacements: Array<{
719
+ id: string;
720
+ startFrame: number;
721
+ endFrame: number;
722
+ position: [number, number, number];
723
+ rotation: [number, number, number];
724
+ scale: number;
725
+ }>;
726
+ /** Camera settings (Gausst coordinate system) */
727
+ camera: {
728
+ fov: number;
729
+ position: [number, number, number];
730
+ rotation: [number, number, number];
731
+ };
732
+ /** Source manifest reference */
733
+ sourceManifest: {
734
+ publishId: string;
735
+ name: string;
736
+ fps: number;
737
+ };
738
+ /** Whether audio was captured */
739
+ hasAudio: boolean;
740
+ /**
741
+ * Overlays that were burned into the recording video track.
742
+ * These are static visual overlays (text, images, shapes, emoji).
743
+ */
744
+ burnedOverlays?: Array<{
745
+ id: string;
746
+ type: string;
747
+ startFrame: number;
748
+ endFrame: number;
749
+ position: {
750
+ x: number;
751
+ y: number;
752
+ width: number;
753
+ height: number;
754
+ };
755
+ content: unknown;
756
+ }>;
757
+ /**
758
+ * Dynamic overlays NOT burned in — interactive/monetizable.
759
+ * CTAs and clickable images are kept as references for re-publishing.
760
+ */
761
+ dynamicOverlays?: Array<{
762
+ id: string;
763
+ type: string;
764
+ startFrame: number;
765
+ endFrame: number;
766
+ position: {
767
+ x: number;
768
+ y: number;
769
+ width: number;
770
+ height: number;
771
+ };
772
+ content: unknown;
773
+ }>;
774
+ /**
775
+ * Multi-camera shot cuts during the recording window.
776
+ * Each entry marks a camera/webcam transform change at a frame offset.
777
+ * Enables NLE editors to recreate camera switches in post-production.
778
+ */
779
+ shotCuts?: Array<{
780
+ /** Frame offset relative to recording start (0 = first frame) */
781
+ frameOffset: number;
782
+ /** Shot preset ID from the published manifest */
783
+ presetId: string;
784
+ /** Camera settings at this cut */
785
+ camera: {
786
+ fov: number;
787
+ position: [number, number, number];
788
+ rotation: [number, number, number];
789
+ };
790
+ /** Webcam transform at this cut (if different from base) */
791
+ webcamTransform?: {
792
+ position: [number, number, number];
793
+ rotation: [number, number, number];
794
+ scale: number;
795
+ };
796
+ }>;
797
+ }
798
+ /**
799
+ * Recording tier determines duration and size limits.
800
+ *
801
+ * Tier is inherited from the creator's account plan (stored on the published
802
+ * manifest). Until creator accounts (#134, #136) are implemented, all
803
+ * recordings default to 'standard'.
804
+ *
805
+ * Access model: recordings are "unlisted" — accessible by anyone with the
806
+ * 12-character random recordingId URL, but not discoverable via browsing
807
+ * or search. Similar to YouTube unlisted videos.
808
+ */
809
+ export type RecordingTier = 'free' | 'standard' | 'professional';
810
+ export interface RecordingTierLimits {
811
+ /** Maximum recording duration in milliseconds */
812
+ maxDurationMs: number;
813
+ /** Maximum file size in bytes */
814
+ maxFileSize: number;
815
+ /** Human-readable label */
816
+ label: string;
817
+ }
818
+ export declare const RECORDING_TIER_LIMITS: Record<RecordingTier, RecordingTierLimits>;
819
+ /**
820
+ * Stored manifest for a participant recording.
821
+ * Saved in KV when a participant uploads their recording.
822
+ */
823
+ export interface RecordingManifest {
824
+ /** Unique recording identifier */
825
+ recordingId: string;
826
+ /** Published video this recording was made against */
827
+ publishId: string;
828
+ /** Participant display name (optional) */
829
+ participantName?: string;
830
+ /** When the recording was uploaded (ISO 8601) */
831
+ uploadedAt: string;
832
+ /** Recording duration in ms */
833
+ durationMs: number;
834
+ /** File size in bytes */
835
+ fileSizeBytes: number;
836
+ /** Output format */
837
+ format: {
838
+ mimeType: string;
839
+ codec: string;
840
+ extension: string;
841
+ };
842
+ /** Output resolution */
843
+ resolution: {
844
+ width: number;
845
+ height: number;
846
+ };
847
+ /** Whether audio was captured */
848
+ hasAudio: boolean;
849
+ /** R2 key for the video file */
850
+ videoKey: string;
851
+ /** R2 key for the session metadata JSON */
852
+ metadataKey: string;
853
+ /** Full session metadata for re-compositing */
854
+ sessionMetadata: SessionMetadata;
855
+ /** Recording tier (determines duration/size limits) */
856
+ tier?: RecordingTier;
857
+ }
858
+ /**
859
+ * Type of ad placement slot
860
+ */
861
+ export type AdSlotType = 'preroll' | 'midroll' | 'postroll' | 'overlay' | 'companion';
862
+ /**
863
+ * Position for overlay/companion ad slots
864
+ */
865
+ export type AdSlotPosition = 'top-left' | 'top-right' | 'bottom-left' | 'bottom-right' | 'center';
866
+ /**
867
+ * Category of ad template
868
+ */
869
+ export type AdTemplateCategory = 'video' | 'display' | 'companion';
870
+ /**
871
+ * Ad slot template defined and managed by Admetise
872
+ *
873
+ * This is the SOURCE OF TRUTH for ad formats. Admetise defines what
874
+ * ad placements are available, and Includu content creators select
875
+ * from these templates when placing ads in their content.
876
+ *
877
+ * Templates follow IAB standards where applicable.
878
+ *
879
+ * @see https://github.com/uMe-Group/Includu/issues/47
880
+ */
881
+ export interface AdSlotTemplate {
882
+ /** Unique template identifier (e.g., "iab-medium-rectangle") */
883
+ id: string;
884
+ /** Display name (e.g., "Medium Rectangle (300×250)") */
885
+ name: string;
886
+ /** Description of the ad format */
887
+ description: string;
888
+ /** Type of ad placement */
889
+ type: AdSlotType;
890
+ /** Category for grouping in UI */
891
+ category: AdTemplateCategory;
892
+ /** Fixed width in pixels (for display/companion ads) */
893
+ width?: number;
894
+ /** Fixed height in pixels (for display/companion ads) */
895
+ height?: number;
896
+ /** Position for overlay ads */
897
+ position?: AdSlotPosition;
898
+ /** Default duration in seconds (for video ads) */
899
+ duration?: number;
900
+ /** Minimum duration in seconds */
901
+ minDuration?: number;
902
+ /** Maximum duration in seconds */
903
+ maxDuration?: number;
904
+ /** IAB standard size identifier (e.g., "300x250") */
905
+ iabSize?: string;
906
+ /** Whether this template is currently active/available */
907
+ active: boolean;
908
+ /** Sort order for UI display */
909
+ sortOrder?: number;
910
+ /** Icon identifier for UI */
911
+ icon?: string;
912
+ }
913
+ /**
914
+ * Ad slot placement by content creator in Includu
915
+ *
916
+ * References a template from Admetise and adds timing information.
917
+ * The creator controls WHEN ads appear, not WHAT format they are.
918
+ */
919
+ export interface AdSlotPlacement {
920
+ /** Unique placement identifier */
921
+ id: string;
922
+ /** Reference to AdSlotTemplate.id (from Admetise) */
923
+ templateId: string;
924
+ /** Frame number when ad should trigger (for midroll/overlay) */
925
+ triggerFrame?: number;
926
+ /** Percentage of video when ad should trigger (0-100) */
927
+ triggerPercent?: number;
928
+ /** Whether this placement is required (must show ad) */
929
+ required?: boolean;
930
+ /**
931
+ * Center position in normalized coordinates (0-1)
932
+ * Default: {x: 0.5, y: 0.5} (centered)
933
+ */
934
+ position?: {
935
+ x: number;
936
+ y: number;
937
+ };
938
+ /**
939
+ * Scale factor relative to template size
940
+ * 1.0 = template size (minimum), max 3.0 (300%)
941
+ * Default: 1.0
942
+ */
943
+ scale?: number;
944
+ /**
945
+ * Z-axis rotation in degrees (0-360)
946
+ * Only applied when rotationEnabled is true
947
+ * Default: 0
948
+ */
949
+ rotation?: number;
950
+ /**
951
+ * X-axis rotation in degrees (-60 to +60)
952
+ * Tilts forward/backward (CSS rotateX)
953
+ * Only applied when rotationEnabled is true
954
+ * Default: 0
955
+ */
956
+ rotationX?: number;
957
+ /**
958
+ * Y-axis rotation in degrees (-60 to +60)
959
+ * Tilts left/right (CSS rotateY)
960
+ * Only applied when rotationEnabled is true
961
+ * Default: 0
962
+ */
963
+ rotationY?: number;
964
+ /**
965
+ * Whether rotation is enabled (opt-in toggle)
966
+ * Default: false
967
+ */
968
+ rotationEnabled?: boolean;
969
+ /**
970
+ * Custom duration in seconds (creator override)
971
+ * Must be >= template.maxDuration (can only extend, not shrink)
972
+ * If not set, uses template.maxDuration
973
+ */
974
+ customDuration?: number;
975
+ /**
976
+ * Perspective transform for corner pinning (opt-in)
977
+ * Enables placing ads on surfaces in video (billboards, screens, etc.)
978
+ * When enabled, overrides position/scale/rotation transforms
979
+ * @see https://github.com/uMe-Group/Includu/issues/58
980
+ */
981
+ perspective?: PerspectiveTransform;
982
+ /**
983
+ * Animation settings for ad zone entrance/exit
984
+ * Similar to overlay animations but simplified
985
+ */
986
+ animation?: {
987
+ /** Entrance animation type (default: 'none') */
988
+ entranceType?: AnimationType;
989
+ /** Exit animation type (default: 'none') */
990
+ exitType?: AnimationType;
991
+ /** Entrance animation duration in frames (default: 0) */
992
+ entranceFrames?: number;
993
+ /** Exit animation duration in frames (default: 0) */
994
+ exitFrames?: number;
995
+ };
996
+ }
997
+ /**
998
+ * @deprecated Use AdSlotPlacement instead. Kept for backwards compatibility.
999
+ */
1000
+ export interface AdSlot {
1001
+ /** Unique slot identifier */
1002
+ id: string;
1003
+ /** Type of ad placement */
1004
+ type: AdSlotType;
1005
+ /** Position for overlay/companion slots */
1006
+ position?: AdSlotPosition;
1007
+ /** Slot width in pixels (for overlay/companion) */
1008
+ width?: number;
1009
+ /** Slot height in pixels (for overlay/companion) */
1010
+ height?: number;
1011
+ /** Frame number when midroll should trigger */
1012
+ triggerFrame?: number;
1013
+ /** Percentage of video when midroll should trigger (0-100) */
1014
+ triggerPercent?: number;
1015
+ /** Maximum ad duration in seconds */
1016
+ maxDuration?: number;
1017
+ /** Whether this slot must be filled with an ad */
1018
+ required?: boolean;
1019
+ /** Reference to template (new field for migration) */
1020
+ templateId?: string;
1021
+ }
1022
+ /**
1023
+ * Ad zone in Admetise (created when importing from Includu)
1024
+ *
1025
+ * Represents an actual ad placement that can be filled with campaign ads.
1026
+ * Created by importing content from Includu and resolving template references.
1027
+ */
1028
+ export interface AdZone {
1029
+ /** Zone identifier (matches source placement ID) */
1030
+ id: string;
1031
+ /** Reference to the template used */
1032
+ templateId: string;
1033
+ /** Type of ad placement (from template) */
1034
+ type: AdSlotType;
1035
+ /** Whether this zone is active */
1036
+ enabled: boolean;
1037
+ /** Preset position for overlay/companion zones (from template, used as fallback) */
1038
+ presetPosition?: AdSlotPosition;
1039
+ /** Zone width in pixels (from template, used for aspect ratio) */
1040
+ width?: number;
1041
+ /** Zone height in pixels (from template, used for aspect ratio) */
1042
+ height?: number;
1043
+ /** Trigger time in seconds (converted from frames) */
1044
+ triggerTime?: number;
1045
+ /** Percentage of video to trigger (0-100) */
1046
+ triggerPercent?: number;
1047
+ /** VAST/VPAID ad tag URL (configured by advertiser) */
1048
+ adTagUrl?: string;
1049
+ /** Max duration in seconds (from template) */
1050
+ maxDuration?: number;
1051
+ /**
1052
+ * Center position in normalized coordinates (0-1)
1053
+ * Takes precedence over presetPosition when set
1054
+ */
1055
+ centerPosition?: {
1056
+ x: number;
1057
+ y: number;
1058
+ };
1059
+ /**
1060
+ * Scale factor (1.0 = base size, max 3.0)
1061
+ */
1062
+ scale?: number;
1063
+ /**
1064
+ * Z-axis rotation in degrees (0-360)
1065
+ * Only applied when rotationEnabled is true
1066
+ */
1067
+ rotation?: number;
1068
+ /**
1069
+ * X-axis rotation in degrees (-60 to +60)
1070
+ * Tilts forward/backward (CSS rotateX)
1071
+ * Only applied when rotationEnabled is true
1072
+ */
1073
+ rotationX?: number;
1074
+ /**
1075
+ * Y-axis rotation in degrees (-60 to +60)
1076
+ * Tilts left/right (CSS rotateY)
1077
+ * Only applied when rotationEnabled is true
1078
+ */
1079
+ rotationY?: number;
1080
+ /**
1081
+ * Whether rotation is enabled
1082
+ */
1083
+ rotationEnabled?: boolean;
1084
+ /**
1085
+ * Perspective transform for corner pinning
1086
+ * When set, the ad is rendered with perspective correction to fit surfaces
1087
+ * @see https://github.com/uMe-Group/Includu/issues/58
1088
+ */
1089
+ perspective?: PerspectiveTransform;
1090
+ }
1091
+ /**
1092
+ * Age rating for content
1093
+ */
1094
+ export type AgeRating = 'G' | 'PG' | 'PG-13' | 'R';
1095
+ /**
1096
+ * Content restrictions for ad targeting
1097
+ */
1098
+ export interface AdRestrictions {
1099
+ /** Categories that should not advertise on this content */
1100
+ blockedCategories?: string[];
1101
+ /** Content age rating */
1102
+ ageRating?: AgeRating;
1103
+ }
1104
+ /**
1105
+ * Monetization configuration for published content
1106
+ *
1107
+ * Defined by content creator in Includu, consumed by Admetise.
1108
+ * Uses template-based placements for consistency.
1109
+ */
1110
+ export interface MonetizationConfig {
1111
+ /** Whether monetization is enabled */
1112
+ enabled: boolean;
1113
+ /** Ad slot placements (references templates) */
1114
+ placements: AdSlotPlacement[];
1115
+ /**
1116
+ * @deprecated Use placements instead. Kept for backwards compatibility.
1117
+ */
1118
+ adSlots?: AdSlot[];
1119
+ /** Creator's revenue share percentage (0-100) */
1120
+ revenueShare?: number;
1121
+ /** Content restrictions for ad targeting */
1122
+ restrictions?: AdRestrictions;
1123
+ /** Whether 3D ads (Layer 2) are enabled */
1124
+ layer2Enabled?: boolean;
1125
+ /** Whether 2D ads are enabled */
1126
+ layer2DEnabled?: boolean;
1127
+ }
1128
+ /**
1129
+ * Standard ad slot templates following IAB guidelines
1130
+ * These are the default templates that Admetise provides.
1131
+ * Can be extended/modified via Admetise admin.
1132
+ */
1133
+ export declare const STANDARD_AD_TEMPLATES: AdSlotTemplate[];
1134
+ /**
1135
+ * Find a template by ID
1136
+ *
1137
+ * @param templateId - The template ID to find
1138
+ * @param templates - Array of templates (defaults to STANDARD_AD_TEMPLATES)
1139
+ * @returns The template or undefined
1140
+ */
1141
+ export declare function findTemplate(templateId: string, templates?: AdSlotTemplate[]): AdSlotTemplate | undefined;
1142
+ /**
1143
+ * Maps an AdSlotPlacement to an AdZone using template data
1144
+ *
1145
+ * @param placement - The placement from Includu
1146
+ * @param template - The template definition from Admetise
1147
+ * @param fps - Frames per second of the video
1148
+ * @returns AdZone for Admetise
1149
+ */
1150
+ export declare function mapPlacementToZone(placement: AdSlotPlacement, template: AdSlotTemplate, fps: number): AdZone;
1151
+ /**
1152
+ * @deprecated Use mapPlacementToZone instead
1153
+ * Maps an Includu AdSlot to an Admetise AdZone (legacy support)
1154
+ */
1155
+ export declare function mapAdSlotToZone(slot: AdSlot, fps: number): AdZone;
1156
+ /**
1157
+ * Maps all placements from a manifest to AdZones
1158
+ *
1159
+ * @param manifest - Published manifest with monetization config
1160
+ * @param templates - Available templates (defaults to STANDARD_AD_TEMPLATES)
1161
+ * @returns Array of AdZones, or empty array if monetization disabled
1162
+ */
1163
+ export declare function mapManifestToZones(manifest: PublishedManifest, templates?: AdSlotTemplate[]): AdZone[];
1164
+ /**
1165
+ * Get templates grouped by category
1166
+ *
1167
+ * @param templates - Array of templates (defaults to STANDARD_AD_TEMPLATES)
1168
+ * @returns Object with templates grouped by category
1169
+ */
1170
+ export declare function getTemplatesByCategory(templates?: AdSlotTemplate[]): Record<AdTemplateCategory, AdSlotTemplate[]>;
1171
+ /**
1172
+ * Get templates filtered by type
1173
+ *
1174
+ * @param type - The ad slot type to filter by
1175
+ * @param templates - Array of templates (defaults to STANDARD_AD_TEMPLATES)
1176
+ * @returns Filtered templates
1177
+ */
1178
+ export declare function getTemplatesByType(type: AdSlotType, templates?: AdSlotTemplate[]): AdSlotTemplate[];
1179
+ export { computeMatrix3d, isValidQuad } from './perspective';
1180
+ export * from './layer2';
1181
+ export * from './campaigns';
1182
+ export * from './adserving';
1183
+ export * from './gausst';
1184
+ /**
1185
+ * Category for overlay templates
1186
+ */
1187
+ export type OverlayTemplateCategory = 'titles' | 'lower-thirds' | 'badges' | 'cta' | 'social' | 'graphics' | 'motion-gfx';
1188
+ /**
1189
+ * Overlay template preset definition
1190
+ * Used to quickly create common overlay patterns
1191
+ */
1192
+ export interface OverlayTemplatePreset {
1193
+ /** Unique template identifier */
1194
+ id: string;
1195
+ /** Display name */
1196
+ name: string;
1197
+ /** Short description */
1198
+ description: string;
1199
+ /** Category for grouping */
1200
+ category: OverlayTemplateCategory;
1201
+ /** Icon/emoji for quick visual identification */
1202
+ icon: string;
1203
+ /** Overlay type */
1204
+ type: 'text' | 'cta' | 'shape' | 'emoji' | 'image' | 'sprite-sequence' | 'video';
1205
+ /** Default position (percentage 0-100) */
1206
+ position: {
1207
+ x: number;
1208
+ y: number;
1209
+ width: number;
1210
+ height: number;
1211
+ };
1212
+ /** Default duration in seconds */
1213
+ durationSeconds: number;
1214
+ /** Text content defaults (for text overlays) */
1215
+ textDefaults?: {
1216
+ text: string;
1217
+ fontSize: number;
1218
+ fontFamily: string;
1219
+ fontWeight: 'normal' | 'bold';
1220
+ color: string;
1221
+ textAlign: 'left' | 'center' | 'right';
1222
+ background?: {
1223
+ color: string;
1224
+ opacity: number;
1225
+ padding: {
1226
+ x: number;
1227
+ y: number;
1228
+ };
1229
+ scale: number;
1230
+ borderRadius: number;
1231
+ };
1232
+ };
1233
+ /** CTA content defaults (for CTA overlays) */
1234
+ ctaDefaults?: {
1235
+ text: string;
1236
+ url: string;
1237
+ style: {
1238
+ backgroundColor: string;
1239
+ textColor: string;
1240
+ borderRadius: number;
1241
+ fontSize: number;
1242
+ fontWeight: 'normal' | 'bold';
1243
+ padding: {
1244
+ x: number;
1245
+ y: number;
1246
+ };
1247
+ };
1248
+ };
1249
+ /** Emoji content defaults (for emoji overlays) */
1250
+ emojiDefaults?: {
1251
+ emoji: string;
1252
+ size: number;
1253
+ };
1254
+ /** Image content defaults (for image overlays) */
1255
+ imageDefaults?: {
1256
+ src: string;
1257
+ alt: string;
1258
+ fit: 'contain' | 'cover' | 'fill';
1259
+ opacity: number;
1260
+ borderRadius: number;
1261
+ /** Optional click URL to make the image clickable */
1262
+ clickUrl?: string;
1263
+ };
1264
+ /**
1265
+ * Whether this template should have perspective/corner pinning enabled by default
1266
+ * Used for templates like Picture Frame / Screen Replace
1267
+ */
1268
+ perspectiveEnabled?: boolean;
1269
+ /** Sprite sequence content defaults (for sprite-sequence overlays) */
1270
+ spriteDefaults?: {
1271
+ spritesheetUrl: string;
1272
+ frameWidth: number;
1273
+ frameHeight: number;
1274
+ frameCount: number;
1275
+ columns: number;
1276
+ framesPerSecond: number;
1277
+ loop: boolean;
1278
+ pingPong?: boolean;
1279
+ startFrame?: number;
1280
+ opacity?: number;
1281
+ };
1282
+ /** Video content defaults (for video overlays with alpha) */
1283
+ videoDefaults?: {
1284
+ videoUrl: string;
1285
+ loop: boolean;
1286
+ muted: boolean;
1287
+ playbackRate?: number;
1288
+ startTime?: number;
1289
+ opacity?: number;
1290
+ fit?: 'contain' | 'cover' | 'fill';
1291
+ };
1292
+ }
1293
+ /**
1294
+ * Standard overlay template presets
1295
+ * Designed for ease of use across all devices
1296
+ */
1297
+ export declare const OVERLAY_TEMPLATE_PRESETS: OverlayTemplatePreset[];
1298
+ /**
1299
+ * Get overlay templates by category
1300
+ */
1301
+ export declare function getOverlayTemplatesByCategory(category: OverlayTemplateCategory): OverlayTemplatePreset[];
1302
+ /**
1303
+ * Find an overlay template by ID
1304
+ */
1305
+ export declare function findOverlayTemplate(id: string): OverlayTemplatePreset | undefined;
1306
+ /**
1307
+ * Get all overlay template categories with their templates
1308
+ */
1309
+ export declare function getOverlayTemplateCategoriesWithTemplates(): {
1310
+ category: OverlayTemplateCategory;
1311
+ label: string;
1312
+ templates: OverlayTemplatePreset[];
1313
+ }[];
1314
+ /**
1315
+ * Get overlay template categories for the Overlays track (excludes branding categories)
1316
+ */
1317
+ export declare function getOverlayTrackCategories(): {
1318
+ category: OverlayTemplateCategory;
1319
+ label: string;
1320
+ templates: OverlayTemplatePreset[];
1321
+ }[];
1322
+ /**
1323
+ * Get branding template categories for the Branding track
1324
+ */
1325
+ export declare function getBrandingTrackCategories(): {
1326
+ category: OverlayTemplateCategory;
1327
+ label: string;
1328
+ templates: OverlayTemplatePreset[];
1329
+ }[];
1330
+ /**
1331
+ * Get Motion Graphics template categories for the Motion GFX track
1332
+ */
1333
+ export declare function getMotionGfxTrackCategories(): {
1334
+ category: OverlayTemplateCategory;
1335
+ label: string;
1336
+ templates: OverlayTemplatePreset[];
1337
+ }[];
1338
+ /**
1339
+ * @deprecated Use getMotionGfxTrackCategories instead
1340
+ */
1341
+ export declare function get3DTrackCategories(): {
1342
+ category: OverlayTemplateCategory;
1343
+ label: string;
1344
+ templates: OverlayTemplatePreset[];
1345
+ }[];
1346
+ /**
1347
+ * Coordinate system constants for Three.js video compositing
1348
+ *
1349
+ * Based on Gausst legacy code (Patent US8761580B2):
1350
+ * - Y-up axis (Three.js default)
1351
+ * - Metric units: 1 unit = 1 meter
1352
+ * - Reference: 1920 video pixels = 1 meter
1353
+ *
1354
+ * @see docs/architecture/coordinate-system-design.md
1355
+ */
1356
+ export declare const COORDINATE_SYSTEM: {
1357
+ /**
1358
+ * Reference scale: 1920 pixels = 1 meter in world space
1359
+ * This ensures a standard 1920×1080 video is 1m × 0.5625m
1360
+ */
1361
+ readonly PIXELS_PER_METER: 1920;
1362
+ /**
1363
+ * Layer Z positions in meters
1364
+ * - VIDEO: Background video plane
1365
+ * - THREE_D_MIN/MAX: 3D tracked surfaces, webcam
1366
+ * - HUD_MIN/MAX: HTML overlays via CSS2DRenderer
1367
+ */
1368
+ readonly LAYER_Z: {
1369
+ readonly VIDEO: 0;
1370
+ readonly THREE_D_MIN: 0.01;
1371
+ readonly THREE_D_MAX: 10;
1372
+ readonly HUD_MIN: 10.1;
1373
+ readonly HUD_MAX: 100;
1374
+ };
1375
+ /**
1376
+ * Camera defaults for orthographic rendering (video plane)
1377
+ */
1378
+ readonly CAMERA: {
1379
+ readonly NEAR: 0.01;
1380
+ readonly FAR: 1000;
1381
+ readonly POSITION_Z: 50;
1382
+ };
1383
+ /**
1384
+ * Orthographic camera settings for HUD overlays (Layer 3)
1385
+ * Provides predictable 2D positioning for sprites, text, CTAs
1386
+ *
1387
+ * Bounds are set dynamically based on video dimensions.
1388
+ * Objects are positioned in meters relative to center (0,0).
1389
+ */
1390
+ readonly HUD_CAMERA: {
1391
+ /** Camera Z position (arbitrary for orthographic) */
1392
+ readonly POSITION_Z: 10;
1393
+ /** Near clipping plane */
1394
+ readonly NEAR: 0.1;
1395
+ /** Far clipping plane */
1396
+ readonly FAR: 100;
1397
+ /** Default object Z position */
1398
+ readonly OBJECT_Z: 0;
1399
+ };
1400
+ /**
1401
+ * Perspective camera settings for webcam composite layer (Layer 2)
1402
+ * Camera positioned at eye height for 3D scene placement
1403
+ * Reserved for future webcam/chroma key compositing
1404
+ */
1405
+ readonly SCENE_CAMERA: {
1406
+ /** Camera X position (centered) */
1407
+ readonly POSITION_X: 0;
1408
+ /** Camera Y position (eye height) */
1409
+ readonly POSITION_Y: 1.2;
1410
+ /** Camera Z position (distance from scene) */
1411
+ readonly POSITION_Z: 4;
1412
+ /** Vertical field of view in degrees (~43mm equivalent) */
1413
+ readonly FOV: 47;
1414
+ /** Near clipping plane */
1415
+ readonly NEAR: 0.1;
1416
+ /** Far clipping plane */
1417
+ readonly FAR: 100;
1418
+ /** Look-at target Y position */
1419
+ readonly LOOK_AT_Y: 1.2;
1420
+ };
1421
+ /**
1422
+ * Film gate constants (for future camera matching)
1423
+ * Based on 35mm full-frame sensor
1424
+ */
1425
+ readonly FILM_GATE: {
1426
+ readonly HORIZONTAL_APERTURE: 1.417;
1427
+ readonly VERTICAL_APERTURE: 0.945;
1428
+ };
1429
+ };
1430
+ /**
1431
+ * Convert video pixel dimensions to world-space meters
1432
+ *
1433
+ * @param pixelWidth - Video width in pixels
1434
+ * @param pixelHeight - Video height in pixels
1435
+ * @returns World-space dimensions in meters
1436
+ */
1437
+ export declare function pixelsToMeters(pixelWidth: number, pixelHeight: number): {
1438
+ width: number;
1439
+ height: number;
1440
+ };
1441
+ /**
1442
+ * Convert world-space meters to video pixels
1443
+ *
1444
+ * @param meterWidth - Width in meters
1445
+ * @param meterHeight - Height in meters
1446
+ * @returns Pixel dimensions
1447
+ */
1448
+ export declare function metersToPixels(meterWidth: number, meterHeight: number): {
1449
+ width: number;
1450
+ height: number;
1451
+ };
1452
+ /**
1453
+ * Convert overlay percentage position (0-100) to world-space meters
1454
+ *
1455
+ * @param percentX - X position as percentage (0-100, left to right)
1456
+ * @param percentY - Y position as percentage (0-100, top to bottom)
1457
+ * @param videoWidthMeters - Video width in meters
1458
+ * @param videoHeightMeters - Video height in meters
1459
+ * @returns World-space position {x, y} in meters, centered at origin
1460
+ */
1461
+ export declare function percentToWorldSpace(percentX: number, percentY: number, videoWidthMeters: number, videoHeightMeters: number): {
1462
+ x: number;
1463
+ y: number;
1464
+ };
1465
+ /**
1466
+ * Convert world-space meters to overlay percentage position (0-100)
1467
+ *
1468
+ * @param worldX - X position in meters (origin = center)
1469
+ * @param worldY - Y position in meters (origin = center)
1470
+ * @param videoWidthMeters - Video width in meters
1471
+ * @param videoHeightMeters - Video height in meters
1472
+ * @returns Percentage position {x, y} (0-100)
1473
+ */
1474
+ export declare function worldSpaceToPercent(worldX: number, worldY: number, videoWidthMeters: number, videoHeightMeters: number): {
1475
+ x: number;
1476
+ y: number;
1477
+ };
1478
+ /**
1479
+ * Camera tracking data format (from Gausst legacy)
1480
+ * Position: mm × 100, Rotation: degrees × 1000
1481
+ */
1482
+ export interface TrackingPacket {
1483
+ x: number;
1484
+ y: number;
1485
+ z: number;
1486
+ pan: number;
1487
+ tilt: number;
1488
+ roll: number;
1489
+ fov: number;
1490
+ focus: number;
1491
+ }
1492
+ /**
1493
+ * Convert Gausst tracking packet to world-space transform
1494
+ *
1495
+ * @param packet - Raw tracking data from hardware
1496
+ * @returns Position in meters, rotation in radians, FOV in degrees
1497
+ */
1498
+ export declare function trackingPacketToWorldSpace(packet: TrackingPacket): {
1499
+ position: {
1500
+ x: number;
1501
+ y: number;
1502
+ z: number;
1503
+ };
1504
+ rotation: {
1505
+ x: number;
1506
+ y: number;
1507
+ z: number;
1508
+ };
1509
+ fov: number;
1510
+ };
1511
+ /**
1512
+ * Convert FOV to focal length (for matching real camera optics)
1513
+ *
1514
+ * Formula from Gausst: focalLength = (aperture / 2) / tan(fov / 2) * 25.4
1515
+ *
1516
+ * @param fovDegrees - Field of view in degrees
1517
+ * @param filmApertureInches - Horizontal film aperture (default: 1.417" = 36mm)
1518
+ * @returns Focal length in millimeters
1519
+ */
1520
+ export declare function fovToFocalLength(fovDegrees: number, filmApertureInches?: number): number;
1521
+ /**
1522
+ * Convert focal length to FOV
1523
+ *
1524
+ * @param focalLengthMM - Focal length in millimeters
1525
+ * @param filmApertureInches - Horizontal film aperture (default: 1.417" = 36mm)
1526
+ * @returns Field of view in degrees
1527
+ */
1528
+ export declare function focalLengthToFov(focalLengthMM: number, filmApertureInches?: number): number;
1529
+ export { webcamVertexShader, webcamFragmentShader, getDefaultPlayerUniforms, getDefaultEditorUniforms, type WebcamShaderUniforms } from './layer2/shaders';
1530
+ export { WEBCAM_BASE_HEIGHT_METERS, SILHOUETTE_HEIGHT_RATIO, getWebcamBaseDimensions, getWebcamMeshYOffset, getObjectEuler, getCameraEuler, GAM_PIXELS_TO_METERS, AD_TEMPLATE_DIMENSIONS, getAdDimensions, CHROMA_KEY_COLORS, getChromaKeyColorHex, featherToUV, featherEdgesToUV } from './layer2/webcam-utils';
1531
+ //# sourceMappingURL=index.d.ts.map