@kirigami/plugin-embed
v0.2.2
Published
<youtube>/<vimeo> video embed cards for Kirigami — oEmbed-backed, localStorage-cached, cover thumbnail + play button, powered by @kirigami/canva's observer.
Maintainers
Readme
@kirigami/plugin-embed
YouTube / Vimeo embed cards for the Kirigami static site generator.
Overview
@kirigami/plugin-embed turns a bare <youtube id="…"> or <vimeo id="…">
tag into a real video card — a cover thumbnail, the video title, and a play
button — with no build-time network call: the oEmbed lookup happens in
the visitor's browser, on first paint, via
@kirigami/canva's observer.
The result is cached in localStorage, so later lookups can reuse stored metadata. Concurrent first-time requests are not deduplicated, and thumbnails still load. The play button is a single inline SVG
themed off the project's own --accent — nothing to draw yourself.
Part of the Kirigami project ecosystem.
Table of contents
- @kirigami/plugin-embed
- Overview
- What's new in 0.2.2
- What's new in 0.1.5
- What's new in 0.1.4
- What's new in 0.1.3
- What's new in 0.1.1
- Installation
- Configuration
- Usage
- How it works
- Generated assets and failure behavior
- Styling
- Requirements
- License
What's new in 0.2.2
- The YouTube player URL carries
feature=oembed, like the iframe YouTube's own oEmbed endpoint returns.
What's new in 0.1.5
- Dependency bump to
@kirigami/canva2.6.0 /@kirigami/sdk0.2.1;homepage+ README pointed at the site (metadata only).
What's new in 0.1.4
- Dependency bump to
@kirigami/canva2.5.1.
What's new in 0.1.3
- Superseded the 16∶9 aspect-ratio floor with a
maxWidthcap + the real ratio. A full-page-wide.embed(nomax-width) still read as huge even at a "correct" ratio, so the floor hack is gone:.embednow caps atmax-width: var(--embed-max-width, 40rem), and the video's actual aspect-ratio is used. Two new options:maxWidth(default"40rem","none"removes the cap) andforcedAspectRatio(e.g."1 / 1"to pin every card in a grid to one uniform shape).
What's new in 0.1.1
- Aspect-ratio floored at 16∶9 — a real, reported bug: a narrower source
video (4∶3, portrait, a Short) produced an unusually tall card that
dominated the page next to normal widescreen ones. The real player, once
clicked, still showed at its own true ratio, pillarboxed rather than
stretched. (Superseded by 0.1.3's
maxWidthcap, above.)
Installation
kiri install embedor by hand:
npm install --save-dev @kirigami/plugin-embedplugins:
- name: "@kirigami/plugin-embed"
active: trueNeeds an esbuild task in kirigami.yaml — that's where the observer script
ships to the browser.
Configuration
Options
| Option | Type | Default | Description |
|---|---|---|---|
| style | boolean | true | Append the default .embed card styles to every sass task. Set false to write your own. |
| maxWidth | string | "40rem" | Caps how wide (and, via aspect-ratio, how tall) a card can get — any CSS length, or "none" to remove the cap. Ignored when style is false. |
| forcedAspectRatio | string | "" | Pin every card to one shape ("16 / 9", "1 / 1", …) instead of each video's own real ratio — handy for a uniform grid. Empty uses each video's real ratio. Ignored when style is false. |
Usage
Straight in HTML — the tag is deliberately non-closing, like <img>:
<youtube id="dQw4w9WgXcQ">
<vimeo id="1084537">or, inside Markdown, the shorthand:
{% youtube dQw4w9WgXcQ %}
{% vimeo 1084537 %}Both forms produce the exact same tag — the shorthand just saves typing raw HTML in prose.
Only YouTube and Vimeo providers are implemented. Other providers require a custom observer registration and an endpoint the browser can access; provider access policies are not part of this package’s API.
How it works
src/embed.jsregistersyoutubeandvimeoon@kirigami/canva'sobserver, which sweeps the page for those tags (on load, and for anything added later) and hands each one to the plugin.- The tag is swapped immediately for a
.embedplaceholder — sized by the default 16∶9 aspect-ratio — reserving space while metadata loads. A later aspect-ratio change can still move surrounding content. - The video's oEmbed data is read from
localStorage(kirigami-embed:<provider>:<id>) if a previous visit already resolved this id, or fetched from the provider's oEmbed endpoint otherwise and cached for next time. - Once that resolves, the thumbnail and title are patched into the same
placeholder, and the aspect-ratio is updated to the video's own real
ratio (4∶3, square, portrait, a Short — whatever it actually is). It's
the card's
max-width(maxWidth, default40rem) that keeps a narrower video from ever looking oversized, not a distorted ratio — the real player, once clicked, shows at that same real ratio too, nothing is ever stretched. - Clicking the play button swaps the placeholder's content for the real
player
<iframe>— the player loads only after that click; metadata and thumbnail requests happen earlier.
Generated assets and failure behavior
The prepros:php hook includes php/embed.php for the Markdown shortcuts.
Without an esbuild task, registration warns and skips the browser script;
the shortcuts still emit tags, but they do not become cards. Include the
generated JavaScript in the page.
With style: true, each sass:after call writes .generated-vars.scss in
the installed plugin directory and appends it with assets/_embed.scss.
The generated file sets --embed-max-width and, when requested, an
!important aspect-ratio rule. The install directory must be writable.
Builds sharing that installation share the file; their options are not
isolated there. style: false skips both files and ignores the sizing options.
The browser accepts YouTube IDs matching 10–12 word/hyphen characters and Vimeo IDs containing only digits. Missing or malformed IDs leave the HTML tag unchanged; a Markdown shortcut without an ID emits a comment.
Metadata cache entries have no expiry. Invalid JSON triggers a refetch;
failed cache writes are ignored, but a failed localStorage read prevents
fetching (audit A18). Requests are subject to browser network and CORS rules;
this plugin supplies no proxy, timeout, or retry. A failed request logs to
the console and leaves the play button usable without metadata. Playback
uses youtube-nocookie.com or player.vimeo.com with autoplay requested.
Metadata and thumbnail requests occur before the click.
Styling
The bundled .embed card (.embed__title, .embed__play, .embed__player)
is themed off @kirigami/canva conf's --accent / --surface-2, so it
tracks your project's own palette automatically. Set style: false and
target those same class names to restyle it from scratch.
Requirements
The current localStorage read can throw in restricted browser contexts and prevent metadata retrieval (audit A18). This is a known limitation, not an automatic in-memory fallback.
- Node.js
>= 24.0.0 - npm
>= 10.2.3 @kirigami/kirigami>= 3.0.0(declaredkirigami.minVersion)- A
sasstask for the bundled styles - An
esbuildtask inkirigami.yaml
License
GPL-3.0-or-later © Maxime Larrivée-Roy, 2026
