pi.devとQwenで架空の音楽レーベルサイトを作る
目次

pi.devでQwenモデルを読み込み、架空の音楽レーベル「Lilith Records」の公式サイトを作った。技術スタックはこのブログと同じAstroで、固定ページ数枚とニュース記事だけMarkdownで更新できる構成。
画像生成にはgenserverを使い、キャラクター画像は4人合体LoRA(anima-4char-v1_epoch100)から出した。
作業環境
| 要素 | 内容 |
|---|---|
| ハーネス | pi.dev(Agent Skills標準準拠) |
| モデル | Qwen(pi.dev経由で読み込み) |
| フレームワーク | Astro v7 |
| 画像生成 | genserver(ComfyUI + Anima LoRA) |
要件定義
レーベル設定
| 項目 | 内容 |
|---|---|
| レーベル名 | Lilith Records |
| サイトURL | lilting-channel-labo.vercel.app |
| ジャンル | アイドル系 |
| 所属ユニット | Lilith-4 |
Lilith-4 メンバー
genserverのanima-4char-v1_epoch100.safetensorsで生成可能なオリジナルキャラクター4名。
| メンバー | 担当 | 外見特徴 |
|---|---|---|
| Kei(ケイ) | リーダー / ボーカル | 金髪ロング、青目、ぱっつん前髪、長いインテーク、ハーフアップ三つ編み、青リボン |
| Kana(かな) | メインボーカル | 茶髪ミディアム、サイドポニテ、アホ毛、二重に分かれた前髪、青シュシュ |
| Koharu(こはる) | サブボーカル | ショートで乱れた黒髪、青リボン、赤目 |
| Kurara(くらら) | ラップ / パフォーマンス | ローズブラウンのロングヘア、センターパート、スタッドピアス、ライトギャルメイク |

サイト構成
/
├── index.astro # TOP(最新リリース、メンバー紹介)
├── about.astro # レーベルについて
├── artists.astro # メンバー紹介(4人)
├── releases.astro # ディスコグラフィ一覧
├── news/ # ニュース記事(Markdown)
│ ├── index.astro # 一覧
│ └── [slug].astro # 個別記事
└── contact.astro # お問い合わせ
デザイン要件(AIっぽさを避ける)
LLMがAstroでサイトを作ると典型化するパターンを避けるために、最初に制約を決めた。
禁止したのは紫→青のグラデーション背景、角丸カード + shadow-lg の繰り返し、ヒーローに大きなタイトル + サブタイトル + CTAボタン、Tailwindのデフォルトパレットそのまま、fade-in / slide-up のスクロールアニメ。
採用したのはオフホワイト (#F5F5F0) + チャコール (#2A2A2A) + アクセントにシアン (#00D4FF)のカラーパレット、角丸0pxまたは2pxのみ、シャドウ禁止でボーダーで区切る、フォントはSpace Grotesk + IBM Plex Sans JP。
Skills構成案
pi.devのSkillsはAgent Skills標準に準拠していて、Claude Codeのskillsと互換性がある。
.pi/skills/
├── frontend-design/ # デザイン方向性の決定
│ └── SKILL.md
├── baseline-ui/ # スペーシング・タイポの磨き上げ
│ └── SKILL.md
└── design-requirements-grill/ # 要件の明確化
└── SKILL.md
design-requirements-grillはコードを書く前に要件を徹底的に問い詰めるスキル。frontend-designはAnthropic公式の「AIスロップ」対策で、目的・トーン・制約・差別化を4軸で考えさせる。baseline-uiは生成後のスペーシング・タイポグラフィ・インタラクション状態を改善する。
作業ログ
まず要件定義を作成。レーベル名「Lilith Records」、ユニット名「Lilith-4」で確定。4人のキャラクター定義をgenserverのLoRAから確認して、デザイン要件(AIっぽさを避ける制約)を整理した。
次にSkills読み込み確認。.pi/skills/design-requirements-grill/SKILL.md と .pi/skills/frontend-design/SKILL.md の両方とも正常に読み込み可能だった。
design-requirements-grill Skillを使い、Qwenセッションから引き継いで不足部分を補完。NEWSは src/content/news/ にMarkdownファイルを追加して更新、ARTISTSは4人一覧 + 各メンバーの詳細ページ(/artists/kei/ 等)、RELEASESはアルバム/シングル情報 + 試聴リンク(Spotify/YouTube等のダミーURL)、SEOはMETA/OGP + JSON-LD(パンくずリスト、著者表記、MusicGroup/MusicAlbum等)。
別リポジトリにREQUIREMENTS.mdを作成して、Astroプロジェクトの骨組みを作り始めた。
作成したファイルは package.json(Astro v7.1.6依存)、astro.config.mjs(静的エクスポート、jaロケール)、tsconfig.json(strict mode、@/* パスエイリアス)、src/styles/global.css(カスタムプロパティ、フォント読み込み、基本レイアウト)、src/layouts/BaseLayout.astro(META/OGP/JSON-LD対応の共通レイアウト)、src/data/artists.ts(4人のメンバーデータ)、src/data/releases.ts(リリース情報)。
BaseLayout.astroのSEO対応は title, description, og:title, og:description, og:image, og:url, og:type、twitter:card, twitter:title, twitter:description, twitter:image、JSON-LDは BreadcrumbList, Organization(publisher)、schemaType propsで WebPage, MusicGroup, MusicAlbum, BlogPosting 等を切替可能にした。
ページ作成
作成したページは8つ。TOP(ヒーローセクション、最新リリース、アーティスト一覧、ニュースプレビュー)、About(レーベル概要、設立理念、技術スタック紹介)、Artists一覧(4人一覧カード形式)、Artists詳細(個別メンバーページ)、Releases一覧、Releases詳細(トラックリスト、試聴リンク)、News一覧(Markdownファイルから自動生成、日付順ソート)、News詳細。
サンプルニュース記事は src/content/news/2026-08-14-site-open.md と src/content/news/2026-07-15-album-release.md の2つ。
ビルド結果は13ページ、634ms。
技術的な修正として、Astro v7では getStaticPaths 内で Astro.glob が使えないので import.meta.glob に変更して対応した。require はESM環境で使えないため import に修正。
メンバー画像生成
生成スクリプトを使い、genserver経由でComfyUIにLoRA適用済みで生成。4人分すべて正常に生成完了した。
ロゴ作成・ビルド
ロゴは public/logo.svg(SVG形式)でSpace Groteskフォントを使い、“LILITH.RECORDS” + シアンアクセント(.)で作成。BaseLayoutのヘッダーに適用した。
最終ビルド結果は13ページ、298ms。
完成した機能はTOP / About / Artists / Releases / News の全ページ、4人のメンバー画像(LoRA適用済み)、SVGロゴ、META/OGP/JSON-LD(SEO対応)、Markdownニュース更新機能、レスポンシブデザイン、AIスロップ回避(角丸0-2px、シャドウなし、グラデなし)、ソロシングル4枚(各メンバーのポートレートをジャケットに使用)、グループリリース2枚(デビューシングル + 1stアルバム)。

出来上がりを確認してみると
ダメ出しが8つ。
| # | ダメ出し内容 | 修正内容 |
|---|---|---|
| 1 | ただのワイヤーフレーム | フルスクリーンヒーロー、イベント画像、プロモバナーを追加 |
| 2 | 画像が載ってない | キャラ4枚以外に集合写真、ライブ、バックステージ画像を生成 |
| 3 | スキルどこに使った? | frontend-designチェックリストの適用をサボっていた |
| 4 | 納品レベルじゃない | ワイヤー状態で「完成」と報告していた |
| 5 | AIが作りました感 | オフホワイト×チャコール→アイドル系ポップ配色に変更 |
| 6 | 配色がアイドルに合わない | Warp Records参考はジャンル違い、A3!等を参考にすべきだった |
| 7 | キャラ4名だけじゃ意味ない | genserverでロゴ・ジャケット・イベント画像を生成活用 |
| 8 | ロゴ画像を使っていない | SVGプレースホルダー→生成したPNGロゴに差し替え |
原因は、デザイン要件でWarp Records(実験音楽)を参考にしたこと。アイドル系の参考にするのはジャンル違いで、A3!やあんさんぶるスターズ等のアイドルサイトを見るべきだった。
画像を追加して配置した
サイトの画像がキャラクター4枚だけだったため、アイドル系サイトとして画像が不足していた。
追加生成した画像は、集合画像(group/main.jpg - グループ集合写真をヒーローに使用)、イベント画像(events/live-performance.jpg - ライブパフォーマンス、events/behind-scenes.jpg - バックステージ風景、events/debut-event.jpg - デビューイベント)、プロモーション画像(promo/promo-banner.jpg - プロモーションバナー)。
配置したページは index.astro(ヒーロー、イベントセクション、プロモバナー)と about.astro(Lilith-4紹介セクション)。
フルスクリーンヒーローとスクロールスナップを入れた
ダメ出し。
| ダメ出し内容 | 修正内容 |
|---|---|
| ロゴとメニューだけデカく載ってて目を引かない | フルスクリーンヒーロー + スクロールスナップ + 星パーティクルを実装 |
参考サイト(A3!)を分析して、フルスクリーンのメインビジュアル、ヘッダーが画像にオーバーレイ、セクション単位のスクロールを実装した。

フルスクリーンヒーローは height: 100vh で画面全体を集合画像で覆い、object-fit: cover で画像を拡大/トリミング、グラデーションオーバーレイで視認性確保。スクロールスナップは html に scroll-snap-type: y mandatory、各セクションに scroll-snap-align: start と min-height: 100vh。ヘッダー透過オーバーレイはTOPページで透明背景、ロゴ/テキスト白、他ページで白背景、通常テキスト。星パーティクルはCanvas APIで40個の星をランダム配置、4色(マゼンタ、シアン、イエロー、ピンク)でキラキラ、requestAnimationFrame で滑らかなアニメーション。
アイドルサイトは目を引く大きな画像がないと始まらない。ヘッダーは画像にオーバーレイして目立たなくした。スクロールスナップでテンポよくセクションを切り替えるようにした。
出した画像が使えなかったのでやり直し
ヒーロー画像とイベント画像を生成したが、品質問題が発生した。髪色が混ざる(Kanaの茶髪が他のキャラに移る)、人数が合わない(3人しか描かれない、5人になる)、キャラクターの特徴が分離しない。
JSON形式で各キャラクターの位置・役割・外見を明示してみた。
scene_spec = {
"version": 1,
"characters": [
{"id": "keichan", "enabled": True,
"outfit": "white and blue idol costume",
"position": "left", "depth": "foreground",
"pose": "hand on hip", "expression": "confident smile"},
# ... 4人分
],
}
結果はダメだった。構造化シーンコンパイラが出力したpromptで名前が壊れた。“kurara” → “Kure” / “Kura” に短縮、“koharu” → “Kohar” に短縮。LoRAトリガーワードは入っているが、説明文中の名前が壊れるため、キャラクターの特徴が正しく適用されなかった。
英語プロンプトを直接指定し、構造化シーンコンパイラをスキップして再試行。名前は正しく入るが、シードによって4人が描かれない、髪色が混ざる等の問題が残った。
個別生成して合成してみたら使い物にならなかった
4人を個別生成→背景除去→合成する方法を試した。
# 4人を個別生成(1girl, solo)
for char in [kei, kana, koharu, kurara]:
generate(char.prompt) # 白背景、ソロ
# 背景除去(簡易版)
img_rgba = remove_background(img)
# 1536x864キャンバスに横一列配置
canvas.paste(img_rgba, (x, y), img_rgba)
| ダメ出し内容 | 修正内容 |
|---|---|
| 4人は出るがトップサイトに使われる絵ではない | 個別合成ではなく4人横一列を複数シード生成→人間が選択 |
白背景切り抜きを並べただけで「同じ空間にいる感」がない。背景除去が雑で不自然。個別合成だと、プロのサイト画像に求められる一体感が全く出なかった。4人を確実に描くことと、アイドルサイトとして成立する画像を作ることは、全然別の話だった。
複数シードで4人が出るまで粘った
4人LoRAの学習データには「横一列立ち絵」が10種類ある。シンプルな構図なら安定する可能性があるので、カラフルな背景付きで4人横一列を生成し、4人全員がちゃんと出るまで複数シード試した。
resp = httpx.post("http://127.0.0.1:8000/api/generate", json={
"text_ja": prompt,
"skip_translate": True,
"use_lora": True,
"count": 8, # 8 seed生成
...
})
8枚生成して5枚が「4人全員描かれている、キャラ分離OK、アイドルサイトとして成立」の3条件を満たした。採用した画像。

4人の表情が最も自然で、ポーズのバランスも良かったため main.jpg に採用した。
イベント画像も同様に、各イベント(記者会見、楽屋、ライブ)で6枚生成→人間が選択。debut-eventとbehind-scenesにはそれぞれ指定した楽屋画像を配置(ファイル名の混乱あり、後述)。live-performanceはv2-5(歌とダンスのみ、バンドなし)を採用。
4人LoRAでは1回の生成で完璧な画像は出なかった。複数シード生成→人間が選ぶ、が一番まともな手順だった。「4人全員描かれている」「キャラ分離OK」「サイト画像として成立」の3条件を満たすまでシードを変えて生成し続けた。
ロゴ修正(viewBoxと文字切れ)
SVGロゴのviewBoxが 0 0 400 80 で、“RECORDS”の”D”以降が切れていた。
<!-- 修正前 -->
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 400 80">
<!-- 修正後 -->
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 500 80">
追加修正として、ロゴサイズを40px → 60px(CSS)、ドロップシャドウ追加(ヒーロー画像上で視認性向上)、PNG(1024x1024正方形)→ SVG(横長テキスト)に変更。
ファイルを取り違えた
指定した画像は楽屋の画像だったが、それを debut-event.jpg(記者会見用)に入れてしまっていた。
ファイル名は debut-event.jpg(記者会見)だが、中身は楽屋の画像だった。
正解は、指定した楽屋画像 → behind-scenes.jpg(楽屋用)、記者会見画像 → 新規生成(文字あり・なし両方)、ファイル名の混乱を修正。
ファイル名ではなく中身を確認すべきだった。
実験記事の書き方を間違えていた
このブログの実験記事は、最初に雛形のドラフトを書いたあと、そこに経過を追記していって、最後に構成と文体を整える、という書き方をしている。今回サイトの構築のほうに意識がいってしまったあまり、ドラフトに追記するのを忘れた。ついでに修正内容を逐次コミットして履歴に残すのも忘れていた。
フルスクリーンヒーロー以降、今回の構造化シーン、画像再生成、ロゴ修正の作業を記事に追記できていなかったので、その間の失敗と修正の過程が記事に記録されていなかった。
LiltingChannelLaboの最後のコミットは d7a74a1 feat(lilith): 画像アスペクト比修正 + SVGロゴ で、その後の変更(候補7採用、ロゴviewBox修正、イベント画像差し替え)が未コミットだった。候補画像(candidate-*.jpg)が大量に残っていた。
記事に今回の失敗と修正をすべて追記し、LiltingChannelLaboの変更をコミットし、候補画像の整理(採用したもの以外を削除)を行った。
記者会見画像を選び直してイベント情報を充実させた
記者会見画像は18枚の候補(文字あり6枚、文字なし6枚、v2 6枚)から選択して debut-event.jpg として配置した。


イベントセクションに詳細情報を追加。日付(2026.07.15、2026.08.20)、会場(渋谷 Club QUATTRO、Lilith Records Studio)、チケット価格(¥4,500、¥8,000)、開場/開演時刻、ステータス(SOLD OUT、受付中)、CTAボタン(チケット予約)。
最終的なデザイン調整として、各セクションに背景色で視覚的な違いを追加。Artistsセクションは薄いシアングラデーション、Releaseセクションは薄いマゼンタグラデーション、Newsセクションは薄いマゼンタグラデーション、Eventsセクションはシアン→マゼンタグラデーション。
リポジトリ
完成したサイトはVercelで公開している。コードは GitHub (hide3tu/LiltingChannelLabo) の 2026/08/14/lilith-records/ 配下。
この記事の作成、文体等の調整、サイトの作成と画像生成、全体調整、全てQwen3.7 / 3.8で行っている。
最初の構築まではQwen 3.7 Plus、そのあとがQwen3.7 Maxで、ファイルの取り違え以降はQwen 3.8 Max、記事を整えているのもQwen3.8 Maxで、人間はほとんど介在していない。
文体の修正チェックに関しては、前から調整を繰り返しているAIスロップ検出のBERTは使わず(開発環境が別なので入ってない)、文体チェックスキルをQwenに読み込ませ、直列実行させて修正をかけたあと、セッションを切り直して、文体チェックスキルの構成ABCDEセクションをバラバラに実行させ再度修正、そのあとこちらで指摘した箇所を直させる方式をとっている。
実はあまり文章自体には手を入れておらず、ほとんどQwenの取って出しになっている(日本語記事の方)。まあまあ文章はいい方なのかなという印象、ただし構築はClaude SonnetやCodex Sonnetをみてると微妙なとこはある、Opus4程度かなあという感じだが、この程度の作業なら振っても問題はなさそう、という印象。