docs(rfc): add rfc structure (#316)

This commit is contained in:
rahim
2026-01-20 16:13:34 +11:00
committed by GitHub
parent 35c6cb1e16
commit 7702601cf4
17 changed files with 280 additions and 189 deletions
+68
View File
@@ -0,0 +1,68 @@
# Implementation Plans
Working notes and implementation details for AI agents and developers.
## Purpose
This directory contains:
- Step-by-step implementation plans
- Working notes during development
- AI-agent context for executing RFCs
- Completed work logs with key decisions
## What Belongs Here
- Implementation details and code snippets
- Debugging notes and discoveries
- Task breakdowns for complex features
- Post-implementation summaries
## What Doesn't Belong Here
Design proposals and architectural decisions belong in `/rfcs`. This directory is for **how** to implement, not **what** or **why**.
## Compaction Rule
Before merging a PR, compact completed plans:
1. Remove verbose implementation details
2. Point to PR and commits for specifics
3. Keep key decisions and important notes
4. Update status to COMPLETED
Example compacted plan:
```markdown
# Feature Name
**Status:** COMPLETED
**PR:** [#123](https://github.com/videojs/v10/pull/123)
## Summary
Brief description of what was implemented.
## Key Decisions
- Decision 1: Rationale
- Decision 2: Rationale
## Notes
Any gotchas or important context for future reference.
```
## Relationship to RFCs
Plans may link to their parent RFC:
```markdown
# Implementing Feature X
**RFC:** [/rfcs/feature-x.md](/rfcs/feature-x.md)
## Tasks
...
```
+16 -25
View File
@@ -1,38 +1,29 @@
# Store React/DOM Bindings
> **STATUS: COMPLETED** — Superseded by `proxies.md` for API changes.
**Status:** COMPLETED (Superseded by reactive.md)
## Summary
Implemented React and Lit bindings for `@videojs/store`:
Implemented React and Lit bindings for `@videojs/store`: `createStore()` factory returning Provider + hooks/controllers.
- `createStore()` factory returning Provider + hooks/controllers
- Skins define store configs, export Provider + Skin + extendConfig
- Base hooks/controllers for testing and advanced use
## Key PRs
## Completed Work
| Phase | PR | Description |
| ----- | ----------------------------------------------- | ------------------------------------------------------------- |
| 0 | [#283](https://github.com/videojs/v10/pull/283) | `uniqBy`, `composeCallbacks`, `extendConfig` utilities |
| 0.5 | [#287](https://github.com/videojs/v10/pull/287) | Queue task refactor (unified tasks map, status discriminator) |
| 1 | [#288](https://github.com/videojs/v10/pull/288) | React bindings (createStore, Provider, hooks) |
| 2 | [#289](https://github.com/videojs/v10/pull/289) | Lit bindings (controllers, mixins, context) |
| 3 | [#292](https://github.com/videojs/v10/pull/292) | DOM media slices (playback, time, buffer, volume, source) |
| 4 | [#290](https://github.com/videojs/v10/pull/290) | Mutation hooks/controllers |
| 5 | [#291](https://github.com/videojs/v10/pull/291) | Optimistic hooks/controllers |
| 6 | [#298](https://github.com/videojs/v10/pull/298) | Frosted skin (React + HTML) |
| Phase | PR | Description |
| ----- | ------------------------------------------------------------------------------------------------ | ------------------------------------------------------ |
| 0 | [#283](https://github.com/videojs/v10/pull/283) | `uniqBy`, `composeCallbacks`, `extendConfig` utilities |
| 0.5 | [#287](https://github.com/videojs/v10/pull/287) | Queue task refactor |
| 1 | [#288](https://github.com/videojs/v10/pull/288) | React bindings |
| 2 | [#289](https://github.com/videojs/v10/pull/289) | Lit bindings |
| 3 | [#292](https://github.com/videojs/v10/pull/292) | DOM media slices |
| 4-5 | [#290](https://github.com/videojs/v10/pull/290), [#291](https://github.com/videojs/v10/pull/291) | Mutation/Optimistic hooks |
| 6 | [#298](https://github.com/videojs/v10/pull/298) | Frosted skin |
## Key Decisions
- Hook naming: `useStore`, `useSelector`, `useRequest`, `useTasks`, `useMutation`, `useOptimistic`
- Controller naming: `SelectorController`, `RequestController`, `TasksController`, etc.
- Mutation/Optimistic: Discriminated union types with `status` field
- Lit mixins: `StoreMixin` (combined), `StoreProviderMixin`, `StoreAttachMixin`
- Provider resolution: Isolated by default; `inherit` prop for parent context
- Package structure: `store/react` and `store/lit`
- Provider resolution: Isolated by default; `inherit` prop for parent context
- Lit mixins: `StoreMixin` (combined), `StoreProviderMixin`, `StoreAttachMixin`
## Superseded By
## Notes
The selector-based APIs (`useSelector`, `SelectorController`, `store.subscribe()`) are being
replaced by proxy-based reactivity. See **`proxies.md`** for the migration plan.
Selector-based APIs were later replaced by proxy-based reactivity. See `reactive.md`.
+7 -23
View File
@@ -1,42 +1,26 @@
# Queue Simplification
> **STATUS: COMPLETED**
**Status:** COMPLETED
## Summary
Simplified Queue from ~524 LOC to ~405 LOC. Removed convenience features only used in tests/docs, kept what's essential for async media operations.
Simplified Queue from ~524 LOC to ~405 LOC. Removed convenience features only used in tests/docs, kept essentials for async media operations.
## Why Queue Exists
All writes are async requests — this is the architecture. Queue handles:
All writes are async requests. Queue handles:
- Supersession (rapid clicks → only last executes)
- AbortController propagation
- Task lifecycle tracking (pending/success/error)
- Error surfacing for UI
## Features Removed
## Removed
- `cancel()` method (use `abort()`)
- `flush()` method (no configurable scheduling)
- `queued` getter (internal detail)
- `TaskScheduler` type, `QueueConfig` interface
- `delay()`, `microtask` exports
- `schedule` param on `QueueTask`
- `cancel()`, `flush()`, `queued` getter
- `TaskScheduler`, `QueueConfig`, `schedule` param
- `delay()`, `microtask`, DOM schedulers (`raf()`, `idle()`)
- `onDispatch`, `onSettled` hooks
- DOM schedulers (`raf()`, `idle()`)
## Files Changed
| File | Change |
| ------------------------- | ------------------------------------ |
| `core/queue.ts` | Main simplification |
| `core/task.ts` | NEW: Extracted task types and guards |
| `core/index.ts` | Added task.ts export |
| `core/request.ts` | Removed schedule field |
| `core/store.ts` | Removed schedule from enqueue |
| `dom/` | DELETED entire directory |
| Various controllers/hooks | Updated imports |
## Final API
+14 -49
View File
@@ -1,9 +1,19 @@
# Reactive State
**Status:** COMPLETE
**Status:** COMPLETED
**PR:** [#311](https://github.com/videojs/v10/pull/311)
Replaced class-based `State` with proxy-based reactive primitives. Inspired by [Valtio](https://github.com/pmndrs/valtio).
## Summary
Replaced class-based `State` with proxy-based reactive primitives inspired by Valtio.
## Key Decisions
| Decision | Rationale |
| ----------------------------- | ---------------------------------------------------- |
| Auto-batch to microtask | Coalesce rapid mutations, export `flush()` for tests |
| React: `useSyncExternalStore` | Version counter for change detection |
| Lit: `SnapshotController` | `host.requestUpdate()` + optional callback |
## API
@@ -11,53 +21,8 @@ Replaced class-based `State` with proxy-based reactive primitives. Inspired by [
import { batch, flush, reactive, snapshot, subscribe, subscribeKeys, track } from '@videojs/store';
```
| Export | Purpose |
| -------------------------------- | ---------------------------------------------- |
| `reactive(initial)` | Create reactive state with parent bubbling |
| `isReactive(value)` | Check if value is reactive |
| `subscribe(state, fn)` | Subscribe to all changes |
| `subscribeKeys(state, keys, fn)` | Subscribe to specific key changes |
| `batch(fn)` | Group mutations, flush after |
| `flush()` | Force pending notifications (for tests) |
| `snapshot(state)` | Return frozen shallow copy |
| `track(state)` | Track property access for fine-grained updates |
## Key Behaviors
- **Auto-batching** — Notifications deferred to microtask
- **Nested tracking** — Auto-wraps nested objects, changes bubble to parents
- **Synchronous reads** — Mutations apply immediately, only notifications are deferred
## Decisions
| Question | Decision |
| ------------- | -------------------------------------------------------------------- |
| Batching | Auto-batch to microtask. Export `flush()` for tests. |
| React pattern | `useSyncExternalStore` with version counter for change detection |
| Lit pattern | `SnapshotController` with `host.requestUpdate()` + optional callback |
## Breaking Changes
**Removed:**
Removed: `useMutation`, `useOptimistic`, `useSelector`, `MutationController`, `OptimisticController`, `SelectorController`
- React: `useMutation`, `useOptimistic`, `useSelector`
- Lit: `MutationController`, `OptimisticController`, `SelectorController`
**Migration:**
| Before | After |
| ----------------------------------- | ------------------------------------- |
| `useSelector(store, s => s.volume)` | `useSnapshot(store.state).volume` |
| `useMutation(store, 'play')` | `useSnapshot(store.queue.tasks).play` |
| `SelectorController` | `SnapshotController` |
| `store.subscribe(fn)` | `subscribe(store.state, fn)` |
## Testing
Use `flush()` for synchronous assertions:
```ts
state.volume = 0.5;
flush();
expect(listener).toHaveBeenCalledOnce();
```
Migration: Use `useSnapshot(store.state)` and `subscribe(store.state, fn)` instead.
+3 -1
View File
@@ -14,9 +14,11 @@ type(scope): lowercase description
| Prefix | Use for |
| ------------ | ------------------------------------ |
| `RFC:` | Request for comments / proposals |
| `[RFC]` | Request for comments / proposals |
| `Discovery:` | Exploration / research / prototyping |
**Note:** RFC PRs use `[RFC] Title` format while open. When merged, the squash commit uses `docs(rfc): title`.
## PR Body Template
```markdown
+2 -2
View File
@@ -13,8 +13,8 @@ Infer commit scope from changed file paths.
| `packages/react/` | `react` |
| `packages/react-native/` | `react-native` |
| `packages/icons/` | `icons` |
| `packages/skins/` | `skins` |
| `site/` | `site` |
| `rfcs/` | `rfc` |
| `.claude/` | `claude` |
| `.github/workflows/` | `ci` |
| `.github/` | `cd` |
@@ -34,7 +34,7 @@ From `commitlint.config.js`:
```
cd, ci, claude, core, docs, html, icons, packages,
plan, react-native, react, root, site, skins, store,
plan, react-native, react, rfc, root, site, store,
test, utils
```
+13
View File
@@ -475,6 +475,19 @@ get size(): number { ... }
add(cleanup: CleanupFn): void { ... }
```
## Design Documents
| Location | Purpose |
| ---------------- | ----------------------------------------------------------------- |
| `rfcs/` | Design proposals, API decisions, architecture — public discussion |
| `.claude/plans/` | Implementation notes, AI-agent context, working drafts |
**RFCs** focus on **what** and **why**. Write an RFC for major API changes, architectural decisions, or patterns used across packages.
**Implementation plans** focus on **how**. Use `.claude/plans/` for step-by-step implementation details, debugging notes, and AI-agent context.
Before merging, compact completed plans: keep key decisions and important notes, point to PRs/commits for details. See `.claude/plans/README.md`.
## Rule Placement
CLAUDE.md contains repo-wide conventions. Domain-specific patterns live in skills:
+13 -4
View File
@@ -79,10 +79,7 @@ pnpm dev
This will run the entire workspace in developer mode, meaning all applications (examples and website) will also be started on their respective ports.
```sh
# Run a specific app
pnpm dev:html
pnpm dev:react
pnpm dev:next
# Run the documentation site
pnpm dev:site
```
@@ -175,6 +172,18 @@ When your changes introduce new patterns:
- **Code conventions** → Update `CLAUDE.md` Code Rules section
- **Domain patterns** → Update relevant skill in `.claude/skills/`
## RFCs (Design Documents)
For significant architectural decisions and API designs, we use RFCs (Request for Comments). See [`rfcs/README.md`](./rfcs/README.md) for the full process.
**When to write an RFC:**
- Introducing a new public API surface
- Making architectural changes affecting multiple packages
- Proposing patterns used throughout the codebase
**Skip the RFC for:** Bug fixes, small contained features, implementation details.
## Creating a Pull Request
By submitting a pull request, you agree that your contribution is provided under the
+2 -2
View File
@@ -11,7 +11,7 @@ Modern, modular, and composable media player framework for Web and React.
Thanks for checking out the project! It's in its early stages and currently a mix of prototyping
and early structure pointing in the direction we want to go with Video.js v10 (so be kind 🙏).
- Read our [early architecture goals][architecture].
- Read our [design documents][rfcs].
- Read the [v10 discussion topic][v10-discussion].
- Watch [Heff's recent presentation][heff-presentation].
@@ -58,7 +58,7 @@ Please see our [contributing guide](./CONTRIBUTING.md) for getting setup locally
Please note that this project is released with a [Contributor Code of Conduct][coc]. By
participating in this project you agree to abide by its terms.
[architecture]: ./docs/ARCHITECTURE.md
[rfcs]: ./rfcs
[v10-discussion]: https://github.com/videojs/video.js/discussions/9035
[heff-presentation]: https://players.brightcove.net/3737230800001/eyILA5XG7K_default/index.html?videoId=6379311036112
[coc]: https://github.com/videojs/video.js/blob/main/CODE_OF_CONDUCT.md
+23 -25
View File
@@ -9,30 +9,28 @@ export default {
},
],
rules: {
'scope-enum': [2, 'always', [
'cd',
'ci',
'claude',
'core',
'docs',
'demo',
'example',
'examples',
'example/html',
'example/react',
'example/next',
'html',
'icons',
'packages',
'plan',
'react-native',
'react',
'root',
'site',
'skins',
'store',
'test',
'utils',
]],
'scope-enum': [
2,
'always',
[
'cd',
'ci',
'claude',
'core',
'docs',
'html',
'icons',
'packages',
'plan',
'react-native',
'react',
'rfc',
'root',
'site',
'store',
'test',
'utils',
],
],
},
};
-58
View File
@@ -1,58 +0,0 @@
# Video.js 10 Architecture
**Status:** Technical Preview (initial working showcase for Demuxed)
- Current codebase is an early push by the team to have a working showcase for Demuxed.
- Architecture and patterns will evolve as we refine and plan the longterm structure.
## Early Goals
- Establish a common, TanStackbased core for consistent state management across supported platforms and frameworks.
- Ensure composition and compound patterns are firstclass.
- Adopt TypeScript throughout for safety and DX.
- Design for modularity, treeshaking, and performance.
- Fully support SSR / hydration.
- Create a compiler to handle transformation and output across multiple JS and CSS frameworks.
## Core Principles
- **Common Core:** TanStack state-driven architecture; DOM lives in a separate package; maps to web, React, and React Native.
- **Composition-first:** Compound component and functional patterns. E.g., React has `render(attrs, state)` prop to allow full control of element type or animations.
- **TypeScript everywhere.**
- **Modular & tree-shakeable.**
- **Performance-focused:** Minimal bundle size and payload, smooth 60+ FPS target.
- **SSR + hydration safe/optimized.**
## Accessibility
- Non-negotiable.
- Core owns ARIA roles, labels, navigation, and focus.
- Captions, keyboard navigation/shortcuts, and focus management.
- Meets WCAG 2.2 / CVAA standards outofbox.
## State & Reactivity
- State hooks and components support **controlled/uncontrolled** mode (`value` / `onChange`).
- State-driven architecture powers Web, React, and ReactNative.
- Maintain 16 ms frame budget.
- Offload heavy style computations to CSS.
- Minimal playback engine per user case.
- Stream + lazy caption parsing for large files.
- SSR: preload rendition segments in document head, ship parsed manifest, minimal composed-playback engine for faster TTF (timetofirstframe).
## Styling
- **Styleagnostic core:** No CSS shipped in Core or Primitives.
- **Styleready hooks:** Stable `data-*` attrs and CSS vars for easy theming.
- Default skins in separate exports (optional entry points).
- Primitives avoid Shadow DOM; themed skins may opt in.
- DOM trees stay one level deep per component part (Root, Thumb, Track, etc.).
- No internal JS animations.
- Components toggle data attributes (`data-open`, `data-starting-style`, etc.) for CSS or Motion libraries to hook into.
## CrossBrowser Compatibility
- Ensure consistent behavior across major browsers.
- Abstract differences in media APIs (fullscreen, PiP, captions, streaming).
- Normalize vendorspecific features through adapters and polyfills.
- Maintain uniform rendering, controls, and accessibility regardless of platform.
+111
View File
@@ -0,0 +1,111 @@
# RFCs
Request for Comments (RFC) documents for Video.js 10 architecture and API design decisions.
## What Belongs Here
RFCs document significant design decisions that benefit from review and discussion:
- Major API changes or new APIs
- Architectural decisions
- Design patterns used across packages
- Breaking changes with migration paths
## When to Write an RFC
Write an RFC when:
- Introducing a new public API surface
- Making architectural changes that affect multiple packages
- Proposing patterns that will be used throughout the codebase
- Changes need input from multiple contributors
Skip the RFC for:
- Bug fixes
- Small features contained to one package
- Implementation details that don't affect public APIs
- Documentation updates
## File Format
RFCs use a YAML frontmatter header for status tracking:
```markdown
---
status: draft
---
# Title
Content...
```
When implemented, add implementation details:
```markdown
---
status: implemented
implemented-in: v10.0.0-alpha.5
implementation-plan: .claude/plans/example.md
---
```
## Status Lifecycle
| Status | Meaning |
| ------------- | ---------------------------------- |
| `draft` | Under discussion, not yet accepted |
| `accepted` | Approved for implementation |
| `implemented` | Code shipped |
| `superseded` | Replaced by another RFC |
## Directory Structure
```
rfcs/
├── README.md # This file
├── feature-name.md # Single-file RFC
└── feature-name/ # Multi-file RFC
├── index.md # Overview and quick start
├── decisions.md # Design decisions and rationale
└── examples.md # Usage examples
```
## Contributing an RFC
### Branch and PR Workflow
1. **Create branch**: `rfc/feature-name`
2. **PR title while open**: `[RFC] Feature Name`
3. **Squash commit when merged**: `docs(rfc): feature name`
### Example
```bash
git checkout -b rfc/slice-accessor-design
# ... write RFC ...
git push -u origin rfc/slice-accessor-design
gh pr create --title "[RFC] Slice Accessor Design"
```
When the RFC is accepted and merged, the squash commit becomes:
```
docs(rfc): slice accessor design
```
## Relationship to Implementation Plans
RFCs focus on **what** and **why** — the design, rationale, and public API.
Implementation details live in `.claude/plans/` — step-by-step plans, code snippets, and AI-agent context for executing the RFC.
An RFC may link to its implementation plan:
```markdown
---
status: implemented
implementation-plan: .claude/plans/feature-name.md
---
```
@@ -1,3 +1,7 @@
---
status: draft
---
# Player API Design
Unified API for Media and Container concerns. Two stores internally, one API for users.
@@ -1,3 +1,7 @@
---
status: implemented
---
# Store Queue Design
## Overview