Files
AshuaiXsinfo/src/components/textblock/textblock.html
T
xiaoshuai 9b63424740 chore: 初始化仓库,提交 vibevideo 源码
- src/: HyperFrames 封装 CLI(hv)、组件、品牌样式、音频(TTS/混音)工具
- projects/: 各项目 project.yaml 与文案
- interactive/: 井字棋演示页
- .gitignore: 忽略 node_modules、构建产物与 HyperFrames 运行期缓存
2026-10-12 18:06:20 +08:00

110 lines
3.6 KiB
HTML

<!doctype html>
<html lang="zh-CN"
data-composition-variables='[{"id": "heading", "type": "string", "label": "标题", "default": "用 **加粗** 和 [[高亮]]"},{"id": "body", "type": "string", "label": "正文(可空)", "default": "支持 **加粗** 与 [[强调色]]"}]'>
<head>
<meta charset="UTF-8" />
<title>文字块</title>
<link rel="stylesheet" href="assets/brand/tokens.css" />
<link rel="stylesheet" href="assets/brand/base.css" />
<style>
.stage {
display: flex;
flex-direction: column;
justify-content: center;
}
.heading {
font-size: calc(60 * var(--u));
font-weight: 700;
line-height: 1.15;
letter-spacing: -0.02em;
margin-bottom: calc(24 * var(--u));
}
.body {
font-size: calc(30 * var(--u));
font-weight: 500;
line-height: 1.55;
color: var(--text-dim);
max-width: 82%;
}
/* 逐行浮现:每行一个块 */
.line { overflow: hidden; }
.line > span { display: inline-block; }
.accent { color: var(--accent); }
.strong { color: var(--text); font-weight: 700; }
</style>
</head>
<body>
<div
class="stage"
data-composition-id="textblock"
data-width="1920"
data-height="1080"
data-duration="4"
>
<div id="heading" class="heading"></div>
<div id="body" class="body"></div>
<script>
const v = window.hv ? hv.readVars() : null;
const str = (k, d) => (v ? v.str(k, d) : d);
const HEAD = str("heading", "未命名标题");
const BODY = str("body", "");
const headingEl = document.getElementById("heading");
const bodyEl = document.getElementById("body");
/* 支持在文字里用 **强调** 和 [[高亮]] 标记 */
const rich = (text) => {
const frag = document.createDocumentFragment();
const re = /\*\*([^*]+)\*\*|\[\[([^\]]+)\]\]/g;
let last = 0;
let m;
while ((m = re.exec(text)) !== null) {
if (m.index > last) frag.appendChild(document.createTextNode(text.slice(last, m.index)));
const el = document.createElement("span");
if (m[1]) {
el.className = "strong";
el.textContent = m[1];
} else {
el.className = "accent";
el.textContent = m[2];
}
frag.appendChild(el);
last = m.index + m[0].length;
}
if (last < text.length) frag.appendChild(document.createTextNode(text.slice(last)));
return frag;
};
headingEl.textContent = "";
headingEl.appendChild(rich(HEAD));
bodyEl.textContent = "";
if (BODY) {
const span = document.createElement("span");
span.appendChild(rich(BODY));
bodyEl.appendChild(span);
} else {
bodyEl.style.display = "none";
}
// 时长跟随宿主(可能由配音决定),拿不到才用组件默认值
const DUR = (window.hv && hv.duration()) || 4;
const tl = gsap.timeline({ paused: true });
tl.fromTo(headingEl, { opacity: 0, y: 28 }, { opacity: 1, y: 0, duration: 0.5, ease: "power3.out" }, 0.1)
.fromTo(bodyEl, { opacity: 0, y: 24 }, { opacity: 1, y: 0, duration: 0.5, ease: "power3.out" }, 0.35)
.to(".stage", { opacity: 0, duration: 0.3, ease: "power1.in" }, DUR - 0.3);
window.__timelines = window.__timelines || {};
window.__timelines["textblock"] = tl;
tl.seek(0);
</script>
</div>
</body>
</html>