feat: initialize Video.js 10 monorepo with core architecture

- Set up monorepo structure with core, HTML, React, and React Native packages
- Add TypeScript configuration with project references
- Create foundational packages: media-store, playback-engine, media, icons
- Implement platform-specific packages for HTML, React, and React Native
- Add comprehensive documentation and development tooling
- Include CLAUDE.md with development guidelines and conventional commits

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Christian Pillsbury
2025-07-29 10:41:46 -07:00
co-authored by Claude
commit 4b0d84e9c8
55 changed files with 3421 additions and 0 deletions
@@ -0,0 +1,30 @@
{
"name": "@vjs-10/playback-engine",
"version": "0.1.0",
"description": "An abstraction for building or abstracting media source management (provides a common contract for things like hls.js or dash.js).",
"main": "dist/index.js",
"types": "dist/index.d.ts",
"files": [
"dist"
],
"scripts": {
"build": "tsc",
"test": "echo \"No tests yet\"",
"clean": "rm -rf dist"
},
"keywords": [
"media",
"playback",
"engine",
"hls",
"dash",
"streaming"
],
"license": "Apache-2.0",
"devDependencies": {
"typescript": "^5.3.0"
},
"publishConfig": {
"access": "public"
}
}
@@ -0,0 +1,83 @@
export interface MediaSource {
src: string;
type: string;
}
export interface PlaybackEngineOptions {
autoplay?: boolean;
preload?: 'none' | 'metadata' | 'auto';
}
export abstract class PlaybackEngine {
protected element: HTMLMediaElement | null = null;
protected options: PlaybackEngineOptions;
constructor(options: PlaybackEngineOptions = {}) {
this.options = options;
}
abstract attach(element: HTMLMediaElement): void;
abstract detach(): void;
abstract load(source: MediaSource): Promise<void>;
abstract play(): Promise<void>;
abstract pause(): void;
abstract seekTo(time: number): void;
getElement(): HTMLMediaElement | null {
return this.element;
}
}
export class NativePlaybackEngine extends PlaybackEngine {
attach(element: HTMLMediaElement): void {
this.element = element;
}
detach(): void {
this.element = null;
}
async load(source: MediaSource): Promise<void> {
if (!this.element) {
throw new Error('No media element attached');
}
this.element.src = source.src;
await new Promise((resolve, reject) => {
const onLoad = () => {
this.element!.removeEventListener('loadedmetadata', onLoad);
this.element!.removeEventListener('error', onError);
resolve(void 0);
};
const onError = () => {
this.element!.removeEventListener('loadedmetadata', onLoad);
this.element!.removeEventListener('error', onError);
reject(new Error('Failed to load media'));
};
this.element.addEventListener('loadedmetadata', onLoad);
this.element.addEventListener('error', onError);
});
}
async play(): Promise<void> {
if (!this.element) {
throw new Error('No media element attached');
}
await this.element.play();
}
pause(): void {
if (!this.element) {
throw new Error('No media element attached');
}
this.element.pause();
}
seekTo(time: number): void {
if (!this.element) {
throw new Error('No media element attached');
}
this.element.currentTime = time;
}
}
@@ -0,0 +1,9 @@
{
"extends": "../../../tsconfig.base.json",
"compilerOptions": {
"outDir": "./dist",
"rootDir": "./src"
},
"include": ["src/**/*"],
"exclude": ["dist", "node_modules"]
}