diff --git a/packages/html/src/cdn/audio-minimal-ui.ts b/packages/html/src/cdn/audio-minimal-ui.ts
new file mode 100644
index 00000000..96aeef70
--- /dev/null
+++ b/packages/html/src/cdn/audio-minimal-ui.ts
@@ -0,0 +1 @@
+import '../define/audio/minimal-ui';
diff --git a/packages/html/src/cdn/audio-minimal.ts b/packages/html/src/cdn/audio-minimal.ts
index 5fece6d6..14b88692 100644
--- a/packages/html/src/cdn/audio-minimal.ts
+++ b/packages/html/src/cdn/audio-minimal.ts
@@ -1,2 +1 @@
-import '../define/audio/player';
import '../define/audio/minimal-skin';
diff --git a/packages/html/src/cdn/audio-ui.ts b/packages/html/src/cdn/audio-ui.ts
new file mode 100644
index 00000000..d60b162f
--- /dev/null
+++ b/packages/html/src/cdn/audio-ui.ts
@@ -0,0 +1 @@
+import '../define/audio/ui';
diff --git a/packages/html/src/cdn/audio.ts b/packages/html/src/cdn/audio.ts
index 27849430..b30c0ef2 100644
--- a/packages/html/src/cdn/audio.ts
+++ b/packages/html/src/cdn/audio.ts
@@ -1,2 +1 @@
-import '../define/audio/player';
import '../define/audio/skin';
diff --git a/packages/html/src/cdn/video-minimal-ui.ts b/packages/html/src/cdn/video-minimal-ui.ts
new file mode 100644
index 00000000..60e3ef8a
--- /dev/null
+++ b/packages/html/src/cdn/video-minimal-ui.ts
@@ -0,0 +1 @@
+import '../define/video/minimal-ui';
diff --git a/packages/html/src/cdn/video-minimal.ts b/packages/html/src/cdn/video-minimal.ts
index 917f2732..c3c0a8ff 100644
--- a/packages/html/src/cdn/video-minimal.ts
+++ b/packages/html/src/cdn/video-minimal.ts
@@ -1,2 +1 @@
-import '../define/video/player';
import '../define/video/minimal-skin';
diff --git a/packages/html/src/cdn/video-ui.ts b/packages/html/src/cdn/video-ui.ts
new file mode 100644
index 00000000..181750ea
--- /dev/null
+++ b/packages/html/src/cdn/video-ui.ts
@@ -0,0 +1 @@
+import '../define/video/ui';
diff --git a/packages/html/src/cdn/video.ts b/packages/html/src/cdn/video.ts
index a5f4f119..185f189e 100644
--- a/packages/html/src/cdn/video.ts
+++ b/packages/html/src/cdn/video.ts
@@ -1,2 +1 @@
-import '../define/video/player';
import '../define/video/skin';
diff --git a/packages/html/src/define/audio/minimal-skin.tailwind.ts b/packages/html/src/define/audio/minimal-skin.tailwind.ts
index 8e969a27..513bf64d 100644
--- a/packages/html/src/define/audio/minimal-skin.tailwind.ts
+++ b/packages/html/src/define/audio/minimal-skin.tailwind.ts
@@ -20,19 +20,8 @@ import { cn } from '@videojs/utils/style';
import { safeDefine } from '../safe-define';
import { SkinElement } from '../skin-element';
-// Side-effect imports: register all custom elements used in the template.
-import '../media/container';
-import '../ui/error-dialog';
-import '../ui/mute-button';
-import '../ui/play-button';
-import '../ui/playback-rate-button';
-import '../ui/popover';
-import '../ui/seek-button';
-import '../ui/time';
-import '../ui/time-slider';
-import '../ui/tooltip';
-import '../ui/tooltip-group';
-import '../ui/volume-slider';
+// Register the player, container, and all UI custom elements.
+import './minimal-ui';
const SEEK_TIME = 10;
diff --git a/packages/html/src/define/audio/minimal-skin.ts b/packages/html/src/define/audio/minimal-skin.ts
index 7a8f97e3..0e7f2e9f 100644
--- a/packages/html/src/define/audio/minimal-skin.ts
+++ b/packages/html/src/define/audio/minimal-skin.ts
@@ -4,19 +4,8 @@ import { safeDefine } from '../safe-define';
import { SkinElement } from '../skin-element';
import styles from './minimal-skin.css?inline';
-// Side-effect imports: register all custom elements used in the template.
-import '../media/container';
-import '../ui/error-dialog';
-import '../ui/mute-button';
-import '../ui/play-button';
-import '../ui/playback-rate-button';
-import '../ui/popover';
-import '../ui/seek-button';
-import '../ui/time';
-import '../ui/time-slider';
-import '../ui/tooltip';
-import '../ui/tooltip-group';
-import '../ui/volume-slider';
+// Register the player, container, and all UI custom elements.
+import './minimal-ui';
const SEEK_TIME = 10;
diff --git a/packages/html/src/define/audio/minimal-ui.ts b/packages/html/src/define/audio/minimal-ui.ts
new file mode 100644
index 00000000..d328a9c3
--- /dev/null
+++ b/packages/html/src/define/audio/minimal-ui.ts
@@ -0,0 +1,16 @@
+// Side-effect-only module: registers the audio player, container, and all
+// audio UI custom elements used by the minimal skin without creating a skin
+// element. Use this entry when building an ejected (light DOM) player layout.
+import './player';
+
+import '../ui/error-dialog';
+import '../ui/mute-button';
+import '../ui/play-button';
+import '../ui/playback-rate-button';
+import '../ui/popover';
+import '../ui/seek-button';
+import '../ui/time';
+import '../ui/time-slider';
+import '../ui/tooltip';
+import '../ui/tooltip-group';
+import '../ui/volume-slider';
diff --git a/packages/html/src/define/audio/skin.tailwind.ts b/packages/html/src/define/audio/skin.tailwind.ts
index 0bc6a859..5f51e482 100644
--- a/packages/html/src/define/audio/skin.tailwind.ts
+++ b/packages/html/src/define/audio/skin.tailwind.ts
@@ -20,19 +20,8 @@ import { cn } from '@videojs/utils/style';
import { safeDefine } from '../safe-define';
import { SkinElement } from '../skin-element';
-// Side-effect imports: register all custom elements used in the template.
-import '../media/container';
-import '../ui/error-dialog';
-import '../ui/mute-button';
-import '../ui/play-button';
-import '../ui/playback-rate-button';
-import '../ui/popover';
-import '../ui/seek-button';
-import '../ui/time';
-import '../ui/time-slider';
-import '../ui/tooltip';
-import '../ui/tooltip-group';
-import '../ui/volume-slider';
+// Register the player, container, and all UI custom elements.
+import './ui';
const SEEK_TIME = 10;
diff --git a/packages/html/src/define/audio/skin.ts b/packages/html/src/define/audio/skin.ts
index b6bb18b7..69e64d57 100644
--- a/packages/html/src/define/audio/skin.ts
+++ b/packages/html/src/define/audio/skin.ts
@@ -4,19 +4,8 @@ import { safeDefine } from '../safe-define';
import { SkinElement } from '../skin-element';
import styles from './skin.css?inline';
-// Side-effect imports: register all custom elements used in the template.
-import '../media/container';
-import '../ui/error-dialog';
-import '../ui/mute-button';
-import '../ui/play-button';
-import '../ui/playback-rate-button';
-import '../ui/popover';
-import '../ui/seek-button';
-import '../ui/time';
-import '../ui/time-slider';
-import '../ui/tooltip';
-import '../ui/tooltip-group';
-import '../ui/volume-slider';
+// Register the player, container, and all UI custom elements.
+import './ui';
const SEEK_TIME = 10;
diff --git a/packages/html/src/define/audio/ui.ts b/packages/html/src/define/audio/ui.ts
new file mode 100644
index 00000000..a55d5992
--- /dev/null
+++ b/packages/html/src/define/audio/ui.ts
@@ -0,0 +1,16 @@
+// Side-effect-only module: registers the audio player, container, and all
+// audio UI custom elements without creating a skin element. Use this entry
+// when building an ejected (light DOM) player layout.
+import './player';
+
+import '../ui/error-dialog';
+import '../ui/mute-button';
+import '../ui/play-button';
+import '../ui/playback-rate-button';
+import '../ui/popover';
+import '../ui/seek-button';
+import '../ui/time';
+import '../ui/time-slider';
+import '../ui/tooltip';
+import '../ui/tooltip-group';
+import '../ui/volume-slider';
diff --git a/packages/html/src/define/video/minimal-skin.tailwind.ts b/packages/html/src/define/video/minimal-skin.tailwind.ts
index faff15ac..f05a0775 100644
--- a/packages/html/src/define/video/minimal-skin.tailwind.ts
+++ b/packages/html/src/define/video/minimal-skin.tailwind.ts
@@ -25,25 +25,8 @@ import { cn } from '@videojs/utils/style';
import { safeDefine } from '../safe-define';
import { SkinElement } from '../skin-element';
-// Side-effect imports: register all custom elements used in the template.
-import '../media/container';
-import '../ui/buffering-indicator';
-import '../ui/captions-button';
-import '../ui/controls';
-import '../ui/error-dialog';
-import '../ui/fullscreen-button';
-import '../ui/mute-button';
-import '../ui/pip-button';
-import '../ui/play-button';
-import '../ui/playback-rate-button';
-import '../ui/popover';
-import '../ui/poster';
-import '../ui/seek-button';
-import '../ui/time';
-import '../ui/time-slider';
-import '../ui/tooltip';
-import '../ui/tooltip-group';
-import '../ui/volume-slider';
+// Register the player, container, and all UI custom elements.
+import './minimal-ui';
const SEEK_TIME = 10;
diff --git a/packages/html/src/define/video/minimal-skin.ts b/packages/html/src/define/video/minimal-skin.ts
index cb1d44d0..45469a22 100644
--- a/packages/html/src/define/video/minimal-skin.ts
+++ b/packages/html/src/define/video/minimal-skin.ts
@@ -4,24 +4,8 @@ import { safeDefine } from '../safe-define';
import { SkinElement } from '../skin-element';
import styles from './minimal-skin.css?inline';
-// Side-effect imports: register all custom elements used in the template.
-import '../media/container';
-import '../ui/buffering-indicator';
-import '../ui/controls';
-import '../ui/error-dialog';
-import '../ui/fullscreen-button';
-import '../ui/mute-button';
-import '../ui/pip-button';
-import '../ui/play-button';
-import '../ui/playback-rate-button';
-import '../ui/popover';
-import '../ui/poster';
-import '../ui/seek-button';
-import '../ui/time';
-import '../ui/time-slider';
-import '../ui/tooltip';
-import '../ui/tooltip-group';
-import '../ui/volume-slider';
+// Register the player, container, and all UI custom elements.
+import './minimal-ui';
const SEEK_TIME = 10;
diff --git a/packages/html/src/define/video/minimal-ui.ts b/packages/html/src/define/video/minimal-ui.ts
new file mode 100644
index 00000000..394fbade
--- /dev/null
+++ b/packages/html/src/define/video/minimal-ui.ts
@@ -0,0 +1,22 @@
+// Side-effect-only module: registers the video player, container, and all
+// video UI custom elements used by the minimal skin without creating a skin
+// element. Use this entry when building an ejected (light DOM) player layout.
+import './player';
+
+import '../ui/buffering-indicator';
+import '../ui/captions-button';
+import '../ui/controls';
+import '../ui/error-dialog';
+import '../ui/fullscreen-button';
+import '../ui/mute-button';
+import '../ui/pip-button';
+import '../ui/play-button';
+import '../ui/playback-rate-button';
+import '../ui/popover';
+import '../ui/poster';
+import '../ui/seek-button';
+import '../ui/time';
+import '../ui/time-slider';
+import '../ui/tooltip';
+import '../ui/tooltip-group';
+import '../ui/volume-slider';
diff --git a/packages/html/src/define/video/skin.tailwind.ts b/packages/html/src/define/video/skin.tailwind.ts
index 6882dbe9..f88fc345 100644
--- a/packages/html/src/define/video/skin.tailwind.ts
+++ b/packages/html/src/define/video/skin.tailwind.ts
@@ -25,25 +25,8 @@ import { cn } from '@videojs/utils/style';
import { safeDefine } from '../safe-define';
import { SkinElement } from '../skin-element';
-// Side-effect imports: register all custom elements used in the template.
-import '../media/container';
-import '../ui/buffering-indicator';
-import '../ui/captions-button';
-import '../ui/error-dialog';
-import '../ui/controls';
-import '../ui/fullscreen-button';
-import '../ui/mute-button';
-import '../ui/pip-button';
-import '../ui/play-button';
-import '../ui/playback-rate-button';
-import '../ui/popover';
-import '../ui/poster';
-import '../ui/seek-button';
-import '../ui/time';
-import '../ui/time-slider';
-import '../ui/tooltip';
-import '../ui/tooltip-group';
-import '../ui/volume-slider';
+// Register the player, container, and all UI custom elements.
+import './ui';
const SEEK_TIME = 10;
diff --git a/packages/html/src/define/video/skin.ts b/packages/html/src/define/video/skin.ts
index df4649a2..0bf19a10 100644
--- a/packages/html/src/define/video/skin.ts
+++ b/packages/html/src/define/video/skin.ts
@@ -4,25 +4,8 @@ import { safeDefine } from '../safe-define';
import { SkinElement } from '../skin-element';
import styles from './skin.css?inline';
-// Side-effect imports: register all custom elements used in the template.
-import '../media/container';
-import '../ui/buffering-indicator';
-import '../ui/captions-button';
-import '../ui/error-dialog';
-import '../ui/controls';
-import '../ui/fullscreen-button';
-import '../ui/mute-button';
-import '../ui/pip-button';
-import '../ui/play-button';
-import '../ui/playback-rate-button';
-import '../ui/popover';
-import '../ui/poster';
-import '../ui/seek-button';
-import '../ui/time';
-import '../ui/time-slider';
-import '../ui/tooltip';
-import '../ui/tooltip-group';
-import '../ui/volume-slider';
+// Register the player, container, and all UI custom elements.
+import './ui';
const SEEK_TIME = 10;
diff --git a/packages/html/src/define/video/ui.ts b/packages/html/src/define/video/ui.ts
new file mode 100644
index 00000000..02951e2e
--- /dev/null
+++ b/packages/html/src/define/video/ui.ts
@@ -0,0 +1,22 @@
+// Side-effect-only module: registers the video player, container, and all
+// video UI custom elements without creating a skin element. Use this entry
+// when building an ejected (light DOM) player layout.
+import './player';
+
+import '../ui/buffering-indicator';
+import '../ui/captions-button';
+import '../ui/controls';
+import '../ui/error-dialog';
+import '../ui/fullscreen-button';
+import '../ui/mute-button';
+import '../ui/pip-button';
+import '../ui/play-button';
+import '../ui/playback-rate-button';
+import '../ui/popover';
+import '../ui/poster';
+import '../ui/seek-button';
+import '../ui/time';
+import '../ui/time-slider';
+import '../ui/tooltip';
+import '../ui/tooltip-group';
+import '../ui/volume-slider';
diff --git a/packages/html/tsdown.cdn.config.ts b/packages/html/tsdown.cdn.config.ts
index 4a251cae..085829cf 100644
--- a/packages/html/tsdown.cdn.config.ts
+++ b/packages/html/tsdown.cdn.config.ts
@@ -12,7 +12,17 @@ const skinsDir = resolve(dirname(fileURLToPath(import.meta.url)), '../skins/src'
const buildModes: BuildMode[] = ['dev', 'prod'];
-const presets = ['video', 'video-minimal', 'audio', 'audio-minimal', 'background'];
+const presets = [
+ 'video',
+ 'video-minimal',
+ 'video-ui',
+ 'video-minimal-ui',
+ 'audio',
+ 'audio-minimal',
+ 'audio-ui',
+ 'audio-minimal-ui',
+ 'background',
+];
const media = ['hls-video', 'mux-video', 'simple-hls-video', 'dash-video'];
const entries = [
diff --git a/packages/skins/src/default/css/components/poster.css b/packages/skins/src/default/css/components/poster.css
index a1393346..c2a4349a 100644
--- a/packages/skins/src/default/css/components/poster.css
+++ b/packages/skins/src/default/css/components/poster.css
@@ -15,7 +15,8 @@
.media-default-skin > img:not([data-visible]) {
opacity: 0;
}
-.media-default-skin media-poster ::slotted(img) {
+.media-default-skin media-poster ::slotted(img),
+.media-default-skin media-poster img {
position: absolute;
inset: 0;
width: 100%;
@@ -31,6 +32,7 @@
}
.media-default-skin:fullscreen media-poster ::slotted(img),
+.media-default-skin:fullscreen media-poster img,
.media-default-skin:fullscreen > img {
object-fit: contain;
}
diff --git a/packages/skins/src/minimal/css/components/poster.css b/packages/skins/src/minimal/css/components/poster.css
index 0236c610..44b371e7 100644
--- a/packages/skins/src/minimal/css/components/poster.css
+++ b/packages/skins/src/minimal/css/components/poster.css
@@ -15,7 +15,8 @@
.media-minimal-skin > img:not([data-visible]) {
opacity: 0;
}
-.media-minimal-skin media-poster ::slotted(img) {
+.media-minimal-skin media-poster ::slotted(img),
+.media-minimal-skin media-poster img {
position: absolute;
inset: 0;
width: 100%;
@@ -31,6 +32,7 @@
}
.media-minimal-skin:fullscreen media-poster ::slotted(img),
+.media-minimal-skin:fullscreen media-poster img,
.media-minimal-skin:fullscreen > img {
object-fit: contain;
}
diff --git a/site/scripts/build-ejected-skins.ts b/site/scripts/build-ejected-skins.ts
index 2b2d9689..ad0c616b 100644
--- a/site/scripts/build-ejected-skins.ts
+++ b/site/scripts/build-ejected-skins.ts
@@ -679,19 +679,10 @@ function resolveCss(cssPath: string): string {
}
function getHtmlSkinCdnFileName(skin: HtmlSkinDef): string {
- if (skin.id.includes('minimal-video')) {
- return 'video-minimal';
- }
+ const isMinimal = skin.id.includes('minimal');
+ const prefix = skin.id.includes('video') ? 'video' : 'audio';
- if (skin.id.includes('minimal-audio')) {
- return 'audio-minimal';
- }
-
- if (skin.id.includes('video')) {
- return 'video';
- }
-
- return 'audio';
+ return isMinimal ? `${prefix}-minimal-ui` : `${prefix}-ui`;
}
function prependHtmlSkinScripts(html: string, skin: HtmlSkinDef): string {