自社デザインで作り込む

自社デザインで作り込む(業者向け)

スターターマニュアル(構造だけを簡単に説明したマニュアル)も公開中です。

⚠ プログラム改造についての重要なお願い

プログラム本体(エンジン層=core/admin/assets/)のカスタマイズは原則お断りしています。フレームとパーツ(frames/parts/)を作り込むことで、ほとんどのご要望は実現できます。

どうしてもプログラム本体の改造が必要な場合は、それ以降のサポート・バージョンアップ対応を一切お受けできないことを条件に、お客様の責任において行っていただけます。改造された場合、不具合対応やアップデート時の互換性は保証の対象外となりますので、あらかじめご了承ください。

▶ おすすめの近道:Cowork や Codex などのAIエージェントを使える環境の場合

ローカルを直接編集できるAI(Cowork 等)に、このページと以下の指示文とDL内の既存 frames/parts/ を“教材”として読ませ、AIに作らせるのが近道です。

Frames CMS 用に、自社デザインを「フレーム」(またはパーツ)として作りたいです。まずこのマニュアルと、DL内の既存 frames/(例 frame7・biz64-red)・parts/(例 cta)を2〜3個読んで作法を把握してください。次に、目的に一番近い既存フレームのフォルダを複製し、私が渡す静的HTML/CSSに置き換えてください。

【重要】自社デザインはそのまま入らないことが多いので、CMSの対応範囲に“寄せて”ください。範囲を超える要素は、最も近い対応形に調整し、変更点を箇条書きで私に報告してください(エンジンを改造して無理に合わせない)。判断に迷う要素は勝手に決めず、先に私に確認してください。
主な制約:
・メイン画像=キャッチ+サブ文+ボタン最大2個(スタイルは塗り/枠線の2種のみ。3個以上やボタン個別の色指定は不可)。
・全体構成=ヘッダー(ロゴ・メニュー)+メイン画像(トップのみ)+本文(パーツ)+フッター、の枠組み。
・メニュー=横並び+ハンバーガー(必要ならドロップダウン/サイドメニュー型)。
・本文の各セクションは「パーツ」として作る(凝った独自の動きはCMSの範囲=HTML/CSS/JSのみで)。

ルール:PHPは書かない/core・admin・assets は触らない/{{ }} の差し込み口は消さない・改名しない/色は theme.css の変数で/1フォルダ=1フレーム/mainimg.html は必ず用意/frames/ に作業ファイルを残さない。最後に JSON の妥当性と {{ }} の消え残りをチェックしてください。
このマニュアルは web制作会社・フリーランスの制作者向けです。HTML/CSS/JS/JSON が読める前提で、既存の入門マニュアル(「フレームの作り方」「パーツの作り方」)より一段踏み込んだ“作り込み”レベルを扱います。PHP は書きません。表示は CMS 本体(エンジン)が行います。

はじめに

このマニュアルの位置づけ

Frames CMS は「フレーム(サイトの枠)を差し替えるだけで、壊れないリニューアルができる」ことを売りにした商用 CMS です。制作会社は 自社デザインでフレームとパーツを作り込み、CMS ごとクライアントに納品 できます。このマニュアルは、その作り込みの手順・規約・つまずきポイントをまとめたものです。

技術スタックは PHP 8.0+ / SQLite。ただし制作者が PHP を書く場面はありません。作るのは HTML・CSS・JSON・JS だけで、描画はエンジンが担います。

CMS は概念的に3層でできている

どこを触ってよいかを最初に押さえてください。CMS は次の3層に分かれます。

① エンジン層CMS 本体
core/admin/assets/
描画・管理画面・共通JS。触らない
② 着せ替え層業者が作り込む部分
frames/parts/plugins/
HTML/CSS/JSON/JS で作る。ここだけ触る
③ お客さんの中身運用データ
data/uploads/
本文・画像・設定。触らない

制作者が触るのは②だけです。フレームもパーツも HTML/CSS/JSON/JS で作り、エンジン(①)は改造しません。お客さんのデータ(③)にも触れません。

できること/やらないこと

やること(②の範囲)やらないこと
フレーム(frames/<id>/)を作る:骨格・メイン画像・メニュー・色・同梱素材エンジン層(PHP)の改造。差し込み口の仕組み自体を変えること
パーツ(parts/<name>/)を作る:入力定義+描画テンプレ+CSS/JS差し込み口({{…}} プレースホルダ)の削除・改名
テーマ変数(色)を使ってCSSを書くカラーコードの直書き(テーマ変更やダーク系フレームで破綻する)
完成物を frames/parts/ にドロップインして納品お客さんのデータ(data/uploads/)への書き込み
3つの禁止(最重要)。 ① 差し込み口 {{…}} を消さない・改名しない(消すとロゴ・メニュー・本文が出なくなります)。 ② 色はカラーコード直書きせず、テーマ変数前提で書く(第1部7章・第3部)。 ③ 配布フォルダ(frames/parts/)に作業用・テンポラリファイルを残さない(購入者〔ライセンスを持つ制作会社〕が購入者ページからダウンロードする配布物のため)。

用語の早見

用語意味
フレームサイトの「枠」。frames/<id>/ 一式(骨格・メイン画像・メニュー・色・JS)。差し替えの単位。
パーツ本文に積む「部品」。parts/<name>/(入力定義 part.json + 描画テンプレ template.html)。
差し込み口(プレースホルダ){{SITE_NAME}} のような {{…}}。エンジンがここに値を差し込む。
エンジンCMS 本体(core/)。テンプレートを読んで値を差し込み、HTML を出力する。

差し込み口の共通ルール(テンプレ記法)

フレームの layout.htmlmainimg.html、パーツの template.html は、すべて 同じテンプレート記法で書きます。ここで一度だけ定義するので、以降の章はこの記法を前提に読んでください。エンジン(core/render.php)は Mustache 風の自作エンジンで、次の4つの記法を解釈します。

記法意味
{{key}}値を出力する(HTMLエスケープあり)。文字テキスト・URL・クラス名などに使う。
{{{key}}}値を生(raw)で出力する。<br> や HTML 断片を活かしたいとき。キャッチ/サブ文・本文・メニュー・フッターなど。
{{#key}}…{{/key}}key が真または非空配列のとき中を出力。配列なら繰り返し(中で各要素のキーが使える)。有無の出し分け・スライドの反復に使う。
{{^key}}…{{/key}}key が偽または空のとき中を出力(反転セクション)。「無いときの代替」に使う。

真偽の判定は、bool はそのまま、配列・文字列は「空でなければ真」です。有無フラグ(HAS_LOGOHAS_CATCH など)と本体(LOGO_URLMV_CATCH など)が対で用意されているので、「あるときだけ出す」を {{#HAS_…}}…{{/HAS_…}} で囲むのが基本形です。

<!-- ロゴがあれば画像、無ければサイト名テキスト -->
<h1 class="logo"><a href="{{HOME_URL}}">{{#HAS_LOGO}}<img src="{{LOGO_URL}}" alt="{{SITE_NAME}}">{{/HAS_LOGO}}{{^HAS_LOGO}}{{SITE_NAME}}{{/HAS_LOGO}}</a></h1>
同じプレースホルダは、出てくる場所すべてが置換されます。だから同じ {{{NAV}}} を2回書けば2か所に同じメニューが出ます(2メニュー型フレームの応用で使います)。
エスケープの使い分けを間違えないこと。<br> 入りのテキスト(キャッチ・サブ文・本文)を {{key}}(2重)で出すと <br> がそのまま文字になって表示されます。改行や装飾を活かす値は 必ず3重カッコ {{{key}}} にします。逆に、URL・クラス名・ボタン文字などは {{key}}(2重)で安全側に。

第1部 フレーム編

1. フレームとは/フォルダ構成

フレームは、サイトの枠(骨格・ヘッダー・メイン画像・メニュー・色・フッター土台)を1セットにしたものです。お客さんは管理画面でフレームを選ぶだけで、本文(パーツ)を保ったままサイト全体の見た目を差し替えられます。制作者の仕事は、この frames/<id>/ 一式を自社デザインで用意することです。

フォルダ構成

フレームは frames/<id>/<id> はフレームキー=フォルダ名)に置きます。中身は次のとおりです。

ファイル/フォルダ役割必須
layout.htmlフレームの骨格。ヘッダー・メニュー・本文・フッターの器。差し込み口は第1部2章。必須
mainimg.htmlメイン画像(メインビジュアル)のテンプレート。差し込み口は第1部4章。静止画フレームも必ず同梱必須
frame.jsonフレームの設定(表示名・メイン画像タイプ・メニュー挙動・同梱素材枠)。全キーは第1部3章。必須級
css/theme.cssテーマ色(色変数)。フレームの配色はここ。第1部7章。必須
css/style.cssフレーム本体のCSS。レイアウト・メイン画像テキストの標準位置/色/読みやすさはここが持つ。必須
js/main.jsフレーム固有のJS(スライド動作・ヘッダー演出など)。無ければ frames/<id>/main.js をフォールバック参照。任意
thumb.webpフレーム選択UIのサムネイル(自動参照)。任意
images/フレーム同梱画像。メイン画像の標準(フォールバック)画像や飾り。命名規則で自動検出される枠がある(第1部4・8章)。任意
メニュー開閉・スクロール・ページトップは共通JS が担当します。これらは assets/common/common.js(エンジン層)が受け持つので、フレームごとに書きません。フレームの js/main.js は、そのフレーム固有の演出(スライドの動き・ヘッダーのフェードなど)だけを書きます。挙動の設定値は frame.json からエンジンが window.CMS_FRAME_OPTS 経由で共通JSに渡します。

フォルダを置けば効くもの(JSONに書かなくてよい)

次は frame.json に書かず、frames/<id>/ファイル名の規約どおり置くだけで効きます。

ファイル役割
thumb.webpフレーム選択UIのサムネイル。
images/mainimgN.*mainimgN_s.*メイン画像のフレーム標準(フォールバック)画像。お客さん未設定の間だけ表示。_s はスマホ用。
images/movie.mp4(または .webm)+ movie_s.*動画タイプのフレーム標準動画/スマホ用。検出されるのは mp4/webm のみmovie.jpg 等は動画ソースにならない)。

2. layout.html の差し込み口

layout.html はフレームの骨格で、エンジンが用意する差し込み口に値を差し込んで1ページを組み立てます。制作者は、この差し込み口を正しい場所に置くことが仕事です(消す・改名するとロゴ・メニュー・本文・CSS/JS が出なくなります)。

差し込み口の一覧

プレースホルダ内容
{{META_TITLE}} / {{META_DESCRIPTION}}<head> 用のタイトル・説明。
{{{HEAD_CSS}}}CSS自動読込(Tablerアイコン・パーツCSS・inview・テーマ色上書き等)。</head> の直前に置く。
{{SITE_NAME}}サイト名。
{{#HAS_LOGO}}…{{/HAS_LOGO}} / {{^HAS_LOGO}}…{{/HAS_LOGO}} / {{LOGO_URL}}ロゴ。画像があれば <img>、無ければサイト名テキスト(下の「ロゴの書き方」を必ず使う)。
{{LOGO_HERO_URL}} / {{#HAS_LOGO_HERO}}メイン画像の上に重ねる用ロゴ(透過ヘッダーがメイン画像に重なる状態で使う)。使うフレームは frame.jsonuses_logo_hero: true が必要(第1部3章)。
{{HOME_URL}}トップへのリンク。
{{{NAV}}}メインメニュー(<ul>…</ul>)。単一メニュー型フレーム用(PC/スマホはCSSで出し分け)。
{{{NAV_PC}}} / {{{NAV_MOBILE}}}2メニュー型フレーム用。PC表示ONの項目だけ/スマホ表示ONの項目だけを出力(第1部6章)。
{{#IS_HOME}}{{{MAINVISUAL}}}{{/IS_HOME}}メイン画像(ホームのみ出す)。
{{{CONTENT}}}本文(各パーツの描画結果)。
{{{FOOTER}}}フッター(CMSが出力)。
{{{SCRIPTS}}}JS自動読込(jQuery・共通JS・パーツJS・フレームのmain.js)。</body> の直前に置く。
{{BASE}} / {{FRAME}}フレーム同梱アセットの参照用。例:{{BASE}}/frames/{{FRAME}}/images/bg.svg。ルート/サブディレクトリ設置どちらでも正しく解決する。
{{BODY_CLASS}}<body> に付けるクラス。トップは home、下層は page-<slug>(出るのはどちらか一方)。全同梱フレームがこの形を使っている(2026-08。旧 {{#IS_HOME}}home{{/IS_HOME}} から置き換え済み)。下層のクラスが付くので「会社概要のページだけ余白を変える」といった指定ができる。
置き場所の固定ルール。{{{HEAD_CSS}}}</head> の直前、{{{SCRIPTS}}}</body> の直前。これを外すとパーツのCSS/JSやアイコンが効きません。また共通JS(common.js)が参照するランドマーク #menubar#menubar_hdr#menubar-overlay.pagetop は、配布テンプレの規約どおり残してください。

ロゴの書き方(必須の形)

ロゴは必ず次の形にします。ロゴ画像が未設定ならサイト名の入力値をテキスト表示する形です(フレーム同梱のダミー logo は見にいきません)。

<h1 class="logo"><a href="{{HOME_URL}}">{{#HAS_LOGO}}<img src="{{LOGO_URL}}" alt="{{SITE_NAME}}">{{/HAS_LOGO}}{{^HAS_LOGO}}{{SITE_NAME}}{{/HAS_LOGO}}</a></h1>
ロゴのフォールバックは双方向です。HAS_LOGO は通常ロゴ/上重ねロゴのどちらか一方でもあれば真LOGO_URL は通常ロゴが無ければ上重ねロゴに、LOGO_HERO_URL は上重ねロゴが無ければ通常ロゴにフォールバックします。HAS_LOGO_HERO は専用の上重ねロゴが設定されているときだけ真です。透過ヘッダー↔固定ヘッダーの出し分けはフレームのCSS/JS(または IS_HOME)で行う=フレームの責務です。

実例:frame7 の layout.html

標準的な単一メニュー型フレーム(_dist/frames/frame7)の実物です。差し込み口の置き場所の手本にしてください。

<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>{{META_TITLE}}</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="description" content="{{META_DESCRIPTION}}">
<link rel="stylesheet" href="{{BASE}}/frames/{{FRAME}}/css/theme.css">
<link rel="stylesheet" href="{{BASE}}/frames/{{FRAME}}/css/style.css">
{{{HEAD_CSS}}}
</head>

<body class="{{BODY_CLASS}}">

<div id="container">

<div id="header-container">
<header>

<h1 id="logo"><a href="{{HOME_URL}}">{{#HAS_LOGO}}<img src="{{LOGO_URL}}" alt="{{SITE_NAME}}">{{/HAS_LOGO}}{{^HAS_LOGO}}{{SITE_NAME}}{{/HAS_LOGO}}</a></h1>

<!--開閉メニュー-->
<div id="menubar">
<nav>
{{{NAV}}}
</nav>
</div>
<!--/#menubar-->

</header>

{{#IS_HOME}}
{{{MAINVISUAL}}}
{{/IS_HOME}}

</div>
<!--/#header-container-->

<div id="contents">
<main>
{{{CONTENT}}}
</main>
</div>
<!--/#contents-->

<!--フッター(全ページ共通/CMSが出力)-->
{{{FOOTER}}}

<!--メニューオーバーレイ(メニュー外クリックで閉じる用)-->
<div id="menubar-overlay"></div>

</div>
<!--/#container-->

<!--ページの上部へ戻るボタン-->
<div class="pagetop"><a href="#"><i class="ti ti-chevrons-up"></i></a></div>

<!--開閉ボタン(ハンバーガーアイコン)-->
<div id="menubar_hdr">
<span></span><span></span><span></span>
</div>

<!--CMSが共通スクリプトを出力-->
{{{SCRIPTS}}}

</body>
</html>

アイコンが <i class="ti ti-chevrons-up"> になっている点に注目してください。アイコンは Tabler Icons に一本化されています(第2部7章)。

3. frame.json 全キー

frame.json はフレームの設定ファイルです。使うキーだけ書けばよく、書かないキーは既定値で動きます。ここが frame.json の権威リファレンスです(エンジン core/frame.php が実際に読むキーと一致)。

最小例

{
  "name": "フレーム表示名",
  "description": "短い説明",
  "mainvisual_type": "static"
}

1. 基本情報

キー説明
name文字列フレームの表示名(管理画面「デザイン」のフレーム選択や見出しに出る)。必須級
description文字列フレームの短い説明(管理画面に表示)。
uses_logo_hero真偽(既定 falsetrue で「サイト基本設定」に『メイン画像の上に重ねるロゴ(任意)』欄を出す。layout.html{{LOGO_HERO_URL}} を使うフレームだけ true に。既定は非表示(使わないフレームで出すと問い合わせの元になるため)。

2. メイン画像(mainvisual_*)

キー型 / 値既定説明
mainvisual_type"static" / "slideshow" / "video"staticメイン画像のタイプ。管理画面の入力欄と既定動作が変わる。見た目は mainimg.html が決める
mainvisual_shared_text真偽falsetrue=スライド全体で共通の1メッセージ型(テキストを {{#MV_IMAGES}} の外に1つ置く。例:lp4)。管理画面の2枚目以降のテキスト入力を隠す。
mainvisual_align_lock真偽falsetrueテキスト位置を固定(背景SVG等で土台が固定のフレーム)。管理画面の「テキストの位置」プルダウンを隠し、描画は位置クラスを付けない(フレームCSSに任せる)。文字色プルダウンは残る。
mainvisual_text_hide真偽falsetrueメイン画像のテキスト・ボタンを一切出さない(ロゴだけ中央配置するフレーム等)。管理画面のテキスト/ボタン入力欄を丸ごと隠し、描画でも出さない(mainimg.html にテキスト枠が残っていても安全に抑止)。値は hidden で温存。
mainvisual_no_button真偽falsetrueメイン画像上の「ボタン」だけ非表示。キャッチ/サブは出す。mainvisual_text_hide(全部消す)との違いに注意=こちらはテキストだけ出すフレーム用。値は hidden で温存。
mainvisual_no_sp真偽falsetrue=管理画面の「スマホ用画像/スマホ用動画」入力欄を隠す。SPの別画像を使わないフレーム用(例:portfolio1)。SP画像は元々「任意」なので機能上は無くても動く(UI整理)。既存値は hidden で温存。
assets の差し込み口フレーム固有素材は {{ASSET_<key>}}{{#HAS_ASSET_<key>}}(既定を含めて素材があるか)/{{#CUSTOM_ASSET_<key>}}(お客さんが差し替えたときだけ)/{{#OFF_ASSET_<key>}}(お客さんが「この素材を使わない」を選んだとき・2026-08-04追加)で出し分けます。素材の状態は①未設定 ②差し替え ③使わないの3つ。{{#HAS_ASSET_}} で要素ごと囲んでおけば「使わない」でその要素ごと消えるのでフレーム側の作業は不要です。style.css に飾りを直書きして {{#CUSTOM_ASSET_}} で上書きする型だけ、{{#OFF_ASSET_}} で打ち消しCSS(background-image:none など)を出す必要があります。新しく作るなら {{#HAS_ASSET_}} 型が素直です。
mainvisual_count数値 1〜61静止画タイプで使うメイン画像の枚数。2枚組・3枚組など複数の静止画を同時に配置するフレーム用。書かなければ1枚=従来どおり2 にすると管理画面に「メイン画像1/メイン画像2」の枠が出て、描画にも2枚渡ります。テキスト・ボタンは常に1セット(1枚目の入力値)で、管理画面も2枚目以降は画像だけになります。そのため mainimg.html「ループの中は <picture> だけ・テキストはループの外」で書きます(テキスト一式はループ外でも使えます)。<picture class="img{{n}}"> と書けば img1 img2 が付くので、並べ方は style.css.img1 .img2 を作り込みます(左右2分割・上下2段・重ねる等)。※スライドショー型の <div class="slide"> でループごと包む書き方を流用すると、箱ごと複製されて2枚目にもテキスト枠が付くので使わないでください。フレーム同梱の標準画像も images/mainimg1.* mainimg2.* を置けば枚数ぶん出ます。1未満・7以上はクランプされ壊れません。スライドショー・動画タイプでは無視。
mainvisual_text_overlay_media文字列(@mediaの条件)""管理画面の「文字色(白文字/濃い文字)」の上書きを効かせる範囲小さい端末でテキストを画像の外へ「段落ち」させるフレームは必ず書きます。段落ちした先はページの背景(各フレーム --bg-color: #fff)なので、白文字のままだと読めなくなるためです。ここに「重なっている間の条件」を書くと、その中だけ上書きが効き、外れたらフレーム本来の文字色に戻ります(=段落ち後の色は、フレームのCSSが自分で決めておけばよい)。書き方=フレームCSSが max-width:700px で段落ちさせているなら "(min-width:701px)"、幅だけでなく高さでも段落ちするなら "(min-width:501px) and (min-height:501px)" のように and でつなぎます。@media{} は書きません(本体が付けます)。書かなければ無条件=従来どおり(=テキストが常に画像に重なるフレーム)。安全のため許可文字以外は捨て、括弧が閉じていなければ丸ごと無視します(壊れたCSSは出ません)。設定例:biz64-red・lp4・portfolio2 (min-width:701px)/frame11 (min-width:700px)/portfolio1 (min-width:501px) and (min-height:501px)
mainimg_class文字列""(任意)メイン画像ラッパに付ける追加クラス。
mainvisual_size_select真偽falsetrue=管理画面のメイン画像テキストに「文字サイズ(大/中/小)」プルダウンを出すopt-in)。選択値は .textmv-size-lg/md/sm クラスとして出力されるので、フレームの style.css.mainimg .text.mv-size-lg h2{…} 等のサイズを定義する(中=既定)。CSS未定義でも壊れないが効かない。
テキストの位置・色の標準と読みやすさ処理(影/スクリム)はフレームのCSSが持ちます。詳細は第1部5章。

3. メニュー(menu_*)

キー型 / 値既定説明
menu_breakpoint数値(px)900この幅より狭いとメニューがハンバーガーに。9999=常にハンバーガー。管理画面で上書き可だが、フレーム切替時はこのフレーム標準値が採用される。
menu_dropdowns文字列の配列[]ドロップダウン(親子メニュー)をhover開閉させるCSSセレクタ。2メニュー型でPCヘッダーのnavを指定(例:["header nav"])。
menu_hide_when_hidden真偽falsetrue=ヘッダーをスクロールで隠す演出(is-hide)と連動して開閉メニューの扱いを変える。2メニュー型(例:seikotsu1)用。
menu_keep_hamburger真偽falsePCの広い画面でもハンバーガー(≡)を出したままにするスイッチ。「PCで横メニュー+ハンバーガーも常時」型フレーム(例:frame9-slide)で使う。CSS側でも .small-screen 限定を外すこと(第1部6章)。
menu_breakpoint_lock真偽falsetrue=管理画面の「メニューの切り替え幅」を丸ごと非表示にし、切替幅をこのフレームの menu_breakpoint に固定(お客さんが変更不可)。最初からハンバーガー専用のフレームで、幅を小さくされて崩れるのを防ぐ。
menu_sidebar真偽falseサイドメニュー型(2カラム)フレームの宣言true のときだけメニューの「見出し(リンクなし)」項目が有効に。false(1カラム)では見出しはデータを消さず出力・表示しない(1カラムに見出しが紛れて崩れるのを防ぐ)。例:frame3-c2。
PCに横メニュー(hoverドロップダウン)を持つフレームに 9999 を入れないこと。共通JSは「幅 ≥ breakPoint のときだけ hover 開閉」なので、9999だと常に小画面扱いになりホバーが効かず“クリックでしか開かない”症状になります。横メニューを持つフレームは 1000 前後が目安です(詳細と対処は第1部6章)。

4. フレーム固有の差し替え素材(assets)

お客さんが管理画面(デザイン→「このフレーム専用の素材」)から差し替えられる画像枠を宣言します。layout.html / mainimg.html 内で {{ASSET_<key>}} / {{#HAS_ASSET_<key>}} / {{#CUSTOM_ASSET_<key>}} として使えます。

"assets": [
  { "key": "mv_pic", "type": "image", "label": "テキスト横の写真", "default": "images/sub.jpg", "hint": "正方形推奨" }
]
項目説明
keyテンプレで使う名前({{ASSET_mv_pic}} など)。英数字。
type"image"
label管理画面に出るラベル。
default同梱の既定画像(images/...)。入れておけばお客さん未差し替えでも {{ASSET_<key>}} に入り、{{#HAS_ASSET_<key>}} も真になる。
hint(任意)入力欄の補足。

{{#HAS_ASSET_<key>}}=default 含めて素材があるか。{{#CUSTOM_ASSET_<key>}}お客さんが差し替えたときだけ真(CSS背景の上書きなど「入れたときだけ効かせたい」用途)。仕組みの詳細は第1部8章。

実例:biz64-red の frame.json

静止画・位置固定・文字サイズ選択・同梱素材つきの実物(_dist/frames/biz64-red)です。

{
  "name": "斜めカット1枚ビジュアル(biz64-red)",
  "description": "メイン画像を斜めにカットし、横にテキストを並べる1枚構成。背景の角に飾り画像が入り、差し替えも可能。",
  "mainvisual_type": "static",
  "mainvisual_align_lock": true,
  "mainvisual_size_select": true,
  "assets": [
    { "key": "bg_decor", "type": "image", "label": "トップ背景の飾り画像(左上)",
      "hint": "トップページの左上にうっすら出る大きな飾りです。未設定のときはフレーム標準の飾りを表示します。",
      "default": "images/bg1.png" }
  ]
}
name / description の書き方。業種名・色・共通機能(PC/SP別アップ、テキスト/ボタンが任意、メニューのドロップダウン等の標準機能)は書きません(中身・色は管理画面で自由に変えられるので誤解のもと)。メイン画像の構造・演出・固有の差し替え枠に絞って簡潔に。name のカッコ内はフレームキー(フォルダ名)なのでそのまま残します。

4. mainimg.html の作り方

メイン画像(メインビジュアル)は mainimg.html が形を決めます。CMS は「素材(画像・動画・テキスト・ボタン)」だけを持ち、HTML の形は mainimg.html が決める という分担です。全フレームに必ず同梱してください(静止画フレームも)。無ければ CMS 既定で描画されます。

仕組み(これだけ理解すればOK)

メイン画像は スライド単位です。{{#MV_IMAGES}} … {{/MV_IMAGES}} で各スライドを繰り返し、その中でそのスライドのテキスト/ボタンが使えます(スライドごとに別文言にできる)。動画タイプだけは、テキストをスライドの外(トップレベル)に置きます。

3タイプ

タイプ(mainvisual_type作り
static(静止画)画像1枚。{{#MV_IMAGES}} を使い、CSS/構造はそのまま(複数入っても1枚目だけ使う)。
slideshow複数スライドを繰り返す。動きは frames/<id>/js/main.js.slide-indicators 等の演出要素は残す。
video<video>。テキストはトップレベルで出す。スマホ用動画は <source media> で出し分け。

差し込み口(スライドの中={{#MV_IMAGES}} … {{/MV_IMAGES}} の内側)

差し込み口内容
{{url}}画像URL(パソコン用)。
{{MV_SP}} / {{#HAS_SP}}スマホ用画像のURL/有無。<picture> 内で {{#HAS_SP}}<source media="(max-width:800px)" srcset="{{MV_SP}}">{{/HAS_SP}} のように使う。未設定なら {{url}} が使われる。
{{n}} / {{#is_first}}…{{/is_first}}1始まりの番号(img1 等)/最初の1枚だけ出す判定。
{{#HAS_CATCH}}{{{MV_CATCH}}}{{/HAS_CATCH}}キャッチ(<br>済み→3重カッコ)。
{{#HAS_SUB}}{{{MV_SUB}}}{{/HAS_SUB}}サブテキスト(同上・3重カッコ)。
{{MV_TEXT_CLASS}}テキスト位置クラス。<div class="text {{MV_TEXT_CLASS}}"> のように使う(詳細は第1部5章)。
{{#HAS_BTN1}}…{{/HAS_BTN1}} / {{MV_BTN1_TEXT}} / {{MV_BTN1_URL}} / {{MV_BTN1_CLASS}}ボタン1。クラスは {{MV_BTN1_CLASS}} を使うbtn / btn inverse を直書きしない。管理画面で塗り/枠線を選べる)。
{{#HAS_BTN2}}…{{/HAS_BTN2}} / {{MV_BTN2_*}}ボタン2(同上。既定は btn inverse)。
{{#HAS_TEXT}}…{{/HAS_TEXT}}キャッチ・サブ・ボタンのどれかがある時(テキスト枠の空枠防止)。

差し込み口(トップレベル=主に動画タイプ)

差し込み口内容
{{#HAS_VIDEO}}…{{/HAS_VIDEO}} / {{MV_VIDEO}}動画がある時/動画URL(パソコン用)。
{{MV_VIDEO_SP}} / {{#HAS_VIDEO_SP}}スマホ用動画。<video> 内で {{#HAS_VIDEO_SP}}<source src="{{MV_VIDEO_SP}}" media="(max-width:800px)" type="video/mp4">{{/HAS_VIDEO_SP}} を、パソコン用 <source src="{{MV_VIDEO}}">に置く(media付きが先に一致)。
動画用テキスト{{{MV_CATCH}}} / {{{MV_SUB}}} / {{MV_TEXT_CLASS}} / {{#HAS_BTN1}}… がトップレベルにも入る。
{{#HAS_IMAGES}}…{{/HAS_IMAGES}}画像が1枚でもある時({{^HAS_IMAGES}} で「無い時」の代替も書ける)。
{{BASE}} / {{FRAME}}フレーム同梱アセットの参照用。例:<img src="{{BASE}}/frames/{{FRAME}}/images/bg1.svg">
{{ASSET_<key>}} / {{#HAS_ASSET_<key>}}お客さんが管理画面から差し替えるフレーム固有素材(第1部8章)。
3重/2重の使い分け。MV_CATCH / MV_SUB<br> 入りなので必ず3重カッコ {{{ }}}。ボタンの文字・URL(MV_BTN1_TEXT 等)は2重カッコ {{ }}でOKです。

変換のやり方(静的HTML → mainimg.html)

  1. 静的HTMLのメイン画像ブロック全体<div class="mainimg …"> 〜末尾)をコピー。
  2. 繰り返すスライドを1個に減らし{{#MV_IMAGES}} … {{/MV_IMAGES}} で囲む。imgN の数字は img{{n}} に。
  3. 画像を <picture>{{#HAS_SP}}<source media="(max-width:800px)" srcset="{{MV_SP}}">{{/HAS_SP}}<img src="{{url}}" alt=""></picture> に。元テンプレにスマホ用 srcset があれば {{MV_SP}} に置換(ブレークポイントは元のまま)。
  4. テキスト枠:位置クラスを {{MV_TEXT_CLASS}} に/見出しは {{#HAS_CATCH}}<h2>{{{MV_CATCH}}}</h2>{{/HAS_CATCH}}/説明は {{#HAS_SUB}}…{{{MV_SUB}}}…{{/HAS_SUB}}/ボタンは {{#HAS_BTN1}}…{{/HAS_BTN1}}。枠全体を {{#HAS_TEXT}} … {{/HAS_TEXT}} で囲む。
  5. .slide-indicatorsintro-horizontal 等の演出クラス・付随要素はそのまま残す
  6. 動画タイプは <video> のスライドを {{#HAS_VIDEO}} … {{/HAS_VIDEO}} で囲み、テキストはトップレベルの {{{MV_CATCH}}} 等で出す。
  7. 静止画タイプはスライド1枚想定。{{#MV_IMAGES}} を使い構造はそのままでOK。
ボタン内の用途固定アイコンは外す。電話・カレンダー・封筒などの用途固定アイコンは、文字をお客さんが入れ替えるので削除します。汎用装飾(矢印svg等)は残してOK。ボタンのクラスは {{MV_BTN1_CLASS}} / {{MV_BTN2_CLASS}}(値は btnbtn inverse の2種)に統一します。

雛形(静止画・static)

<div class="mainimg">
{{#MV_IMAGES}}
<div class="slide img{{n}}">
{{#HAS_TEXT}}<div class="text {{MV_TEXT_CLASS}}">
{{#HAS_CATCH}}<h2>{{{MV_CATCH}}}</h2>{{/HAS_CATCH}}
{{#HAS_SUB}}<p class="mb1rem">{{{MV_SUB}}}</p>{{/HAS_SUB}}
{{#HAS_BTN1}}<div class="btn-container">
<div class="{{MV_BTN1_CLASS}}"><a href="{{MV_BTN1_URL}}">{{MV_BTN1_TEXT}}</a></div>
{{#HAS_BTN2}}<div class="{{MV_BTN2_CLASS}}"><a href="{{MV_BTN2_URL}}">{{MV_BTN2_TEXT}}</a></div>{{/HAS_BTN2}}
</div>{{/HAS_BTN1}}
</div>{{/HAS_TEXT}}
<picture>{{#HAS_SP}}<source media="(max-width:800px)" srcset="{{MV_SP}}">{{/HAS_SP}}<img src="{{url}}" alt=""></picture>
</div>
{{/MV_IMAGES}}
</div>

スライドショーは上に <div class="slide-indicators"></div>{{/MV_IMAGES}} の直後に足し、動きは js/main.js に。共通の1メッセージ型(テキストを繰り返しの外に1つ・lp4)は frame.json"mainvisual_shared_text": true を入れます。

雛形(動画・video)

<div class="mainimg video-zone">
{{#HAS_VIDEO}}
<div class="slide img1">
{{#HAS_TEXT}}<div class="text {{MV_TEXT_CLASS}}">
{{#HAS_CATCH}}<h2>{{{MV_CATCH}}}</h2>{{/HAS_CATCH}}
{{#HAS_SUB}}<p class="mb1rem">{{{MV_SUB}}}</p>{{/HAS_SUB}}
</div>{{/HAS_TEXT}}
<video class="bgVideo" autoplay muted loop playsinline preload="metadata">
{{#HAS_VIDEO_SP}}<source src="{{MV_VIDEO_SP}}" media="(max-width:800px)" type="video/mp4">{{/HAS_VIDEO_SP}}
<source src="{{MV_VIDEO}}" type="video/mp4">
</video>
</div>
{{/HAS_VIDEO}}
</div>

実例:frame7 の mainimg.html

<div class="mainimg">
{{#MV_IMAGES}}
<div class="slide img{{n}}">
{{#HAS_TEXT}}
<div class="text {{MV_TEXT_CLASS}}">
<div class="text-bg">
{{#HAS_CATCH}}<h2>{{{MV_CATCH}}}</h2>{{/HAS_CATCH}}
{{#HAS_SUB}}<p>{{{MV_SUB}}}</p>{{/HAS_SUB}}
{{#HAS_BTN1}}
<div class="btn-container">
<div class="{{MV_BTN1_CLASS}}"><a href="{{MV_BTN1_URL}}">{{MV_BTN1_TEXT}}</a></div>
{{#HAS_BTN2}}<div class="{{MV_BTN2_CLASS}}"><a href="{{MV_BTN2_URL}}">{{MV_BTN2_TEXT}}</a></div>{{/HAS_BTN2}}
</div>
{{/HAS_BTN1}}
</div>
</div>
{{/HAS_TEXT}}
<picture>{{#HAS_SP}}<source media="(max-width:800px)" srcset="{{MV_SP}}">{{/HAS_SP}}<img src="{{url}}" alt=""></picture>
</div>
{{/MV_IMAGES}}
</div>
フレーム標準(フォールバック)画像・動画は命名規則で置くだけ。frame.json 記載も mainimg.html の変更も不要です。images/mainimgN.*mainimgN_s.*(スマホ用)、動画は movie.mp4.webmmovie_s.*。お客さん未設定の間だけ表示され、1枚でもアップされると全部オフになります(第1部8章)。

5. メイン画像テキストの作法

Frames CMS は「お客さんが管理画面で明示的に選んだ時だけ」位置・色を上書きする設計です。選ばなければフレームのCSSが標準になります。これが「フレームを切り替えたら、その配布フレームのサムネ通りに出る」を支えています。だから新フレームを作る時は、メイン画像テキストの標準をそのフレームのCSSに持たせるのが責務です。

位置クラス({{MV_TEXT_CLASS}}

お客さんの選択MV_TEXT_CLASS の値意味
おまかせ空(クラス無し)フレーム標準位置(フレームCSSに任せる)。
left left-parts左寄せ。
中央center center-parts中央寄せ(標準が左/右でも中央に強制できる)。
right right-parts右寄せ。

左/中央/右を効かせたいフレームは、対応する .left-parts / .center-parts / .right-parts のCSSをそのフレーム側で用意します(用意の無いクラスは無視=標準位置のまま=後方互換)。位置を動かしたくない土台固定フレームは、位置クラスを使わず frame.jsonmainvisual_align_lock: true にします。

位置・色・読みやすさはフレームのCSSが持つ

  • 標準の位置.mainimg .slide .text 相当の基本CSSで決める。切り替えさせたいなら上の3クラスも用意。
  • 標準の文字色・読みやすさ:写真の上で読めるよう、.text の基本CSSに色+影(必要ならスクリム)を持たせる。お客さん未選択でも読める状態にしておくのがフレームの責務。種データ(デモ文言)側で色や位置を固定しないこと。
  • 「白文字/濃い文字」の効き先:管理画面の文字色は .mainimg の中の h1〜h6p に効く(中間に .text 等のクラスは不要)。=キャッチの見出しは h1〜h6 どれでもよく、.text で囲っていなくても色は効く。ただしスライドショーだけは各スライドを .imgN で囲む(スライド別に色を変えるため)。
  • 小さい端末でテキストを画像の外へ「段落ち」させるフレームを作ったらframe.jsonmainvisual_text_overlay_media を書いてください(上の一覧参照)。お客さんが「白文字」を選ぶのは写真の上で読みづらいからであって、段落ちして白背景に出た文字まで白くしてよいわけではありません。このキーを書けば「重なっている間だけ」効き、外れたらフレーム本来の色に戻ります。

文字サイズ(大/中/小)

frame.jsonmainvisual_size_select: true を入れると(opt-in)、管理画面に「文字サイズ 大/中/小」プルダウンが出ます。選択値は .textmv-size-lg / mv-size-md / mv-size-sm クラスとして出力されるので、フレームの style.css でサイズを定義します(中=既定)。

.mainimg .text.mv-size-lg h2{ font-size: … }
.mainimg .text.mv-size-md h2{ font-size: … }  /* 既定 */
.mainimg .text.mv-size-sm h2{ font-size: … }

参考として siyou 系フレームの基準値(キャッチ h2 /サブ p)は、小=max(15px,3vw) / .85rem、中=max(18px,3.6vw) / .95rem、大=max(22px,4.6vw) / 1.05rem です。フレームごとに基準サイズが違うので、実物をプレビューしながら調整してください。CSS未定義のままtrueにしても壊れませんが効きません。文字なしフレームや固定サイズで良いフレームは付けません(=効かない選択肢を出さない)。

ロック系フラグの使い分け

フラグ効果使う場面
mainvisual_align_lockテキスト位置を固定(位置プルダウンを隠す・位置クラスを付けない)。文字色は残る。背景SVG等で土台が固定のフレーム。
mainvisual_text_hideテキスト・ボタンを一切出さない(入力欄も丸ごと隠す)。ロゴだけ中央配置するフレーム等。
mainvisual_no_buttonボタンだけ非表示。キャッチ/サブは出す。テキストだけ出すフレーム。
mainvisual_no_spスマホ用画像/動画の入力欄を隠す(機能は残る・UI整理)。SP別画像を使わないフレーム(例:portfolio1)。
mainvisual_text_overlay_media文字色の上書きを「画像に重なっている間だけ」に限定する。小さい端末でテキストを画像の外へ段落ちさせるフレーム(biz64-red / frame11 / lp4 / portfolio1 / portfolio2)。
これらのフラグで隠した値は hidden で温存されます。テキスト有りフレームに戻せば復活するので、着せ替えでデータが消えません。

6. メニューの型

メニューはデータ(menu_items)をエンジンの build_nav() が2階層の <ul> にして {{{NAV}}} 系に差し込みます。フレーム側は、どの「型」でメニューを出すかを layout.html の構造と frame.json で選びます。型は次の4つです。

① 単一メニュー型

メニューは #menubar 1つ(PC=横並び/スマホ=ドロワーをCSSで兼用)。layout.html{{{NAV}}} を1回置きます。項目ごとのPC/スマホ出し分けは、管理画面の show_pc/show_mobilehide-pc/hide-mobile クラスになり、共通CSSが出し分けます。例:frame7・biz64-red・kagu1・lp4。

② 2メニュー型

PCメニュー(header nav)とスマホメニュー(#menubar)を別HTML2つで持ちます(ヘッダーをスクロールでふわっと消す演出などのため)。layout.html{{{NAV_PC}}}(PC表示ONの項目だけ)と {{{NAV_MOBILE}}}(スマホ表示ONだけ)を置きます。CSSで隠すのではなく最初から振り分けて出す方式です。frame.jsonmenu_dropdowns(例 ["header nav"])・menu_hide_when_hidden: truemenu_breakpoint: 1000 を入れます。例:seikotsu1。

③ PC横メニュー+常時ハンバーガー型

PCで横メニューを出しつつ、ハンバーガー(≡)も常に出すタイプ(例:frame9-slide)。CMSの標準は「幅で横⇄ハンバーガーを切り替える」前提なので、3点セットで作ります。

  1. frame.json"menu_keep_hamburger": true(最重要)。これが無いと共通JSがPC幅でハンバーガーを display:none にします。
  2. menu_breakpoint通常値にする(9999にしない)。PC横メニューが @media で消える幅に合わせる(例:横メニューが max-width:800px で消えるなら 800)。
  3. ハンバーガー一式(#menubar_hdr#menubar ドロワー・オーバーレイ)のCSSを .small-screen 限定から外し、全画面で有効にする。

④ サイドメニュー型(2カラム)

frame.json"menu_sidebar": true。このときだけメニューの「見出し(リンクなし)」項目が有効になります(<li class="menu-heading"><span>…</span></li>)。1カラムに切り替えると見出しはデータを消さずに隠れます。例:frame3-c2。

横メニューを持つフレームに menu_breakpoint: 9999 を入れないこと。共通JSは「幅 ≥ breakPoint のときだけ hover 開閉」なので、9999だと常に小画面扱いになり、PCの横メニューのホバーが効かず“クリックでしか開かない”症状になります。9999 は「最初からハンバーガー専用」のフレーム(横メニューのCSSを持たないフレーム)用です。そのタイプは併せて menu_breakpoint_lock: true で幅を固定すると安全です。
メニュー切替幅はお客さんも管理画面で変更できますが、フレーム切替時はそのフレームの標準値(frame.json)にリセットされます。切替幅を触らせたくないフレームは menu_breakpoint_lock: true で固定できます。

7. テーマカラー(theme.css)

フレームの配色は css/theme.css:root でCSS変数として定義します。お客さんは管理画面(デザイン)で主要色を調整・リセットでき、エンジンが全CSSの後に <style>:root{…}</style> を注入して上書きします。

色はカラーコード直書きせず、必ずテーマ変数で書きます。直書きすると、お客さんの色変更やダーク系フレームで破綻します。#fff/#333 のベタ指定を見つけたら変数化が基本です。

自動文字色

背景色の輝度 (0.299R+0.587G+0.114B)/255 を計算し、>0.6 なら #333、それ以外は #fff を自動で文字色にします(contrast_text_color())。だから背景変数に対する「相方(文字色)変数」が自動で決まります。

色変数は「3点セット(対)」で揃っている=鉄則

全フレームの theme.css は、4つの「面(サーフェス)」それぞれに背景・文字・枠線の3変数が対で用意されています。変数名は全フレーム共通(値だけ違う)。

背景文字(相方)枠線
標準--bg-color--bg-inverse-color--bg-border-color
標準の反転(暗い面)--bg-inverse-color--bg-color--bg-inverse-border-color
メイン--primary-color--primary-inverse-color--primary-border-color
薄い--light-color--light-inverse-color--light-border-color
アクセント--accent-color--accent-inverse-color--accent-border-color
鉄則:背景色を自前で敷くなら、文字色も“同じ面の相方変数”で必ずセット指定する。片方だけ指定(もう片方は継承やベタ #fff/#333)は禁止です。セクションの背景クラスが文字色を継承で書き換えるため、対で固定しないと「背景は自前色・文字は継承色」になって同化して消えます。詳細な直し方は第3部(色・テーマ設計)で扱います。

--bg-border-color(各 theme.css に必須)

背景に対して見える枠線色です。明るいフレームは #ddd/#ccc 等、黒背景フレームは rgba(255,255,255,.5) 等の明色にします。共通CSS(フォーム枠・区切り線)が var(--bg-border-color) を使うので、黒背景フレームでもフォーム枠が埋もれません。新フレームを作る時は theme.css に背景に合った --bg-border-color を必ず入れてください。

ロゴの大きさも theme.css が持つ

ロゴ画像はお客さんが自分で持ち込む素材で、縦横比も余白の入り方も一枚ずつ違います。フレーム側に「正解の幅」を決めようがないので、幅を theme.css の変数にして、お客さんが管理画面から倍率で調整できるようにしています。

  • theme.css :root--logo-width(ロゴ画像の幅)と --logo-font-size(ロゴを画像でなく文字=サイト名で出す場合の大きさ)を置きます。トップだけ大きなロゴを出すフレーム(frame9系)は --logo-hero-width / --logo-hero-font-size も。
  • style.css は必ずこの形で書きます。
    header .logo img { width: calc(var(--logo-width) * var(--logo-scale, 1)); max-width: 85vw; }
    header .logo a { font-size: calc(var(--logo-font-size) * var(--logo-scale, 1)); }
  • --logo-scale(倍率)はCMS本体が出します。管理画面「サイト基本設定 → ロゴの大きさ」で選ばれたときだけ :root{--logo-scale:1.2}<head> 末尾に出ます。未選択なら何も出ないので var() の既定値 1 が効き、フレーム本来の大きさになります。=フレーム側は既定値を theme.css に書くだけでよく、倍率のことは考えなくて構いません。
  • width を px で直書きしない。直書きすると管理画面の「ロゴの大きさ」が効かないフレームになり、お客さんから見ると不具合になります。
  • max-width: 85vw を省かない。ロゴ幅は px の固定値で画面幅に追従しません。320px幅の端末では width:200px でも画面の62%を占めるため、お客さんが「大きめ」を選ぶとはみ出します。
--logo-width(基準)と --logo-scale(倍率)は掛け算
別の変数なので競合しません。管理画面の「このフレームのCSSを直接編集する」で :root{--logo-width:300px} にして、「サイト基本設定 → ロゴの大きさ」で「大きめ(120%)」を選ぶと 360px になります。どちらかが優先されて片方が無効になる、という関係ではありません。
出力順は 編集CSS → パレット5色 → --logo-scale なので、編集CSSに --logo-scale を直接書いても、プルダウンで「標準」以外を選んでいればそちらが後勝ちします。
編集CSSで header .logo img{width:250px} のように幅を直書きした場合だけ、calc() ごと上書きされて倍率が効かなくなります。

8. フレーム同梱アセット

「そのフレームでだけ使い、お客さんが管理画面から差し替える」素材(biz64 の背景飾り・lp4 のメイン画像内の画像など)の仕組みです。

お客さんが差し替えられる素材枠(assets)

frame.jsonassets で枠を宣言すると(第1部3章)、管理画面(デザイン→「このフレーム専用の素材」)にアップ欄が出ます。layout.html / mainimg.html の両方で使えます。

差し込み口意味
{{ASSET_<key>}}差し替え画像→無ければ default のURL(どちらも無ければ空)。
{{#HAS_ASSET_<key>}}表示できる画像がある(差し替え or default)。<img> の出し分けに使う。
{{#CUSTOM_ASSET_<key>}}お客さんが差し替えたときだけ真。CSS背景の上書き等「入れたときだけ効かせたい」用途。

値は設定キー frame_assets:<frameKey> にフレーム別保存され、別フレームに切替えると使われず・戻れば復活します(削除もされない)。ホーム限定の装飾には {{BODY_CLASS}}home / page-<slug>)も使えます。

実例:biz64-red の背景飾り(layout.html の head 内)

{{#IS_HOME}}{{#CUSTOM_ASSET_bg_decor}}<style>body.home{background-image:url('{{ASSET_bg_decor}}');}</style>{{/CUSTOM_ASSET_bg_decor}}{{/IS_HOME}}

お客さんが差し替えた時だけ背景を上書きし、未差し替え時はフレーム同梱の defaultimages/bg1.png)が使われます。

メイン画像のフォールバック(命名規則で自動検出)

お客さんがメイン画像/動画を1枚も入れていない時だけ、フレーム同梱の素材を表示します(無料版で各フレームの個性を出すため)。JSON宣言は不要・命名規則だけです。

種類置き方
画像images/mainimgN.*(PC)+ mainimgN_s.*(スマホ用・任意)。slideshow なら N=1,2,3… を順に、それ以外は先頭1枚。
動画images/movie.mp4(または .webm)+ movie_s.*(スマホ用・任意)。mp4/webm のみ検出movie.jpg 等はポスター画像でも動画ソースにならない)。
オール・オア・ナッシング。お客さんが画像を1枚でもアップした瞬間、フォールバックは全部オフになり、お客さんのスライドだけ表示されます(追加/削除で番号がズレても破綻しない安全設計)。mainimg.html は通常どおり {{#MV_IMAGES}}{{MV_VIDEO}} を書いておけば、フォールバック画像もそこに流れて表示されます。

9. フレーム完成チェックリスト

納品前に次を確認してください。

観点チェック
必須ファイルlayout.html / mainimg.html / frame.json / css/theme.css / css/style.css が揃っている(mainimg.html は静止画フレームも同梱)。
差し込み口の位置{{{HEAD_CSS}}}</head> 直前、{{{SCRIPTS}}}</body> 直前。ランドマーク(#menubar#menubar_hdr#menubar-overlay.pagetop)が残っている。
ロゴ「ロゴの形」どおり(画像 or サイト名テキストのフォールバック)。
メイン画像テキストMV_CATCH/MV_SUB は3重カッコ、ボタンは2重カッコ。ボタンクラスは {{MV_BTN1_CLASS}}/{{MV_BTN2_CLASS}}(直書きしない)。テキスト枠は {{#HAS_TEXT}} で囲む。用途固定アイコンは外した。
位置・色・サイズ使う位置クラス(.left/.center/.right-parts)のCSSがある。標準文字色+影で未選択でも読める。mainvisual_size_select を付けたなら mv-size-* のCSSがある。
メニュー型に合った layout 構造と frame.jsonmenu_breakpoint 等)。横メニューに 9999 を入れていない。
カラーコード直書きが無く、テーマ変数(3点セット)で書いている。--bg-border-colortheme.css に入れた。
JSON妥当性frame.json が壊れていない(python3 -m json.tool frame.json でエラーが出ない)。
JS構文js/main.jsnode --check js/main.js でエラー無し。
プレースホルダ残り出力に {{ }} がそのまま残っていない(残っていれば綴りミス)。
配布物の掃除frames/<id>/ に作業用・テンポラリファイルが残っていない。

第2部 パーツ編

パーツは、お客さんが本文(ページ)に積んでいく部品です。制作者は、パーツの「入力欄の定義」と「描画テンプレ」を用意します。フレームと同じく、ここでも PHP は書きません。

1. パーツとは/part.json + template.html

パーツは parts/<name>/ に2ファイル(+任意でサムネ画像1枚)で作ります。

ファイル役割
part.jsonパーツの定義。タイトル・カテゴリ・並び順と、管理画面に出す入力欄(fields)を宣言する。
template.html描画テンプレ。入力値を差し込んで公開HTMLを組み立てる。
thumb.webp
(任意)
パーツピッカー(「+パーツを追加」→「サムネから選ぶ」、着せ替えの「サムネで選ぶ」)に出る見本画像。フレームの thumb.webp とまったく同じ流儀で、パーツフォルダに1枚置くだけで自動参照されます。動きを見せたいパーツは thumb.mp4(自動ループ・音なし。mp4があればそちらが優先)。置かない場合は頭文字だけのプレースホルダになります。
フォルダを置けば即・選択肢に出ます。エンジンが parts/*/part.json を動的スキャンするので、フォルダを置けば追加・消せば消える(再ビルド不要)。statuspublic 以外(hidden 等)はパーツピッカーに出ません。

template.html の基本形

どのパーツも、次の形が土台です。{{{SECTION_ATTR}}}(背景色・アンカーID)と {{{HEAD}}}(共通の見出し・本文)を必ず置き、その中にパーツ固有のHTMLを書きます(共通部分の詳細は第2部4章)。

<section{{{SECTION_ATTR}}}>
{{{HEAD}}}
  …パーツ固有のHTML…
</section>

実例:cta(誘導ボックス)

text/textarea/link/icon の基本型がそろった小さなパーツ(デモ/parts/cta)です。

// part.json
{
  "title": "CTA(誘導ボックス)",
  "category": "CTA・誘導",
  "sort": 10,
  "fields": [
    { "key": "title",    "type": "text",     "label": "見出し" },
    { "key": "body",     "type": "textarea", "label": "本文" },
    { "key": "btn_text", "type": "text",     "label": "ボタンの文字" },
    { "key": "btn_url",  "type": "link",     "label": "ボタンのリンク先URL" },
    { "key": "btn_icon", "type": "icon",     "label": "ボタンのアイコン(任意・未選択ならメール)", "default": "ti ti-mail" }
  ]
}
<!-- template.html -->
<section{{{SECTION_ATTR}}}>
{{{HEAD}}}
<div class="ui-tools-cta1-parts inview">
{{#title}}<h3>{{title}}</h3>{{/title}}
{{#body}}<p>{{{body}}}</p>{{/body}}
{{#btn_text}}<p class="btn-parts"><a href="{{btn_url}}">{{#btn_icon}}<i class="{{btn_icon}}"></i> {{/btn_icon}}{{^btn_icon}}<i class="ti ti-mail"></i> {{/btn_icon}}{{btn_text}}</a></p>{{/btn_text}}
</div>
</section>

{{#title}}…{{/title}} のように、入力があるときだけ出す形が基本です。本文は <br> を活かすため {{{body}}}(3重)。アイコンは {{btn_icon}} をそのまま class に入れ、未選択時は {{^btn_icon}} で既定アイコンを出しています。

2. part.json のフィールド型一覧/repeater

fields に入力欄を並べます。1項目だけの入力fields行を繰り返す入力(カード一覧・ギャラリー等)は repeater を使います。型は通常フィールドでも repeater 行でも同じものが使えます。

フィールド型

用途 / 出力
text1行テキスト。{{key}}(エスケープあり)。
textarea複数行(本文)。改行→<br>かんたん記法変換。{{{key}}}(raw)。
linkリンク先URL欄。「サイト内ページから選ぶプルダウン+自由入力(外部URL/#アンカー)」の2本立て。保存値は page:<slug> か素のURL。描画時に現URLへ変換、削除済みページは空=リンク切れ防止javascript: 等は遮断。{{key}} に最終href。
selectプルダウン。options は文字列 or {value,label}両対応(値≠表示)。スタイル違いの吸収に使う。{{#key_値}} の真偽フラグも自動付与。
image画像アップ。{{key}}=ファイル名、{{key_url}}=URL。動画も入れられ、{{key_is_video}}<video>/<img> 分岐できる。
iconTablerアイコン選択(日本語パレット+全6000点検索)。値は ti ti-xxx<i class="{{key}}">(第2部7章)。
checklist1行=1項目 → <li> 群。行頭「×」で取り消し線(含まない項目)。料金表の特典用。
bullets1行=1項目 → <li> 群(×処理なし)。箇条書き用。
stars1〜5の選択 → 塗り星+空星(インラインSVG)。
embedURL/<iframe>貼付 → 安全なレスポンシブiframe。YouTube等をembedに変換、https のみ許可
toggleセグメント型ボタン(左寄せ/中央寄せ 等)。値はoptionのvalue。
swatch色見本付きボタン(背景色)。optionsに color を持たせる。
table| 区切りテキスト → 表を生成(先頭行/列を見出しにするか指定可)。多列テーブル用。

repeater(繰り返し行)

行を繰り返す入力は repeater で宣言します。key(配列名)・label(行の呼び名)・fields(行内の入力)を持ちます。テンプレでは {{#<key>}} … {{/<key>}} で繰り返し、中で行のキーが使えます。

管理画面での repeater 行は開閉式で、▲▼で並べ替えできます(保存順はDOM順=画面の並びどおり)。これはエンジンが自動で用意する挙動なので、制作者が作り込む必要はありません。行が閉じて見えても「データ欠落」ではありません(クリックで開く仕様)。

実例:list1(select スタイル + repeater)

// part.json(抜粋)
{
  "title": "カラムリスト(画像・見出し・本文)",
  "category": "リスト",
  "sort": 20,
  "fields": [
    { "key": "style", "type": "select", "label": "スタイル",
      "options": [
        { "value": "",             "label": "標準" },
        { "value": "-auto",        "label": "自動幅(横並び)" },
        { "value": "-border",      "label": "枠線つき" },
        { "value": "-shadow",      "label": "影つき" },
        { "value": "-auto-border", "label": "自動幅+枠線" }
      ] }
  ],
  "repeater": {
    "key": "rows", "label": "項目",
    "fields": [
      { "key": "image",    "type": "image",    "label": "画像" },
      { "key": "title",    "type": "text",     "label": "見出し" },
      { "key": "body",     "type": "textarea", "label": "本文" },
      { "key": "btn_text", "type": "text",     "label": "ボタンの文字(任意)" },
      { "key": "btn_url",  "type": "link",     "label": "ボタンのリンク先(任意)" }
    ]
  }
}
<!-- template.html -->
<section{{{SECTION_ATTR}}}>
{{{HEAD}}}
<div class="list1{{style}}-parts">
{{#rows}}
<div class="list-parts inview">
{{#image_url}}<figure><img src="{{image_url}}" alt=""></figure>{{/image_url}}
<div class="text-parts">
{{#title}}<h4>{{title}}</h4>{{/title}}
{{#body}}<p>{{{body}}}</p>{{/body}}
</div>
{{#btn_text}}<p class="btn-parts"><a href="{{btn_url}}">{{btn_text}}</a></p>{{/btn_text}}
</div>
{{/rows}}
</div>
</section>

select の値がそのまま list1{{style}}-parts のクラス名に乗る点に注目してください(-border なら list1-border-parts)。スタイル違いは別パーツにせず、select「スタイル」で吸収するのが原則です。

3. template.html の記法

基本の4記法は「差し込み口の共通ルール」で説明したとおりです。パーツで特に押さえるポイントは次のとおりです。

やりたいこと書き方
テキスト(1行){{key}}(エスケープ)。
本文(改行・かんたん記法を活かす){{{key}}}(3重)。
画像<img src="{{key_url}}">(URLは _url 付き)。
写真/動画の両対応{{#key_is_video}}<video …><source src="{{key_url}}"></video>{{/key_is_video}}{{^key_is_video}}<img src="{{key_url}}">{{/key_is_video}}
入力があるときだけ出す{{#key}} … {{/key}}(無いときの代替は {{^key}} … {{/key}})。
繰り返し(repeater){{#rows}} … {{/rows}}。中で行のキーを使う。
select のスタイル分岐クラスに乗せる(class="list1{{style}}-parts")/または {{#style_値}} … {{/style_値}} の自動フラグ。
inview クラスは、スクロールで要素が見えたときにふわっと表示する共通演出です。パーツの主要ブロックに付けておくと、他パーツと動きがそろいます(JSはエンジンが用意)。
出力に {{ }} がそのまま残っていないかを最後に確認してください(残っていればキー名の綴りミスです)。

4. 共通の見出し・背景・アンカー

全パーツに共通の入力欄がエンジンから自動で足されます(common_head_fields())。制作者はこれらを part.json に書く必要はありません。テンプレに {{{SECTION_ATTR}}}{{{HEAD}}} を置けば効きます。

キー役割 / 出力先
bgswatch背景色(なし/薄い色/標準色/メインカラー/アクセント)→ {{{SECTION_ATTR}}} に背景クラス。
h_texttextセクションの見出し。管理画面では常時表示。空欄なら {{{HEAD}}} に見出しは出ない。
h_levelselect見出しタイプ。h2 / h3 の2択・既定 h2(「なし」は廃止=見出しを出さない時は h_text を空に)。
h_aligntoggle見出しの寄せ(左/中央)。中央なら .c 付与。
h_decotext装飾テキスト(h2 のときだけ出る <span>)。
leadtextarea本文(見出しの下のリード文)。
lead_aligntoggle本文の寄せ(左/中央)。
anchortextアンカーID。{{{SECTION_ATTR}}}<section id="…"> を出力=ページ内リンク(#id)の着地点。LPのセクションジャンプ用。

これらは {{{HEAD}}}(見出し+本文のHTML)と {{{SECTION_ATTR}}}<section> の背景クラス+アンカーID)に展開されます。だからパーツのテンプレは、冒頭で必ずこの2つを置くのが基本形です(第2部1章)。

管理画面のUI(2026-07-12〜):これらのうち「セクションの見出し」だけを常時表示し、残り(背景色・見出しタイプ・寄せ・装飾・本文・アンカー)は既定で閉じた折りたたみ「セクションの背景色・見出しスタイル・説明文・ID」にまとめています。各パーツの主入力(repeater 等)が上に来て見つけやすくするためで、テンプレ側の書き方({{{HEAD}}}{{{SECTION_ATTR}}})は変わりません

5. パーツCSSの鉄則:色は「3点セット(対)」で揃える

これはパーツを作るうえで最も間違えやすいところです。第1部7章の3点セット(面ごとに背景・文字・枠線が対)を、パーツCSSでも必ず守ります。

共通見出しの「背景色」プルダウンは、セクションに背景クラスを付けます。各クラスは背景+文字(相方)を両方セットするので、中のパーツは何もしないとセクションの文字色を継承します。

お客さんの選択section に付くクラス
なし(クラス無し)
薄い色bg-parts bg1-light-parts
標準色bg-parts bg1-parts(暗い面)
メインカラーbg1-primary-parts
アクセントbg1-accent-parts
鉄則:パーツが自前で背景色を敷くなら、文字色も“同じ面の相方変数”で必ずセット指定する。片方だけ指定(もう片方は継承やベタ #fff/#333)は禁止です。対で固定しないと、色背景セクションで「背景は自前色・文字は継承色」になって同化して消えます

直し方の2つの型

  1. 塗りのあるカード型=背景と文字を対で固定:background: var(--light-color); color: var(--light-inverse-color);
  2. 枠線だけ・塗りなしのアウトライン型background: transparent; + 文字色は指定せず継承 + 枠線や装飾は currentColor(=今の文字色)にする。これで背景に応じて自動反転し常に見える。
ダーク系フレーム注意。フレームには明暗が逆のもの(--bg-color が暗色)があります。「白背景・黒文字」と決め打ちでカラーコードを直書きしないこと。上の対変数(または currentColor)で書けば、明るいフレームでもダーク系でも自動で正しくなります。
白/淡色カードで文字色未指定のパーツを作ったら要注意。色背景セクションに置くと文字が消えます。カードに color: var(--bg-inverse-color) を固定して解消します(透明カードは不要)。

6. カテゴリ/sort/CSS・JSの置き場所

項目説明
categoryパーツピッカーの2段階(カテゴリ→パーツ)の分類。既存カテゴリ例:基本/リスト/表・料金/ステップ・流れ/CTA・誘導/ギャラリー/埋め込み/レイアウト/装飾・効果。
sort同カテゴリ内の並び順(小さいほど先)。
statuspublic でピッカーに表示。それ以外は非表示(旧パーツの温存等)。
title / descriptionピッカーの表示名・説明。

CSS・JS の置き場所

パーツのCSS/JSは assets/parts/ に置くと自動読込されます(parts-*.css / parts-*.js)。配布元パーツをCMS化するときは、そのカテゴリのCSS/JSをここにコピーします。パーツ個別フォルダにCSSを置くのではなく、カテゴリ単位の共有ファイルにまとめるのが流儀です。

cms-extra.css は最後に読まれる上書き層です。配布CSSで未カバーの最小要素や、白カードの文字色固定など「全パーツ共通で効かせたい微調整」はここに足します(フレームCSSの後に読まれるので上書きできる)。

7. アイコン(Tabler)

アイコンは Tabler Icons(MIT・商用/再配布OK)に一本化されています。配布元(Template Party)の静的パーツは Font Awesome 前提のことが多いので、CMSに取り込むときは必ず変換します。

基本

  • アイコンの値は ti ti-xxx 形式。テンプレは <i class="{{key}}"></i>、直書きなら <i class="ti ti-phone"></i>
  • part.json"type":"icon"defaultti ti-xxx 形式。
  • 実在チェック:使う名前が同梱CSSに在るか必ず確認する(在らない名前は空白になる)。
    grep '\.ti-yyy{' assets/vendor/tabler-icons/tabler-icons.min.css/名前は tabler.io/icons で確認。

配布パーツのFA→Tabler変換

元(Font Awesome)変換後(Tabler)
<i class="fa-solid fa-xxx">fas/far/fab も)<i class="ti ti-yyy">(FA名→Tabler名に読み替え)
CSS疑似要素 ::before{ font-family:"Font Awesome…"; content:"\fXXX"; }SVGマスク方式へ(下記)
/* FA疑似要素 → SVGマスクへ変換 */
content:""; display:inline-block; width:1em; height:1em;
background-color:currentColor;
-webkit-mask:url("DATA") center/contain no-repeat;
        mask:url("DATA") center/contain no-repeat;
/* DATA は同梱CSSの該当アイコンの --ti:url("…") の中身をコピー */
アイコンを円ボックス化しているパーツの注意。<i> を円背景にして line-height で中央寄せする設計(特徴3列など)は、Tablerが ::before 描画なので中央がズレます。line-height:Xremheight:Xrem に変え、display:inline-flex; align-items:center; justify-content:center; にします。<i> 自身に mask を掛けないこと(円背景が消えます。アイコンは基底CSS .ti::before が描く)。

仕上げ確認

  • grep -rinE 'Font Awesome|fa-solid|fa-regular|fa-brands|"fa-' parts/<名> assets/parts/<該当>.cssFA痕跡ゼロ
  • 実機でアイコンの表示・大きさ・縦位置、色背景セクション上での見え方を確認。
  • 星評価は build_stars_html()(インラインSVG)を使う=webフォント不要。SNSアイコンは sns_services() の組み込み既定(ti ti-brand-*)が出どころ。

8. パーツの着せ替え(スキン化)=“同じ中身の別デザイン”

フレーム着せ替え(サイト全体のガワ差し替え)に加え、パーツ単位でも「入力した内容はそのまま、見た目だけ」を管理画面のプルダウンで切り替える仕組みがあります。自社デザインを、既存パーツの“別の見た目”として1つ足す——という使い方ができます。お客さんは「カラムで入れたけど、やっぱり自社デザインのカードにしたい」を、入力し直さずに切り替えられます。

着せ替えの設定は part.json(JSON)と template.html/CSS だけで完結します。PHP は一切書きません。エンジン(本体プログラム)は無改造のまま、フォルダを置くだけで機能します=サポート対象のまま作り込めます。

仕組みは2つのルールだけ

ルール内容
① 同じ family を宣言する着せ替えの仲間にしたいパーツの part.json に、同じ "family"(グループ名)を書く。エンジンが「同じ family のパーツ」を自動で集め、管理画面に「デザイン(見た目)」プルダウンを出す(制作者はUIを作らない)。
② 項目キー(key)を揃える仲間どうしで、共有したい項目の key を合わせる(カード系なら image / title / body)。キーが同じ項目だけが、着せ替え後もそのまま引き継がれる。

現在、標準の着せ替えグループは6つあります:

  • "family": "card-list"(9パーツ): list1(カラム)/ list-circle1(丸画像)/ list-catalog1(カタログ)/ list-yoko1(横並び)/ list-cource1(コース)/ list-auto2(自動スライド)/ list-staff1(スタッフ)/ ui-tools-free1(汎用レイアウト・配置選択)/ list-ranking1(ランキング)。核キー image/title/body
  • "family": "cta-section"(5パーツ): cta(誘導ボックス)/ ui-tools-cta4(背景写真つき)/ ui-tools-bg-image1(横長ビジュアル)/ list-yoko5(横長レイアウト)/ ui-tools-flex2(横幅いっぱいレイアウト)。核キー title/body/btn_text/btn_url(+任意 subtitle/btn_icon/image)。全員が単発ブロック(同じ形)なのでCTAとレイアウトのカテゴリを跨いで統合(flex2はボタン欄追加済み)。※ui-tools-cta2(ボタン横並び)・ui-tools-free1(汎用レイアウト)・effects-bg-slideup(パララックス背景=一度合流したが単独に戻した。ボタン追加・テキスト表示変更の改善は単独として維持)は非メンバー。
  • "family": "line-cta"(2パーツ): line-btn1(LINEボタン単体)/ line-cta1(QR+ボタン)。共有 btn_text/btn_url。LINE専用なので汎用CTAとは分離。
  • "family": "gallery"(4パーツ): gallery(複数画像)/ ui-tools-thumbnail-changer1(サムネ切替)/ list-yoko-scroll2(横スクロール)/ effects-slideimg(サムネ横スライド)。共有=リピーター rowsimage(+任意 caption/url/width)。写真/動画両対応(image_is_video 分岐)。画像1枚 image は単発なので非メンバー。
  • "family": "step-flow"(6パーツ): step(手順)/ ui-tools-step4(横4列アイコン)/ ui-tools-step3(縦・番号+画像)/ ui-tools-timeline1(沿革年表)/ list-icon1(特徴3列アイコン)/ list-schedule1(スケジュール)。共有=リピーター rowstitle/body(任意で icon/image/time/btn)。改名済み:step の text→body、timeline の year→title。視覚は各パーツ本来のまま(step4/icon1/schedule=icon/step3=image。別メディアなので統合せず切替時は保持)。
  • "family": "overlay"(2パーツ): effects-overlay1(画像リンク横並び)/ effects-overlay2(写真+テキスト+ボタン)。共有=リピーター rowsimage/title/subtitle/body(overlay1は+url、overlay2は+btn_text/btn_url/reverse)。両方リピーター型。

自社デザインを既存グループに加えるのが、いちばん簡単な着せ替え対応です(下記の作例はカード系ですが、CTA系なら核キーを title/body/btn_text/btn_url に合わせて "family": "cta-section" を付けるだけ)。

part.json の書き方(既存の list1 に family を1行足すだけ)

// part.json(抜粋)— ★の1行が着せ替えの宣言
{
  "title": "カラムリスト(画像・見出し・本文)",
  "category": "リスト",
  "sort": 20,
  "family": "card-list",          ← ★これを足すと着せ替えグループに入る
  "fields": [ /* … */ ],
  "repeater": {
    "key": "rows", "label": "項目",
    "fields": [
      { "key": "image", "type": "image",    "label": "画像" },
      { "key": "title", "type": "text",     "label": "見出し" },
      { "key": "body",  "type": "textarea", "label": "本文" }
      /* ↑この image / title / body が“共有キー”。仲間全員でこの3つを揃える */
    ]
  }
}
プルダウンは「同じ family の仲間が2つ以上あるとき」だけ出ます。そのインストールに1つしか無ければ出ません(無料版はカード系が1つなので出ない=製品版のアップセルにもなる)。仲間を parts/ に置いた数だけ自動で選択肢が増えます(再ビルド不要)。

データの温存(着せ替えの肝)

切り替え先のスキンに無い項目(例:スタッフの「役職」を、役職欄の無いカタログに切り替えたとき)は、画面から消えますがデータは保持されています。元のデザインに戻すと再表示されます。だから安心して行き来できます。これはメイン画像テキストの hidden 温存(第1部5章)と同じ考え方です。

つまり family は、仲間全員の項目を合わせたスーパーセット(総和)を器にします。各スキンは自分が使う項目だけをテンプレで描き、他は温存。そのパーツ固有の項目(スタッフの role など)は、キーが他と被らなければ自由に足してOKです(着せ替え時は保持され、そのデザインに戻すと出る)。任意項目は必ず {{#key}}…{{/key}} で囲み、空のとき出ないようにします。

最重要の注意:同じ key に“違う意味”を持たせないこと。仲間の中で同じキー名を使うなら、意味・使い方も合わせます。実際、着せ替え対応の下ごしらえで次の統一を行いました:
・スタッフの名前・コメントは、他が title / body なのに独自の name / comment だった → title / body に統一(ラベルは「名前」「コメント」のまま)。
・丸画像の「画像の形」は style というキーだったが、カラムの style(枠線/影の接尾辞)と意味が別物 → 丸画像を shape に改名
同名キーで意味が違うと、着せ替えた瞬間に相手のテンプレへ誤った値が流れて崩れます。「同じ意味=同じキー/違う意味=違うキー」を徹底してください。

新しい着せ替えグループを作る

カードとは別に、独自の着せ替えグループを作れます(例:バナー3種を相互に着せ替え)。仲間にしたいパーツへ別の名前の family(例 "family": "banner")を付け、そのグループ内で項目キーを揃えるだけです。family 名が違えば別グループ=互いに混ざりません。

作例:自社デザインのカードを card-list に加える

共有キー(image / title / body)で作れば、既存カード系との相互着せ替えに乗ります。

// parts/mycard1/part.json
{
  "title": "自社カード(オリジナル)",
  "category": "リスト",
  "sort": 50,
  "family": "card-list",
  "repeater": {
    "key": "rows", "label": "項目",
    "fields": [
      { "key": "image", "type": "image",    "label": "画像" },
      { "key": "title", "type": "text",     "label": "見出し" },
      { "key": "body",  "type": "textarea", "label": "本文" }
    ]
  }
}
<!-- parts/mycard1/template.html -->
<section{{{SECTION_ATTR}}}>
{{{HEAD}}}
<div class="mycard1-parts">
{{#rows}}
<div class="mycard1-item inview">
{{#image_url}}<div class="image-parts"><img src="{{image_url}}" alt=""></div>{{/image_url}}
{{#title}}<h4>{{title}}</h4>{{/title}}
{{#body}}<p>{{{body}}}</p>{{/body}}
</div>
{{/rows}}
</div>
</section>

あとは自社の見た目を assets/parts/parts-list.css(またはカテゴリ用の parts-*.css)に .mycard1-parts として書けば完成です。これを parts/ に置くと、カード系のプルダウンに「自社カード(オリジナル)」が自動で加わり、既存カードと相互に着せ替えできます。

画像の囲みは <div class="image-parts"> を標準に。従来の <figure> もCSSで等価に扱われますが、新規は image-parts で揃えると、仲間パーツ間でCSSが共通化しやすくなります。

着せ替え対応の手順(まとめ)

  1. 仲間にしたいパーツの part.json に、同じ "family" を書く。
  2. 共有したい項目の key を仲間で揃える(カード系なら image / title / body)。固有項目はキーが被らなければ自由。
  3. 同名キーに違う意味を持たせない(違う意味なら別キー名にする)。
  4. parts/ に置く → 管理画面に「デザイン(見た目)」プルダウンが自動で出る(仲間が2つ以上のとき)。

9. パーツ完成チェックリスト

観点チェック
2ファイルpart.json(定義)と template.html(描画)が揃っている。
基本形テンプレ冒頭に {{{SECTION_ATTR}}}{{{HEAD}}} がある。
エスケープ本文は {{{key}}}(3重)、テキスト・URLは {{key}}(2重)。
画像画像は {{key_url}}。動画対応は {{#key_is_video}} 分岐。
出し分け任意項目は {{#key}}…{{/key}} で囲む(空要素を出さない)。
スタイル違い別パーツにせず select「スタイル」で吸収。
着せ替え(任意)着せ替え対応にするなら family を宣言し、仲間と項目 keyimage/title/body…)を揃える。同名キーで意味を変えない(第2部8章)。
色(鉄則)背景を敷くなら文字色も相方変数でセット。#fff/#333 直書き無し。白/淡色カードは文字色固定。
アイコンti ti-xxx。FA痕跡ゼロ。使う名前は同梱CSSに実在。
CSS/JSassets/parts/ に置いて自動読込。
JSON妥当性python3 -m json.tool part.json でエラー無し。
プレースホルダ残り出力に {{ }} が残っていない。
配布物の掃除parts/<name>/ に作業用ファイルが残っていない。

第3部 色・テーマ設計

色は、フレームとパーツを横断する共通テーマです。第1部7章・第2部5章で触れた「テーマ変数」と「3点セット」を、ここで一枚にまとめます。ここを守れば、お客さんが色を変えても、フレームを差し替えても壊れません。

1. 仕組み:変数注入と自動文字色

色は設定キー theme_colors(JSON)に持ち、お客さんが管理画面(デザイン)で調整・リセットできます。エンジンが全CSSの後ろに <style>:root{ … }</style> を注入して色を上書きします。だからフレーム/パーツのCSSは、色をカラーコードではなく変数で書いておけば、注入された値に自動で追従します。

背景色に対する文字色は、輝度 (0.299R+0.587G+0.114B)/255>0.6 なら #333、それ以外は #fff が自動で選ばれます。この「相方の文字色」が各面の *-inverse-color 変数です。

2. 3点セット早見表

4つの「面」それぞれに、背景・文字・枠線の3変数が対で用意されています(変数名は全フレーム共通・値だけ違う)。

背景文字(相方)枠線
標準--bg-color--bg-inverse-color--bg-border-color
標準の反転(暗い面)--bg-inverse-color--bg-color--bg-inverse-border-color
メイン--primary-color--primary-inverse-color--primary-border-color
薄い--light-color--light-inverse-color--light-border-color
アクセント--accent-color--accent-inverse-color--accent-border-color

3. セクション背景クラスと「消える文字」

共通見出しの「背景色」プルダウンは、<section> に背景クラスを付け、背景色と文字色(相方)を両方セットします。中のパーツが何もしなければ、セクションの文字色を継承します。

選択section のクラス効く色
なし(無し)フレーム標準
薄い色bg-parts bg1-light-parts--light-color--light-inverse-color
標準色bg-parts bg1-parts--bg-inverse-color(暗い面)↔ --bg-color
メインカラーbg1-primary-parts--primary-color--primary-inverse-color
アクセントbg1-accent-parts--accent-color--accent-inverse-color
文字が消える原因はほぼこれ。パーツが自前で背景を敷いたのに文字色を継承のままにすると、色背景セクションで「自前の背景色 × セクションの文字色」になり同化します。背景を敷いたら文字も相方変数で必ずセットしてください。

4. 書き方の2つの型(再掲・保存版)

  1. 塗りカード型background: var(--light-color); color: var(--light-inverse-color); のように対で固定。ホバーで色を変えるなら、ホバー時も別の面の対(例 --accent-color--accent-inverse-color)で。
  2. アウトライン型(塗りなし)background: transparent; + 文字色は継承 + 枠線・装飾は currentColor。背景に応じて自動反転し、どの面でも見える。
ダーク系フレームがある前提で書く。明暗が逆のフレーム(--bg-color が暗色)でも正しくなるよう、#fff/#333 の決め打ちを避け、対変数か currentColor で書きます。

5. --bg-border-color を忘れない

各フレームの theme.css に、背景に対して見える枠線色 --bg-border-color を必ず入れます。明るいフレームは #ddd/#ccc黒背景フレームは rgba(255,255,255,.5) 等の明色。共通CSS(フォーム枠・区切り線)がこの変数を使うので、黒背景でも枠が埋もれません。


第4部 配布・同期

作ったフレーム・パーツは、最終的に購入者(ライセンスを持つ制作会社)が購入者ページからダウンロードして frames/parts/ に置き、クライアントのサイトへ設置(納品)します。配布フォルダに何を入れ、何を入れないかを正しく守ることが、この章の目的です。

1. 配布はドロップイン

追加のフレーム/パーツはドロップインで配ります。購入者は、ダウンロードしたフレームフォルダを frames/ に、パーツフォルダを parts/置くだけ(再ビルドもDB操作も不要)。エンジンが frames/*parts/*/part.json を動的に読むので、置けば増え、消せば消えます。

購入者ページ(マイページ)にログインできるのは、購入者(ライセンスを持つ制作会社)だけです。制作会社のクライアントはログインできません。フレーム・パーツは購入者がダウンロードし、クライアントのサイトへ設置(納品)します。

2. 配布フォルダにゴミを残さない

frames/parts/ は、購入者(制作会社)が購入者ページから直接ダウンロードする配布フォルダです。作業用・テンポラリファイル(メモ、旧版バックアップ、.DS_Store、未使用の実験ファイル等)を絶対に残さないでください。納品前に必ず中身を確認します。
  • 静的版 HTML のバックアップはフォルダ内に置かない(元の静的HTMLは別管理。間違えても戻せる)。
  • 標準クラスへ置換して使われなくなった -parts 系CSSは削除する(「フレームHTMLで使っていないクラスは他でも使わない」が前提)。ただし共有される可能性のあるものは残す判断もあるので、消す前に依頼元に確認。

3. 作業範囲を守る

  • 依頼が無い限り、担当ファイル以外は触らない(他フレーム・他パーツ・エンジン層)。
  • お客さんのデータ(data/uploads/)には触れない。
  • CSSを触るのは、標準クラス化に伴う追加・後始末など必要な範囲だけ。既存の見た目(色・形)はできるだけ元の雰囲気を保つ。

4. 製品版・無料版と納品

Frames CMS は1つのプログラムで無料版/製品版の両方に対応します(別ビルド不要)。守るべきは“本体”ではなく“売り物”=フレームとプレミアムパーツで、購入者ページからのダウンロードで配布制限します。

ふるまい
無料版管理画面に「無料版」表示、サイト下部に制作クレジット。見本フレーム数個+標準パーツに絞る(初心者が迷わない+アップセル動線)。
製品版有効なシリアルで解除。透かし・クレジットを消し、フッターにシリアルをHTMLコメントで埋める(流出時の照合用)。
制作者(web制作会社)としては、作った②の一式をドロップインで納品し、お客さんの運用データ(③)はそのまま引き継げる、と理解しておけば十分です。

付録 FAQ/つまずきポイント

よくあるつまずき

症状原因と対処
ロゴ・メニュー・本文が出ない差し込み口({{{NAV}}}{{{CONTENT}}} 等)を消した/改名した。元の名前に戻す。
パーツのCSSやアイコンが効かない{{{HEAD_CSS}}}</head> 直前に無い/{{{SCRIPTS}}}</body> 直前に無い。
キャッチに <br> が文字で出る2重カッコで出している。MV_CATCH/MV_SUB・本文は3重カッコ {{{ }}} に。
色背景セクションで文字が消える背景だけ自前指定で文字色が継承のまま。相方変数でセット(第3部)。
アイコンが表示されない(空白)Tablerに存在しない名前。grep '\.ti-名前{' …tabler-icons.min.css で実在確認。
PCで横メニューがホバーで開かないmenu_breakpoint9999 を入れている。横メニューを持つフレームは 1000 前後に(第1部6章)。
PCでハンバーガーが出ない(出したい)menu_keep_hamburger: true + ハンバーガーCSSの .small-screen 限定を外す(第1部6章③)。
フレームを替えたらメイン画像の文字が見えない種データで位置・色を固定していないか確認。標準はフレームCSS任せ(auto/標準)にする(第1部5章)。
管理画面で repeater の行が閉じている仕様(開閉式)。クリックで開く。データ欠落ではない。