Use when changing the `/wolves/` teaser hero, Trailer 1 player, the delivered-render embed, poster, ended URL card, or trailer fidelity tests.
metadata
{"context7-sources":["/websites/tailwindcss"]}
Wolves teaser
Overview
Keep /wolves/ faithful to the owner-authored Trailer 1 cut while preserving
its role as a teaser website. The page owns a chromeless YouTube iframe that
plays the owner's delivered render of the cut — every plate, the bridge, and
the end card are burned into the video — plus three browser jobs around it:
the page heading's yield, an opening black mask, and one browser-drawn URL
card that covers YouTube's endscreen after the cut ends. Below the stage, the
page links into /wolves/experience/.
The trailer design is not derivable from one manifest. Its copy and timing,
visual treatment, composition, and rendered result live in separate
destiny-vids sources, and the playable picture is the owner's own YouTube
upload. Read the sources before changing what the records describe.
When to Use
Use this skill when changing:
src/WolvesTeaserApp.vue
src/components/wolves/WolvesTrailerLine.vue
src/data/wolves-trailer-plates.ts
src/tests/wolvesTrailerPlates.test.ts
the teaser poster, hero placement, player geometry, the ended URL card, or
trailer-specific assets
Any design change without direct owner approval: load
../design-gate/SKILL.md and stop at its gate.
Core Process
Read the authoritative sources listed below.
The embed is the owner's delivered render. Never redraw its plates in the
browser while it plays — a browser plate over the burned-in plate is a
double-draw and a defect.
Keep wolves-trailer-plates.ts as the authored record; never reword or
nudge the owner's copy locally. The records drive the heading yield, the
opening black mask, and the ended URL card.
Pin timing, treatments, segments, and lossless tokenisation in
wolvesTrailerPlates.test.ts.
Drive the dev-only window.__wolvesTeaser harness to the reference beats.
Compare desktop and mobile against the render at the same timestamps.
Run lint, typecheck, focused tests, test:gate, and build.
Sources of Truth
The playable picture is the owner's own upload: YouTube u-ZWdKcHyXM,
"Seven Days to the Wolves" (the re-upload of "Wolves Trailer Final") — the delivered 4K60 render of Trailer 1.1. Verify any
swap beat by beat against the authored schedule before trusting it.
All paths in this table are relative to ~/src/destiny-vids.
Thing
File
Plate schedule and owner copy
stories/trailer-1-plates.json
Title and end-card design
cards/maintitle.html
Book-box design
cards/bookline.html
Day-card design
cards/daycard.html
Composition and timeline
scripts/build_trailer1.py
Rendered plates, RGBA 1920×1080
renders/plates-trailer-1/*.png
Final comparison picture
renders/trailer-1.mp4
The manifest carries windows and copy. It does not carry the design. A
manifest-only implementation can be numerically correct and still look nothing
like the film.
The Cut Is the Delivered Render
The render is full-frame 16:9 throughout, 114.998 s against an authored
115.02 s, with music and every plate burned in. Its three segments:
Window
Picture
0 → 88.2
the picture; black through 12.2
88.2 → 102.2
day falling into night
102.2 → 115.02
the night scene as the end-card poster
Because the render carries the cut, the browser draws nothing over the playing
video. The three remaining browser jobs:
Opening black mask. Keep an opaque black gate over the player through
BURST = 12.200, cleared across exactly two 59.94 fps frames
(2 * 1001 / 60000). The render opens on the same black, so the mask hides
YouTube's startup chrome and is pixel-identical to the cut beneath it.
Heading yield. The page h1 still steps aside before the render's own
title card (see "The Title Lands Once").
Ended URL card. When the cut ends, YouTube paints an endscreen over the
faded-to-black last frame. Cover it with the teaser's held URL card — the
March night wallpaper (public/img/wallpapers/bluefin-03-night.webp) under
the browser-drawn event rows and the wolves.projectbluefin.io CTA — in the
same treatment the cut's own end card uses. The end-card records' opacities
all resolve to 1 at TRAILER_ENDCARD_HOLD_SECONDS (113.82), so the ended
overlay is a fully arrived frame, never a mid-fade one.
End detection is redundant on purpose: the onStateChange ENDED event and
a clock tolerance (getCurrentTime() within 0.05 s of the 115.02 s duration),
because the encode stops at 114.998 s and the event may never fire.
Coordinate Mapping and Sizing
Only the ended URL card is browser-drawn. Its type sizes key off player
width: every card clamp resolves to its maximum at 1920px, so the player
carries container-type: inline-size and card sizes are expressed in cqw,
where 1cqw is 1% of frame width.
Element
Card value
px at 1920
cqw
poster CTA
clamp(2.8rem,5vw,5.2rem)
83.2
4.3333
poster title
clamp(1.7rem,2.5vw,2.45rem)
39.2
2.0417
poster subtitle
clamp(1.1rem,1.7vw,1.5rem)
24
1.25
poster tag
1.1rem
17.6
0.9167
The card root is 16px. wolves-cinematic.scss sets the site's root near 10px,
so never copy rem values across directly; convert through the px column.
Authored Treatments
These rules govern the ended URL card and any future browser-drawn plate; the
render's own plates already carry them.
Every B/b and F/f is blue at #4285f4, the Bluefin wordmark blue.
It is not --wc-gold (#60a5fa), which is a UI token. Do not apply this
rule to the Linux Foundation event title or the CTA's b/f.
The O in WOLVES is the Kubernetes helm, as is the O in Extinction. The
mark is public/brands/kubernetes-icon-white.svg — CNCF's published white
symbolic icon, reproduced unmodified, so nothing here recolours anybody's
trademark.
A spaced | is drawn as a sear, not set as a font glyph. The sear is
blue heat: flare rgb(196 226 255), mid rgb(147 197 253), halo
rgb(37 99 235).
Glyph halo, never a scrim. The owner removed the black box. Contrast
belongs to the letterforms; a translucent full-card background is a
regression.
Hairline: 34% wide on the title, 42% on the poster, 1px,
rgb(96 165 250 / 28%).
Typeface: use --wc-font-display. Do not use --wc-font-weyland or
--wc-font-weyland-mono for the authored plates.
The render host lacked Inter, so the rendered PNGs use DejaVu Sans. The website
has Inter and the card explicitly names the site's display token. Use the
authored token unless the owner asks to reproduce the render host's fallback.
Plate Schedule
These windows are burned into the render; the records remain the authored
description and drive the heading yield (maintitle) and the ended URL card
(endcard-*). The book and day-card records no longer have browser elements.
ID
Window
Notes
maintitle-a
11.0–15.4
title only; credits hidden
maintitle-b
15.4–22.6
credits and sear appear; title must not move
book-a
26.9–33.64
four-line box at [1030,443]
book-b
31.0–34.9
transparent timing continuation at [1000,470]; never render
daycard-extinction
88.8–93.8
fade in 0.4; fade out 0.5
daycard-survival
94.4–100.6
fade in 0.5; fade out 0.6
endcard-event
102.2–115.02
title, subtitle, hairline
endcard-cta
105.2–115.02
CTA and tags over the event card
Iframe Geometry
The player is the delivered 16:9 frame and the render fills it edge to edge:
.wt-player-frame is inset: 0 and the iframe is 100% × 100%. There is no
aperture — an earlier recreation embedded a letterboxed 2.39:1 music video and
clipped YouTube's chrome into a 1920:804 aperture, and that geometry went away
with that source. Verify a new source's actual frame before reviving it: a 200
from the dev server is not proof (the SPA fallback answers 200 for missing
assets), and a container's 16:9 says nothing about baked bars — extract frames
and look.
Set pointer-events: none on the iframe. Playback belongs to the site's media
widget; allowing pointer hover over the cross-origin iframe asks YouTube to
paint chrome again, and the page cannot style it away. The opaque poster is an
entry surface only: remove it as soon as playback starts and never restore it
for pause or seek. Covering the player while its clock advances makes Play and
Seek look broken, and replacing a paused frame with poster art hides the video.
A transient YouTube centre glyph is less destructive than hiding the requested
frame. This rule applies to the poster, not the authored black gate. The black
gate still covers the embed until the 12.2-second reveal.
new YT.Player(div, …) replaces the host div with the iframe. Target the
resulting iframe through the wrapper's :deep(iframe) rule.
YouTube rejects numeric loopback origins. Test at
http://projectbluefin.io.localhost:5173/wolves/, not localhost.
The Title Lands Once
The page and the cut both know the film's name, and for a while both said it.
.wt-heading (page h1), .wt-poster-title (poster overlay) and the authored
maintitle plate each spelled Seven Days to the Wolves, so two of them were
legible together at every measured beat — the h1 sat above the frame for the
eleven seconds before the title card, and the card then "revealed" words the
audience had already read. The page read as glitchy and the reveal did nothing.
A theater darkens before the title hits. The rules that keep it that way:
Exactly one surface may carry the film title at any instant. The poster
is a kicker (TRAILER 1) and controls only; it does not name the film.
The heading is fully down before the card opens, never cross-faded with
it. A dissolve still puts two copies on screen at once, which is the defect.
TRAILER_HEADING_YIELD_SECONDS is the lead, and it ends at the card's start.
The yield is opacity, never display or v-if. The heading keeps its box
so the measured viewport budget that holds the whole frame above the fold does
not move when the words leave.
The heading does not return mid-picture. Restoring it when the card closes
pops a full-width title back in over a running film. It returns only when the
trailer is not playing, where it is page furniture again.
trailerHeadingOpacity() owns this and derives its beat from the maintitle
plate's own window, so re-porting the cut moves the heading with the card. The
invariant is pinned in wolvesTrailerPlates.test.ts, which sweeps the whole
110 s at 0.1 s and asserts the heading and the card are never both legible.
Reuse the Wolves Media Widget
MediaWidget.vue is store-backed by default and is also the teaser transport.
Its optional artwork, elapsed, duration, and playing props activate
external single-track mode without mutating the cinematic store. Keep
showSkipControls true by default for the show and set it false for the teaser.
The teaser owns play, pause, replay, and ratio seek through the IFrame API.
Do not copy the widget markup or stylesheet into the teaser. A visual copy
immediately drifts from the show and creates two transport accessibility
surfaces to maintain.
The widget is the ongoing transport, while the idle poster carries centered
Play and Fullscreen convenience buttons. Once entered, pause, resume,
and seek stay in the widget so the video frame remains visible. Fullscreen the
entire .wt-stage, not the iframe, so title, authored overlays, and widget
remain in the fullscreen tree. Hide the standfirst there and fit the 16:9
player to the remaining viewport.
Treat Play and Seek as user intent even when the IFrame API or player is still
loading. The button appears before onReady, so queue intent in teaser state;
on readiness, restore the requested time and start only if the phase is still
playing. Calling playVideo() on a missing or not-ready player loses the click.
The progress control must seek continuously during pointer drag. A click-only
div with role="slider" is not a working slider. Use pointer capture from
pointerdown through pointerup or pointercancel, seek on the final
pointerup coordinate rather than trusting the last move event, and set
touch-action: none on the track so a touch drag seeks instead of scrolling
the page.
The transport clock is YouTube's own for the full 115.02-second runtime: the
render carries the music, the howl, and the five-second URL hold itself, so
there is no synthetic silent hold. The widget reaches 1:55 / 1:55 as the
video ends, and the ended phase freezes the URL card at
TRAILER_ENDCARD_HOLD_SECONDS over YouTube's endscreen. Do not show the poster
over the ended phase; it would replace the requested last screen.
Inline Mark Trap
Tailwind Preflight sets replaced elements, including img, to display: block.
Current documentation confirms the reset and recommends adding an inline
class when inline behaviour is required (source: /websites/tailwindcss).
A helm standing in for a letter must therefore explicitly use
display: inline. Otherwise it takes its own line, ignores text centring, and
renders the title as "SEVEN DAYS TO THE W", helm, "LVES".
Also state width: 100% on lockup rows. A flex item containing a replaced
element can collapse below the available width and wrap unexpectedly.
Common Rationalizations
Rationalization
Reality
"The timing manifest is authoritative, so it is enough."
It has no plate design and no three-picture composition. Read the cards and builder.
"The browser should keep drawing its plates over the new video."
The render has every plate burned in; a browser copy is a double-draw.
"The new video is 16:9, so the old aperture math still applies."
Container aspect says nothing about baked bars. Extract frames and measure.
"A dark scrim makes the words safer."
The owner explicitly removed it. Use the authored glyph halo.
"The helm is just an image; default image CSS is fine."
Preflight makes it block-level and breaks the word.
"The title looks centred."
Measure line count and bounds; visual inspection missed the three-line helm break.
"The page needs its h1, so the duplicate title is unavoidable."
Keep the h1 for page identity and yield it on a timer. Identity and the reveal are not in conflict.
Red Flags
YouTube startup chrome is visible before the 12.2-second reveal.
A browser-drawn plate appears over the playing render (double-draw).
The video is swapped for a different upload without beat-by-beat frame
verification against the authored schedule.
Plate type uses Michroma.
A plate has a full-card translucent background.
An empty book-b record renders as a collapsed box.
The title or Extinction wraps only when the helm is present.
YouTube chrome or its endscreen overlays the picture; the ended phase must
cover it with the opaque URL card.
A second teaser-only transport copies MediaWidget markup or styles.
Play is available only in the fixed widget and is not obvious on initial load.
Fullscreen targets the iframe, causing the title, overlays, or widget to disappear.
The transport parks at 1:50 or ends early instead of reaching 1:55 / 1:55.
Ended state shows the poster or a faded/empty end card instead of the URL.
Play or Seek advances behind an opaque poster, or Pause replaces the current frame.
The progress control jumps on click but does not track mouse or touch drag.
The iframe accepts pointer events.
The page heading and the render's title card are legible at the same time, or
the poster names the film.
The heading is hidden with display/v-if, moving the frame up the page.
The event title's B/F is recoloured, or the CTA's b/f is blue.
Plate timings are adjusted locally rather than re-ported from destiny-vids.
Verification
After Play, the complete player is pixel-black at 0 and 12.19 seconds;
black opacity is 0.5 halfway through the two-frame reveal and 0 afterward.
The browser adds nothing over the render at 13, 30, 95, 104, and 108
seconds, driven there with window.__wolvesTeaser.seekTo() — no lockup,
no backdrop, no day card.
Exactly one surface spells the film title at 0, 12, and 18 seconds,
measured from folded opacity and bounds, not by eye.
The heading's box is unchanged across the yield at 1920×1080 and 390×844.
Player is fully above the fold on desktop and mobile.
No horizontal scroll exists at 1920×1080 or 390×844.
The iframe fills the 16:9 frame edge to edge and has
pointer-events: none.
Playback, pause, replay, click seek, keyboard seek, and pointer-drag seek
work through the external media-widget mode without restoring the poster.
The idle Play and Fullscreen buttons are centered and keyboard accessible;
fullscreen owns .wt-stage and exposes an Exit Fullscreen label.
The transport reaches 1:55 / 1:55; the ended phase shows a fully opaque
wolves.projectbluefin.io card over the night wallpaper, with no YouTube
endscreen and no poster.
src/tests/wolvesTeaserApp.test.ts, src/tests/wolvesTrailerPlates.test.ts,
lint, typecheck, test:gate, and build pass.