Install and activate the optional Video Plugin with bun run pmx plugins add video
before using @video in your project.
Embed a video with a titled Markdown link. This supplied motion study includes captions and loads when you press Play:
Compare linear and eased motion
The caption describes the movement; ordinary video links remain links. YouTube, Vimeo, Loom, and local files use the same directive with provider-specific options.
bun run pmx plugins add video
This installs @pathmx/video and activates it in package.json. Start from an
initialized Quickstart project.
Save the supplied MP4 and
WebVTT captions into paths/video/, keeping
the filenames easing.mp4 and easing.en.vtt. Create paths/motion.page.md:
# Compare two movements
[@video(captions="./video/easing.en.vtt" language="en") Linear and eased motion](./video/easing.mp4)
Run bun run dev, open /motion.page, and play the video. Use CC to hide/show
captions; pause and resume to compare the two motions. The actual caption file
starts with WEBVTT and contains timed text cues; it is ready to use beside the
supplied clip.
YouTube, Vimeo, and Loom use their provider thumbnails automatically. Choose a
different preview with thumbnail, using a path relative to the Source or an
HTTPS image URL:
[@video(thumbnail="./images/presentation.jpg") Recording a presentation](https://www.loom.com/share/e00c8856f48049519ca6bece165b449a)
The image appears before playback. A missing thumbnail leaves the Play button available. Changing the preview during a live edit does not restart playback.
Local files and HTTPS video-file URLs use the same directive:
[@video(thumbnail="./motion-preview.svg" width=640) Motion study](./motion.mp4)
MP4, WebM, MOV, and M4V file URLs are supported. Playback depends on the browser's
support for the file's codecs. width sets a maximum width in CSS pixels; the
video still shrinks to fit its container. At widths of 360px or less, shared
playback controls sit below the picture so touch targets do not obscure it. Without it, the video uses the content
width. Playback shows the complete picture without cropping.
Attach one WebVTT caption track and its language:
[@video(captions="./lesson.en.vtt" language="en") Lesson](./lesson.mp4)
captions accepts a local .vtt path or an HTTPS URL. language is required;
use a language tag such as en, es-MX, or fr. Paths resolve relative to the
Source, just like thumbnails.
Captions are enabled initially and can be toggled with the CC control. Editing the caption reference preserves the video's playback position. Automatically positioned captions stay clear of visible controls; explicit positions in the WebVTT file remain as authored. If the track fails to load, playback remains available and a caption error appears.
When a captioned video or its track comes from another origin, that server must allow anonymous cross-origin requests (CORS). Serving both files with your site avoids additional server configuration.
YouTube, Vimeo, and Loom use captions supplied by their providers. The captions
and language parameters apply to video files.
Put the starting time in the URL, using seconds or hours, minutes, and seconds:
[@video Layout & Composition](https://youtu.be/a5KYlHNKQB8?t=1m)
[@video Alike](https://vimeo.com/194276412#t=1m)
[@video Motion study](./motion.mp4?t=1)
YouTube watch, short, Shorts, live, and embed URLs are supported, along with Loom share and embed URLs. Vimeo video-page and player URLs are also supported. For an unlisted Vimeo video, keep the complete sharing URL, including its privacy hash:
[@video Vimeo film](https://vimeo.com/194276412)
[@video Unlisted recording](https://player.vimeo.com/video/76979871?h=8272103f6e)
Use a single video rather than a playlist or channel.
The authored title names the player for assistive technology. Give each video a clear title describing its content.
YouTube and video files use a compact floating control island for playback, seeking, speed, volume, and fullscreen. It fades after a short period of idle playback and returns on pointer movement, a tap, or keyboard interaction. It stays visible while paused or while its controls are focused or being adjusted. The volume slider appears when its control is hovered or focused. Browsers that require device volume controls omit the slider. Video files also offer picture-in-picture when the browser supports it. On narrow players, additional controls wrap below the timeline to preserve touch targets.
YouTube captions are requested on when available; open YouTube to change caption settings when using the floating controls. On browsers without page fullscreen support, YouTube uses its native player. On iPhone Safari, playback opens in the system fullscreen player; closing it returns to the page. Safari may require a second tap on YouTube’s Play button after loading the embed. Vimeo and Loom use their built-in controls, including the options allowed by the video owner.
If a video using the floating controls cannot play, a link to open the video appears. Native provider players handle their own playback errors. For broad device support, use H.264 video in an MP4 file. WebM support depends on the browser and device. A browser that reports WebM as unsupported shows the open-video fallback.
Embedded videos remain subject to their provider's access restrictions.
Try the video example.
When Player is active, a standalone video is one Beat with its authored title. Its preview and playing instance share the same place in the sequence. Authored Beat groups remain groups. Activating the Beat does not start playback.
Focus dims the surrounding page and expands the active video to fit the viewport. Use the expand/reduce icon to compare this immersive view with the authored size and normal Focus lighting. Fullscreen remains a separate playback control. A video-only slide centers the video against a dark background, preserving the complete picture.
Play/Pause and expansion appear as icon-and-label Beat actions. Keyboard input inside video controls stays with the video. Moving to another Beat or opening the Block Grid pauses controllable playback; returning keeps its position. Switching modes preserves the media instance, and finishing a video does not automatically advance. Provider-native iframes retain their own playback controls and may not support pausing when leaving a Beat.
Try the short video lesson.