@beautifi/plugin 0.1.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.
@@ -0,0 +1,105 @@
1
+ /**
2
+ * Video Renderer
3
+ *
4
+ * Renders video cinemagraphs with seamless transitions from CSS animations.
5
+ * Handles video playback, loading states, and fallback to CSS on failure.
6
+ */
7
+ /**
8
+ * Video playback state
9
+ */
10
+ export type VideoPlaybackState = 'loading' | 'buffering' | 'playing' | 'paused' | 'error';
11
+ /**
12
+ * Video renderer configuration
13
+ */
14
+ export interface VideoRendererConfig {
15
+ /** Transition duration for CSS to video swap (ms) */
16
+ transitionDuration?: number;
17
+ /** Enable debug logging */
18
+ debug?: boolean;
19
+ /** Auto-play when video is ready */
20
+ autoPlay?: boolean;
21
+ /** Loop video playback */
22
+ loop?: boolean;
23
+ /** Mute video (required for autoplay) */
24
+ muted?: boolean;
25
+ }
26
+ /**
27
+ * VideoRenderer class
28
+ *
29
+ * Handles seamless video overlay and playback with CSS transition effects.
30
+ */
31
+ export declare class VideoRenderer {
32
+ private config;
33
+ private activeVideos;
34
+ constructor(config?: VideoRendererConfig);
35
+ /**
36
+ * Prepare a video overlay for an image
37
+ *
38
+ * @param imageId - Unique ID for tracking
39
+ * @param imageElement - The image element to overlay
40
+ * @param videoUrl - URL of the video to play
41
+ * @param onFallback - Callback if video fails to load
42
+ * @returns Promise that resolves when video is ready to play
43
+ */
44
+ prepareVideo(imageId: string, imageElement: HTMLImageElement, videoUrl: string, onFallback?: () => void): Promise<boolean>;
45
+ /**
46
+ * Play video and transition from CSS animation
47
+ */
48
+ play(imageId: string): boolean;
49
+ /**
50
+ * Pause video playback
51
+ */
52
+ pause(imageId: string): boolean;
53
+ /**
54
+ * Resume video playback
55
+ */
56
+ resume(imageId: string): boolean;
57
+ /**
58
+ * Stop video and remove overlay
59
+ */
60
+ stop(imageId: string): void;
61
+ /**
62
+ * Check if video is playing for an image
63
+ */
64
+ isPlaying(imageId: string): boolean;
65
+ /**
66
+ * Check if video is prepared for an image
67
+ */
68
+ isPrepared(imageId: string): boolean;
69
+ /**
70
+ * Get current playback state
71
+ */
72
+ getState(imageId: string): VideoPlaybackState | null;
73
+ /**
74
+ * Destroy all videos and cleanup
75
+ */
76
+ destroy(): void;
77
+ /**
78
+ * Create wrapper element around image
79
+ */
80
+ private createWrapper;
81
+ /**
82
+ * Create video element with proper attributes
83
+ */
84
+ private createVideoElement;
85
+ /**
86
+ * Wait for video to be ready to play
87
+ */
88
+ private waitForVideoReady;
89
+ /**
90
+ * Transition from image to video
91
+ */
92
+ private transitionToVideo;
93
+ /**
94
+ * Transition from video back to image
95
+ */
96
+ private transitionToImage;
97
+ /**
98
+ * Cleanup video element and restore image
99
+ */
100
+ private cleanup;
101
+ /**
102
+ * Debug logging
103
+ */
104
+ private log;
105
+ }
@@ -0,0 +1,42 @@
1
+ import { TrackedImage, ViewportCallback } from './types';
2
+
3
+ /**
4
+ * ViewportObserver class
5
+ *
6
+ * Efficiently tracks image visibility using IntersectionObserver.
7
+ */
8
+ export declare class ViewportObserver {
9
+ private observer;
10
+ private visibilityHandler;
11
+ private callback;
12
+ private threshold;
13
+ private rootMargin;
14
+ private observedElements;
15
+ private isDocumentVisible;
16
+ private debug;
17
+ constructor(callback: ViewportCallback, options?: {
18
+ threshold?: number;
19
+ rootMargin?: string;
20
+ debug?: boolean;
21
+ });
22
+ /**
23
+ * Initialize the observer
24
+ */
25
+ init(): void;
26
+ /**
27
+ * Start observing an image
28
+ */
29
+ observe(image: TrackedImage): void;
30
+ /**
31
+ * Stop observing an image
32
+ */
33
+ unobserve(image: TrackedImage): void;
34
+ /**
35
+ * Check if document is currently visible
36
+ */
37
+ isVisible(): boolean;
38
+ /**
39
+ * Clean up resources
40
+ */
41
+ destroy(): void;
42
+ }
@@ -0,0 +1,55 @@
1
+ import { LivePhotoOptions, TrackedImage } from './types';
2
+
3
+ export declare const beautifi: {
4
+ /**
5
+ * Initialize the plugin
6
+ */
7
+ init: (options: LivePhotoOptions) => void;
8
+ /**
9
+ * Check if initialized
10
+ */
11
+ isInitialized: () => boolean;
12
+ /**
13
+ * Get current options
14
+ */
15
+ getOptions: () => Required<LivePhotoOptions> | null;
16
+ /**
17
+ * Get tracked images
18
+ */
19
+ getTrackedImages: () => TrackedImage[];
20
+ /**
21
+ * Destroy and clean up
22
+ */
23
+ destroy: () => void;
24
+ };
25
+ export declare const LiveMyPhotos: {
26
+ /**
27
+ * Initialize the plugin
28
+ */
29
+ init: (options: LivePhotoOptions) => void;
30
+ /**
31
+ * Check if initialized
32
+ */
33
+ isInitialized: () => boolean;
34
+ /**
35
+ * Get current options
36
+ */
37
+ getOptions: () => Required<LivePhotoOptions> | null;
38
+ /**
39
+ * Get tracked images
40
+ */
41
+ getTrackedImages: () => TrackedImage[];
42
+ /**
43
+ * Destroy and clean up
44
+ */
45
+ destroy: () => void;
46
+ };
47
+ export type { LivePhotoOptions, TrackedImage, } from './types';
48
+ export { LivePhotoError, DEFAULT_OPTIONS, DEFAULT_ANIMATION_CONFIG, } from './types';
49
+ export { ImageDetector } from './ImageDetector';
50
+ export { ViewportObserver } from './ViewportObserver';
51
+ export { GeminiApiClient } from './GeminiApiClient';
52
+ export { AnimationRenderer } from './AnimationRenderer';
53
+ export { VeoClient } from './VeoClient';
54
+ export { VideoRenderer } from './VideoRenderer';
55
+ export default beautifi;
@@ -0,0 +1,86 @@
1
+ /**
2
+ * beautifi Lite - Minimal CSS-only animation bundle
3
+ *
4
+ * This is a lightweight (<5KB) version of beautifi that provides
5
+ * basic CSS-based animations without requiring AI processing.
6
+ *
7
+ * Users can upgrade to the full AI-powered version for advanced features.
8
+ *
9
+ * @packageDocumentation
10
+ */
11
+ export interface beautifiLiteOptions {
12
+ /** Selector for images to animate */
13
+ selector?: string;
14
+ /** Animation intensity: 'subtle' | 'moderate' | 'strong' */
15
+ intensity?: 'subtle' | 'moderate' | 'strong';
16
+ /** Animation type: 'breathe' | 'sway' | 'parallax' | 'pulse' */
17
+ type?: 'breathe' | 'sway' | 'parallax' | 'pulse';
18
+ /** Whether to loop the animation */
19
+ loop?: boolean;
20
+ /** Animation duration in milliseconds */
21
+ duration?: number;
22
+ /** Enable intersection observer for lazy animation */
23
+ lazyLoad?: boolean;
24
+ }
25
+ /**
26
+ * beautifi Lite - CSS-only animation engine
27
+ *
28
+ * Provides lightweight, CSS-based animations for images without AI processing.
29
+ * Use this for basic effects or as a fallback when AI is not available.
30
+ */
31
+ export declare class beautifiLite {
32
+ private options;
33
+ private observer;
34
+ private styleElement;
35
+ private animatedElements;
36
+ constructor(options?: beautifiLiteOptions);
37
+ /**
38
+ * Initialize the lite animation engine
39
+ */
40
+ private init;
41
+ /**
42
+ * Inject global CSS for animations
43
+ */
44
+ private injectGlobalStyles;
45
+ /**
46
+ * Setup intersection observer for lazy loading
47
+ */
48
+ private setupIntersectionObserver;
49
+ /**
50
+ * Process all matching elements
51
+ */
52
+ private processElements;
53
+ /**
54
+ * Animate a single element
55
+ */
56
+ animateElement(element: HTMLElement): void;
57
+ /**
58
+ * Pause animation on an element
59
+ */
60
+ pause(element?: HTMLElement): void;
61
+ /**
62
+ * Resume animation on an element
63
+ */
64
+ resume(element?: HTMLElement): void;
65
+ /**
66
+ * Stop and cleanup animation on an element
67
+ */
68
+ stop(element: HTMLElement): void;
69
+ /**
70
+ * Destroy the lite engine and cleanup
71
+ */
72
+ destroy(): void;
73
+ /**
74
+ * Check if an element is currently animated
75
+ */
76
+ isAnimated(element: HTMLElement): boolean;
77
+ /**
78
+ * Get the number of animated elements
79
+ */
80
+ get count(): number;
81
+ }
82
+ /**
83
+ * Initialize beautifi Lite with options
84
+ */
85
+ export declare function initLite(options?: beautifiLiteOptions): beautifiLite;
86
+ export default beautifiLite;
@@ -0,0 +1,204 @@
1
+ /**
2
+ * beautifi - Core Type Definitions
3
+ *
4
+ * This file contains all TypeScript interfaces and types used throughout
5
+ * the beautifi plugin.
6
+ */
7
+ /**
8
+ * Animation intensity levels
9
+ */
10
+ export type AnimationIntensity = 'subtle' | 'medium' | 'strong';
11
+ /**
12
+ * Animation type styles
13
+ */
14
+ export type AnimationType = 'breathing' | 'parallax' | 'sway' | 'auto';
15
+ /**
16
+ * Animation states
17
+ */
18
+ export type AnimationState = 'idle' | 'loading' | 'playing' | 'paused' | 'error';
19
+ /**
20
+ * Error codes for different failure scenarios
21
+ */
22
+ export type LivePhotoErrorCode = 'API_ERROR' | 'NETWORK_ERROR' | 'TIMEOUT_ERROR' | 'VALIDATION_ERROR' | 'RATE_LIMIT_ERROR' | 'RENDER_ERROR' | 'UNKNOWN_ERROR';
23
+ /**
24
+ * Event types emitted by the plugin
25
+ */
26
+ export type LivePhotoEventType = 'init' | 'imageDetected' | 'animationStart' | 'animationComplete' | 'animationPause' | 'animationResume' | 'animationError' | 'videoStart' | 'videoReady' | 'videoError' | 'destroy';
27
+ /**
28
+ * Animation mode - determines how images are animated
29
+ * - 'auto': CSS animation immediately + AI video in background (default)
30
+ * - 'css': CSS animation only, no video generation
31
+ * - 'video': Wait for video, no CSS animation
32
+ */
33
+ export type AnimationMode = 'auto' | 'css' | 'video';
34
+ /**
35
+ * Video generation state
36
+ */
37
+ export type VideoState = 'idle' | 'generating' | 'ready' | 'error';
38
+ /**
39
+ * Global plugin configuration options
40
+ */
41
+ export interface LivePhotoOptions {
42
+ /** API key for Gemini backend (required) */
43
+ apiKey: string;
44
+ /** Cloud Functions endpoint URL (optional, uses default if not provided) */
45
+ endpoint?: string;
46
+ /** CSS selector for target images (default: 'img') */
47
+ selector?: string;
48
+ /** Default animation intensity (default: 'subtle') */
49
+ intensity?: AnimationIntensity;
50
+ /** Default animation type (default: 'auto') */
51
+ type?: AnimationType;
52
+ /** Whether animations should loop (default: true) */
53
+ loop?: boolean;
54
+ /** Respect prefers-reduced-motion (default: true) */
55
+ respectReducedMotion?: boolean;
56
+ /** Enable debug logging (default: false) */
57
+ debug?: boolean;
58
+ /** Viewport intersection threshold for lazy loading (default: 0.1) */
59
+ threshold?: number;
60
+ /** Root margin for eager loading (default: '50px') */
61
+ rootMargin?: string;
62
+ /** Request timeout in milliseconds (default: 10000) */
63
+ timeout?: number;
64
+ /** Maximum retry attempts (default: 3) */
65
+ maxRetries?: number;
66
+ /** Animation mode: 'auto' | 'css' | 'video' (default: 'auto') */
67
+ mode?: AnimationMode;
68
+ /** Video endpoint URL (if different from main endpoint) */
69
+ videoEndpoint?: string;
70
+ }
71
+ /**
72
+ * Per-image animation configuration (from data attributes)
73
+ */
74
+ export interface AnimationConfig {
75
+ /** Whether animation is enabled for this image */
76
+ enabled: boolean;
77
+ /** Animation intensity level */
78
+ intensity: AnimationIntensity;
79
+ /** Animation type/style */
80
+ type: AnimationType;
81
+ /** Whether animation loops continuously */
82
+ loop: boolean;
83
+ /** Delay before animation starts (ms) */
84
+ delay: number;
85
+ }
86
+ /**
87
+ * Animation frame data from Gemini API
88
+ */
89
+ export interface AnimationFrameData {
90
+ /** Frame timestamp */
91
+ timestamp: number;
92
+ /** Transform data for this frame */
93
+ transform: {
94
+ translateX: number;
95
+ translateY: number;
96
+ scale: number;
97
+ rotate: number;
98
+ };
99
+ /** Optional opacity value */
100
+ opacity?: number;
101
+ }
102
+ /**
103
+ * Gemini API response for animation generation
104
+ */
105
+ export interface GeminiAnimationResponse {
106
+ /** Whether the request was successful */
107
+ success: boolean;
108
+ /** Unique animation ID */
109
+ animationId: string;
110
+ /** Animation duration in milliseconds */
111
+ duration: number;
112
+ /** Frame rate (fps) */
113
+ frameRate: number;
114
+ /** Animation keyframes */
115
+ frames: AnimationFrameData[];
116
+ /** Detected animation type */
117
+ detectedType: AnimationType;
118
+ /** Cache status (hit/miss) */
119
+ cacheStatus?: 'hit' | 'miss';
120
+ /** Error message if success is false */
121
+ error?: string;
122
+ }
123
+ /**
124
+ * API request payload
125
+ */
126
+ export interface GeminiAnimationRequest {
127
+ /** Image URL or hash */
128
+ imageUrl: string;
129
+ /** Image hash for caching */
130
+ imageHash?: string;
131
+ /** Requested animation type */
132
+ type: AnimationType;
133
+ /** Requested intensity */
134
+ intensity: AnimationIntensity;
135
+ /** Whether to loop */
136
+ loop: boolean;
137
+ }
138
+ /**
139
+ * Tracked image element with metadata
140
+ */
141
+ export interface TrackedImage {
142
+ /** Original image element */
143
+ element: HTMLImageElement;
144
+ /** Unique ID for this tracked image */
145
+ id: string;
146
+ /** Current animation state */
147
+ state: AnimationState;
148
+ /** Animation configuration for this image */
149
+ config: AnimationConfig;
150
+ /** API response data (when loaded) */
151
+ animationData?: GeminiAnimationResponse;
152
+ /** Error if animation failed */
153
+ error?: LivePhotoError;
154
+ }
155
+ /**
156
+ * Base event payload
157
+ */
158
+ export interface LivePhotoEventBase {
159
+ /** Event type */
160
+ type: LivePhotoEventType;
161
+ /** Event timestamp */
162
+ timestamp: number;
163
+ }
164
+ /**
165
+ * Image-related event payload
166
+ */
167
+ export interface LivePhotoImageEvent extends LivePhotoEventBase {
168
+ /** Image element involved */
169
+ element: HTMLImageElement;
170
+ /** Image tracking ID */
171
+ imageId: string;
172
+ }
173
+ /**
174
+ * Error event payload
175
+ */
176
+ export interface LivePhotoErrorEvent extends LivePhotoImageEvent {
177
+ type: 'animationError';
178
+ /** Error details */
179
+ error: LivePhotoError;
180
+ }
181
+ /**
182
+ * Event handler function type
183
+ */
184
+ export type LivePhotoEventHandler<T extends LivePhotoEventBase = LivePhotoEventBase> = (event: T) => void;
185
+ /**
186
+ * Viewport observer callback
187
+ */
188
+ export type ViewportCallback = (image: TrackedImage, isIntersecting: boolean) => void;
189
+ /**
190
+ * Custom error class for beautifi
191
+ */
192
+ export declare class LivePhotoError extends Error {
193
+ readonly code: LivePhotoErrorCode;
194
+ readonly originalError?: Error | undefined;
195
+ constructor(message: string, code: LivePhotoErrorCode, originalError?: Error | undefined);
196
+ }
197
+ /**
198
+ * Default configuration values
199
+ */
200
+ export declare const DEFAULT_OPTIONS: Required<Omit<LivePhotoOptions, 'apiKey'>>;
201
+ /**
202
+ * Default animation configuration
203
+ */
204
+ export declare const DEFAULT_ANIMATION_CONFIG: AnimationConfig;
package/package.json ADDED
@@ -0,0 +1,79 @@
1
+ {
2
+ "name": "@beautifi/plugin",
3
+ "version": "0.1.0",
4
+ "description": "beautifi JavaScript plugin that transforms static images into lifelike animated photos using AI",
5
+ "type": "module",
6
+ "main": "dist/beautifi.cjs.js",
7
+ "module": "dist/beautifi.esm.js",
8
+ "browser": "dist/beautifi.umd.js",
9
+ "types": "dist/types/index.d.ts",
10
+ "exports": {
11
+ ".": {
12
+ "import": "./dist/beautifi.esm.js",
13
+ "require": "./dist/beautifi.cjs.js",
14
+ "types": "./dist/types/index.d.ts"
15
+ },
16
+ "./lite": {
17
+ "import": "./dist/beautifi-lite.esm.js",
18
+ "require": "./dist/beautifi-lite.cjs.js",
19
+ "types": "./dist/types/lite.d.ts"
20
+ },
21
+ "./package.json": "./package.json"
22
+ },
23
+ "jsdelivr": "dist/beautifi.min.js",
24
+ "unpkg": "dist/beautifi.min.js",
25
+ "sideEffects": false,
26
+ "files": [
27
+ "dist",
28
+ "README.md"
29
+ ],
30
+ "scripts": {
31
+ "dev": "vite",
32
+ "build": "tsc && vite build",
33
+ "build:lite": "vite build --config vite.lite.config.ts",
34
+ "build:all": "npm run build && npm run build:lite && npm run sri",
35
+ "sri": "npx tsx scripts/generate-sri.ts",
36
+ "typecheck": "tsc --noEmit",
37
+ "test": "vitest run",
38
+ "test:watch": "vitest",
39
+ "lint": "eslint src --ext .ts",
40
+ "clean": "rm -rf dist"
41
+ },
42
+ "keywords": [
43
+ "beautifi",
44
+ "animation",
45
+ "images",
46
+ "ai-photos",
47
+ "gemini",
48
+ "ai",
49
+ "cinemagraph",
50
+ "image-animation",
51
+ "living-photos"
52
+ ],
53
+ "author": "AgenticCompany",
54
+ "license": "MIT",
55
+ "repository": {
56
+ "type": "git",
57
+ "url": "git+https://github.com/AgenticCompany/beautifi.git"
58
+ },
59
+ "homepage": "https://beautif.ai",
60
+ "bugs": {
61
+ "url": "https://github.com/AgenticCompany/beautifi/issues"
62
+ },
63
+ "devDependencies": {
64
+ "@types/node": "^20.10.0",
65
+ "@typescript-eslint/eslint-plugin": "^6.13.0",
66
+ "@typescript-eslint/parser": "^6.13.0",
67
+ "eslint": "^8.55.0",
68
+ "prettier": "^3.1.0",
69
+ "typescript": "^5.3.0",
70
+ "vite": "^5.0.0",
71
+ "terser": "^5.31.0",
72
+ "vite-plugin-dts": "^3.6.0",
73
+ "vitest": "^1.0.0"
74
+ },
75
+ "publishConfig": {
76
+ "access": "public",
77
+ "registry": "https://registry.npmjs.org/"
78
+ }
79
+ }