refactor(skills): rename graphic-overlays skill to talking-head-recut (#1720)

Rename the `graphic-overlays` workflow skill to `talking-head-recut`:

- move skills/graphic-overlays/ -> skills/talking-head-recut/
- update SKILL.md frontmatter name, H1, and self-references
- update all /graphic-overlays route references (hyperframes router,
  general-video, root + cli-template AGENTS.md/CLAUDE.md, docs, quickstart)
- update telemetry --skill flag, example composition id, timeline key
- update .prettierignore path and scripts/test-skills-fresh.sh

Identifier-only rename: the graphic-overlay card mechanism, design
references, and trigger wording are unchanged.

Co-authored-by: kiritowoo <295860553+kiritowoo@users.noreply.github.com>
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
kiritowoo
2026-06-26 00:32:51 +08:00
committed by GitHub
co-authored by kiritowoo Claude Opus 4.8
parent 1494f715fb
commit 56859b618f
37 changed files with 24 additions and 24 deletions
+39
View File
@@ -0,0 +1,39 @@
# Attribution
The `talking-head-recut` skill (its card-based design system — styles, layouts, frames,
fonts, and the GSAP-driven composition workflow) is **adapted from** the open-source
**vtake-skills** project (`vtake-cut`):
> https://github.com/notedit/vtake-skills
Adaptations for this repo: renamed to `talking-head-recut`; transcription repointed to
local Whisper via `hyperframes transcribe` (dropping the third-party `@notedit/vtake`
CLI and the `vtake.app` proxy); audio/metadata extraction inlined with `ffmpeg`/`ffprobe`;
the fixed third-party brand outro removed in favour of an optional, neutral outro;
artifacts aligned to the `videos/<project>/` convention.
The original is MIT-licensed; its notice is retained below as required.
```
MIT License
Copyright (c) 2026 leeoxiang
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
```
File diff suppressed because it is too large Load Diff
Binary file not shown.
File diff suppressed because one or more lines are too long
@@ -0,0 +1,145 @@
# V—Take Visual Design Library
This directory is a **reference library** for the talking-head-recut skill. Style, layout,
and video frame are three **orthogonal** dimensions you can freely mix when
designing a takeaway video.
```
Style × Layout × VideoFrame
(10) (4) (3) = 120 possible combinations
```
Read a reference file when you decide to use that dimension. Each file is a
self-contained HTML fragment that follows the talking-head-recut card-HTML contract
(scoped `<style>`, no `<script>`, no external URLs, animations only via
`data-anim-*`).
## Layouts — how video and card share the canvas
| key | file | what it does | best for |
| --------- | -------------------------------------------- | ------------------------------------------------------- | --------------------------------------- |
| `split` | [layouts/split.html](layouts/split.html) | 50/50 side-by-side (landscape) or top/bottom (portrait) | speaker + data equal weight |
| `stack` | [layouts/stack.html](layouts/stack.html) | video on top (~52%), card below | talking-head with summary card |
| `pip` | [layouts/pip.html](layouts/pip.html) | card fills canvas, video rounded PiP in corner | content-heavy moment, speaker secondary |
| `overlay` | [layouts/overlay.html](layouts/overlay.html) | video full-bleed, glass card floats on bottom | cinematic / dramatic moments |
A layout is a **two-part recipe**: pick a `card.zone` value to put in
`storyboard.json` AND author a GSAP tween for `#video-wrap` to its
target rect in the composition's `<script>`. Open the layout file's
header for the recommended `zone` + the GSAP statement to paste.
(Earlier docs referenced a `card.layout` field — that field does NOT
exist in the real schema; the strict v3 schema only has `card.zone`.)
## Styles — the card's visual language
| key | file | character | accent | suggested font |
| ------------ | ------------------------------------------------ | ---------------------------------------------------- | --------- | ------------------- |
| `academic` | [styles/academic.html](styles/academic.html) | warm paper · grid · serif · blue highlight | `#2557a7` | serif |
| `editorial` | [styles/editorial.html](styles/editorial.html) | cream · coral block · big italic quote | `#ff3a2d` | Playfair-like serif |
| `minimal` | [styles/minimal.html](styles/minimal.html) | pure black/white · huge type · generous space | `#000` | Inter |
| `spotlight` | [styles/spotlight.html](styles/spotlight.html) | dark purple gradient · glow · dramatic | `#a78bfa` | sans |
| `geom` | [styles/geom.html](styles/geom.html) | chartreuse + hot pink + black collision | `#d4ff00` | Inter bold |
| `whiteboard` | [styles/whiteboard.html](styles/whiteboard.html) | paper · Caveat handwriting · sketched borders | `#ff6b35` | Caveat |
| `audit` | [styles/audit.html](styles/audit.html) | manila paper · justified serif · APPROVED stamp | `#8b1d1d` | serif |
| `terminal` | [styles/terminal.html](styles/terminal.html) | dark · monospace · ASCII border · prompt cursor | `#4ade80` | mono |
| `swiss` | [styles/swiss.html](styles/swiss.html) | white · Helvetica · strict double rules · red accent | `#e8190f` | Helvetica/Inter |
| `xhs` | [styles/xhs.html](styles/xhs.html) | cream + hot pink · chips · #hashtags · ❤️💬 row | `#ff2e63` | sans |
Choose by content tone, not by content type — `academic` works for finance
too if the tone is reflective; `terminal` works for non-tech if the tone is
"engineering rigor".
## Video Frames — decoration around the video element
| key | file | character | when to skip |
| ---------- | -------------------------------------------- | ------------------------------------------------------------ | ------------------------------------------------ |
| `clean` | [frames/clean.html](frames/clean.html) | no decoration; raw video | default; safest |
| `hairline` | [frames/hairline.html](frames/hairline.html) | double-stroke + four-corner viewfinder ticks | over `overlay` layout (clashes with full-bleed) |
| `polaroid` | [frames/polaroid.html](frames/polaroid.html) | white photo frame + Caveat label + blue washi tape (no tilt) | over `overlay` layout; portrait PiP gets cramped |
A frame is a decorative div that sits **next to** the `#video-wrap` inside
the composition's `#stage`. It is one-time HTML (not animated), but you can
fade it in/out across cards. See each frame file for the placement snippet
and the inline `<style>` it needs.
## Decision guide (loose, not prescriptive)
| video content | suggested combos |
| -------------------------------- | -------------------------------------------------------- |
| interview / dialogue | `academic` × `stack`, `audit` × `split` |
| product launch / announcement | `editorial` × `overlay`, `geom` × `pip` |
| data analysis / financial report | `audit` × `split`, `swiss` × `stack`, `terminal` × `pip` |
| social clip (9:16) | `xhs` × `overlay`, `editorial` × `stack` |
| technical tutorial | `terminal` × `split`, `whiteboard` × `pip` |
| emotional story / narration | `spotlight` × `overlay`, `whiteboard` × `overlay` |
| minimalist presentation | `minimal` × `split`, `swiss` × `overlay` |
These are starting points only. Look at the transcript, pick the tone, then
pick the visual.
## Portrait sizing — bigger type for mobile
Every `references/styles/*.html` is sized for a **1920×1080 landscape**
preview. When the final composition is **portrait (1080×1920)** — the
default for social / mobile — scale every visual size up so it reads on a
phone held close.
| token | landscape | **portrait** | scale |
| --------------------- | --------- | ------------ | ----- |
| hero title (h1/h2) | 6496px | **88132px** | ×1.35 |
| detail / body | 2430px | **3040px** | ×1.30 |
| kicker / chip / meta | 1418px | **1822px** | ×1.25 |
| primary number / stat | 4860px | **6488px** | ×1.40 |
| horizontal padding | 4064px | **2436px** | ÷1.5 |
`portraitPx ≈ round(landscapePx × 1.3)`. Hero headlines can go ×1.4;
small meta stays at ×1.2. Padding **shrinks** in portrait since the card
is narrower.
For a card that must work in both, use a container query on the card
root: `container-type: inline-size` + `font-size: clamp(64px, 8.5cqi, 132px)`.
## Source aspect ratio independence
Output canvas is independent of source video aspect. Three supported
output ratios (selected by the user in Step 7.0 of SKILL.md):
| ratio | canvas | `storyboard.layout` | best for |
| ------ | --------- | ------------------------------------------------------ | ---------------------------------------------------------- |
| `16:9` | 1920×1080 | `"landscape"` | YouTube / TV / desktop playback |
| `9:16` | 1080×1920 | `"portrait"` | TikTok / Reels / short-form mobile |
| `4:5` | 1080×1350 | `"portrait"` (schema treats 4:5 as portrait since h>w) | Instagram feed / WeChat Moments / works for both platforms |
The layout reference files in `layouts/` document **landscape** and
**portrait** bounds only. For **4:5** derive bounds by proportional
vertical scaling from portrait: `4:5 y/h = round(portrait y/h × 0.703)`,
keep `x/w` identical. The composer doesn't care about the named layout
value; it just uses `composition.width × height`.
- Landscape video on landscape canvas → `videoBounds` matches video aspect, no letterbox
- Portrait video on landscape canvas → `videoBounds` is a narrower box (e.g. `pip` becomes 248×440); empty side filled by card or background
- Landscape video on portrait canvas → `videoBounds` becomes a wide-but-short band; `stack` and `overlay` work best
- Portrait video on portrait canvas → most natural; any layout
The layout reference files show landscape values; for portrait you usually
flip the long axis: `split` becomes top/bottom, `pip` video bubble shrinks
~20%, `overlay` card slot widens to full width.
## Constraints you must obey when copying from these references
1. **No `<script>`** — animations only via `data-anim-*` attributes
2. **No external URLs** — no Google Fonts CDN, no remote images; the
skill provides Caveat / LXGW WenKai TC / Inter / Virgil locally
3. **All `<style>` rules must be prefixed with `.card[data-card-id="..."]`**
the hyperframes sanitizer auto-scopes them, but write them already-scoped to
stay readable
4. **No `on*=` inline handlers**
5. **CSS variables for colors** when you want a card to switch theme cleanly;
inline hex when you want this specific style's signature look
If a reference uses a font you don't have, fall back:
- Playfair Display / Noto Serif SC → `ui-serif, "Songti SC", "Times New Roman", serif`
- Noto Sans SC → `ui-sans-serif, system-ui, sans-serif`
- JetBrains Mono → `ui-monospace, "SF Mono", Menlo, monospace`
- Kalam → `'Caveat', cursive`
@@ -0,0 +1,92 @@
<!--
Frame: clean — no decoration. Raw video edge.
─────────────────────────────────────────────────────────────────────
When to use
- Default; safest.
- Pairs with any layout and any style.
- Required over the `overlay` layout (decorative frames clash with full-bleed video).
How to apply in the composition
No extra HTML — just leave #video-wrap without the `framed` class.
.video-wrapper { border-radius: 0; box-shadow: none; }
How to apply on PiP layouts
Even with `clean`, PiPs benefit from a 14px border-radius + soft shadow
(see layouts/pip.html). That's a layout-level treatment, not a frame.
Placement
None. This reference exists as documentation of the "no-frame" option.
-->
<!doctype html>
<html lang="zh-CN">
<head>
<meta charset="utf-8" />
<title>frame · clean (no decoration)</title>
<style>
html,
body {
margin: 0;
padding: 0;
background: #0a0c12;
color: #fff;
font-family: ui-sans-serif, system-ui, sans-serif;
}
.stage {
position: relative;
width: 1920px;
height: 1080px;
transform-origin: top left;
transform: scale(0.5);
background: #0a0c12;
overflow: hidden;
}
.video-wrap {
position: absolute;
left: 240px;
top: 140px;
width: 1440px;
height: 810px;
background: #1a1f2e;
background-image: repeating-linear-gradient(
45deg,
transparent 0 12px,
rgba(255, 255, 255, 0.05) 12px 13px
);
}
.v-label {
position: absolute;
left: 24px;
top: 24px;
padding: 8px 14px;
border: 1px solid rgba(255, 255, 255, 0.45);
border-radius: 3px;
color: rgba(255, 255, 255, 0.7);
font:
600 16px/1 ui-monospace,
monospace;
letter-spacing: 0.14em;
}
.note {
position: absolute;
left: 240px;
bottom: 60px;
right: 240px;
text-align: center;
color: rgba(255, 255, 255, 0.5);
font:
14px/1.4 ui-monospace,
monospace;
letter-spacing: 0.12em;
}
</style>
</head>
<body>
<div class="stage">
<div class="video-wrap">
<span class="v-label">VIDEO · no chrome</span>
</div>
<div class="note">CLEAN — let the video speak for itself.</div>
</div>
</body>
</html>
@@ -0,0 +1,171 @@
<!--
Frame: hairline — double stroke + four-corner viewfinder ticks
─────────────────────────────────────────────────────────────────────
When to use
- Professional / cinematographic feel without going full polaroid.
- Pairs well with: split, stack, pip layouts.
- Pairs well with: academic, audit, swiss, terminal styles.
- Skip on overlay layout — the decorative chrome clashes with full-bleed video.
How to apply in the composition
Add ONE decorative div as a sibling of #video-wrap (not a child — the
video element is muted/playsinline and the decorative div should sit
above it). The accent color is configurable per scene.
<div class="video-wrapper" id="video-wrap">
<video src="input-video.mp4" ...></video>
</div>
<div class="frame-deco frame-deco--hairline"
style="left:240px; top:140px; width:1440px; height:810px;
--frame-accent: #2557a7;">
<span class="tick tl"></span>
<span class="tick tr"></span>
<span class="tick bl"></span>
<span class="tick br"></span>
</div>
CSS (4 corners via explicit spans — preferred over ::before/::after
because pseudo-elements give you at most 2 corners cleanly):
.frame-deco { position: absolute; pointer-events: none; z-index: 3; }
.frame-deco--hairline {
box-shadow:
inset 0 0 0 2px var(--frame-accent),
inset 0 0 0 6px color-mix(in srgb, var(--frame-accent) 13%, transparent),
0 0 0 1px rgba(0,0,0,.1);
}
.frame-deco .tick { position: absolute; width: 24px; height: 24px; }
.frame-deco .tick.tl { top: -3px; left: -3px; border-top: 4px solid var(--frame-accent); border-left: 4px solid var(--frame-accent); }
.frame-deco .tick.tr { top: -3px; right: -3px; border-top: 4px solid var(--frame-accent); border-right: 4px solid var(--frame-accent); }
.frame-deco .tick.bl { bottom: -3px; left: -3px; border-bottom: 4px solid var(--frame-accent); border-left: 4px solid var(--frame-accent); }
.frame-deco .tick.br { bottom: -3px; right: -3px; border-bottom: 4px solid var(--frame-accent); border-right: 4px solid var(--frame-accent); }
When the layout changes mid-composition
Move + resize the frame-deco div together with #video-wrap using GSAP:
tl.to('#video-wrap, .frame-deco', { left:, top:, width:, height:, ... }, T);
Or fade out the deco entirely before transitioning to a clean PiP.
-->
<!doctype html>
<html lang="zh-CN">
<head>
<meta charset="utf-8" />
<title>frame · hairline (double stroke + viewfinder ticks)</title>
<style>
html,
body {
margin: 0;
padding: 0;
background: #0a0c12;
color: #fff;
font-family: ui-sans-serif, system-ui, sans-serif;
}
.stage {
position: relative;
width: 1920px;
height: 1080px;
transform-origin: top left;
transform: scale(0.5);
background: #0a0c12;
overflow: hidden;
}
.video-wrap {
position: absolute;
left: 240px;
top: 140px;
width: 1440px;
height: 810px;
background: #1a1f2e;
background-image: repeating-linear-gradient(
45deg,
transparent 0 12px,
rgba(255, 255, 255, 0.05) 12px 13px
);
}
.v-label {
position: absolute;
left: 24px;
top: 24px;
padding: 8px 14px;
border: 1px solid rgba(255, 255, 255, 0.45);
border-radius: 3px;
color: rgba(255, 255, 255, 0.7);
font:
600 16px/1 ui-monospace,
monospace;
letter-spacing: 0.14em;
}
.frame-deco {
position: absolute;
left: 240px;
top: 140px;
width: 1440px;
height: 810px;
pointer-events: none;
z-index: 3;
--frame-accent: #2557a7;
box-shadow:
inset 0 0 0 2px var(--frame-accent),
inset 0 0 0 6px rgba(37, 87, 167, 0.13),
0 0 0 1px rgba(0, 0, 0, 0.1);
}
.tick {
position: absolute;
width: 24px;
height: 24px;
}
.tick.tl {
top: -3px;
left: -3px;
border-top: 4px solid var(--frame-accent, #2557a7);
border-left: 4px solid var(--frame-accent, #2557a7);
}
.tick.tr {
top: -3px;
right: -3px;
border-top: 4px solid var(--frame-accent, #2557a7);
border-right: 4px solid var(--frame-accent, #2557a7);
}
.tick.bl {
bottom: -3px;
left: -3px;
border-bottom: 4px solid var(--frame-accent, #2557a7);
border-left: 4px solid var(--frame-accent, #2557a7);
}
.tick.br {
bottom: -3px;
right: -3px;
border-bottom: 4px solid var(--frame-accent, #2557a7);
border-right: 4px solid var(--frame-accent, #2557a7);
}
.note {
position: absolute;
left: 240px;
bottom: 60px;
right: 240px;
text-align: center;
color: rgba(255, 255, 255, 0.5);
font:
14px/1.4 ui-monospace,
monospace;
letter-spacing: 0.12em;
}
</style>
</head>
<body>
<div class="stage">
<div class="video-wrap">
<span class="v-label">VIDEO</span>
</div>
<div class="frame-deco">
<span class="tick tl"></span>
<span class="tick tr"></span>
<span class="tick bl"></span>
<span class="tick br"></span>
</div>
<div class="note">
HAIRLINE — double stroke (2px inner + soft 6px halo) + four-corner viewfinder ticks. Accent
color matches the card style.
</div>
</div>
</body>
</html>
@@ -0,0 +1,131 @@
<!--
Frame: polaroid — white photo frame + Caveat label + blue washi tape (no tilt)
─────────────────────────────────────────────────────────────────────
When to use
- Casual, personal, warm feel. Looks great for interviews, memoirs, vlogs.
- Pairs well with: split, stack, pip layouts.
- Pairs well with: academic, whiteboard, editorial, xhs styles.
- Skip on overlay layout (clashes with full-bleed).
- In portrait PiP (narrow video bubble), polaroid gets cramped — prefer hairline.
IMPORTANT — NO TILT
Earlier iterations of the design tilted the polaroid by -1.4° / 5°. User
explicitly removed the tilt (chat L770790). Keep the polaroid card,
label, and washi tape all UPRIGHT.
How to apply in the composition
Replace the bare #video-wrap with a wrapper div that draws the polaroid
around it. The polaroid card has its own background + padding; the video
sits inside a sub-region.
HTML pattern (use absolute positioning to fit the layout's video bounds):
<div class="frame-deco frame-deco--polaroid"
style="left:240px; top:140px; width:1440px; height:990px;">
<div class="polaroid-card">
<div class="polaroid-photo">
<!-- the actual #video-wrap element, sized to fill -->
<div class="video-wrapper" id="video-wrap">
<video src="input-video.mp4" ...></video>
</div>
</div>
<div class="polaroid-caption">speaker · 2026</div>
</div>
<div class="washi"></div>
</div>
The video bounds in storyboard.json should be the OUTER polaroid bounds.
The CSS inset values below carve out the inner photo area.
Suggested CSS
.frame-deco--polaroid { position: absolute; }
.polaroid-card {
position: absolute; inset: 24px;
background: #fefefe; padding: 14px 14px 64px;
box-shadow: 0 28px 60px -18px rgba(0,0,0,.55),
0 4px 12px rgba(0,0,0,.12);
box-sizing: border-box;
}
.polaroid-photo {
position: relative; width: 100%; height: calc(100% - 50px);
overflow: hidden; background: #000;
}
.polaroid-photo .video-wrapper {
position: absolute; inset: 0; width: 100%; height: 100%; border-radius: 0;
}
.polaroid-caption {
position: absolute; bottom: 18px; left: 0; right: 0;
text-align: center;
font: 700 32px/1 "Caveat", ui-serif, cursive;
color: #1d1c1a;
}
.washi {
position: absolute; top: 12px; left: 20%;
width: 120px; height: 28px;
background: rgba(180,210,235,.85);
background-image: repeating-linear-gradient(90deg,
transparent 0 6px, rgba(255,255,255,.3) 6px 7px);
box-shadow: 0 3px 8px rgba(0,0,0,.15);
}
-->
<!doctype html>
<html lang="zh-CN">
<head>
<meta charset="utf-8" />
<title>frame · polaroid (white photo frame + caveat label, no tilt)</title>
<style>
html, body { margin: 0; padding: 0; background: #0a0c12; color: #fff;
font-family: ui-sans-serif, system-ui, sans-serif; }
.stage { position: relative; width: 1920px; height: 1080px;
transform-origin: top left; transform: scale(0.5);
background: #0a0c12; overflow: hidden; }
.frame-deco { position: absolute; left: 240px; top: 70px; width: 1440px; height: 940px; }
.polaroid-card {
position: absolute; inset: 24px;
background: #fefefe; padding: 14px 14px 64px;
box-shadow: 0 28px 60px -18px rgba(0,0,0,.55), 0 4px 12px rgba(0,0,0,.12);
box-sizing: border-box;
}
.polaroid-photo {
position: relative; width: 100%; height: calc(100% - 50px);
overflow: hidden; background: #1a1f2e;
background-image: repeating-linear-gradient(45deg,
transparent 0 12px, rgba(255,255,255,.05) 12px 13px);
}
.v-label { position: absolute; left: 24px; top: 24px;
padding: 8px 14px; border: 1px solid rgba(255,255,255,.45);
border-radius: 3px; color: rgba(255,255,255,.7);
font: 600 16px/1 ui-monospace, monospace; letter-spacing: .14em; }
.polaroid-caption {
position: absolute; bottom: 18px; left: 0; right: 0;
text-align: center;
font: 700 32px/1 "Caveat", ui-serif, cursive;
color: #1d1c1a;
}
.washi {
position: absolute; top: 12px; left: 20%;
width: 120px; height: 28px;
background: rgba(180,210,235,.85);
background-image: repeating-linear-gradient(90deg,
transparent 0 6px, rgba(255,255,255,.3) 6px 7px);
box-shadow: 0 3px 8px rgba(0,0,0,.15);
}
.note { position: absolute; left: 240px; bottom: 18px; right: 240px;
text-align: center; color: rgba(255,255,255,.5);
font: 14px/1.4 ui-monospace, monospace; letter-spacing: .12em; }
</style>
</head>
<body>
<div class="stage">
<div class="frame-deco">
<div class="polaroid-card">
<div class="polaroid-photo">
<span class="v-label">VIDEO</span>
</div>
<div class="polaroid-caption">speaker · 2026</div>
</div>
<div class="washi"></div>
</div>
<div class="note">POLAROID — white frame, Caveat handwritten caption, blue washi tape on top. Upright (no tilt).</div>
</div>
</body>
</html>
@@ -0,0 +1,164 @@
<!--
Layout: overlay — video full-bleed, glass card floats on bottom
─────────────────────────────────────────────────────────────────────
Implementation: card.zone = "video-overlay" + leave #video-wrap at
full-bleed (no tween needed if it starts full-bleed). The "card" is
positioned by CSS inside the video-overlay zone's full-canvas wrapper.
Recommended storyboard.json card entry (strict v3):
{
"id": "card-XX",
"intent": "cinematic / dramatic moment with glass overlay",
"startSec": 8, "endSec": 14,
"accentIndex": 0,
"zone": "video-overlay",
"contentHints": { "kicker": "...", "title": "...", "detail": "..." }
}
GSAP target for #video-wrap (full-bleed — usually unchanged):
tl.to('#video-wrap',
{ left: 0, top: 0, width: COMPOSITION_W, height: COMPOSITION_H,
duration: 0.6, ease: 'power2.inOut' }, START_SEC);
// Use defaults: landscape 1920×1080 / portrait 1080×1920 / 4:5 1080×1350
Recommended card-host inline style (since zone="video-overlay" gives
full-canvas bounds, you typically inset the actual card visual via CSS):
landscape glass card, mid-left:
.card[data-card-id="X"] .root {
position: absolute; left: 48px; top: 460px;
width: 660px; height: 540px;
background: rgba(15,16,22,.78);
backdrop-filter: blur(22px) saturate(140%);
-webkit-backdrop-filter: blur(22px) saturate(140%);
border-radius: 18px;
box-shadow: 0 30px 80px -20px rgba(0,0,0,.45);
}
portrait glass card, bottom band:
.card[data-card-id="X"] .root {
position: absolute; left: 24px; top: 1280px;
width: 1032px; height: 564px;
/* same glass treatment */
}
4:5 glass card (y/h × 0.703):
.card[data-card-id="X"] .root {
position: absolute; left: 24px; top: 900px;
width: 1032px; height: 397px;
/* same glass treatment */
}
Legibility gradient (insert as a third absolute layer between video
and card-host, in the composition's <div id="stage">):
<div class="legibility"></div>
.legibility {
position: absolute; inset: 0; pointer-events: none; z-index: 2;
background:
linear-gradient(180deg, rgba(0,0,0,.55) 0%, transparent 22%,
transparent 50%, rgba(0,0,0,.72) 100%);
}
Notes
- Card root MUST be transparent or use rgba/glass background — see
Pattern A in SKILL.md "Transparent card backgrounds".
- Glass without legibility gradient = white-on-white catastrophe over
bright video. Always pair them.
- Glass on a light video also benefits from a darker base color (use
rgba(15,16,22,.78) over rgba(255,255,255,.10) when source has bright
daylight / interior shots).
-->
<!doctype html>
<html lang="zh-CN">
<head>
<meta charset="utf-8" />
<title>layout · overlay (video full-bleed, glass card)</title>
<style>
html,
body {
margin: 0;
padding: 0;
background: #0a0c12;
color: #fff;
font-family: ui-sans-serif, system-ui, sans-serif;
}
.stage {
position: relative;
width: 1920px;
height: 1080px;
transform-origin: top left;
transform: scale(0.5);
background: #0a0c12;
overflow: hidden;
}
.video-region {
position: absolute;
left: 0;
top: 0;
width: 1920px;
height: 1080px;
background: #1a1f2e;
background-image: repeating-linear-gradient(
45deg,
transparent 0 12px,
rgba(255, 255, 255, 0.05) 12px 13px
);
}
.gradient {
position: absolute;
inset: 0;
pointer-events: none;
background:
linear-gradient(135deg, rgba(0, 0, 0, 0.55) 0%, transparent 35%),
linear-gradient(180deg, transparent 50%, rgba(0, 0, 0, 0.55) 100%);
}
.card-region {
position: absolute;
left: 48px;
top: 460px;
width: 660px;
height: 540px;
background: rgba(255, 255, 255, 0.1);
backdrop-filter: blur(18px) saturate(140%);
-webkit-backdrop-filter: blur(18px) saturate(140%);
border-radius: 18px;
box-shadow: 0 30px 80px -20px rgba(0, 0, 0, 0.45);
display: flex;
align-items: center;
justify-content: center;
color: #fff;
font:
600 24px/1.3 ui-monospace,
monospace;
letter-spacing: 0.12em;
}
.label {
padding: 12px 18px;
border: 1.5px solid rgba(255, 255, 255, 0.7);
border-radius: 4px;
}
.v-label {
position: absolute;
left: 28px;
top: 28px;
color: rgba(255, 255, 255, 0.55);
padding: 8px 14px;
border: 1px solid rgba(255, 255, 255, 0.3);
border-radius: 3px;
font:
600 16px/1 ui-monospace,
monospace;
letter-spacing: 0.14em;
}
</style>
</head>
<body>
<div class="stage">
<div class="video-region"><span class="v-label">VIDEO · 1920×1080 (full-bleed)</span></div>
<div class="gradient"></div>
<div class="card-region"><span class="label">CARD · 660×540 glass</span></div>
</div>
</body>
</html>
@@ -0,0 +1,143 @@
<!--
Layout: pip — card fills canvas, video rounded PiP in corner
─────────────────────────────────────────────────────────────────────
Implementation: card.zone = "fullscreen" + shrink #video-wrap to a
corner pill via GSAP, and add a .pip-pill CSS class for the chrome.
Recommended storyboard.json card entry (strict v3):
{
"id": "card-XX",
"intent": "content-heavy moment with speaker as small accent",
"startSec": 8, "endSec": 14,
"accentIndex": 0,
"zone": "fullscreen",
"contentHints": { "kicker": "...", "title": "...", "detail": "..." }
}
GSAP target for #video-wrap (corner pill — pick one per source aspect):
landscape (1920×1080), 16:9 source video:
tl.set('#video-wrap', { className: 'video-wrapper pip-pill' }, START_SEC);
tl.to('#video-wrap',
{ left: 1432, top: 28, width: 460, height: 258,
duration: 0.6, ease: 'power2.inOut' }, START_SEC);
landscape, 9:16 source video (vertical phone footage):
tl.to('#video-wrap',
{ left: 1644, top: 28, width: 248, height: 440, ... }, START_SEC);
portrait (1080×1920), 16:9 source video:
tl.to('#video-wrap',
{ left: 690, top: 28, width: 360, height: 203, ... }, START_SEC);
portrait, 9:16 source video:
tl.to('#video-wrap',
{ left: 738, top: 28, width: 312, height: 555, ... }, START_SEC);
4:5 (1080×1350) — y values × 0.703, w/h × 0.703:
landscape-source: { left: 690, top: 28, width: 360, height: 203 } → keep, fits
portrait-source : { left: 738, top: 28, width: 312, height: 390 }
Recommended .pip-pill CSS (add to composition <style>):
.video-wrapper.pip-pill {
border-radius: 14px;
box-shadow:
0 24px 60px -20px rgba(0,0,0,.45),
0 0 0 4px rgba(255,255,255,.7),
0 0 0 5px rgba(0,0,0,.18);
overflow: hidden;
}
Notes
- Card-first composition for content-heavy talks.
- Default corner is top-right (above); for bottom-right flip y to
canvasH - videoH - 28 (e.g. portrait 16:9 source bottom-right:
{ left: 690, top: 1689, width: 360, height: 203 }).
- DOM order: card-host appears BEFORE video-wrapper for the pip window
so the video pill paints on top of the card. If you keep them in
natural DOM order (video first, card second), use z-index on the
card-host to push it behind.
-->
<!doctype html>
<html lang="zh-CN">
<head>
<meta charset="utf-8" />
<title>layout · pip (card hero + video pill)</title>
<style>
html,
body {
margin: 0;
padding: 0;
background: #0a0c12;
color: #fff;
font-family: ui-sans-serif, system-ui, sans-serif;
}
.stage {
position: relative;
width: 1920px;
height: 1080px;
transform-origin: top left;
transform: scale(0.5);
background: #0a0c12;
overflow: hidden;
}
.region {
position: absolute;
box-sizing: border-box;
display: flex;
align-items: center;
justify-content: center;
font:
600 24px/1.3 ui-monospace,
monospace;
letter-spacing: 0.12em;
}
.card-region {
left: 0;
top: 0;
width: 1920px;
height: 1080px;
background: #f1ead8;
color: #1a1d2b;
}
.video-region {
left: 1432px;
top: 28px;
width: 460px;
height: 258px;
background: #1a1f2e;
color: #fff;
border-radius: 14px;
box-shadow:
0 24px 60px -20px rgba(0, 0, 0, 0.45),
0 0 0 4px rgba(255, 255, 255, 0.7),
0 0 0 5px rgba(0, 0, 0, 0.18);
background-image: repeating-linear-gradient(
45deg,
transparent 0 12px,
rgba(255, 255, 255, 0.05) 12px 13px
);
}
.label {
padding: 12px 18px;
border: 1.5px solid currentColor;
border-radius: 4px;
}
.v-label {
font:
600 14px/1 ui-monospace,
monospace;
letter-spacing: 0.14em;
padding: 6px 10px;
border: 1px solid currentColor;
border-radius: 3px;
}
</style>
</head>
<body>
<div class="stage">
<div class="region card-region"><span class="label">CARD · 1920×1080 (full-bleed)</span></div>
<div class="region video-region"><span class="v-label">VIDEO · 460×258 PIP</span></div>
</div>
</body>
</html>
@@ -0,0 +1,121 @@
<!--
Layout: split — 50/50 side-by-side
─────────────────────────────────────────────────────────────────────
Real schema only has `card.zone` (5 enum values) — there is NO
`card.layout` field, and video bounds are composition-level
(`videoTrack.bounds`, one-time). The "split look" is implemented by:
1. setting card.zone = "side-panel" for each card in this stretch
2. tweening #video-wrap to the other half via GSAP between cards
Recommended storyboard.json card entry (strict v3):
{
"id": "card-XX",
"intent": "speaker + data side-by-side",
"startSec": 8, "endSec": 14,
"accentIndex": 0,
"zone": "side-panel",
"contentHints": { "kicker": "...", "title": "...", "detail": "..." }
}
GSAP target for #video-wrap during this card (paste in <script>):
landscape (1920×1080):
tl.to('#video-wrap',
{ left: 960, top: 0, width: 960, height: 1080,
duration: 0.6, ease: 'power2.inOut' }, START_SEC);
portrait (1080×1920) — flips to top/bottom:
tl.to('#video-wrap',
{ left: 0, top: 960, width: 1080, height: 960,
duration: 0.6, ease: 'power2.inOut' }, START_SEC);
4:5 (1080×1350) — derive by ×0.703 on y/h:
tl.to('#video-wrap',
{ left: 0, top: 675, width: 1080, height: 675,
duration: 0.6, ease: 'power2.inOut' }, START_SEC);
Notes
- Card-host (from card.zone="side-panel") covers half the canvas;
opaque card background is fine — it only paints its own half.
- Flip card/video sides: swap which side gets the speaker tween.
- With 1418px page-level gap, set composition bg to deep color
(e.g. #0a0c12) so the gap reads as a clean separator.
-->
<!doctype html>
<html lang="zh-CN">
<head>
<meta charset="utf-8" />
<title>layout · split (50/50)</title>
<style>
html,
body {
margin: 0;
padding: 0;
background: #0a0c12;
color: #fff;
font-family: ui-sans-serif, system-ui, sans-serif;
}
.stage {
position: relative;
width: 1920px;
height: 1080px;
transform-origin: top left;
transform: scale(0.5);
background: #0a0c12;
overflow: hidden;
}
.region {
position: absolute;
box-sizing: border-box;
display: flex;
align-items: center;
justify-content: center;
font:
600 24px/1.3 ui-monospace,
monospace;
letter-spacing: 0.12em;
}
.card-region {
left: 18px;
top: 18px;
width: 942px;
height: 1044px;
background: #f1ead8;
color: #1a1d2b;
}
.video-region {
left: 978px;
top: 18px;
width: 924px;
height: 1044px;
background: #1a1f2e;
background-image: repeating-linear-gradient(
45deg,
transparent 0 12px,
rgba(255, 255, 255, 0.05) 12px 13px
);
}
.label {
padding: 12px 18px;
border: 1.5px solid currentColor;
border-radius: 4px;
}
.meta {
position: absolute;
left: 18px;
top: -36px;
font:
12px/1 ui-monospace,
monospace;
letter-spacing: 0.18em;
color: #888;
}
</style>
</head>
<body>
<div class="stage">
<div class="meta">SPLIT · 1920×1080 · card 960 | video 960</div>
<div class="region card-region"><span class="label">CARD · 960×1080</span></div>
<div class="region video-region"><span class="label">VIDEO · 960×1080</span></div>
</div>
</body>
</html>
@@ -0,0 +1,109 @@
<!--
Layout: stack — video on top, card below
─────────────────────────────────────────────────────────────────────
Implementation: card.zone = "lower-third" + tween #video-wrap to top band.
Recommended storyboard.json card entry (strict v3):
{
"id": "card-XX",
"intent": "talking-head + caption-style summary below",
"startSec": 8, "endSec": 14,
"accentIndex": 0,
"zone": "lower-third",
"contentHints": { "kicker": "...", "title": "...", "detail": "..." }
}
GSAP target for #video-wrap (top band):
landscape (1920×1080) — video top 52%:
tl.to('#video-wrap',
{ left: 14, top: 14, width: 1892, height: 548,
duration: 0.6, ease: 'power2.inOut' }, START_SEC);
portrait (1080×1920) — video top 44%:
tl.to('#video-wrap',
{ left: 0, top: 0, width: 1080, height: 844,
duration: 0.6, ease: 'power2.inOut' }, START_SEC);
4:5 (1080×1350) — y/h × 0.703:
tl.to('#video-wrap',
{ left: 0, top: 0, width: 1080, height: 593,
duration: 0.6, ease: 'power2.inOut' }, START_SEC);
Notes
- Sleek vertical: gives the speaker a wider stage on top.
- Card below is a full-width statement — great for one big sentence
or one big number.
- The `lower-third` zone resolves to bottom 30% by default
(`resolveZoneBounds`); for a 48% card adjust the GSAP tween to also
move card-host height, or use `zone="whiteboard-area"` + custom CSS.
- 14px gap between video and card looks clean — set composition bg to
a deep color (#0a0c12) so the gap reads as a separator.
-->
<!doctype html>
<html lang="zh-CN">
<head>
<meta charset="utf-8" />
<title>layout · stack (video top, card bottom)</title>
<style>
html,
body {
margin: 0;
padding: 0;
background: #0a0c12;
color: #fff;
font-family: ui-sans-serif, system-ui, sans-serif;
}
.stage {
position: relative;
width: 1920px;
height: 1080px;
transform-origin: top left;
transform: scale(0.5);
background: #0a0c12;
overflow: hidden;
}
.region {
position: absolute;
box-sizing: border-box;
display: flex;
align-items: center;
justify-content: center;
font:
600 24px/1.3 ui-monospace,
monospace;
letter-spacing: 0.12em;
}
.video-region {
left: 14px;
top: 14px;
width: 1892px;
height: 548px;
background: #1a1f2e;
background-image: repeating-linear-gradient(
45deg,
transparent 0 12px,
rgba(255, 255, 255, 0.05) 12px 13px
);
}
.card-region {
left: 14px;
top: 576px;
width: 1892px;
height: 504px;
background: #f1ead8;
color: #1a1d2b;
}
.label {
padding: 12px 18px;
border: 1.5px solid currentColor;
border-radius: 4px;
}
</style>
</head>
<body>
<div class="stage">
<div class="region video-region"><span class="label">VIDEO · 1920×562 (top 52%)</span></div>
<div class="region card-region"><span class="label">CARD · 1920×518 (bottom 48%)</span></div>
</div>
</body>
</html>
@@ -0,0 +1,172 @@
<!--
Style: academic — warm paper · serif · blue highlight · coral annotation
─────────────────────────────────────────────────────────────────────
Tokens
bg #f1ead8 (warm paper)
ink #1a1d2b
muted #5b5749
accent #2557a7 (blue, used for kicker chip + text highlight)
accent2#c14d2c (coral, used for dashed quote box)
Fonts
headline & body — serif. Falls back to "ui-serif, 'Songti SC', serif"
mono — "ui-monospace, monospace"
Best with
layouts: split, stack, pip
frames: clean, hairline
content: 访谈反思 / 学术总结 / 长视频拆解
-->
<!doctype html>
<html lang="zh-CN">
<head>
<meta charset="utf-8" />
<title>style · academic</title>
<style>
/* preview wrapper — NOT part of the card fragment */
html,
body {
margin: 0;
padding: 0;
background: #0a0c12;
font-family: ui-sans-serif, system-ui, sans-serif;
}
.stage {
position: relative;
width: 1920px;
height: 1080px;
transform-origin: top left;
transform: scale(0.5);
overflow: hidden;
}
.card-host {
position: absolute;
left: 0;
top: 0;
width: 1920px;
height: 1080px;
}
</style>
</head>
<body>
<div class="stage">
<div class="card-host">
<div class="card" data-card-id="ref-academic">
<style>
.card[data-card-id="ref-academic"] .root {
--bg: #f1ead8;
--ink: #1a1d2b;
--muted: #5b5749;
--accent: #2557a7;
--accent2: #c14d2c;
--font-head: ui-serif, "Songti SC", "Times New Roman", serif;
--font-body: ui-serif, "Songti SC", "Times New Roman", serif;
--font-mono: ui-monospace, "SF Mono", Menlo, monospace;
width: 100%;
height: 100%;
position: relative;
overflow: hidden;
background-color: var(--bg);
background-image:
linear-gradient(rgba(91, 87, 73, 0.2) 1px, transparent 1px),
linear-gradient(90deg, rgba(91, 87, 73, 0.2) 1px, transparent 1px),
radial-gradient(120% 80% at 50% 0%, #fff8e9 0%, transparent 60%);
background-size:
28px 28px,
28px 28px,
100% 100%;
padding: 32px 40px;
box-sizing: border-box;
display: flex;
flex-direction: column;
justify-content: center;
gap: 16px;
color: var(--ink);
font-family: var(--font-body);
}
.card[data-card-id="ref-academic"] .meta {
display: flex;
align-items: baseline;
gap: 14px;
}
.card[data-card-id="ref-academic"] .kicker {
padding: 7px 14px;
background: var(--accent);
color: #fff;
font: 700 16px/1 var(--font-mono);
letter-spacing: 0.16em;
}
.card[data-card-id="ref-academic"] .time {
font: 15px/1 var(--font-mono);
color: var(--muted);
letter-spacing: 0.1em;
}
.card[data-card-id="ref-academic"] .title {
margin: 0;
font: 700 92px/1.05 var(--font-head);
color: var(--ink);
letter-spacing: 0.01em;
display: inline;
background: linear-gradient(
transparent 62%,
rgba(37, 87, 167, 0.2) 62%,
rgba(37, 87, 167, 0.2) 92%,
transparent 92%
);
-webkit-box-decoration-break: clone;
box-decoration-break: clone;
padding: 0 8px;
}
.card[data-card-id="ref-academic"] .detail {
margin: 0;
font: 30px/1.5 var(--font-body);
color: var(--muted);
max-width: 94%;
}
.card[data-card-id="ref-academic"] .hl {
background: linear-gradient(transparent 60%, rgba(37, 87, 167, 0.25) 60%);
padding: 0 4px;
}
.card[data-card-id="ref-academic"] .quote {
align-self: flex-start;
padding: 10px 18px;
border: 1.5px dashed var(--accent2);
color: var(--accent2);
font: italic 600 24px/1 var(--font-head);
transform: rotate(-1deg);
}
</style>
<div class="root">
<div class="meta">
<span class="kicker" data-anim="fade-in" data-anim-at="0.05" data-anim-duration="0.4"
>TAKEAWAY</span
>
<span class="time">00:18 → 00:46</span>
</div>
<h2
class="title"
data-anim="kinetic-chars"
data-anim-at="0.25"
data-anim-duration="0.55"
data-anim-stagger="0.04"
data-anim-pattern="pop"
>
<span class="char"></span><span class="char"></span><span class="char"></span>
<span class="char"></span>
</h2>
<p class="detail" data-anim="fade-in" data-anim-at="0.7" data-anim-duration="0.45">
复杂的解释往往是<span class="hl">未经压缩的思考</span
>。当你能用最少的词说清最重要的点时, 你也就真正想明白了这件事。
</p>
<div class="quote" data-anim="scale-pop" data-anim-at="1.05" data-anim-duration="0.5">
"Compression is comprehension."
</div>
</div>
</div>
</div>
</div>
</body>
</html>
@@ -0,0 +1,170 @@
<!--
Style: audit — manila paper · justified serif · APPROVED stamp · brick + navy
─────────────────────────────────────────────────────────────────────
Tokens
bg #ebd9b4 (manila)
ink #1d1a14
muted #6b5e44
accent #8b1d1d (brick red — stamp + heading underline)
accent2#1c3a6b (navy — footnote markers)
Fonts
headline — serif; ui-serif, "Songti SC", "Times New Roman", serif
body — serif justified
Best with
layouts: split, stack
frames: hairline, clean
content: 财报分析 / 调查报告 / 数据稽核 / 严肃陈述
-->
<!doctype html>
<html lang="zh-CN">
<head>
<meta charset="utf-8" />
<title>style · audit</title>
<style>
html,
body {
margin: 0;
padding: 0;
background: #0a0c12;
font-family: ui-sans-serif, system-ui, sans-serif;
}
.stage {
position: relative;
width: 1920px;
height: 1080px;
transform-origin: top left;
transform: scale(0.5);
overflow: hidden;
}
.card-host {
position: absolute;
left: 0;
top: 0;
width: 1920px;
height: 1080px;
}
</style>
</head>
<body>
<div class="stage">
<div class="card-host">
<div class="card" data-card-id="ref-audit">
<style>
.card[data-card-id="ref-audit"] .root {
--bg: #ebd9b4;
--ink: #1d1a14;
--muted: #6b5e44;
--accent: #8b1d1d;
--accent2: #1c3a6b;
--font-head: ui-serif, "Songti SC", "Times New Roman", serif;
--font-body: ui-serif, "Songti SC", "Times New Roman", serif;
--font-mono: ui-monospace, "SF Mono", Menlo, monospace;
width: 100%;
height: 100%;
position: relative;
overflow: hidden;
background-color: var(--bg);
background-image:
repeating-linear-gradient(0deg, rgba(0, 0, 0, 0.02) 0 1px, transparent 1px 28px),
radial-gradient(120% 80% at 20% 0%, rgba(255, 250, 235, 0.45) 0%, transparent 60%);
padding: 48px 64px 56px;
box-sizing: border-box;
display: flex;
flex-direction: column;
gap: 18px;
color: var(--ink);
font-family: var(--font-body);
}
.card[data-card-id="ref-audit"] .head {
display: flex;
justify-content: space-between;
align-items: baseline;
border-bottom: 2px solid var(--ink);
padding-bottom: 10px;
}
.card[data-card-id="ref-audit"] .kicker {
font: 700 14px/1 var(--font-mono);
letter-spacing: 0.3em;
text-transform: uppercase;
color: var(--ink);
}
.card[data-card-id="ref-audit"] .ref {
font: 13px/1 var(--font-mono);
color: var(--muted);
letter-spacing: 0.14em;
}
.card[data-card-id="ref-audit"] .title {
margin: 0;
font: 700 76px/1.1 var(--font-head);
color: var(--ink);
letter-spacing: 0.005em;
}
.card[data-card-id="ref-audit"] .title .accent {
color: var(--accent);
}
.card[data-card-id="ref-audit"] .body {
margin: 0;
font: 26px/1.55 var(--font-body);
color: var(--ink);
text-align: justify;
column-count: 2;
column-gap: 32px;
max-width: 100%;
}
.card[data-card-id="ref-audit"] .body .sup {
color: var(--accent2);
font-weight: 700;
}
.card[data-card-id="ref-audit"] .foot {
border-top: 1px solid var(--muted);
padding-top: 10px;
font: italic 14px/1.4 var(--font-body);
color: var(--muted);
}
.card[data-card-id="ref-audit"] .stamp {
position: absolute;
right: 56px;
top: 120px;
padding: 12px 22px;
border: 4px solid var(--accent);
color: var(--accent);
font: 800 36px/1 var(--font-head);
letter-spacing: 0.14em;
transform: rotate(-12deg);
opacity: 0.9;
box-shadow: 0 0 0 1px var(--accent) inset;
}
</style>
<div class="root">
<div class="head">
<span class="kicker" data-anim="fade-in" data-anim-at="0.05" data-anim-duration="0.35"
>EXHIBIT · TAKEAWAY</span
>
<span class="ref">REF / VT-2026-014</span>
</div>
<span class="stamp" data-anim="scale-pop" data-anim-at="0.7" data-anim-duration="0.4"
>APPROVED</span
>
<h2 class="title" data-anim="fade-in" data-anim-at="0.25" data-anim-duration="0.5">
第三季度<span class="accent">现金流</span>由负转正
</h2>
<p class="body" data-anim="fade-in" data-anim-at="0.55" data-anim-duration="0.5">
经营性现金流首次为正<span class="sup"></span>,主要由订阅业务驱动。 自由现金流由 -2.1
亿改善至 +0.8 亿,按当前轨迹推算<span class="sup"></span>,全年有望实现正向 1.52.0
亿。 与此同时,应收账款周转天数从 64 天压缩至 51 天,回款效率创近两年新高。
</p>
<div class="foot" data-anim="fade-in" data-anim-at="0.95" data-anim-duration="0.4">
① 含一次性税务返还 0.3 亿;② 假设 Q4 续约率不低于 91%。
</div>
</div>
</div>
</div>
</div>
</body>
</html>
@@ -0,0 +1,189 @@
<!--
Style: editorial — cream · coral block · big italic quote · Playfair-like serif
─────────────────────────────────────────────────────────────────────
Tokens
bg #f1e8d5 (cream)
ink #0e1018
muted #6b6353
accent #ff3a2d (coral red — used as block accents + italic quote color)
accent2 #1f6bff (blue — used for ring/circle outline)
accent3 #f2cf3a (yellow dot)
Fonts
headline — Playfair Display fallback: ui-serif, "Songti SC", serif
body — ui-serif, serif
Best with
layouts: overlay, pip, stack
frames: clean, polaroid
content: 产品发布 / 编辑专栏 / 大字宣言
-->
<!doctype html>
<html lang="zh-CN">
<head>
<meta charset="utf-8" />
<title>style · editorial</title>
<style>
html,
body {
margin: 0;
padding: 0;
background: #0a0c12;
font-family: ui-sans-serif, system-ui, sans-serif;
}
.stage {
position: relative;
width: 1920px;
height: 1080px;
transform-origin: top left;
transform: scale(0.5);
overflow: hidden;
}
.card-host {
position: absolute;
left: 0;
top: 0;
width: 1920px;
height: 1080px;
}
</style>
</head>
<body>
<div class="stage">
<div class="card-host">
<div class="card" data-card-id="ref-editorial">
<style>
.card[data-card-id="ref-editorial"] .root {
--bg: #f1e8d5;
--ink: #0e1018;
--muted: #6b6353;
--accent: #ff3a2d;
--accent2: #1f6bff;
--accent3: #f2cf3a;
/* IMPORTANT — this skill only ships Caveat / LXGW WenKai TC / Inter / Virgil.
Playfair Display is NOT bundled; if you list it first the font resolver
can't load it and you'll get inconsistent rendering across machines.
The editorial look uses italic-bold serif at large size — ui-serif on
macOS resolves to Times/New York which is close enough; for a real
Playfair you'd need to add the woff2 to public/fonts/. */
--font-head: ui-serif, "Songti SC", "Times New Roman", serif;
--font-body: ui-serif, "Songti SC", serif;
--font-mono: ui-monospace, "SF Mono", Menlo, monospace;
width: 100%;
height: 100%;
position: relative;
overflow: hidden;
background: var(--bg);
padding: 56px 64px;
box-sizing: border-box;
display: flex;
flex-direction: column;
justify-content: center;
gap: 24px;
color: var(--ink);
font-family: var(--font-body);
}
.card[data-card-id="ref-editorial"] .kicker {
align-self: flex-start;
padding: 8px 16px;
background: var(--ink);
color: var(--bg);
font: 700 16px/1 var(--font-mono);
letter-spacing: 0.22em;
}
.card[data-card-id="ref-editorial"] .title {
margin: 0;
font: italic 800 132px/0.95 var(--font-head);
color: var(--ink);
letter-spacing: -0.01em;
max-width: 92%;
}
.card[data-card-id="ref-editorial"] .first {
font-style: italic;
color: var(--accent);
}
.card[data-card-id="ref-editorial"] .quote-mark {
font: 800 220px/0.5 var(--font-head);
color: var(--accent);
position: absolute;
top: 24px;
right: 64px;
opacity: 0.9;
}
.card[data-card-id="ref-editorial"] .detail {
margin: 0;
font: 28px/1.5 var(--font-body);
color: var(--muted);
max-width: 78%;
}
.card[data-card-id="ref-editorial"] .hl {
background: linear-gradient(transparent 62%, rgba(255, 58, 45, 0.22) 62%);
color: var(--ink);
padding: 0 4px;
}
.card[data-card-id="ref-editorial"] .accents {
position: absolute;
}
.card[data-card-id="ref-editorial"] .block-coral {
top: 64px;
right: 88px;
width: 96px;
height: 96px;
background: var(--accent);
transform: rotate(12deg);
}
.card[data-card-id="ref-editorial"] .dot-yellow {
top: 200px;
right: 60px;
width: 36px;
height: 36px;
background: var(--accent3);
border-radius: 50%;
}
.card[data-card-id="ref-editorial"] .ring-blue {
bottom: 80px;
right: 80px;
width: 80px;
height: 80px;
border: 4px solid var(--accent2);
border-radius: 50%;
}
</style>
<div class="root">
<span
class="accents block-coral"
data-anim="scale-pop"
data-anim-at="0.15"
data-anim-duration="0.5"
></span>
<span
class="accents dot-yellow"
data-anim="fade-in"
data-anim-at="0.35"
data-anim-duration="0.4"
></span>
<span
class="accents ring-blue"
data-anim="fade-in"
data-anim-at="0.55"
data-anim-duration="0.4"
></span>
<span class="kicker" data-anim="fade-in" data-anim-at="0.05" data-anim-duration="0.4"
>TAKEAWAY</span
>
<h1 class="title" data-anim="fade-in" data-anim-at="0.3" data-anim-duration="0.6">
<span class="first"></span>正的创造,从拒绝套路开始。
</h1>
<p class="detail" data-anim="fade-in" data-anim-at="0.8" data-anim-duration="0.45">
停止模仿、停止套模板,把每一个想法都当作<span class="hl">第一次表达</span>
只有这样,作品才会带上你的体温。
</p>
</div>
</div>
</div>
</div>
</body>
</html>
@@ -0,0 +1,181 @@
<!--
Style: geom — chartreuse + hot pink + black collision · bold Helvetica
─────────────────────────────────────────────────────────────────────
Tokens
bg #0a0a0a (deep black for contrast)
ink #ffffff
muted #aaaaaa
accent #d4ff00 (chartreuse — primary slab)
accent2#ff2e88 (hot pink — secondary slab + dot)
accent3#ffffff (white — line work)
Fonts
headline — Inter Black / ui-sans-serif with very wide weight
body — Inter
Best with
layouts: pip, overlay, stack
frames: clean, hairline
content: 产品发布 / 大胆宣言 / 撞色封面 / 短视频高光
-->
<!doctype html>
<html lang="zh-CN">
<head>
<meta charset="utf-8" />
<title>style · geom</title>
<style>
html,
body {
margin: 0;
padding: 0;
background: #0a0c12;
font-family: ui-sans-serif, system-ui, sans-serif;
}
.stage {
position: relative;
width: 1920px;
height: 1080px;
transform-origin: top left;
transform: scale(0.5);
overflow: hidden;
}
.card-host {
position: absolute;
left: 0;
top: 0;
width: 1920px;
height: 1080px;
}
</style>
</head>
<body>
<div class="stage">
<div class="card-host">
<div class="card" data-card-id="ref-geom">
<style>
.card[data-card-id="ref-geom"] .root {
--bg: #0a0a0a;
--ink: #ffffff;
--muted: #aaaaaa;
--accent: #d4ff00;
--accent2: #ff2e88;
--accent3: #ffffff;
--font-sans: "Inter", ui-sans-serif, system-ui, sans-serif;
--font-mono: ui-monospace, "SF Mono", Menlo, monospace;
width: 100%;
height: 100%;
position: relative;
overflow: hidden;
background: var(--bg);
color: var(--ink);
font-family: var(--font-sans);
}
.card[data-card-id="ref-geom"] .slab-1 {
position: absolute;
left: 0;
top: 0;
width: 540px;
height: 200px;
background: var(--accent);
}
.card[data-card-id="ref-geom"] .slab-2 {
position: absolute;
right: 0;
bottom: 0;
width: 360px;
height: 360px;
background: var(--accent2);
}
.card[data-card-id="ref-geom"] .stripe {
position: absolute;
left: -40px;
top: 760px;
height: 4px;
width: 600px;
background: var(--accent3);
transform: rotate(-6deg);
}
.card[data-card-id="ref-geom"] .content {
position: absolute;
left: 64px;
top: 240px;
right: 480px;
bottom: 80px;
display: flex;
flex-direction: column;
justify-content: center;
gap: 28px;
}
.card[data-card-id="ref-geom"] .kicker {
align-self: flex-start;
padding: 8px 14px;
background: var(--ink);
color: var(--bg);
font: 800 18px/1 var(--font-mono);
letter-spacing: 0.24em;
}
.card[data-card-id="ref-geom"] .title {
margin: 0;
font: 900 156px/0.92 var(--font-sans);
color: var(--ink);
letter-spacing: -0.04em;
text-transform: uppercase;
}
.card[data-card-id="ref-geom"] .stroke {
-webkit-text-stroke: 3px var(--accent);
color: transparent;
}
.card[data-card-id="ref-geom"] .detail {
margin: 0;
font: 600 26px/1.4 var(--font-sans);
color: var(--muted);
max-width: 88%;
}
.card[data-card-id="ref-geom"] .detail .pink {
color: var(--accent2);
}
</style>
<div class="root">
<span
class="slab-1"
data-anim="slide-in"
data-anim-at="0.1"
data-anim-duration="0.45"
data-anim-from="left"
data-anim-distance="540"
></span>
<span
class="slab-2"
data-anim="slide-in"
data-anim-at="0.25"
data-anim-duration="0.45"
data-anim-from="right"
data-anim-distance="360"
></span>
<span
class="stripe"
data-anim="grow-x"
data-anim-at="0.5"
data-anim-duration="0.5"
data-anim-target-w="600"
></span>
<div class="content">
<span class="kicker" data-anim="fade-in" data-anim-at="0.05" data-anim-duration="0.4"
>TAKEAWAY</span
>
<h1 class="title" data-anim="fade-in" data-anim-at="0.55" data-anim-duration="0.5">
<span class="stroke">BIG</span><br />IDEA.
</h1>
<p class="detail" data-anim="fade-in" data-anim-at="0.95" data-anim-duration="0.4">
别再做温和的中间方案。要么<span class="pink">最大胆</span>,要么不做。
</p>
</div>
</div>
</div>
</div>
</div>
</body>
</html>
@@ -0,0 +1,130 @@
<!--
Style: minimal — pure black on white · huge type · generous space
─────────────────────────────────────────────────────────────────────
Tokens
bg #ffffff
ink #000000
muted #6b7280
accent #000000 (no color; weight & size do the work)
Fonts
headline & body — Inter, ui-sans-serif, system-ui, sans-serif
Best with
layouts: split, stack, overlay
frames: clean, hairline
content: 极简陈述 / 数据揭示 / 大字标题
-->
<!doctype html>
<html lang="zh-CN">
<head>
<meta charset="utf-8" />
<title>style · minimal</title>
<style>
html,
body {
margin: 0;
padding: 0;
background: #0a0c12;
font-family: ui-sans-serif, system-ui, sans-serif;
}
.stage {
position: relative;
width: 1920px;
height: 1080px;
transform-origin: top left;
transform: scale(0.5);
overflow: hidden;
}
.card-host {
position: absolute;
left: 0;
top: 0;
width: 1920px;
height: 1080px;
}
</style>
</head>
<body>
<div class="stage">
<div class="card-host">
<div class="card" data-card-id="ref-minimal">
<style>
.card[data-card-id="ref-minimal"] .root {
--bg: #ffffff;
--ink: #000000;
--muted: #6b7280;
--font-sans: "Inter", ui-sans-serif, system-ui, sans-serif;
width: 100%;
height: 100%;
position: relative;
overflow: hidden;
background: var(--bg);
color: var(--ink);
padding: 80px 96px;
box-sizing: border-box;
display: flex;
flex-direction: column;
justify-content: center;
gap: 56px;
font-family: var(--font-sans);
}
.card[data-card-id="ref-minimal"] .kicker {
font: 600 14px/1 var(--font-sans);
letter-spacing: 0.32em;
color: var(--ink);
text-transform: uppercase;
}
.card[data-card-id="ref-minimal"] .title {
margin: 0;
font: 900 132px/0.95 var(--font-sans);
color: var(--ink);
letter-spacing: -0.04em;
}
.card[data-card-id="ref-minimal"] .detail {
margin: 0;
font: 400 36px/1.4 var(--font-sans);
color: var(--muted);
max-width: 82%;
letter-spacing: -0.005em;
}
.card[data-card-id="ref-minimal"] .rule {
width: 0;
height: 4px;
background: var(--ink);
}
</style>
<div class="root">
<span class="kicker" data-anim="fade-in" data-anim-at="0.05" data-anim-duration="0.4"
>TAKEAWAY</span
>
<h1
class="title"
data-anim="kinetic-chars"
data-anim-at="0.3"
data-anim-duration="0.6"
data-anim-stagger="0.05"
data-anim-pattern="pop"
>
<span class="char"></span><span class="char"></span><span class="char"></span
><span class="char"></span> <span class="char"></span><span class="char"></span>
</h1>
<div
class="rule"
data-anim="grow-x"
data-anim-at="0.9"
data-anim-duration="0.5"
data-anim-target-w="240"
></div>
<p class="detail" data-anim="fade-in" data-anim-at="1.05" data-anim-duration="0.45">
用户给一个新界面的时间不超过五秒。这意味着第一屏不需要解释,需要让人立刻知道这是什么、为什么有用。
</p>
</div>
</div>
</div>
</div>
</body>
</html>
@@ -0,0 +1,142 @@
<!--
Style: spotlight — dark purple gradient · violet glow · dramatic
─────────────────────────────────────────────────────────────────────
Tokens
bg radial-gradient deep purple-blue (#0e0a24 → #1b1648)
ink #f5f3ff (off-white)
muted #b6b4d0
accent #a78bfa (violet) — used as glow + kicker dot
accent2#7c6bff (deeper violet) — used as outer-glow second layer
Fonts
headline — ui-serif fallback for serif drama; or Playfair-like
body — ui-sans-serif
Best with
layouts: overlay, pip
frames: clean (skip hairline/polaroid — clashes with glow)
content: 情绪故事 / 旁白 / 角色弧线 / 黑暗时刻
-->
<!doctype html>
<html lang="zh-CN">
<head>
<meta charset="utf-8" />
<title>style · spotlight</title>
<style>
html,
body {
margin: 0;
padding: 0;
background: #0a0c12;
font-family: ui-sans-serif, system-ui, sans-serif;
}
.stage {
position: relative;
width: 1920px;
height: 1080px;
transform-origin: top left;
transform: scale(0.5);
overflow: hidden;
}
.card-host {
position: absolute;
left: 0;
top: 0;
width: 1920px;
height: 1080px;
}
</style>
</head>
<body>
<div class="stage">
<div class="card-host">
<div class="card" data-card-id="ref-spotlight">
<style>
.card[data-card-id="ref-spotlight"] .root {
--ink: #f5f3ff;
--muted: #b6b4d0;
--accent: #a78bfa;
--accent2: #7c6bff;
--font-head: ui-serif, "Songti SC", serif;
--font-body: ui-sans-serif, system-ui, sans-serif;
--font-mono: ui-monospace, monospace;
width: 100%;
height: 100%;
position: relative;
overflow: hidden;
color: var(--ink);
font-family: var(--font-body);
background:
radial-gradient(70% 55% at 28% 30%, rgba(167, 139, 250, 0.35) 0%, transparent 55%),
radial-gradient(80% 70% at 80% 80%, rgba(124, 107, 255, 0.22) 0%, transparent 60%),
linear-gradient(160deg, #1b1648 0%, #0e0a24 100%);
padding: 48px 56px;
box-sizing: border-box;
display: flex;
flex-direction: column;
justify-content: center;
gap: 22px;
}
.card[data-card-id="ref-spotlight"] .meta {
display: flex;
align-items: center;
gap: 14px;
}
.card[data-card-id="ref-spotlight"] .kicker-dot {
width: 10px;
height: 10px;
border-radius: 50%;
background: var(--accent);
box-shadow:
0 0 18px var(--accent),
0 0 4px var(--accent);
}
.card[data-card-id="ref-spotlight"] .kicker {
font: 600 16px/1 var(--font-mono);
letter-spacing: 0.26em;
color: var(--accent);
}
.card[data-card-id="ref-spotlight"] .title {
margin: 0;
font: 800 104px/1.05 var(--font-head);
color: var(--ink);
letter-spacing: -0.005em;
text-shadow: 0 4px 60px rgba(167, 139, 250, 0.45);
}
.card[data-card-id="ref-spotlight"] .hl {
color: var(--accent);
text-shadow: 0 0 24px rgba(167, 139, 250, 0.7);
}
.card[data-card-id="ref-spotlight"] .detail {
margin: 0;
font: 28px/1.55 var(--font-body);
color: var(--muted);
max-width: 88%;
}
</style>
<div class="root">
<div class="meta">
<span
class="kicker-dot"
data-anim="scale-pop"
data-anim-at="0.05"
data-anim-duration="0.4"
></span>
<span class="kicker" data-anim="fade-in" data-anim-at="0.1" data-anim-duration="0.4"
>TAKEAWAY</span
>
</div>
<h2 class="title" data-anim="blur-in" data-anim-at="0.3" data-anim-duration="0.7">
在最暗的房间里,<span class="hl">一道光</span>就够了。
</h2>
<p class="detail" data-anim="fade-in" data-anim-at="1.0" data-anim-duration="0.5">
所有伟大决定都是在不确定的时候做出的。怕的不是黑,是不敢点亮那一根火柴。
</p>
</div>
</div>
</div>
</div>
</body>
</html>
@@ -0,0 +1,188 @@
<!--
Style: swiss — pure white · Helvetica · strict double rules · red accent slab
─────────────────────────────────────────────────────────────────────
Tokens
bg #ffffff
ink #111111
muted #555555
accent #e8190f (signal red — slab + number)
Fonts
headline & body — Helvetica / Inter / system sans
Best with
layouts: split, stack, overlay
frames: clean, hairline
content: 严肃陈述 / 排版主导 / 文化机构 / 极简数据
-->
<!doctype html>
<html lang="zh-CN">
<head>
<meta charset="utf-8" />
<title>style · swiss</title>
<style>
html,
body {
margin: 0;
padding: 0;
background: #0a0c12;
font-family: ui-sans-serif, system-ui, sans-serif;
}
.stage {
position: relative;
width: 1920px;
height: 1080px;
transform-origin: top left;
transform: scale(0.5);
overflow: hidden;
}
.card-host {
position: absolute;
left: 0;
top: 0;
width: 1920px;
height: 1080px;
}
</style>
</head>
<body>
<div class="stage">
<div class="card-host">
<div class="card" data-card-id="ref-swiss">
<style>
.card[data-card-id="ref-swiss"] .root {
--bg: #ffffff;
--ink: #111111;
--muted: #555555;
--accent: #e8190f;
--font-sans:
"Helvetica Neue", Helvetica, "Inter", ui-sans-serif, system-ui, sans-serif;
--font-mono: ui-monospace, "SF Mono", Menlo, monospace;
width: 100%;
height: 100%;
position: relative;
overflow: hidden;
background: var(--bg);
color: var(--ink);
font-family: var(--font-sans);
padding: 48px 64px;
box-sizing: border-box;
display: grid;
grid-template-rows: auto 1fr auto;
gap: 24px;
}
.card[data-card-id="ref-swiss"] .top-rule {
height: 4px;
background: var(--ink);
}
.card[data-card-id="ref-swiss"] .top-meta {
display: flex;
justify-content: space-between;
align-items: baseline;
padding-top: 12px;
font: 700 14px/1 var(--font-mono);
letter-spacing: 0.26em;
color: var(--ink);
text-transform: uppercase;
}
.card[data-card-id="ref-swiss"] .top-meta .num {
color: var(--accent);
}
.card[data-card-id="ref-swiss"] .body {
display: grid;
grid-template-columns: 1fr 320px;
gap: 56px;
align-items: end;
}
.card[data-card-id="ref-swiss"] .title {
margin: 0;
font: 700 116px/0.95 var(--font-sans);
color: var(--ink);
letter-spacing: -0.025em;
}
.card[data-card-id="ref-swiss"] .title .red {
color: var(--accent);
}
.card[data-card-id="ref-swiss"] .detail {
margin: 0;
font: 400 24px/1.45 var(--font-sans);
color: var(--muted);
}
.card[data-card-id="ref-swiss"] .slab {
background: var(--accent);
color: #fff;
padding: 24px 28px;
font: 700 56px/1 var(--font-sans);
letter-spacing: -0.02em;
align-self: end;
}
.card[data-card-id="ref-swiss"] .slab small {
display: block;
font: 600 14px/1 var(--font-mono);
letter-spacing: 0.18em;
margin-top: 6px;
color: rgba(255, 255, 255, 0.85);
}
.card[data-card-id="ref-swiss"] .bottom-rule {
height: 1px;
background: var(--ink);
}
.card[data-card-id="ref-swiss"] .bottom-meta {
display: flex;
justify-content: space-between;
align-items: baseline;
padding-top: 12px;
font: 600 13px/1 var(--font-mono);
letter-spacing: 0.22em;
color: var(--muted);
}
</style>
<div class="root">
<div>
<div
class="top-rule"
data-anim="grow-x"
data-anim-at="0.05"
data-anim-duration="0.45"
data-anim-target-w="1792"
></div>
<div
class="top-meta"
data-anim="fade-in"
data-anim-at="0.3"
data-anim-duration="0.35"
>
<span>V—TAKE / TAKEAWAY</span>
<span class="num">№ 09</span>
</div>
</div>
<div class="body">
<h2 class="title" data-anim="fade-in" data-anim-at="0.45" data-anim-duration="0.55">
<span class="red">设计</span>不是装饰,<br />而是结构。
</h2>
<div
class="slab"
data-anim="slide-in"
data-anim-at="0.55"
data-anim-duration="0.45"
data-anim-from="right"
data-anim-distance="120"
>
92<small>STRUCTURE INDEX</small>
</div>
</div>
<div>
<div class="bottom-rule"></div>
<div class="bottom-meta">
<span>RATIO 1 : 1.618</span>
<span>00:42 → 01:14</span>
</div>
</div>
</div>
</div>
</div>
</div>
</body>
</html>
@@ -0,0 +1,196 @@
<!--
Style: terminal — dark · JetBrains Mono · ASCII border · prompt · multi-color highlight
─────────────────────────────────────────────────────────────────────
Tokens
bg #0d1117 (deep terminal)
ink #e6edf3
muted #7d8590
accent #4ade80 (green — primary output)
accent2#fbbf24 (amber — string/warn)
accent3#f472b6 (magenta — variable)
accent4#60a5fa (blue — function/path)
Fonts
mono (everything) — ui-monospace, "SF Mono", Menlo, monospace
(Real JetBrains Mono would need a woff2 ship; mono fallback fine.)
Best with
layouts: split, pip
frames: hairline, clean
content: 技术分析 / 代码片段 / 性能数据 / 工程思考
Notes
- "Blinking cursor" must be a CSS animation, NOT a data-anim. Allowed
because pure CSS @keyframes on a single visual indicator is harmless.
- For animated reveal of lines, use data-anim="fade-in" per line.
-->
<!doctype html>
<html lang="zh-CN">
<head>
<meta charset="utf-8" />
<title>style · terminal</title>
<style>
html,
body {
margin: 0;
padding: 0;
background: #0a0c12;
font-family: ui-sans-serif, system-ui, sans-serif;
}
.stage {
position: relative;
width: 1920px;
height: 1080px;
transform-origin: top left;
transform: scale(0.5);
overflow: hidden;
}
.card-host {
position: absolute;
left: 0;
top: 0;
width: 1920px;
height: 1080px;
}
</style>
</head>
<body>
<div class="stage">
<div class="card-host">
<div class="card" data-card-id="ref-terminal">
<style>
.card[data-card-id="ref-terminal"] .root {
--bg: #0d1117;
--ink: #e6edf3;
--muted: #7d8590;
--green: #4ade80;
--amber: #fbbf24;
--magenta: #f472b6;
--blue: #60a5fa;
--font-mono: ui-monospace, "SF Mono", Menlo, "Courier New", monospace;
width: 100%;
height: 100%;
position: relative;
overflow: hidden;
background: var(--bg);
color: var(--ink);
padding: 36px 48px;
box-sizing: border-box;
font: 28px/1.55 var(--font-mono);
}
.card[data-card-id="ref-terminal"] .ascii-frame {
position: absolute;
inset: 16px;
border: 2px solid #2c333e;
border-radius: 6px;
box-shadow:
inset 0 0 0 1px #1a1f27,
0 0 0 1px #06080c;
}
.card[data-card-id="ref-terminal"] .titlebar {
position: absolute;
left: 36px;
top: 12px;
padding: 0 8px;
background: var(--bg);
font: 600 14px/1 var(--font-mono);
color: var(--muted);
letter-spacing: 0.12em;
}
.card[data-card-id="ref-terminal"] .content {
position: relative;
padding: 18px 12px;
display: flex;
flex-direction: column;
gap: 14px;
}
.card[data-card-id="ref-terminal"] .prompt {
color: var(--green);
}
.card[data-card-id="ref-terminal"] .line .blue {
color: var(--blue);
}
.card[data-card-id="ref-terminal"] .line .amber {
color: var(--amber);
}
.card[data-card-id="ref-terminal"] .line .pink {
color: var(--magenta);
}
.card[data-card-id="ref-terminal"] .line .green {
color: var(--green);
}
.card[data-card-id="ref-terminal"] .line .muted {
color: var(--muted);
}
.card[data-card-id="ref-terminal"] .kicker {
color: var(--muted);
font: 600 16px/1 var(--font-mono);
letter-spacing: 0.22em;
margin-bottom: 4px;
}
.card[data-card-id="ref-terminal"] .headline {
font: 700 56px/1.15 var(--font-mono);
color: var(--ink);
margin: 4px 0 14px;
}
.card[data-card-id="ref-terminal"] .headline .hl {
background: rgba(74, 222, 128, 0.18);
color: var(--green);
padding: 0 6px;
}
.card[data-card-id="ref-terminal"] .cursor {
display: inline-block;
width: 14px;
height: 28px;
background: var(--green);
margin-left: 4px;
vertical-align: -4px;
animation: ref-term-blink 1s steps(1) infinite;
}
@keyframes ref-term-blink {
50% {
opacity: 0;
}
}
</style>
<div class="root">
<div class="ascii-frame"></div>
<span class="titlebar">~/notes/takeaway-007.md</span>
<div class="content">
<div class="kicker" data-anim="fade-in" data-anim-at="0.05" data-anim-duration="0.3">
$ cat takeaway
</div>
<h2
class="headline"
data-anim="fade-in"
data-anim-at="0.25"
data-anim-duration="0.45"
>
缓存命中率提升到 <span class="hl">92%</span>
</h2>
<div class="line" data-anim="fade-in" data-anim-at="0.55" data-anim-duration="0.35">
<span class="prompt">$</span> bench --tier <span class="amber">"hot"</span>
<span class="muted">--n 10k</span>
</div>
<div class="line" data-anim="fade-in" data-anim-at="0.8" data-anim-duration="0.35">
<span class="muted"></span> <span class="blue">p50</span>=<span class="green"
>12ms</span
>
<span class="blue">p99</span>=<span class="green">38ms</span>
<span class="pink">hit</span>=<span class="green">92.4%</span>
</div>
<div class="line" data-anim="fade-in" data-anim-at="1.05" data-anim-duration="0.35">
<span class="muted">// before this change: hit=63%, p99=210ms</span>
</div>
<div class="line" data-anim="fade-in" data-anim-at="1.35" data-anim-duration="0.3">
<span class="prompt">$</span><span class="cursor"></span>
</div>
</div>
</div>
</div>
</div>
</div>
</body>
</html>
@@ -0,0 +1,170 @@
<!--
Style: whiteboard — paper · Caveat handwriting · sketched borders · marker highlight
─────────────────────────────────────────────────────────────────────
Tokens
bg #fdf6e3 (warm paper)
ink #1a1a1a
muted #6e6a5b
accent #ff6b35 (orange marker)
accent2#2557a7 (blue pen — annotations)
accent3#ffe066 (yellow highlighter)
Fonts
headline & body — Caveat (handwriting); falls back to "ui-serif, cursive"
annotations — Caveat
Best with
layouts: pip, overlay, split
frames: polaroid, clean
content: 教程 / 解构 / 草图思考 / 灵感整理
Notes
- SVG strokes have subtle path jitter to look hand-drawn.
- data-anim "draw-path" is ideal for the sketched border + highlights.
-->
<!doctype html>
<html lang="zh-CN">
<head>
<meta charset="utf-8" />
<title>style · whiteboard</title>
<style>
html,
body {
margin: 0;
padding: 0;
background: #0a0c12;
font-family: ui-sans-serif, system-ui, sans-serif;
}
.stage {
position: relative;
width: 1920px;
height: 1080px;
transform-origin: top left;
transform: scale(0.5);
overflow: hidden;
}
.card-host {
position: absolute;
left: 0;
top: 0;
width: 1920px;
height: 1080px;
}
</style>
</head>
<body>
<div class="stage">
<div class="card-host">
<div class="card" data-card-id="ref-whiteboard">
<style>
.card[data-card-id="ref-whiteboard"] .root {
--bg: #fdf6e3;
--ink: #1a1a1a;
--muted: #6e6a5b;
--accent: #ff6b35;
--accent2: #2557a7;
--accent3: #ffe066;
--font-hand: "Caveat", "LXGW WenKai TC", ui-serif, cursive;
width: 100%;
height: 100%;
position: relative;
overflow: hidden;
background-color: var(--bg);
background-image:
radial-gradient(circle at 30% 20%, rgba(0, 0, 0, 0.025) 0%, transparent 50%),
radial-gradient(circle at 80% 70%, rgba(0, 0, 0, 0.02) 0%, transparent 50%);
padding: 48px 56px;
box-sizing: border-box;
display: flex;
flex-direction: column;
justify-content: center;
gap: 26px;
color: var(--ink);
font-family: var(--font-hand);
}
.card[data-card-id="ref-whiteboard"] .sketch-border {
position: absolute;
inset: 16px;
pointer-events: none;
}
.card[data-card-id="ref-whiteboard"] .sketch-border path {
stroke: var(--ink);
stroke-width: 3;
fill: none;
stroke-linecap: round;
stroke-linejoin: round;
}
.card[data-card-id="ref-whiteboard"] .kicker {
align-self: flex-start;
font: 700 32px/1 var(--font-hand);
color: var(--accent);
transform: rotate(-2deg);
padding-left: 8px;
}
.card[data-card-id="ref-whiteboard"] .title {
margin: 0;
font: 700 120px/1 var(--font-hand);
color: var(--ink);
}
.card[data-card-id="ref-whiteboard"] .marker {
position: relative;
display: inline-block;
padding: 0 8px;
color: var(--ink);
}
.card[data-card-id="ref-whiteboard"] .marker::before {
content: "";
position: absolute;
left: 0;
right: 0;
top: 30%;
bottom: 18%;
background: var(--accent3);
z-index: -1;
transform: skewX(-4deg);
}
.card[data-card-id="ref-whiteboard"] .detail {
margin: 0;
font: 400 40px/1.4 var(--font-hand);
color: var(--muted);
max-width: 92%;
}
.card[data-card-id="ref-whiteboard"] .note {
align-self: flex-start;
padding: 6px 12px;
font: 600 28px/1 var(--font-hand);
color: var(--accent2);
border-bottom: 3px wavy var(--accent2);
transform: rotate(-1deg);
}
</style>
<div class="root">
<svg class="sketch-border" viewBox="0 0 1888 1048" preserveAspectRatio="none">
<path
d="M 12 12 L 1876 16 L 1872 1036 L 16 1032 Z"
data-anim="draw-path"
data-anim-at="0.05"
data-anim-duration="0.8"
/>
</svg>
<span class="kicker" data-anim="fade-in" data-anim-at="0.1" data-anim-duration="0.4">
✎ TAKEAWAY
</span>
<h2 class="title" data-anim="fade-in" data-anim-at="0.4" data-anim-duration="0.5">
把复杂问题<span class="marker">画出来</span>
</h2>
<p class="detail" data-anim="fade-in" data-anim-at="0.85" data-anim-duration="0.45">
文字让人争辩,图让人对齐。当所有人都在白板前看同一张图,分歧自然消失。
</p>
<span class="note" data-anim="fade-in" data-anim-at="1.2" data-anim-duration="0.4">
← 试试每次会议都画
</span>
</div>
</div>
</div>
</div>
</body>
</html>
@@ -0,0 +1,206 @@
<!--
Style: xhs (小红书) — cream + hot pink · chips · #hashtags · ❤️💬 row
─────────────────────────────────────────────────────────────────────
Tokens
bg #fff5e9 (warm cream)
ink #1d1418
muted #8a7a78
accent #ff2e63 (hot pink — chip + interaction icon)
accent2#ff8a4c (orange — tag)
accent3#f0c419 (yellow — pin)
Fonts
headline & body — Noto Sans SC fallback: ui-sans-serif, system-ui, "PingFang SC", sans-serif
Best with
layouts: overlay, stack (especially in portrait/9:16)
frames: clean, polaroid
content: 社交剪辑 / 生活方式 / 种草 / 短视频高光
-->
<!doctype html>
<html lang="zh-CN">
<head>
<meta charset="utf-8" />
<title>style · xhs (小红书)</title>
<style>
html,
body {
margin: 0;
padding: 0;
background: #0a0c12;
font-family: ui-sans-serif, system-ui, sans-serif;
}
.stage {
position: relative;
width: 1920px;
height: 1080px;
transform-origin: top left;
transform: scale(0.5);
overflow: hidden;
}
.card-host {
position: absolute;
left: 0;
top: 0;
width: 1920px;
height: 1080px;
}
</style>
</head>
<body>
<div class="stage">
<div class="card-host">
<div class="card" data-card-id="ref-xhs">
<style>
.card[data-card-id="ref-xhs"] .root {
--bg: #fff5e9;
--ink: #1d1418;
--muted: #8a7a78;
--accent: #ff2e63;
--accent2: #ff8a4c;
--accent3: #f0c419;
--font-sans: ui-sans-serif, system-ui, "PingFang SC", "Hiragino Sans GB", sans-serif;
width: 100%;
height: 100%;
position: relative;
overflow: hidden;
background: var(--bg);
color: var(--ink);
font-family: var(--font-sans);
padding: 36px 44px;
box-sizing: border-box;
display: flex;
flex-direction: column;
gap: 22px;
}
.card[data-card-id="ref-xhs"] .user-row {
display: flex;
align-items: center;
gap: 14px;
}
.card[data-card-id="ref-xhs"] .avatar {
width: 56px;
height: 56px;
border-radius: 50%;
background: linear-gradient(135deg, #ff2e63, #ff8a4c);
box-shadow:
0 0 0 3px #fff,
0 0 0 4px rgba(255, 46, 99, 0.3);
}
.card[data-card-id="ref-xhs"] .user-info {
flex: 1;
}
.card[data-card-id="ref-xhs"] .user-name {
font: 700 22px/1.1 var(--font-sans);
color: var(--ink);
}
.card[data-card-id="ref-xhs"] .user-sub {
font: 400 16px/1.3 var(--font-sans);
color: var(--muted);
}
.card[data-card-id="ref-xhs"] .follow {
padding: 8px 20px;
border-radius: 999px;
background: var(--accent);
color: #fff;
font: 700 16px/1 var(--font-sans);
}
.card[data-card-id="ref-xhs"] .title {
margin: 0;
font: 800 84px/1.1 var(--font-sans);
color: var(--ink);
letter-spacing: -0.01em;
}
.card[data-card-id="ref-xhs"] .title .heart {
color: var(--accent);
}
.card[data-card-id="ref-xhs"] .detail {
margin: 0;
font: 500 28px/1.5 var(--font-sans);
color: var(--ink);
max-width: 94%;
}
.card[data-card-id="ref-xhs"] .tags {
display: flex;
flex-wrap: wrap;
gap: 10px;
}
.card[data-card-id="ref-xhs"] .tag {
padding: 8px 18px;
border-radius: 999px;
background: rgba(255, 46, 99, 0.12);
color: var(--accent);
font: 600 18px/1 var(--font-sans);
}
.card[data-card-id="ref-xhs"] .tag.orange {
background: rgba(255, 138, 76, 0.16);
color: var(--accent2);
}
.card[data-card-id="ref-xhs"] .tag.yellow {
background: rgba(240, 196, 25, 0.18);
color: #a98209;
}
.card[data-card-id="ref-xhs"] .interactions {
display: flex;
gap: 28px;
margin-top: auto;
padding-top: 14px;
border-top: 1px solid rgba(0, 0, 0, 0.06);
font: 700 22px/1 var(--font-sans);
color: var(--ink);
}
.card[data-card-id="ref-xhs"] .interactions span {
display: inline-flex;
align-items: center;
gap: 8px;
}
.card[data-card-id="ref-xhs"] .interactions .heart-ic {
color: var(--accent);
font-size: 26px;
}
</style>
<div class="root">
<div class="user-row" data-anim="fade-in" data-anim-at="0.05" data-anim-duration="0.4">
<div class="avatar"></div>
<div class="user-info">
<div class="user-name">@小研究员</div>
<div class="user-sub">关注我,看我每天拆一段视频 · 18分钟前</div>
</div>
<div class="follow">+ 关注</div>
</div>
<h2 class="title" data-anim="fade-in" data-anim-at="0.3" data-anim-duration="0.5">
亲测有效!<span class="heart"></span> 30 秒抓住注意力的小技巧
</h2>
<p class="detail" data-anim="fade-in" data-anim-at="0.7" data-anim-duration="0.45">
开头别废话——直接抛结论。听众的大脑在前 3 秒就决定要不要继续,
这是平台算法之外,最朴素也最重要的事实。
</p>
<div class="tags" data-anim="fade-in" data-anim-at="1.0" data-anim-duration="0.4">
<span class="tag">#内容创作</span>
<span class="tag orange">#播客剪辑</span>
<span class="tag yellow">#开头技巧</span>
</div>
<div
class="interactions"
data-anim="fade-in"
data-anim-at="1.25"
data-anim-duration="0.4"
>
<span><span class="heart-ic"></span> 12.4k</span>
<span>💬 386</span>
<span>⭐ 891</span>
<span
style="margin-left: auto; color: var(--muted); font-weight: 400; font-size: 18px"
>📤 分享</span
>
</div>
</div>
</div>
</div>
</div>
</body>
</html>