Skip to content

Commit a2f41b1

Browse files
karngyanclaude
andcommitted
docs: readme, changesets, ci
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
1 parent 4d98686 commit a2f41b1

7 files changed

Lines changed: 888 additions & 9 deletions

File tree

.changeset/README.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
# Changesets
2+
3+
Hello and welcome! This folder has been automatically generated by `@changesets/cli`, a build tool that works
4+
with multi-package repos, or single-package repos to help you version and publish your code. You can
5+
find the full documentation for it [in our repository](https://github.com/changesets/changesets).
6+
7+
We have a quick list of common questions to get you started engaging with this project in
8+
[our documentation](https://github.com/changesets/changesets/blob/main/docs/common-questions.md).

.changeset/config.json

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
{
2+
"$schema": "https://unpkg.com/@changesets/config@3.1.4/schema.json",
3+
"changelog": "@changesets/cli/changelog",
4+
"commit": false,
5+
"fixed": [],
6+
"linked": [],
7+
"access": "public",
8+
"baseBranch": "main",
9+
"updateInternalDependencies": "patch",
10+
"ignore": []
11+
}

.changeset/initial-release.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
---
2+
"@karnstack/kino": minor
3+
---
4+
5+
Initial release of kino, a premium themeable React video player with a pluggable-provider architecture.
6+
7+
- Translucent glass / macOS-style player chrome: idle play overlay with speed pre-select, auto-hiding control bar, scrubber with buffered shading, drag-to-seek, and storyboard thumbnail previews.
8+
- Speed, quality, and captions menus that gate themselves on provider and platform capabilities.
9+
- Keyboard-first controls (play/pause, seek, volume, rate, mute, captions, fullscreen, and percent seek) that yield to focused text inputs.
10+
- Themeable via the `accentColor` prop and `--kino-*` CSS custom properties.
11+
- Mux provider built on the `@mux/mux-video` element, plus a `MuxPlayer` drop-in that accepts signed playback, thumbnail, and storyboard tokens (auth-agnostic; tokens are minted server-side).
12+
- Headless `Player` root, store, and control primitives exported for custom chrome.
13+
- React 19 peer dependency. Entry points: `@karnstack/kino`, `@karnstack/kino/mux`, and `@karnstack/kino/styles.css`.

.github/workflows/ci.yml

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
name: CI
2+
3+
on:
4+
push:
5+
branches: [main]
6+
pull_request:
7+
branches: [main]
8+
9+
jobs:
10+
build:
11+
runs-on: ubuntu-latest
12+
steps:
13+
- name: Checkout
14+
uses: actions/checkout@v4
15+
16+
- name: Setup pnpm
17+
uses: pnpm/action-setup@v4
18+
19+
- name: Setup Node
20+
uses: actions/setup-node@v4
21+
with:
22+
node-version: 24
23+
cache: pnpm
24+
25+
- name: Install dependencies
26+
run: pnpm install --frozen-lockfile
27+
28+
- name: Typecheck
29+
run: pnpm typecheck
30+
31+
- name: Lint
32+
run: pnpm lint
33+
34+
- name: Test
35+
run: pnpm test
36+
37+
- name: Build
38+
run: pnpm build

README.md

Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
# @karnstack/kino
2+
3+
A premium, themeable React video player with a pluggable-provider architecture. Translucent glass / macOS-style chrome, keyboard-first controls, and a small typed surface. Mux is the first provider.
4+
5+
kino ships the player UI and a provider contract. Each provider adapts a streaming engine to that contract, so the same glass chrome can sit on top of different backends. The Mux provider is built on the `@mux/mux-video` custom element.
6+
7+
## Install
8+
9+
```sh
10+
pnpm add @karnstack/kino
11+
```
12+
13+
The Mux engine (`@mux/mux-video`) is pulled in transitively, so you do not install it yourself. React 19 is a peer dependency (`react` and `react-dom` `>=19`).
14+
15+
## Quick start
16+
17+
```tsx
18+
import { MuxPlayer } from "@karnstack/kino/mux"
19+
import "@karnstack/kino/styles.css"
20+
21+
export function Clip() {
22+
return (
23+
<MuxPlayer
24+
playbackId="your-playback-id"
25+
tokens={{ playback, thumbnail, storyboard }}
26+
accentColor="oklch(50.8% 0.118 165.612)"
27+
/>
28+
)
29+
}
30+
```
31+
32+
Give the player a sized container. It fills `100%` width and height of its parent, so wrap it in an element with the aspect ratio or dimensions you want.
33+
34+
### Tokens are passed in
35+
36+
kino is auth-agnostic. For signed playback you mint the `playback`, `thumbnail`, and `storyboard` tokens server-side and hand them to the player through the `tokens` prop. The player never holds a signing key and never talks to your auth layer; it only appends the tokens you give it to the media, thumbnail, and storyboard URLs. For public playback you can omit `tokens` entirely.
37+
38+
## Theming
39+
40+
The quickest knob is the `accentColor` prop, which drives the scrubber fill, active menu items, and range controls.
41+
42+
```tsx
43+
<MuxPlayer playbackId="..." accentColor="oklch(50.8% 0.118 165.612)" />
44+
```
45+
46+
For deeper control, every visual is driven by CSS custom properties on the `.kino` root. Override them in your own stylesheet, or pass a `theme` object of property/value pairs to set them inline.
47+
48+
| Custom property | Default | Role |
49+
| --- | --- | --- |
50+
| `--kino-accent` | `oklch(50.8% 0.118 165.612)` | Accent color (progress, active items, ranges) |
51+
| `--kino-radius` | `12px` | Corner radius of glass surfaces |
52+
| `--kino-surface` | `color-mix(in oklab, black 55%, transparent)` | Glass surface fill |
53+
| `--kino-surface-strong` | `color-mix(in oklab, black 70%, transparent)` | Stronger surface (idle play button) |
54+
| `--kino-border` | `color-mix(in oklab, white 14%, transparent)` | Hairline borders |
55+
| `--kino-text` | `oklch(98% 0 0)` | Primary text and icons |
56+
| `--kino-text-dim` | `color-mix(in oklab, white 65%, transparent)` | Secondary text (timecode) |
57+
| `--kino-blur` | `18px` | Backdrop blur radius |
58+
| `--kino-shadow` | `0 8px 40px rgba(0, 0, 0, 0.45)` | Surface drop shadow |
59+
| `--kino-ease` | `cubic-bezier(0.22, 1, 0.36, 1)` | Shared transition easing |
60+
61+
```css
62+
.kino {
63+
--kino-accent: oklch(70% 0.15 250);
64+
--kino-radius: 16px;
65+
--kino-blur: 24px;
66+
}
67+
```
68+
69+
## Keyboard shortcuts
70+
71+
The player is keyboard-first. Shortcuts are ignored while a text input, textarea, select, or contenteditable element is focused, and modifier-key combinations (Ctrl/Cmd/Alt) are passed through.
72+
73+
| Key | Action |
74+
| --- | --- |
75+
| `Space` / `K` | Play / pause |
76+
| `<` / `>` | Decrease / increase playback rate (0.25 step) |
77+
| `M` | Toggle mute |
78+
| `C` | Toggle captions |
79+
| `S` | Open the speed menu |
80+
| `F` | Toggle fullscreen |
81+
| `0`-`9` | Seek to 0%-90% of the duration |
82+
83+
## Capability gating
84+
85+
Controls hide themselves when the active provider or platform cannot support them, rather than presenting a dead button. The provider reports a capability set, and each control checks it:
86+
87+
- Quality switching is hidden when the engine exposes no renditions, and is off on iOS where the system owns adaptive playback.
88+
- Custom-chrome fullscreen is off on iOS (the platform uses its native fullscreen for the underlying video element).
89+
- Picture-in-picture is hidden when the browser does not support it.
90+
- The captions menu appears only when the media actually carries subtitle or caption tracks.
91+
92+
## Local development
93+
94+
```sh
95+
pnpm install
96+
pnpm dev # demo harness at http://localhost:5173
97+
pnpm test # vitest
98+
pnpm build # bundle to dist/
99+
pnpm typecheck # tsc --noEmit
100+
pnpm lint # eslint
101+
```
102+
103+
`pnpm dev` runs the demo harness, which plays a public sample clip through a small demo file provider. No Mux account or signed tokens are needed to see the real glass UI. To exercise the Mux provider in the demo, set `VITE_MUX_PLAYBACK_ID` (and optionally the matching token env vars) before running `pnpm dev`.
104+
105+
## Roadmap
106+
107+
- More providers: YouTube, file, and Vimeo
108+
- AirPlay support
109+
- Chapters
110+
- Documented headless primitives for fully custom chrome
111+
112+
## License
113+
114+
MIT

package.json

Lines changed: 31 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,23 @@
44
"description": "Premium themeable React video player with pluggable providers.",
55
"license": "MIT",
66
"type": "module",
7-
"sideEffects": ["**/*.css", "**/mux-video-element.ts", "./dist/mux.js"],
8-
"files": ["dist"],
7+
"sideEffects": [
8+
"**/*.css",
9+
"**/mux-video-element.ts",
10+
"./dist/mux.js"
11+
],
12+
"files": [
13+
"dist"
14+
],
915
"exports": {
10-
".": { "types": "./dist/index.d.ts", "import": "./dist/index.js" },
11-
"./mux": { "types": "./dist/mux.d.ts", "import": "./dist/mux.js" },
16+
".": {
17+
"types": "./dist/index.d.ts",
18+
"import": "./dist/index.js"
19+
},
20+
"./mux": {
21+
"types": "./dist/mux.d.ts",
22+
"import": "./dist/mux.js"
23+
},
1224
"./styles.css": "./dist/styles.css"
1325
},
1426
"scripts": {
@@ -20,16 +32,26 @@
2032
"lint": "eslint .",
2133
"format": "prettier --write ."
2234
},
23-
"peerDependencies": { "react": ">=19", "react-dom": ">=19" },
24-
"dependencies": { "@mux/mux-video": "^0.31.0" },
35+
"peerDependencies": {
36+
"react": ">=19",
37+
"react-dom": ">=19"
38+
},
39+
"dependencies": {
40+
"@mux/mux-video": "^0.31.0"
41+
},
2542
"pnpm": {
26-
"onlyBuiltDependencies": ["esbuild"],
27-
"approvedBuilds": ["esbuild"]
43+
"onlyBuiltDependencies": [
44+
"esbuild"
45+
],
46+
"approvedBuilds": [
47+
"esbuild"
48+
]
2849
},
2950
"devDependencies": {
51+
"@changesets/cli": "^2.31.0",
3052
"@eslint/js": "^9.0.0",
31-
"@testing-library/react": "^16.1.0",
3253
"@testing-library/jest-dom": "^6.6.0",
54+
"@testing-library/react": "^16.1.0",
3355
"@types/react": "^19.0.0",
3456
"@types/react-dom": "^19.0.0",
3557
"@vitejs/plugin-react": "^4.3.0",

0 commit comments

Comments
 (0)