レシピ · 6手 · 1プロンプト実装

デザイン世界観を1ファイルで全面に適用する

パレット・書体・ムードを src/worldview.ts に1回宣言し、サイト/ビジュアル/セッションカード/メールの4面へ一気に派生させる

前提: new-event解説 ch.44module: デザイントークン層 + Worldview

イベントのデザイン面は4つある(サイト CSS 変数 / ビジュアル EventBrand / セッションカード CardTheme / メール Brand)。Worldview はその上流の単一真実源 — 1ファイル書き換えれば4面が変わる。 feature flag は不要(全ページ共通の基盤層)。

カバー範囲を先に正しく: worldview が決めるのはトークン(色・書体・角丸・質感・透かし)。 ページの構成・レイアウト・モーションはトークンでは決まらない — そこは参照実装(starter の page/component)とイベント側コードの責務。「世界観の指示 = トークン4面が一気」であり、 「任意の凝った LP 表現が自動生成される」ではない。

1. 世界観を1ファイルで宣言する

apps/<app>/src/worldview.ts:

import { defineWorldview } from "@event/design";

export const worldview = defineWorldview({
  name: "<app>",
  palette: {
    // hex 推奨(#rgb / #rrggbb)— alpha 派生・混色・明度判定が効く
    bg: "#f1f3ef",       // ページ地色。暗色を置けば「ダークな世界」全体が導出される
    surface: "#fafbf9",  // カード / パネル面
    ink: "#1a211d",      // 文字色(bg に対して十分なコントラスト)
    accent: "#0b6ea8",   // 主張色(1点豪華)
    accentAlt: "#e0653c",
  },
  typography: {
    display: '"Shippori Mincho B1", serif', // 見出し — 世界観の半分は書体で決まる
    body: '"Noto Sans JP", sans-serif',
    mono: 'ui-monospace, monospace',
  },
  mood: {
    radius: "soft",           // sharp | soft | round
    visualsScheme: "dark",    // カード/書き出し画像の舞台(dark 既定 = 紙/SNS の定石)
    watermarkGlyph: "S",      // ビジュアルの巨大 italic 透かし(空で無し)
    // lockScheme: true,      // OS ダーク追従を止めてライト固定
  },
  // logoUrl: "/logo.svg",    // メール header / ビジュアル横組ロゴ
});

世界観ブリーフ → パレットの翻訳ガイド: 「シネマティックで静かな高級感」→ bg を暗色 (#0c0e12 系)・ink を生成り (#f2f0ea 系)・accent は彩度低めの1色・display をセリフ体に。 「祭りのような熱」→ bg 明色・accent 高彩度・radius "round"・watermark に象徴グリフ。 bg に暗色を置くと isDark 判定で dark:null(常にその世界)・舞台・plate 色まで自動で反転する。

2. 面1: サイト本体(design.ts を派生に切り替え)

apps/<app>/src/design.ts:

import { defineDesign, worldviewToDesignInput, type EventDesign } from "@event/design";
import { worldview } from "@/worldview";

export const eventDesign: EventDesign = defineDesign(worldviewToDesignInput(worldview));

(layout.tsx の <style>{tokensToCssVars(eventDesign)}</style> 注入は add-design 済み前提。 未了なら add-design の手順3を先に。)派生則: ink2/ink3/line/accentSoft は ink・accent の alpha から、--radius-* は mood.radius から、dark は明色世界なら accent を 25% 明るく/ 暗色世界なら null(すり替えない)。

3. 面2: ビジュアル(EventBrand を派生に切り替え)

apps/<app>/src/lib/visuals.ts の visualsBrand を差し替え:

import { resolveBrand, type EventBrand } from "@event/visuals";
import { worldviewToBrand } from "@event/design";
import { worldview } from "@/worldview";

export const visualsBrand: EventBrand = resolveBrand(worldviewToBrand(worldview));

visualsScheme="dark" のとき、明色世界でも舞台は mix(ink, #000, 0.55) のダークに置かれ、 文字は surface(明色)が使われる。fgDim/fgFaint/hair は fg の alpha 派生。

4. 面3: セッションカード(CardTheme 登録)

apps/<app>/src/lib/cardThemes.ts:

import type { CardTheme } from "@event/session-card";
import { worldviewToCardTheme } from "@event/design";
import { worldview } from "@/worldview";

export const CARD_THEMES: Record<string, CardTheme> = {
  [worldview.name]: worldviewToCardTheme(worldview),
};

カードスタジオ(SessionCardDesigner)に themes={CARD_THEMES} を渡す (starter は app/admin/card/[id]/CardStudio.tsx)。テーマ切替 UI に世界観テーマが現れ、 選ぶと --card-bg / --card-fg / --card-accent / plate / 書体が世界観になる。 未指定の変数は resolveCardTheme が既定でマージ(部分定義で安全)。

5. 面4: メール(Brand を派生に・env 優先)

apps/<app>/src/lib/mailer.ts の brand を差し替え:

import { worldviewToMailBrand } from "@event/design";
import { worldview } from "@/worldview";

const wvBrand = worldviewToMailBrand(worldview);
const brand: Brand = {
  ...wvBrand,
  name: process.env.MAIL_BRAND_NAME ?? wvBrand.name,
  color: process.env.MAIL_BRAND_COLOR ?? wvBrand.color,
};

設計判断: 暗色世界ではメール shell はライト既定に委ね accent / ロゴだけ持ち込む (メールクライアントの到達性・可読性を世界観の完全再現より優先)。明色世界なら ink/background/surface もパレットから写す。

6. 検証

yarn workspace <app> typecheck   # 派生出力と各面の実型の構造互換が証明される
yarn workspace <app> dev

worldview.ts の accent を1色変えて確認:

  1. サイト全ページのアクセント(リンク/ボタン/nav)が変わる
  2. /admin/visuals の告知ビジュアルのアクセント・透かしが変わる
  3. /admin/card/<id> でテーマに「<app>」が現れ、選ぶとカードが世界観になる
  4. /admin/mail のプレビューの eyebrow / 見出し色が変わる

完了条件: 1ファイルの変更が4面すべてに反映される。