Communitygithub.com

d0-hyperframe

HyperFrames を使って D0 ブランドの動画を作成します。素材の抽出、プロジェクトのセットアップ、シーンレイアウト、GSAP アニメーション、TG コンポーネント仕様、トランジションルールをカバーします。

d0-hyperframe とは?

このスキルは、HyperFrames HTML と GSAP アニメーションを組み合わせて、D0 ブランドのハイクオリティな動画を制作するための完全なワークフローを提供します。フォント、カラー、レイアウト、アニメーション、トランジションのすべてのルールが詳細に定義されており、一貫性のあるブランド表現を実現します。特に、従来の「PPT 感」を排除するために、背景を固定したままコンポーネント単位で要素をクロスステガーさせる新しいトランジションモデルを採用しています。これにより、スムーズでプロフェッショナルな動画体験を提供します。このスキルは Claude Code、Cursor、Codex などの AI エージェントで動作するように設計されており、`npx hyperframes@latest` コマンドで利用可能な HyperFrames CLI と連携します。ユーザーは「D0 の動画を作って」といった自然言語のトリガーから、ブランド資産の自動抽出、プロジェクトの初期化、アニメーション実装、最終的な lint チェックまでを一貫して実行できます。

対応~Claude Code✓Codex CLI~Cursor✓Antigravity
npx skills add https://github.com/scof-real/d0-hyperframe-skill/tree/main/skills/d0-hyperframe

お気に入りのAIに質問する

このエージェントスキルを事前に読み込んだ状態で新しいチャットを開きます。

ドキュメント

D0 HyperFrame 動画制作

HyperFrames HTML + GSAP を使って D0 ブランド動画を制作するための完全なワークフロー。 本ファイルを唯一の権威とします——フォント、カラー、レイアウト、アニメーション、トランジションルールはすべてここで定義します。

フォント仕様は d0-brand スキルを最終的な権威とし、本スキルは動画制作に関連する追加規定のみを上書きします。


トリガーワード

  • "D0 動画を作って" / "d0 hyperframe"
  • "hyperframes で動画を作って" / "/d0-hyperframe"

Step 0 — プロジェクトと素材の初期化

推奨:スキル付属の初期化スクリプトを使用する

リポジトリをインストールしたら、本スキル内のスクリプトを実行します。HyperFrames プロジェクトを初期化し、D0 ロゴ、D0 アバター、必要なすべてのフォントをコピーします。

bash "${CODEX_HOME:-$HOME/.codex}/skills/d0-hyperframe/scripts/bootstrap_project.sh" .

プロジェクトがすでに初期化されている場合は、ブランド素材のみを同期します。

bash "${CODEX_HOME:-$HOME/.codex}/skills/d0-hyperframe/scripts/bootstrap_project.sh" . --assets-only

このスクリプトは Node.js 18+ と npx に依存します。HyperFrames CLI は npx hyperframes@latest で必要に応じて実行され、サードパーティのパッケージはスキルリポジトリにコピーされません。

オプション:ソース HTML から D0_AVATAR とロゴを上書きする

ソースとなるポスター HTML には通常、2 種類の base64 画像がインラインで埋め込まれています。

アセット種類特徴用途
D0 ロゴPNG、約 12–16 KB.brand img または最短の PNGすべてのシーンの左上
D0_AVATARJPEG、約 100 KB.av または最長の JPEGTG コンポーネントのアバター
python3 - << 'EOF'
import re, base64, os

with open('SOURCE.html', 'r') as f:
    src = f.read()

os.makedirs('assets', exist_ok=True)

# ロゴ (最短の PNG)
pngs = re.findall(r'(data:image/png;base64,[A-Za-z0-9+/=]+)', src)
logo_b64 = min(pngs, key=len)
with open('assets/d0-logo.png', 'wb') as f:
    f.write(base64.b64decode(logo_b64.split(',')[1]))

# D0_AVATAR (最長の JPEG)
jpegs = re.findall(r'data:image/jpeg;base64,([A-Za-z0-9+/=]+)', src)
avatar = max(jpegs, key=len)
with open('assets/d0-avatar.jpg', 'wb') as f:
    f.write(base64.b64decode(avatar))

print("assets/ ready:", os.listdir('assets'))
EOF

フォント(手動の場合)

mkdir -p fonts
cp /path/to/d0-hyperframe/assets/fonts/*.woff2 fonts/
# 必要:InstrumentSerif-Regular.woff2, InstrumentSerif-Italic.woff2
#       OpenSans-400/600/700/800-normal.woff2

プロジェクトの初期化(手動の場合)

npx hyperframes@latest init . --non-interactive --example blank --skill=d0-hyperframe

Step 1 — ブランドトークン(CSS)

:root {
  --bg:    #06060d;
  --pu2:   #b3a8f7;
  --white: #f2f2f5;
  --t2:    #8d8d98;
  --t3:    #5a5a66;
  --green: #3ddc84;
  --red:   #f87171;
  --gold:  #f7a93a;
  --bdr:   #23232c;
  --bdr2:  #2e2e39;
  --grad:  linear-gradient(120deg, #5468F5 0%, #9B4FD6 34%, #C25C9A 62%, #DD8B57 100%);
}

@font-face { font-family:'Instrument Serif'; src:url('fonts/InstrumentSerif-Regular.woff2') format('woff2'); font-weight:400; font-style:normal; }
@font-face { font-family:'Instrument Serif'; src:url('fonts/InstrumentSerif-Italic.woff2')  format('woff2'); font-weight:400; font-style:italic; }
@font-face { font-family:'Open Sans'; src:url('fonts/OpenSans-400-normal.woff2') format('woff2'); font-weight:400; }
@font-face { font-family:'Open Sans'; src:url('fonts/OpenSans-600-normal.woff2') format('woff2'); font-weight:600; }
@font-face { font-family:'Open Sans'; src:url('fonts/OpenSans-700-normal.woff2') format('woff2'); font-weight:700; }
@font-face { font-family:'Open Sans'; src:url('fonts/OpenSans-800-normal.woff2') format('woff2'); font-weight:800; }

Step 2 — ステージ構造(永続ステージ + コンポーネントレイヤー)

コアモデル: 1 層の固定背景、コンテンツはコンポーネントに分解。 背景 + 固定要素 (ロゴ/フッター/上部レール) は永続レイヤーに属し、全体を通して動きません。タイトル、データ、TG パネル、チャートなどはそれぞれ独立した .blk コンポーネントであり、各々が個別に入場・退場します。トランジションはコンポーネントレベルで行われ、画面全体ではなくなります——これが「PPT のカチッという切り替え」から脱却するための基本です。

HTML スケルトン

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>D0 · [動画タイトル]</title>
<style>/* トークン + シーン CSS */</style>
</head>
<body>
<div id="main"
  data-composition-id="main"
  data-start="0"
  data-duration="[総秒数]"
  data-width="1920"
  data-height="1080">

  <!-- ── 永続レイヤー:全体を通して動かない、tl アニメーションは記述しない(Step 3 参照) ── -->
  <div class="bg"></div>
  <div class="rail"></div>
  <div class="logo"></div>
  <div class="foot-tag">Agentic Trading for Every Market.</div>
  <div class="foot-url">getdonut.ai</div>

  <!-- ── コンテンツレイヤー:ビートごとにグループ化、コンポーネントはそれぞれ異なるタイミングで出入り(Step 6 参照) ── -->
  <!-- beat 1 -->
  <div class="blk" id="b1-title">...</div>
  <div class="blk" id="b1-sub">...</div>
  <!-- beat 2 -->
  <div class="blk" id="b2-stat">...</div>
  <div class="blk" id="b2-tg">...</div>

</div>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/gsap.min.js"></script>
<script>/* GSAP タイムライン */</script>
</body>
</html>

ステージ CSS(永続レイヤー + コンテンツレイヤー)

/* ステージコンテナ */
#main {
  position: absolute; inset: 0; overflow: hidden;
  font-family: 'Open Sans', sans-serif; color: var(--white);
}

/* 永続背景 — 全体を通して固定、tl アニメーションには決して入れない */
.bg {
  position: absolute; inset: 0; width: 1920px; height: 1080px; z-index: 0;
  background: var(--bg);
  background-image:
    radial-gradient(ellipse 46% 58% at 76% 50%, rgba(150,128,255,.16) 0%, transparent 60%),
    radial-gradient(ellipse 62% 50% at 8%   4%, rgba(110,100,255,.10) 0%, transparent 56%);
}

/* 上部グラデーションレール — 固定、動画全体で 1 本 */
.rail {
  position: absolute; top: 0; left: 0; right: 0; height: 5px; z-index: 10;
  background: var(--grad);
}

/* コンテンツコンポーネント — アニメーションの最小単位、デフォルトで非表示、それぞれ出入り */
.blk { position: absolute; opacity: 0; z-index: 2; }

従来モデルでは、各画面全体 .scene が独自の背景とブロック全体のスライドを持っていました → PPT 感 + カクツキの原因。 新しいモデルは1 層の固定背景のみを持ち、コンテンツを .blk コンポーネントに分解し、トランジションはコンポーネントレベルで発生します(Step 6 参照)。


Step 3 — 固定要素仕様(非交渉)

以下の 3 つの要素はすべてのシーンで一貫しており、入場または退場アニメーションを記述しません。

要素位置フォントサイズ説明
Donut ロゴ左上 top:40px left:72px200×76pxCSS background、<img> は使用しない
Agentic Trading for Every Market.左下 bottom:48px left:72px27pxInstrument Serif italic、--pu2
getdonut.ai右下 bottom:50px right:72px14pxOpen Sans、--t3
/* ロゴ — CSS background、opacity:0 は記述しない */
.logo {
  position: absolute; top: 40px; left: 72px; z-index: 10;
  width: 200px; height: 76px;
  background: url('assets/d0-logo.png') left center / contain no-repeat;
}

/* フッター — 直接表示、アニメーションなし */
.foot-tag {
  position: absolute; bottom: 48px; left: 72px; z-index: 10;
  font-family: 'Instrument Serif', serif; font-style: italic;
  font-size: 27px; color: var(--pu2);
}

.foot-url {
  position: absolute; bottom: 50px; right: 72px; z-index: 10;
  font-size: 14px; font-weight: 700; letter-spacing: .06em; color: var(--t3); opacity: 0;
}

固定要素は永続レイヤーに属し、0 フレーム目から表示され、tl アニメーションは一切記述しません。 foot-tag は直接表示されます。foot-url は一度だけ軽いフェードインを残してもかまいませんが、必須ではありません。


Step 4 — レイアウト原則

左右のバランス、中央の空白をなくす

  • 2 カラムレイアウトを優先:テキスト/データは左、TG コンポーネント/画像は右
  • 右側にキャラクター背景画像がある場合:絶対配置で右側全体に敷き詰め、左から右へのグラデーションマスクを重ねる
.scene-char {
  position: absolute; top:0; right:0; bottom:0; width:62%;
  background: url('assets/bg-char.png') right center / cover no-repeat;
  z-index: 0;
}
.scene-char::after {
  content:''; position:absolute; inset:0;
  background: linear-gradient(to right,
    var(--bg) 0%, rgba(6,6,13,.82) 18%, rgba(6,6,13,.45) 45%, transparent 100%);
}
  • 左側のテキストエリアには position: relative; z-index: 2 を設定し、背景画像の上に重なるようにする

最小フォントサイズ基準

D0 Thorp Engine 動画を基準として、以下を下回ってはいけません。

階層最小フォントサイズフォント
メインタイトル80pxInstrument Serif
シーンサブタイトル56pxInstrument Serif
Kick label / eyebrow18pxOpen Sans 700 uppercase
本文 / feature bullet22pxOpen Sans
データアンカー (stat-val)48pxInstrument Serif
フッタータグ27pxInstrument Serif italic
TG コンポーネント内部テキスト13px(許容される最小値)Open Sans

Step 5 — TG コンポーネント仕様

アバター:必ず D0_AVATAR を使用すること

/* 大きいアバター(ヘッダー、40px) */
.av  { width:40px; height:40px; border-radius:50%; flex:none;
       background: url('assets/d0-avatar.jpg') center/cover no-repeat; }

/* 小さいアバター(メッセージ行、28px) */
.mav { width:28px; height:28px; border-radius:50%; flex:none; margin-top:2px;
       background: url('assets/d0-avatar.jpg') center/cover no-repeat; }

<img> タグは使用しないでください。HyperFrames が重複したメディアノードを検出するのを防ぐためです(lint warning)。 グラデーションによるフォールバックは使用しないでください。実際の D0_AVATAR ファイルでなければなりません。

TG パネル構造

<div id="tg-panel">
  <div class="tg-chrome">
    <div class="dot r"></div><div class="dot y"></div><div class="dot g"></div>
    <div class="tg-url">t.me / D0_Bot</div>
  </div>
  <div class="tg-hdr">
    <div class="av"></div>
    <div>
      <div class="tg-nm">D0</div>
      <div class="tg-st">bot · online</div>
    </div>
  </div>
  <div class="tg-body">
    <div class="msg-user">ユーザープロンプト</div>
    <div class="msg-bot">
      <div class="mav"></div>
      <div class="bbubble">D0 の返信内容</div>
    </div>
  </div>
</div>

Step 6 — トランジションルール(非交渉)

コア原則: 背景は動かさず、コンポーネントを動かす。 「PPT 感」は、背景を含む scene 全体が一緒にスライドアウトすることから生まれます——視聴者は安定したアンカーを失います。 「カクツキ」は、out アニメーションと in アニメーションが首尾相接して発生します——その中間に一瞬の完全な静止が生まれます。 両方の解決策は同じです:固定背景 + コンポーネントのクロスステガー(入退場のオーバーラップ)。

デフォルトトランジション: コンポーネントレベルのクロスステガー(element cross-stagger)

背景 + 固定要素(ロゴ/フッター/レール)は全体を通して動きません。ビートが切り替わるたびに、コンテンツコンポーネントだけを動かします。

  • 古いビートのコンポーネントが順次退場(stagger、.in ease、微妙な移動 + フェードアウト)
  • 新しいビートのコンポーネントが順次入場(stagger、.out ease)
  • 両者の時間は約 0.2–0.3 秒オーバーラップします——古いものがまだ退場し終わらないうちに、新しいものが入場を開始します。これがカクツキをなくすための鍵です。
// ビート切り替え: 古いグループがクロスフェードアウト、新しいグループがクロスフェードイン、時間はオーバーラップ(首尾相接ではない)
function beat(outEls, inEls, t) {
  outEls.forEach((el, i) =>
    tl.to(el, { opacity:0, y:-30, duration:0.45, ease:'power2.in' }, t + i*0.06));
  inEls.forEach((el, i) =>
    tl.fromTo(el, { opacity:0, y:40 },
      { opacity:1, y:0, duration:0.6, ease:'expo.out' }, t + 0.2 + i*0.08));  // +0.2 = オーバーラップ
}
// 使用法:beat(['#b1-title','#b1-sub'], ['#b2-stat','#b2-tg'], 4.0);
  • 移動量は小さい(20–40px)。方向は統一してもよい(例:すべて上方向に移動して「ページをめくるような空気感」を演出)が、背景は決して参加しない。
  • コンポーネントが多い場合は、stagger によって画面に常に動きがあるようにし、「同時入場 → 一緒に静止」を避ける。

いつ画面全体のトランジションを使うか

大きなセクション区切り(例:ブランドタイトルカード → データセクション)でのみ例外的に使用し、その場合もコンテンツレイヤーのみを動かし、背景は動かさない——該当セクションのコンポーネントを #grp コンテナでラップしてから動かします。

// Push-slide(コンテンツコンテナのみを動かし、背景 .bg は動かさない)
tl.to('#grpA',     { x:-1920, duration:0.55, ease:'power3.inOut' }, t);
tl.fromTo('#grpB', { x:1920, opacity:1 }, { x:0, duration:0.55, ease:'power3.inOut' }, t);

// Blur crossfade(感情的なトランジション、通常は最後の遷移に使用)
tl.to('#grpC', { filter:'blur(20px)', opacity:0, duration:0.65, ease:'power2.in' }, t);
tl.fromTo('#grpD', { filter:'blur(20px)', opacity:0 },
  { filter:'blur(0px)', opacity:1, duration:0.65, ease:'power2.out' }, t);

❌ 禁止: 背景を含む scene 全体のスライドアウト、コーナーへのズーム、画面全体のズーム、out/in の首尾相接によるオーバーラップなし。


Step 7 — GSAP アニメーションルール

必ず遵守すること

const tl = gsap.timeline({ paused: true });
// ...tweens...
window.__timelines['main'] = tl;
  • tl.from() ではなく tl.fromTo() を使用する(HyperFrames の seek 決定性を確保するため)
  • 繰り返しアニメーションには Math.floor(duration / cycle) - 1 を使用し、repeat: -1 は禁止
  • 同じ要素に複数のアニメーショングループがある場合は overwrite: 'auto' を追加する
  • 入場には .out easing、退場には .in easing を使用する

レイアウト優先、アニメーションはその後

まず要素の最終状態(CSS による配置)を記述し、その後で fromTo を使って入場パスを記述します。

// ✅ 正しい
 tl.fromTo('#title', { opacity:0, y:40 }, { opacity:1, y:0, duration:0.8, ease:'expo.out' }, 0.3);

永続レイヤーにはアニメーションを追加しない

.bg、.rail、.logo、.foot-tag、.foot-url は全体を通して固定され、アニメーションは .blk コンポーネント上でのみ発生します。背景が一度動き出すと、即座に PPT 感に戻ります——トランジションはコンテンツレイヤーのみを動かします(Step 6 の beat() 参照)。


Step 8 — Lint & プレビュー

npx hyperframes lint     # エラーを 0 にする必要があります
npx hyperframes preview  # http://localhost:300x、ホットリロード
一般的な warning対処法
overlapping_gsap_tweensoverwrite:'auto' を追加
duplicate_media_discovery_risk<img> の代わりに CSS background:url() を使用
composition_file_too_large単一ファイルが 500 行未満の場合は無視可能

依存関係とアセットの出典

  • d0-brand スキル: フォント、フォントサイズ、ブランド原則の最終的な権威であり、本スキルと一緒にインストールする必要があります。
  • HyperFrames CLI: npx hyperframes@latest で必要に応じて取得します。
  • GSAP: 例では 3.14.2 CDN バージョンを固定して使用しています。バージョンをアップグレードする場合は、最初に lint と seek 検証を再実行してください。
  • assets/fonts/: Instrument Serif と Open Sans。ライセンスファイルは対応するフォントディレクトリにあります。
  • assets/brand/: D0 ロゴと D0 アバター。許可を得た Donut チームメンバーのみが D0 ブランドコンテンツに使用できます。

Individual skills in this repo

This repo contains 1 individual skill — each has its own dedicated page.

関連スキル