Skip to content
Brok UI

Loading…

No results

Media Masking

Open source

Media clipped to decorative shapes via CSS clip-path — for images and for autoplaying video, sharing one shape vocabulary.

Version
v1.0.2
Stability
stable
License
MIT
Related
Image Mask

Video Mask — An autoplaying, muted, looping video clipped to a decorative shape (circle, hexagon, diamond, star, arch, blob) via CSS clip-path — sharing image-mask's shape vocabulary.

Preview

Shape
previews.components.video-mask.default.blade.php Blade
<div class="w-full flex justify-center">
    <x-ui.video-mask
        poster="https://picsum.photos/seed/video-mask/960/540"
        shape="blob"
        class="w-full max-w-md"
    />
</div>
Circle Current
Hexagon Current
Diamond Current
Star Current
Arch Current
Blob Current

Installation

terminal
php artisan ui:add video-mask

Registry contract

php artisan ui:add video-mask writes only the files below. The CLI validates each file hash before writing and asks before it replaces a local change, unless you pass --force.

  • blade resources/views/components/ui/video-mask.blade.php
Registry dependencies
None — installs on its own.
Packages
composer: jml/brok:^0.2

Use with AI

A brief for your coding agent: install command, usage, props, guidance and the rules. Copy it, or open a prompt about this component in an assistant.

video-mask.md
# Brok UI: Video Mask (`video-mask`)

An autoplaying, muted, looping video clipped to a decorative shape (circle, hexagon, diamond, star, arch, blob) via CSS clip-path — sharing image-mask's shape vocabulary.

Brok UI is a Laravel Blade component registry. Installed components are plain Blade files the app owns.

## Install

```bash
php artisan ui:add video-mask
```

## Usage

```blade
<div class="w-full flex justify-center">
    <x-ui.video-mask
        poster="https://picsum.photos/seed/video-mask/960/540"
        shape="blob"
        class="w-full max-w-md"
    />
</div>
```

## Props

- `src` (string, default ``) — Video source URL.
- `poster` (string, default ``) — Poster image shown before the video loads or plays.
- `shape` (string, default `blob`) — Clip-path shape: circle, hexagon, diamond, star, arch, or blob.
- `aspect` (string, default `16 / 9`) — CSS aspect-ratio the video is cropped to before the shape mask is applied.
- `autoplay` (bool, default `true`) — Starts playback automatically on load.
- `loop` (bool, default `true`) — Restarts playback automatically when the clip ends.
- `muted` (bool, default `true`) — Mutes audio; required by browsers for autoplay to work.
- `controls` (bool, default `false`) — Shows native video controls instead of playing as silent decoration.
- `label` (string, default `Decorative video`) — Accessible label for the video element.

## Use when

- Use when image or video selection, preview, or media-based comparison is part of the task.
- Giving a background or ambient video a decorative non-rectangular silhouette, matching image-mask's shape vocabulary.
- Wanting an autoplaying, muted, looping video clip framed by a shape rather than a plain rectangle.

## Avoid when

- Do not require media-heavy interaction when a simpler text or list solution would be faster.
- The video carries meaningful audio or content the user needs to control; expose real controls instead of a muted, autoplaying decorative clip.
- The masked media is a still image rather than video; use image-mask.

## Anti-patterns

- Requiring media-heavy interaction when text is faster

## Rules

- Use the `<brok:video-mask>` tag (or `<x-ui.video-mask>`) in Blade; do not rewrite the component.
- Prefer the documented props and variants over utility-class overrides; when a utility must win, use the `!` important modifier.
- Use semantic design tokens (`bg-primary`, `text-muted-foreground`), never raw colour utilities.
- Keep the `data-slot` attributes; they are the styling and test hooks.

## Links

- Docs: https://brokui.dev/docs/components/video-mask
- Registry JSON (files, props, contract): https://brokui.dev/r/open/video-mask.json

Working in Claude Code, Cursor or Codex? Give the agent the whole registry through the MCP server or the Brok UI skill.

API

manifest knowledge + registry-derived coverage

Props

Props accepted by this component: name, type, default value and description.
Prop Type Default Description
src string Video source URL.
poster string Poster image shown before the video loads or plays.
shape string blob Clip-path shape: circle, hexagon, diamond, star, arch, or blob.
aspect string 16 / 9 CSS aspect-ratio the video is cropped to before the shape mask is applied.
autoplay bool true Starts playback automatically on load.
loop bool true Restarts playback automatically when the clip ends.
muted bool true Mutes audio; required by browsers for autoplay to work.
controls bool false Shows native video controls instead of playing as silent decoration.
label string Decorative video Accessible label for the video element.

Slots

  • default —

Data slots

Stable hooks for CSS overrides and browser tests.

video-mask

Behavior

  • Applies a CSS clip-path for the chosen shape directly to the video, so the mask scales responsively with no raster asset or extra markup.
  • Defaults to autoplay, loop, and muted together, matching the browser requirement that autoplaying video be muted.
  • Declares registry capability flags: a11y, responsive, rtl, darkMode, localized.

Guidance

Media selection and presentation

Select, preview, or compare visual media.

Use when

  • Use when image or video selection, preview, or media-based comparison is part of the task.
  • Giving a background or ambient video a decorative non-rectangular silhouette, matching image-mask's shape vocabulary.
  • Wanting an autoplaying, muted, looping video clip framed by a shape rather than a plain rectangle.

Avoid when

  • Do not require media-heavy interaction when a simpler text or list solution would be faster.
  • The video carries meaningful audio or content the user needs to control; expose real controls instead of a muted, autoplaying decorative clip.
  • The masked media is a still image rather than video; use image-mask.

Use instead

  • Text or list representation

Anti-patterns

  • Requiring media-heavy interaction when text is faster
Anatomy
root
Theming hooks
video-mask

Accessibility

WCAG 2.2 AA Keyboard focus-visible RTL-ready Localized labels Dark mode
Keyboard
No component-owned keyboard interaction; native element behavior applies.
Focus
none
  • A muted, autoplaying, looping video carries no essential audio information, so it does not need captions; set controls when the video is not purely decorative.
  • Semantic HTML and a stable data-slot attribute for styling and scripting hooks.
  • Focus-visible rings use the ring token, so keyboard focus is always visible.
  • Disabled and invalid states are conveyed to assistive tech, not by color alone.
  • Targets WCAG 2.2 AA; verify contrast in light, dark, admin and customer surfaces in the preview.
  • Labels go through __() and layout uses logical properties (ms-*, text-start), so it mirrors under dir="rtl" — flip the preview to RTL to confirm.
  • Dark mode uses the same semantic tokens under the dark class; high contrast follows forced-color system tokens.

Livewire

Safe

Livewire can update this component through forwarded wire:* attributes.

Source

The exact, editable file ui:add writes into your app. Previews render this same code; there are no preview-only components.

resources/views/components/ui/video-mask.blade.php Blade
@props([
    'src' => '',
    'poster' => '',
    'shape' => 'blob',
    'aspect' => '16 / 9',
    'autoplay' => true,
    'loop' => true,
    'muted' => true,
    'controls' => false,
    'label' => 'Decorative video',
])

@php
    // Video Mask — clips an autoplaying <video> to a decorative shape with CSS
    // `clip-path`, sharing the exact shape vocabulary as `image-mask`. Shapes are
    // percentage-based (scale with `aspect`) and colour-free. Autoplay defaults
    // to a muted, looping, inline clip (the only configuration browsers allow to
    // autoplay); pass :muted="false" / :controls="true" for a user-driven player.
    $shapes = [
        'circle' => 'circle(50%)',
        'hexagon' => 'polygon(25% 0%, 75% 0%, 100% 50%, 75% 100%, 25% 100%, 0% 50%)',
        'diamond' => 'polygon(50% 0%, 100% 50%, 50% 100%, 0% 50%)',
        'star' => 'polygon(50% 0%, 61% 35%, 98% 35%, 68% 57%, 79% 91%, 50% 70%, 21% 91%, 32% 57%, 2% 35%, 39% 35%)',
        'arch' => 'inset(0 round 999px 999px 0 0)',
        'blob' => 'polygon(40% 4%, 66% 9%, 89% 26%, 96% 51%, 88% 76%, 64% 93%, 38% 96%, 16% 79%, 6% 53%, 13% 27%)',
    ];
    $shape = array_key_exists($shape, $shapes) ? $shape : 'blob';
    $clip = $shapes[$shape];
@endphp

<figure
    data-slot="video-mask"
    data-shape="{{ $shape }}"
    style="aspect-ratio: {{ $aspect }};"
    {{ $attributes->merge(['class' => 'relative block overflow-hidden bg-muted']) }}
>
    <video
        @if ($src) src="{{ $src }}" @endif
        @if ($poster) poster="{{ $poster }}" @endif
        @if ($autoplay) autoplay @endif
        @if ($loop) loop @endif
        @if ($muted) muted @endif
        @if ($controls) controls @endif
        playsinline
        aria-label="{{ __($label) }}"
        class="h-full w-full object-cover"
        style="clip-path: {{ $clip }};"
    ></video>
</figure>

Ownership & lifecycle

Owner, release state, review evidence and adoption for this item.
Owner
Platform UI (@JoshJML)
Current version
1.0.2
Status
Stable
License
open
Accessibility reviewed
No review date recorded
Last breaking change
No date recorded
Deprecation
Not deprecated
Contract
v6
Foundation
≥ 1.0.0