技術約12分で読めます

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

いけさん目次

pi.devでQwenモデルを読み込み、架空の音楽レーベル「Lilith Records」の公式サイトを作った。技術スタックはこのブログと同じAstroで、固定ページ数枚とニュース記事だけMarkdownで更新できる構成。

画像生成にはgenserverを使い、キャラクター画像は4人合体LoRAanima-4char-v1_epoch100)から出した。

作業環境

要素内容
ハーネスpi.dev(Agent Skills標準準拠)
モデルQwen(pi.dev経由で読み込み)
フレームワークAstro v7
画像生成genserver(ComfyUI + Anima LoRA)

要件定義

レーベル設定

項目内容
レーベル名Lilith Records
サイトURLlilting-channel-labo.vercel.app
ジャンルアイドル系
所属ユニットLilith-4

Lilith-4 メンバー

genserverのanima-4char-v1_epoch100.safetensorsで生成可能なオリジナルキャラクター4名。

メンバー担当外見特徴
Kei(ケイ)リーダー / ボーカル金髪ロング、青目、ぱっつん前髪、長いインテーク、ハーフアップ三つ編み、青リボン
Kana(かな)メインボーカル茶髪ミディアム、サイドポニテ、アホ毛、二重に分かれた前髪、青シュシュ
Koharu(こはる)サブボーカルショートで乱れた黒髪、青リボン、赤目
Kurara(くらら)ラップ / パフォーマンスローズブラウンのロングヘア、センターパート、スタッドピアス、ライトギャルメイク

Lilith-4 メンバー4名

サイト構成

/
├── 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:typetwitter: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.mdsrc/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人分すべて正常に生成完了した。

Kei Kana Koharu Kurara

ロゴ作成・ビルド

ロゴは 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アルバム)。

1stアルバム「Awakening」ジャケット

出来上がりを確認してみると

ダメ出しが8つ。

#ダメ出し内容修正内容
1ただのワイヤーフレームフルスクリーンヒーロー、イベント画像、プロモバナーを追加
2画像が載ってないキャラ4枚以外に集合写真、ライブ、バックステージ画像を生成
3スキルどこに使った?frontend-designチェックリストの適用をサボっていた
4納品レベルじゃないワイヤー状態で「完成」と報告していた
5AIが作りました感オフホワイト×チャコール→アイドル系ポップ配色に変更
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 で画像を拡大/トリミング、グラデーションオーバーレイで視認性確保。スクロールスナップは htmlscroll-snap-type: y mandatory、各セクションに scroll-snap-align: startmin-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程度かなあという感じだが、この程度の作業なら振っても問題はなさそう、という印象。