| name | tejas-overlays |
| description | Overlay primitives for Tejas's personal video content — screenshot reveal, code block, architecture diagram, progress rows, browser chrome, pull-quote, keyword emphasis, plus a bespoke-stat-reveal gallery. Use when adding any on-clip overlay in the Tejas aesthetic. For AIS/client work, use /hyperframes-registry instead. |
Tejas · Overlay Primitives
Library of overlay patterns for Tejas's personal-content videos. See MOTION_PHILOSOPHY.md §6 and design spec §6 for the philosophy.
When to fire
- Adding any overlay to a Tejas-aesthetic composition
- Picking a stat/figure reveal (this skill contains the bespoke-stat gallery — §6)
The library
All primitives use --tejas-* tokens from assets/brand-tokens.css. All use spring-led motion (back.out(1.3) in, power2.in out). All live on a data-track-index ≥ 5 in the parent composition.
1 · Keyword emphasis (inline)
See tejas-captions skill — this is a caption-internal primitive, not standalone.
2 · Screenshot / image reveal
<div class="tejas-ss-card clip" data-start="..." data-duration="..." data-track-index="6">
<img src="assets/screenshot.png" alt="">
</div>
<style>
.tejas-ss-card {
position: absolute; top: 18%; left: 80px; right: 80px;
border-radius: 16px; border: 1px solid var(--tejas-border);
background: var(--tejas-surface);
box-shadow: 0 20px 60px rgba(0,0,0,0.7), inset 0 1px 0 var(--tejas-paper-glow);
overflow: hidden; opacity: 0; transform: scale(0.9);
}
.tejas-ss-card img { width: 100%; display: block; }
</style>
<script>
tl.to('.tejas-ss-card', { opacity: 1, scale: 1, duration: 0.48, ease: "back.out(1.2)" }, <start>);
tl.to('.tejas-ss-card', { opacity: 0, scale: 0.96, duration: 0.28, ease: "power2.in" }, <end>);
</script>
3 · Code / terminal block (Mode 2)
<div class="tejas-code clip" data-start="..." data-duration="..." data-track-index="6">
<pre><span class="ln">01</span><span class="k">const</span> a = <span class="k">new</span> Agent();<br><span class="ln">02</span>a.use(tools);</pre>
</div>
<style>
.tejas-code {
background: rgba(15,15,14,0.78); border: 1px solid var(--tejas-border);
border-radius: 10px; padding: 16px 20px;
font: 500 28px/1.6 var(--font-tejas-mono); color: var(--tejas-dim);
}
.tejas-code .ln { color: var(--tejas-muted); margin-right: 14px; opacity: 0.5; }
.tejas-code .k { color: var(--tejas-paper); font-weight: 700; }
.tejas-code .c { color: var(--tejas-muted); font-style: italic; }
.tejas-code .s { color: var(--tejas-soft); }
</style>
<script>
tl.from('.tejas-code pre > *', { opacity: 0, y: 8, duration: 0.32, stagger: 0.08, ease: "power2.out" }, <start>);
</script>
4 · Architecture diagram (nodes)
<div class="tejas-arch clip" data-start="..." data-duration="..." data-track-index="6">
<div class="row"><div class="node">user</div><div class="line"></div><div class="node">agent</div></div>
<div class="vline"></div>
<div class="row"><div class="node">api</div><div class="node">db</div><div class="node">llm</div></div>
<div class="vline"></div>
<div class="row"><div class="node hot">output</div></div>
</div>
<style>
.tejas-arch .node {
border: 1px solid var(--tejas-border-strong);
background: rgba(250,250,246,0.04);
border-radius: 8px; padding: 10px 14px;
font: 500 22px var(--font-tejas-mono); color: var(--tejas-paper);
}
.tejas-arch .node.hot { background: var(--tejas-paper); color: var(--tejas-ink); border-color: var(--tejas-paper); }
.tejas-arch .line { width: 24px; height: 1.5px; background: var(--tejas-border-strong); }
.tejas-arch .vline { width: 1.5px; height: 16px; background: var(--tejas-border-strong); margin: 0 auto; }
.tejas-arch .row { display: flex; align-items: center; gap: 10px; justify-content: center; margin: 8px 0; }
</style>
<script>
tl.from('.tejas-arch .node', { opacity: 0, y: 10, scale: 0.94, duration: 0.32, stagger: 0.12, ease: "back.out(1.3)" }, <start>);
</script>
5 · Progress bar + metric row
<div class="tejas-bars clip" data-start="..." data-duration="..." data-track-index="6">
<div class="prow"><div class="pchip">input</div><div class="pbar"><span style="width: 97%"></span></div><div class="pchip hero">97%</div></div>
</div>
<style>
.tejas-bars .prow { display: flex; align-items: center; gap: 14px; margin: 8px 0; }
.tejas-bars .pchip {
font: 500 22px var(--font-tejas-mono); color: var(--tejas-paper);
padding: 6px 12px; border: 1px solid var(--tejas-border-strong);
background: rgba(250,250,246,0.04); border-radius: 6px; min-width: 100px;
}
.tejas-bars .pchip.hero { background: var(--tejas-paper); color: var(--tejas-ink); border-color: var(--tejas-paper); }
.tejas-bars .pbar { flex: 1; height: 10px; border-radius: 5px; background: var(--tejas-border); overflow: hidden; }
.tejas-bars .pbar > span { display: block; height: 100%; background: var(--tejas-paper); transform: scaleX(0); transform-origin: left center; }
</style>
<script>
tl.to('.tejas-bars .pbar > span', { scaleX: 1, duration: 0.7, stagger: 0.14, ease: "power2.out" }, <start>);
tl.from('.tejas-bars .pchip', { opacity: 0, y: 8, duration: 0.32, stagger: 0.14, ease: "power2.out" }, <start>);
</script>
6 · Browser / app window chrome
<div class="tejas-browser clip" data-start="..." data-duration="..." data-track-index="6">
<div class="chrome">
<div class="dot"></div><div class="dot"></div><div class="dot"></div>
<div class="url">tejasjb.dev</div>
</div>
<div class="body">
<img src="assets/page.png" alt="">
</div>
</div>
<style>
.tejas-browser {
border: 1px solid var(--tejas-border); border-radius: 12px 12px 8px 8px;
background: var(--tejas-surface); overflow: hidden;
box-shadow: 0 20px 60px rgba(0,0,0,0.7);
}
.tejas-browser .chrome { background: var(--tejas-ink); border-bottom: 1px solid var(--tejas-border); padding: 10px 14px; display: flex; align-items: center; gap: 8px; height: 34px; box-sizing: border-box; }
.tejas-browser .dot { width: 10px; height: 10px; border-radius: 50%; background: var(--tejas-border-strong); }
.tejas-browser .url { flex: 1; margin-left: 8px; background: var(--tejas-canvas); border: 1px solid var(--tejas-border); border-radius: 5px; padding: 4px 10px; font: 500 16px var(--font-tejas-mono); color: var(--tejas-dim); }
.tejas-browser .body img { display: block; width: 100%; }
</style>
<script>
tl.from('.tejas-browser', { opacity: 0, y: 16, scale: 0.95, duration: 0.45, ease: "back.out(1.2)" }, <start>);
</script>
7 · Pull-quote / full-bleed text
<div class="tejas-pullquote clip" data-start="..." data-duration="..." data-track-index="7">
<span>We don't</span><br><span>actually</span><br><span>know why.</span>
</div>
<style>
.tejas-pullquote {
position: absolute; inset: 20% 10%;
display: flex; flex-direction: column; align-items: center; justify-content: center;
font: 800 clamp(72px, 10vw, 140px)/1.0 var(--font-tejas-sans);
letter-spacing: -0.03em; color: var(--tejas-paper);
text-shadow: 0 2px 12px rgba(0,0,0,0.7);
text-align: center;
clip-path: inset(0 100% 0 0);
opacity: 0;
}
</style>
<script>
tl.to('.tejas-pullquote', { opacity: 1, clipPath: 'inset(0 0 0 0)', duration: 0.55, ease: "expo.out" }, <start>);
tl.to('.tejas-pullquote', { opacity: 0, duration: 0.3, ease: "power2.in" }, <end>);
</script>
Stat / figure reveals — bespoke per beat
There is no default stat primitive. Every stat moment deserves a reveal designed for its role in the script. Picking "corner badge" for every stat ruins the highest-information moments.
When authoring a stat beat, answer: what's this figure's role? Hero number? Comparison? Percentage? Metaphor? Passing detail? Then pick (or remix, or invent) a shape below that fits. Never reach for the same shape twice in one video unless they pair intentionally (e.g. two editorial pullouts for symmetric stats).
Shape gallery
| # | Shape | Best for | Sketch |
|---|
| A | Editorial pullout | Hero standalone figure that needs to sit and land | Huge Geist 800 number (~120px) + thin hairline rule + tiny letterspaced label |
| B | Iconic metaphor | Stat with a physical analogy (watts → bulb, compute → chip) | Monochrome line-drawn SVG + figure stacked below; SVG path draws in |
| C | Side-by-side comparison | Ratios / magnitude contrasts ("20W vs 20kW") | Two cards with ×N between; hero card flips to paper-on-ink |
| D | Annotated pullout | Stat tied to the word that mentions it | Thin line draws from caption word up to figure floating in frame |
| E | Radial gauge/ring | Percentages, rates, fill values | Thin ring fills to value; figure centered, soft glow on active arc |
| F | Odometer count-up | Big integers that benefit from "watching the number arrive" | Digits in cells, GSAP count-up tween |
| G | Inline text takeover | Stat word inside the caption chunk | The caption word scales to 3-4× and holds while the line continues below |
| H | Full-frame stat moment | Showstopper figure worth 1.5-2s of silence | Captions fade, face softens, figure fills the frame; sibling of §7 pull-quote |
Each shape has a code scaffold in .claude/skills/tejas-overlays/stat-shapes/ — open and adapt per beat. If none fit, invent one: use warm mono, Geist, spring motion, thin borders.
Rule of thumb: if you can summarize the figure's role in two words ("hero number", "ratio punch", "metaphor land", "milestone arrive"), a shape jumps out. If you can't, you're not ready to author the beat.
Checklist before moving on