ArtPlayer is a monorepo for a modern HTML5 video player and its ecosystem packages.
- Homepage:
https://artplayer.org - Local dev site:
http://localhost:8082 - API docs:
https://artplayer.org/document - Packaging model: workspace monorepo with per-package versioning and per-package build output
The repository contains:
packages/artplayer: the core playerpackages/artplayer-plugin-*: UI and playback pluginspackages/artplayer-proxy-*: proxy renderers and playback adapterspackages/artplayer-tool-*: helper toolspackages/artplayer-vitepress: docs site packagedocs/: local demo site, examples, compiled assets, generated docsscripts/: custom build/dev/doc tooling
- Verify the real implementation before editing docs or examples.
- Prefer changing the source package first, then regenerate build artifacts only when needed.
- Keep package APIs small and consistent with existing ArtPlayer plugin conventions.
- Preserve the existing visual and API style of sibling packages instead of inventing a new pattern.
- When touching demo examples, make sure the example still works in
http://localhost:8082. - Do not hand-edit
dist/,docs/compiled/, ordocs/uncompiled/unless a build step generated them.
Use the repo scripts rather than ad hoc bundler commands.
npm run devStarts the local dev site on port 8082 and interactively selects a package to watch. The selected package is built into:
docs/uncompiled/<package>/
npm run buildInteractive build for one package. Outputs:
packages/<name>/dist/*.js|*.legacy.js|*.mjs- copied artifacts into
docs/compiled/
Build all packages:
npm run build allnpm run build:i18n
npm run build:ts
npm run build:docs
npm run build:llm
npm run build:test
npm run lint
npm run build:allNotes:
npm run linttargets package source/types plus scripts and TypeScript demo assets.npm run build:allis expensive; use it when a change truly spans builds/docs/types/lint together.
- Root demo index:
http://localhost:8082 - Demo by package/example:
http://localhost:8082/?libs=./uncompiled/<package>/index.js&example=<example>
- Docs:
http://localhost:8082/document/
For proxy/plugin work, prefer validating on the local demo page rather than reasoning only from source.
packages/artplayer/src/index.js: player entrypackages/artplayer/src/player/: playback mixins and player-facing behaviorpackages/artplayer/src/control/: bottom controlspackages/artplayer/src/setting/: settings panelpackages/artplayer/src/contextmenu/: context menu itemspackages/artplayer/src/plugins/: built-in pluginspackages/artplayer/src/utils/: shared helpers, component base classes, DOM utilitiespackages/artplayer/types/: public TS declarations
Most ecosystem packages follow this pattern:
packages/<package>/
src/index.js
src/*.less # optional
types/*.d.ts # optional but preferred for public APIs
README.md
package.json
dist/*
docs/assets/example/*.js: runnable browser examplesdocs/assets/ts/*.js: TypeScript demo assets targeted by lint/docs flowsdocs/uncompiled/: dev outputdocs/compiled/: production-copied outputdocs/document/: generated docs content
ArtPlayer composes many subsystems during construction. Common integration points:
art.templateart.eventsart.controlsart.settingart.contextmenuart.layersart.pluginsart.player
When extending behavior, prefer integrating with these existing systems rather than bypassing them.
Controls and setting entries are managed through component registries.
Relevant implementation:
packages/artplayer/src/control/index.jspackages/artplayer/src/setting/index.jspackages/artplayer/src/utils/component.js
Important behavior:
art.controls.update(...)andart.setting.update(...)replace existing entries bynameart.controls.remove(name)andart.setting.remove(name)are the correct cleanup APIs- selector-style controls rely on
defaultflags to determine highlighted items
If a plugin conditionally shows UI, it must also clean that UI up when the condition no longer holds.
Standard plugin/export shape:
export default function somePlugin(option = {}) {
return (art) => {
return {
name: 'somePlugin',
}
}
}Naming conventions:
- package:
artplayer-plugin-<name> - global:
artplayerPlugin<Name> - exported function name should match the global naming convention
Proxy packages usually return a non-video element or video-like shim and emulate media element behavior for ArtPlayer.
Examples:
packages/artplayer-proxy-canvaspackages/artplayer-proxy-mediabunny
When editing proxy packages:
- keep the HTMLMediaElement-like surface coherent
- keep event ordering stable
- treat
loadedmetadata,loadeddata,canplay,seeked,waiting, andpause/playsemantics carefully - ensure UI state is updated and cleaned up when source topology changes
The reference implementation for adaptive selector UI is:
packages/artplayer-plugin-hls-control/src/index.js
If adding HLS-like quality/audio selection elsewhere:
- follow the selector format used there
- derive highlighted items from actual current tracks, not only from mode flags
- avoid stale selectors when changing to streams without the same topology
- Always edit
src/andtypes/first. - Rebuild package artifacts after source changes that should ship.
- Do not treat
dist/as source of truth. - If a change affects demo behavior, also verify the matching file in
docs/assets/example/.
For package-specific builds, the normal flow is:
npm run devand pick the package for fast local iteration- validate in
http://localhost:8082 npm run buildand pick the package when ready to update shippable artifacts
If a public package API changes, check whether these also need updates:
- the package
README.md docs/assets/example/<name>.jstypes/<name>.d.ts- any generated compiled outputs if you built the package
Keep examples realistic and runnable. Prefer local demo URLs or stable public sample streams.
- Follow existing plain JavaScript style in the repo.
- Use ASCII unless a file already requires otherwise.
- Match the minimal-comment style of neighboring files.
- Avoid unnecessary abstraction; this codebase generally prefers direct implementation.
- Respect current browser targets:
- modern build:
es2020 - legacy build:
es2015
- modern build:
For most package changes, validate as many of these as apply:
- source file lint passes
- local demo page loads
- expected events fire once and in the correct order
- controls/settings render correctly
- cleanup works after restart, source switch, or destroy
- package build succeeds
For playback/proxy changes specifically:
- test initial load
- test play/pause
- test seek
- test switching source or track topology
- test whether UI reflects the actual selected track/quality
This package now depends on modern mediabunny and supports HLS through mediabunny input handling.
Files to understand first:
packages/artplayer-proxy-mediabunny/src/index.jspackages/artplayer-proxy-mediabunny/src/VideoShim.jspackages/artplayer-proxy-mediabunny/src/MediaBunnyEngine.jspackages/artplayer-proxy-mediabunny/src/input.jspackages/artplayer-proxy-mediabunny/src/m3u8.js
Key expectations:
- HLS source detection should happen in
input.js - track selection should use actual pairable audio/video relationships
- selector UI should mirror the behavior of
artplayer-plugin-hls-control - selector cleanup is required when a later source no longer supports the same controls
- avoid duplicate readiness events during load and track switches
Start with the nearest sibling implementation instead of inventing a new pattern:
- control/setting UI:
artplayer-plugin-hls-control,artplayer-plugin-dash-control - proxy behavior:
artplayer-proxy-canvas,artplayer-proxy-mediabunny - component lifecycle:
packages/artplayer/src/utils/component.js
If a change spans source, examples, and packaging, make all three consistent in the same pass.