From 480d4e2fbb1ba3c0e9077dc0c2132eaa4cef4648 Mon Sep 17 00:00:00 2001 From: "songtianyi.theo" Date: Tue, 23 Jun 2026 00:16:26 +0800 Subject: [PATCH] =?UTF-8?q?feat(svglide):=20=E5=AE=8C=E6=88=90=20beautiful?= =?UTF-8?q?=20=E6=A8=A1=E6=9D=BF=E7=9F=A5=E8=AF=86=E5=90=B8=E6=94=B6?= =?UTF-8?q?=E9=97=AD=E7=8E=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 补齐 34 个 beautiful-html-template family 的 cjk_policy、family_usage_policy、extension_grammar 和 cover/mid/late benchmark roles。 接入 matcher、planner、theme selector、preflight、quality gate 与 dry-run receipt,阻断跨 family 混用、CJK fake italic、未授权 recolor、source inventory claim escalation 等 M15 问题。 验证:M15 targeted 150 tests OK;full unittest discover 736 tests OK;dry-run internal-review / zhipu-minimax passed;json/schema ok;git diff --check OK。 --- .../beautiful-html-template-families.json | 5438 ++++++++++++++++- ...autiful-html-template-families.schema.json | 74 + .../beautiful-template-issue-codes.json | 11 + .../beautiful_template_asset_extractor.py | 243 +- .../scripts/beautiful_template_e2e_dry_run.py | 51 +- ...iful_template_knowledge_absorption_test.py | 345 ++ .../scripts/beautiful_template_matcher.py | 60 +- .../scripts/beautiful_template_runtime.py | 67 + skills/lark-slides/scripts/svg_preflight.py | 218 + .../scripts/svglide_prompt_planner.py | 11 + .../scripts/svglide_quality_gate.py | 30 + .../svglide_theme_template_selector.py | 10 + 12 files changed, 6422 insertions(+), 136 deletions(-) create mode 100644 skills/lark-slides/scripts/beautiful_template_knowledge_absorption_test.py diff --git a/skills/lark-slides/references/beautiful-html-template-families.json b/skills/lark-slides/references/beautiful-html-template-families.json index 64c1db876..c2758cbef 100644 --- a/skills/lark-slides/references/beautiful-html-template-families.json +++ b/skills/lark-slides/references/beautiful-html-template-families.json @@ -17,8 +17,8 @@ "source_template_html": "beautiful-html-templates/templates/8-bit-orbit/template.html", "source_screenshots": [ "beautiful-html-templates/screenshots/8-bit-orbit-1.png", - "beautiful-html-templates/screenshots/8-bit-orbit-5.png", - "beautiful-html-templates/screenshots/8-bit-orbit-6.png" + "beautiful-html-templates/screenshots/8-bit-orbit-6.png", + "beautiful-html-templates/screenshots/8-bit-orbit-5.png" ], "reference_screenshot": "beautiful-html-templates/screenshots/8-bit-orbit-1.png", "reference_svg": "", @@ -68,6 +68,113 @@ "mono": "system-mono" } }, + "cjk_policy": { + "strategy": "replace_family_whole_element", + "display_font_cn": "Noto Sans SC", + "body_font_cn": "Noto Sans SC", + "mono_font_policy": "latin_only_or_system_mono", + "runtime_font_policy": "system_font_only_no_remote_dependency", + "runtime_font_stack": [ + "system-sans-cjk", + "system-sans-cjk-heavy", + "system-sans-cjk-regular", + "system-mono" + ], + "emphasis_policy": "color_or_weight_only", + "italic_policy": "weight_only_emphasis", + "letter_spacing_policy": "reset_letter_spacing_for_cjk_keep_latin_labels", + "mixed_run_spacing": "pangu_spacing", + "latin_accent_policy": "latin_only_allowed_when_semantic_annotation", + "known_degradation": "**No CDN-loadable Chinese pixel font.** The system's arcade aesthetic depends on Tektur's semi-pixel grotesque character — there is no equivalent Chinese face on Google Fonts or major CDNs that reads as \"pixel-art\" while remaining legible. 思源黑体 at weight 900 gives heft but loses the pixel-grid signal entirely. The atmospheric overlays (scanlines, grain, vign", + "design_intent_font_pairing": [ + "Noto Sans SC" + ], + "source_section_heading": "CJK & International Content", + "source_section_sha256": "c4731914b1f8204c6fe1a29d38296893f22b3f441f8ab4e29d9deef0d6acafcc" + }, + "family_usage_policy": { + "closed_visual_system": true, + "cross_family_layout_mix_allowed": false, + "recolor_allowed": false, + "font_substitution_allowed": false, + "decorative_elements_policy": "identity_element_not_noise", + "extend_missing_layout_policy": { + "same_fonts": true, + "same_palette": true, + "same_spacing_rhythm": true, + "same_component_grammar": true, + "same_decorative_vocabulary": true, + "same_chrome": true + }, + "soft_matching_policy": { + "tone_first": true, + "occasion_is_soft_signal": true, + "avoid_for_is_soft_warning": true, + "taste_can_override_industry": true, + "formality_density_as_sanity_check": true + }, + "hard_rules": [ + "preserve_fonts_palette_grid_slide_classes_decorative_elements", + "do_not_recolor_without_explicit_brand_override", + "do_not_mix_template_families", + "extend_missing_layout_inside_same_family", + "do_not_strip_identity_decorations" + ], + "source": "beautiful-html-templates/AGENTS.md", + "source_sha256": "ed619bb7d956303024872f170b96e5270672a03cf40bdf7ce0abc3d8018c9d77" + }, + "extension_grammar": { + "layout_rhythm": "8-bit-orbit: medium density, low formality. Pixel-art neon arcade aesthetic on a deep navy void.", + "spacing_rhythm": "Reuse source spacing tokens and grid gaps: {\"pixel_unit\": \"4px\", \"pad_slide_y\": \"3vh\", \"pad_slide_x\": \"4vw\", \"pad_card_lg\": \"32px 40px\", \"pad_card_md\": \"28px\", \"pad_card_sm\": \"16px 20px\", \"gap_grid_lg\": \"32px\", \"gap_grid_md\": \"24px\", \"gap_grid_sm\": \"16px\", \"conte", + "component_grammar": [ + "stat-block", + "stat-label", + "stat-number", + "stats-grid" + ], + "chrome_rules": [ + "chart-bar-label", + "hbar-label", + "hero-badge", + "hero-badges", + "nav-dots", + "nav-hint", + "pixel-label", + "stat-label" + ], + "decorative_vocabulary": [ + "grid", + "accent line", + "card panels", + "paper texture", + "window chrome", + "poster blocks", + "quote mark", + "sticker collage", + "pixel motif" + ], + "allowed_new_layouts": [ + "comparison", + "risk", + "timeline", + "action_plan", + "case_evidence", + "metric_dashboard" + ], + "forbidden_mutations": [ + "new_palette", + "cross_family_components", + "fake_italic", + "new_decorative_motif", + "remote_font_dependency" + ], + "density_limits": "medium", + "source_basis": { + "template_id": "8-bit-orbit", + "design_signal_sha256": "eb35d1de6cef9496bb26db51614a9c63dcec0784df13dc8aed4caeaeec118323", + "class_name_count": 85 + } + }, "semantic_fit": { "best_for": [ "Anything that should feel like a CRT screen at 2am: cyberpunk", @@ -304,15 +411,60 @@ "screenshot_benchmarks": [ { "path": "beautiful-html-templates/screenshots/8-bit-orbit-1.png", - "role": "reference" - }, - { - "path": "beautiful-html-templates/screenshots/8-bit-orbit-5.png", - "role": "reference" + "role": "cover_reference", + "slide_number": 1, + "why_selected": "README gallery cover reference for 8-bit-orbit: Pixel-art neon arcade aesthetic on a deep navy void.", + "visual_targets": [ + "palette", + "type_scale", + "chrome", + "density", + "layout_balance", + "grid" + ], + "acceptance_use": [ + "matcher_thumbnail", + "visual_qa", + "few_shot_reference" + ] }, { "path": "beautiful-html-templates/screenshots/8-bit-orbit-6.png", - "role": "reference" + "role": "mid_deck_reference", + "slide_number": 6, + "why_selected": "README gallery mid deck reference for 8-bit-orbit: Pixel-art neon arcade aesthetic on a deep navy void.", + "visual_targets": [ + "palette", + "type_scale", + "chrome", + "density", + "layout_balance", + "grid" + ], + "acceptance_use": [ + "matcher_thumbnail", + "visual_qa", + "few_shot_reference" + ] + }, + { + "path": "beautiful-html-templates/screenshots/8-bit-orbit-5.png", + "role": "late_deck_reference", + "slide_number": 5, + "why_selected": "README gallery late deck reference for 8-bit-orbit: Pixel-art neon arcade aesthetic on a deep navy void.", + "visual_targets": [ + "palette", + "type_scale", + "chrome", + "density", + "layout_balance", + "grid" + ], + "acceptance_use": [ + "matcher_thumbnail", + "visual_qa", + "few_shot_reference" + ] } ], "density": "medium" @@ -1011,6 +1163,113 @@ "mono": "system-mono" } }, + "cjk_policy": { + "strategy": "replace_family_whole_element", + "display_font_cn": "Noto Serif SC", + "body_font_cn": "Noto Sans SC", + "mono_font_policy": "latin_only_or_system_mono", + "runtime_font_policy": "system_font_only_no_remote_dependency", + "runtime_font_stack": [ + "system-sans-cjk", + "system-sans-cjk-heavy", + "system-sans-cjk-regular", + "system-mono" + ], + "emphasis_policy": "color_or_weight_only", + "italic_policy": "drop_italic", + "letter_spacing_policy": "reset_letter_spacing_for_cjk_keep_latin_labels", + "mixed_run_spacing": "pangu_spacing", + "latin_accent_policy": "latin_only_allowed_when_semantic_annotation", + "known_degradation": "**No CDN-loadable Chinese monospace face for tabular data.** JetBrains Mono's role here (calendar ledger dates, chart year/value labels, page numbers) depends on monospaced figure rhythm that CJK doesn't provide. 思源黑体 at weight 500 with `font-feature-settings: \"tnum\"` gives tabular Latin digits but Chinese characters remain proportional. For ledger rows wher", + "design_intent_font_pairing": [ + "Noto Serif SC", + "Noto Sans SC" + ], + "source_section_heading": "CJK & International Content", + "source_section_sha256": "93047863328a207b36ba7a98bc89e0571816893492d6e78666d25a2732021cdb" + }, + "family_usage_policy": { + "closed_visual_system": true, + "cross_family_layout_mix_allowed": false, + "recolor_allowed": false, + "font_substitution_allowed": false, + "decorative_elements_policy": "identity_element_not_noise", + "extend_missing_layout_policy": { + "same_fonts": true, + "same_palette": true, + "same_spacing_rhythm": true, + "same_component_grammar": true, + "same_decorative_vocabulary": true, + "same_chrome": true + }, + "soft_matching_policy": { + "tone_first": true, + "occasion_is_soft_signal": true, + "avoid_for_is_soft_warning": true, + "taste_can_override_industry": true, + "formality_density_as_sanity_check": true + }, + "hard_rules": [ + "preserve_fonts_palette_grid_slide_classes_decorative_elements", + "do_not_recolor_without_explicit_brand_override", + "do_not_mix_template_families", + "extend_missing_layout_inside_same_family", + "do_not_strip_identity_decorations" + ], + "source": "beautiful-html-templates/AGENTS.md", + "source_sha256": "ed619bb7d956303024872f170b96e5270672a03cf40bdf7ce0abc3d8018c9d77" + }, + "extension_grammar": { + "layout_rhythm": "biennale-yellow: medium density, high formality. Solar yellow on warm parchment with deep indigo serif and atmospheric sun-glow gradients.", + "spacing_rhythm": "Reuse source spacing tokens and grid gaps: {\"pad_edge\": \"clamp(40px, 4vw, 76px)\", \"pad_region\": \"clamp(40px, 4.2vw, 80px)\", \"pad_foot\": \"clamp(56px, 5vh, 88px)\", \"pad_strand_y\": \"clamp(12px, 1.6vh, 22px)\", \"gap_region\": \"clamp(20px, 2.5vw, 48px)\", \"gap_strand\": \"", + "component_grammar": [ + "s-cal", + "s-chapter", + "s-colophon", + "s-cover", + "s-data", + "s-manifesto", + "s-programme", + "s-quote", + "stat" + ], + "chrome_rules": [ + "footer-row", + "nav-hint", + "pagenum" + ], + "decorative_vocabulary": [ + "grid", + "accent line", + "card panels", + "paper texture", + "window chrome", + "poster blocks", + "quote mark", + "sticker collage" + ], + "allowed_new_layouts": [ + "comparison", + "risk", + "timeline", + "action_plan", + "case_evidence", + "metric_dashboard" + ], + "forbidden_mutations": [ + "new_palette", + "cross_family_components", + "fake_italic", + "new_decorative_motif", + "remote_font_dependency" + ], + "density_limits": "medium", + "source_basis": { + "template_id": "biennale-yellow", + "design_signal_sha256": "d6c6d01ed5c12d642c6565d39c989db23e603ff279f08bbcde38b0a6d5545ea7", + "class_name_count": 77 + } + }, "semantic_fit": { "best_for": [ "Anything that should feel like an art-biennale poster or a museum's annual programme: exhibition decks", @@ -1231,15 +1490,60 @@ "screenshot_benchmarks": [ { "path": "beautiful-html-templates/screenshots/biennale-yellow-1.png", - "role": "reference" + "role": "cover_reference", + "slide_number": 1, + "why_selected": "README gallery cover reference for biennale-yellow: Solar yellow on warm parchment with deep indigo serif and atmospheric sun-glow gradients.", + "visual_targets": [ + "palette", + "type_scale", + "chrome", + "density", + "layout_balance", + "grid" + ], + "acceptance_use": [ + "matcher_thumbnail", + "visual_qa", + "few_shot_reference" + ] }, { "path": "beautiful-html-templates/screenshots/biennale-yellow-5.png", - "role": "reference" + "role": "mid_deck_reference", + "slide_number": 5, + "why_selected": "README gallery mid deck reference for biennale-yellow: Solar yellow on warm parchment with deep indigo serif and atmospheric sun-glow gradients.", + "visual_targets": [ + "palette", + "type_scale", + "chrome", + "density", + "layout_balance", + "grid" + ], + "acceptance_use": [ + "matcher_thumbnail", + "visual_qa", + "few_shot_reference" + ] }, { "path": "beautiful-html-templates/screenshots/biennale-yellow-8.png", - "role": "reference" + "role": "late_deck_reference", + "slide_number": 8, + "why_selected": "README gallery late deck reference for biennale-yellow: Solar yellow on warm parchment with deep indigo serif and atmospheric sun-glow gradients.", + "visual_targets": [ + "palette", + "type_scale", + "chrome", + "density", + "layout_balance", + "grid" + ], + "acceptance_use": [ + "matcher_thumbnail", + "visual_qa", + "few_shot_reference" + ] } ], "density": "medium" @@ -1938,6 +2242,114 @@ "mono": "system-mono" } }, + "cjk_policy": { + "strategy": "replace_family_whole_element", + "display_font_cn": "Noto Sans SC", + "body_font_cn": "Noto Sans SC", + "mono_font_policy": "latin_only_or_system_mono", + "runtime_font_policy": "system_font_only_no_remote_dependency", + "runtime_font_stack": [ + "system-sans-cjk", + "system-sans-cjk-heavy", + "system-sans-cjk-regular", + "system-mono" + ], + "emphasis_policy": "color_or_weight_only", + "italic_policy": "weight_only_emphasis", + "letter_spacing_policy": "reset_letter_spacing_for_cjk_keep_latin_labels", + "mixed_run_spacing": "pangu_spacing", + "latin_accent_policy": "latin_only_allowed_when_semantic_annotation", + "known_degradation": "**No CDN Chinese monospace face for the \"system readout\" voice.** Space Grotesk's quasi-mono role (label-pills, counters, mono-tags, slide counter NN / NN) depends on its slightly geometric character plus the wide-tracked uppercase treatment. Neither survives the CJK translation. The slide counter and chart legend can keep Latin digits + Latin labels intact;", + "design_intent_font_pairing": [ + "Noto Sans SC" + ], + "source_section_heading": "CJK & International Content", + "source_section_sha256": "aa1dd588702cea6dde1e11e9953428559e76a25fa0ff8ec8251df1c72ee00e58" + }, + "family_usage_policy": { + "closed_visual_system": true, + "cross_family_layout_mix_allowed": false, + "recolor_allowed": false, + "font_substitution_allowed": false, + "decorative_elements_policy": "identity_element_not_noise", + "extend_missing_layout_policy": { + "same_fonts": true, + "same_palette": true, + "same_spacing_rhythm": true, + "same_component_grammar": true, + "same_decorative_vocabulary": true, + "same_chrome": true + }, + "soft_matching_policy": { + "tone_first": true, + "occasion_is_soft_signal": true, + "avoid_for_is_soft_warning": true, + "taste_can_override_industry": true, + "formality_density_as_sanity_check": true + }, + "hard_rules": [ + "preserve_fonts_palette_grid_slide_classes_decorative_elements", + "do_not_recolor_without_explicit_brand_override", + "do_not_mix_template_families", + "extend_missing_layout_inside_same_family", + "do_not_strip_identity_decorations" + ], + "source": "beautiful-html-templates/AGENTS.md", + "source_sha256": "ed619bb7d956303024872f170b96e5270672a03cf40bdf7ce0abc3d8018c9d77" + }, + "extension_grammar": { + "layout_rhythm": "block-frame: high density, medium-low formality. Neobrutalist deck with pastel-neon color blocks and chunky black borders.", + "spacing_rhythm": "Reuse source spacing tokens and grid gaps: {\"slide_pad\": \"60px\", \"card_pad_lg\": \"60px\", \"card_pad_md\": \"36px\", \"card_pad_sm\": \"28px\", \"card_pad_xs\": \"22px\", \"gap_lg\": \"48px\", \"gap_md\": \"32px\", \"gap_sm\": \"24px\", \"gap_xs\": \"16px\", \"pad_bottom_clearance\": \"110px\"}", + "component_grammar": [ + "card-deco", + "cards-row", + "stat-card", + "stat-deco", + "stat-label", + "stat-number", + "stat-pill", + "stats-grid" + ], + "chrome_rules": [ + "data-label", + "hero-label", + "nav-btn", + "nav-controls", + "nb-label", + "nb-label-blue", + "nb-label-cream", + "nb-label-green" + ], + "decorative_vocabulary": [ + "grid", + "accent line", + "card panels", + "poster blocks", + "quote mark", + "sticker collage" + ], + "allowed_new_layouts": [ + "comparison", + "risk", + "timeline", + "action_plan", + "case_evidence", + "metric_dashboard" + ], + "forbidden_mutations": [ + "new_palette", + "cross_family_components", + "fake_italic", + "new_decorative_motif", + "remote_font_dependency" + ], + "density_limits": "high", + "source_basis": { + "template_id": "block-frame", + "design_signal_sha256": "8fb4f600625bad9add1bad74786ef9fad4c5f1068b28e46590d168ebdab6a543", + "class_name_count": 97 + } + }, "semantic_fit": { "best_for": [ "Anything that should feel pop-graphic and design-led: indie SaaS launches", @@ -2183,15 +2595,60 @@ "screenshot_benchmarks": [ { "path": "beautiful-html-templates/screenshots/block-frame-1.png", - "role": "reference" + "role": "cover_reference", + "slide_number": 1, + "why_selected": "README gallery cover reference for block-frame: Neobrutalist deck with pastel-neon color blocks and chunky black borders.", + "visual_targets": [ + "palette", + "type_scale", + "chrome", + "density", + "layout_balance", + "grid" + ], + "acceptance_use": [ + "matcher_thumbnail", + "visual_qa", + "few_shot_reference" + ] }, { "path": "beautiful-html-templates/screenshots/block-frame-4.png", - "role": "reference" + "role": "mid_deck_reference", + "slide_number": 4, + "why_selected": "README gallery mid deck reference for block-frame: Neobrutalist deck with pastel-neon color blocks and chunky black borders.", + "visual_targets": [ + "palette", + "type_scale", + "chrome", + "density", + "layout_balance", + "grid" + ], + "acceptance_use": [ + "matcher_thumbnail", + "visual_qa", + "few_shot_reference" + ] }, { "path": "beautiful-html-templates/screenshots/block-frame-8.png", - "role": "reference" + "role": "late_deck_reference", + "slide_number": 8, + "why_selected": "README gallery late deck reference for block-frame: Neobrutalist deck with pastel-neon color blocks and chunky black borders.", + "visual_targets": [ + "palette", + "type_scale", + "chrome", + "density", + "layout_balance", + "grid" + ], + "acceptance_use": [ + "matcher_thumbnail", + "visual_qa", + "few_shot_reference" + ] } ], "density": "high" @@ -2927,6 +3384,114 @@ "mono": "system-mono" } }, + "cjk_policy": { + "strategy": "replace_family_whole_element", + "display_font_cn": "Noto Sans SC", + "body_font_cn": "Noto Serif SC", + "mono_font_policy": "latin_only_or_system_mono", + "runtime_font_policy": "system_font_only_no_remote_dependency", + "runtime_font_stack": [ + "system-sans-cjk", + "system-sans-cjk-heavy", + "system-sans-cjk-regular", + "system-mono" + ], + "emphasis_policy": "color_or_weight_only", + "italic_policy": "color_only_emphasis", + "letter_spacing_policy": "reset_letter_spacing_for_cjk_keep_latin_labels", + "mixed_run_spacing": "pangu_spacing", + "latin_accent_policy": "latin_only_allowed_when_semantic_annotation", + "known_degradation": "**No CDN Chinese face matches Space Grotesk's \"trustworthy consulting\" register exactly.** 思源黑体 reads as more institutional and slightly less contemporary than Space Grotesk. The template will feel slightly more \"official report\" and slightly less \"AI startup\" than its Latin original. This is generally desirable for executive-briefing contexts in Chinese.", + "design_intent_font_pairing": [ + "Noto Sans SC", + "Noto Serif SC" + ], + "source_section_heading": "CJK & International Content", + "source_section_sha256": "4b0c6603213f2b649b6a1bbd1ec0a939b1b5a369e75e68f63660b3d040772e04" + }, + "family_usage_policy": { + "closed_visual_system": true, + "cross_family_layout_mix_allowed": false, + "recolor_allowed": false, + "font_substitution_allowed": false, + "decorative_elements_policy": "identity_element_not_noise", + "extend_missing_layout_policy": { + "same_fonts": true, + "same_palette": true, + "same_spacing_rhythm": true, + "same_component_grammar": true, + "same_decorative_vocabulary": true, + "same_chrome": true + }, + "soft_matching_policy": { + "tone_first": true, + "occasion_is_soft_signal": true, + "avoid_for_is_soft_warning": true, + "taste_can_override_industry": true, + "formality_density_as_sanity_check": true + }, + "hard_rules": [ + "preserve_fonts_palette_grid_slide_classes_decorative_elements", + "do_not_recolor_without_explicit_brand_override", + "do_not_mix_template_families", + "extend_missing_layout_inside_same_family", + "do_not_strip_identity_decorations" + ], + "source": "beautiful-html-templates/AGENTS.md", + "source_sha256": "ed619bb7d956303024872f170b96e5270672a03cf40bdf7ce0abc3d8018c9d77" + }, + "extension_grammar": { + "layout_rhythm": "blue-professional: medium density, medium-high formality. Cream paper background with electric cobalt blue accents; clean modern professional.", + "spacing_rhythm": "Reuse source spacing tokens and grid gaps: {\"pad_slide_x\": \"4vw\", \"pad_slide_y_top\": \"3.5vw\", \"pad_slide_y_bottom\": \"8.5vh\", \"pad_card_lg\": \"1.5rem 1.6rem\", \"pad_card_md\": \"1.4rem 1.5rem\", \"pad_card_sm\": \"1rem 1.2rem\", \"pad_mini\": \"0.9rem 1rem\", \"gap_grid_lg\": \"3", + "component_grammar": [ + "agenda", + "bars", + "closing", + "cover", + "dashboard", + "detail", + "metrics", + "quote", + "split", + "stat-cell" + ], + "chrome_rules": [ + "bar-label", + "metric-label", + "mini-label", + "nav-btn", + "nav-controls" + ], + "decorative_vocabulary": [ + "grid", + "accent line", + "card panels", + "paper texture", + "poster blocks", + "quote mark" + ], + "allowed_new_layouts": [ + "comparison", + "risk", + "timeline", + "action_plan", + "case_evidence", + "metric_dashboard" + ], + "forbidden_mutations": [ + "new_palette", + "cross_family_components", + "fake_italic", + "new_decorative_motif", + "remote_font_dependency" + ], + "density_limits": "medium", + "source_basis": { + "template_id": "blue-professional", + "design_signal_sha256": "327be8c83b43291f46719a8a33d903e6274f29e2c3bf8eec43706929d22c13ac", + "class_name_count": 78 + } + }, "semantic_fit": { "best_for": [ "Anything that should feel modern-considered and lightly authoritative: B2B SaaS pitches", @@ -3162,15 +3727,60 @@ "screenshot_benchmarks": [ { "path": "beautiful-html-templates/screenshots/blue-professional-1.png", - "role": "reference" + "role": "cover_reference", + "slide_number": 1, + "why_selected": "README gallery cover reference for blue-professional: Cream paper background with electric cobalt blue accents; clean modern professional.", + "visual_targets": [ + "palette", + "type_scale", + "chrome", + "density", + "layout_balance", + "grid" + ], + "acceptance_use": [ + "matcher_thumbnail", + "visual_qa", + "few_shot_reference" + ] }, { "path": "beautiful-html-templates/screenshots/blue-professional-6.png", - "role": "reference" + "role": "mid_deck_reference", + "slide_number": 6, + "why_selected": "README gallery mid deck reference for blue-professional: Cream paper background with electric cobalt blue accents; clean modern professional.", + "visual_targets": [ + "palette", + "type_scale", + "chrome", + "density", + "layout_balance", + "grid" + ], + "acceptance_use": [ + "matcher_thumbnail", + "visual_qa", + "few_shot_reference" + ] }, { "path": "beautiful-html-templates/screenshots/blue-professional-8.png", - "role": "reference" + "role": "late_deck_reference", + "slide_number": 8, + "why_selected": "README gallery late deck reference for blue-professional: Cream paper background with electric cobalt blue accents; clean modern professional.", + "visual_targets": [ + "palette", + "type_scale", + "chrome", + "density", + "layout_balance", + "grid" + ], + "acceptance_use": [ + "matcher_thumbnail", + "visual_qa", + "few_shot_reference" + ] } ], "density": "medium" @@ -3806,6 +4416,112 @@ "mono": "system-mono" } }, + "cjk_policy": { + "strategy": "replace_family_whole_element", + "display_font_cn": "Noto Serif SC", + "body_font_cn": "Noto Sans SC", + "mono_font_policy": "latin_only_or_system_mono", + "runtime_font_policy": "system_font_only_no_remote_dependency", + "runtime_font_stack": [ + "system-sans-cjk", + "system-sans-cjk-heavy", + "system-sans-cjk-regular", + "system-mono" + ], + "emphasis_policy": "color_or_weight_only", + "italic_policy": "color_only_emphasis", + "letter_spacing_policy": "reset_letter_spacing_for_cjk_keep_latin_labels", + "mixed_run_spacing": "pangu_spacing", + "latin_accent_policy": "latin_only_allowed_when_semantic_annotation", + "known_degradation": "**No exact online CJK match for Shrikhand's slab-script personality.** The face is Italian-sports-magazine display script with chunky terminals and playful italic forms — there is no Chinese equivalent on Google Fonts, Adobe Fonts, or cn-fontsource. 思源宋体 weight 900 gives heft and editorial register but reads as serious rather than playful. The rotation trans", + "design_intent_font_pairing": [ + "Noto Serif SC", + "Noto Sans SC", + "LXGW WenKai instead of", + "霞鹜文楷 LXGW WenKai instead of 思源宋体 — it carries a hand-written/calligraphic warmth" + ], + "source_section_heading": "CJK & International Content", + "source_section_sha256": "58cbd747240576ccd14e126cf39e2b15b3112e8ad7feeb4daf0ca536ba3b6ff4" + }, + "family_usage_policy": { + "closed_visual_system": true, + "cross_family_layout_mix_allowed": false, + "recolor_allowed": false, + "font_substitution_allowed": false, + "decorative_elements_policy": "identity_element_not_noise", + "extend_missing_layout_policy": { + "same_fonts": true, + "same_palette": true, + "same_spacing_rhythm": true, + "same_component_grammar": true, + "same_decorative_vocabulary": true, + "same_chrome": true + }, + "soft_matching_policy": { + "tone_first": true, + "occasion_is_soft_signal": true, + "avoid_for_is_soft_warning": true, + "taste_can_override_industry": true, + "formality_density_as_sanity_check": true + }, + "hard_rules": [ + "preserve_fonts_palette_grid_slide_classes_decorative_elements", + "do_not_recolor_without_explicit_brand_override", + "do_not_mix_template_families", + "extend_missing_layout_inside_same_family", + "do_not_strip_identity_decorations" + ], + "source": "beautiful-html-templates/AGENTS.md", + "source_sha256": "ed619bb7d956303024872f170b96e5270672a03cf40bdf7ce0abc3d8018c9d77" + }, + "extension_grammar": { + "layout_rhythm": "bold-poster: low density, medium formality. Editorial poster aesthetic with massive Shrikhand display and a single fire-engine red accent.", + "spacing_rhythm": "Reuse source spacing tokens and grid gaps: {\"pad_slide\": \"48px 56px\", \"pad_cell\": \"22px 20px\", \"pad_cell_sm\": \"20px 24px\", \"pad_pillar\": \"32px 24px\", \"pad_card\": \"24px\", \"pad_roadmap\": \"40px 48px\", \"gap_grid_md\": \"24px 32px\", \"gap_grid_roadmap\": \"28px 36px\", \"gap", + "component_grammar": [ + "stat-big", + "stat-context", + "stat-item", + "stat-row" + ], + "chrome_rules": [ + "fc-label", + "gc-label", + "hl-label", + "rm-label", + "si-label", + "tag-label" + ], + "decorative_vocabulary": [ + "grid", + "accent line", + "card panels", + "paper texture", + "poster blocks", + "quote mark", + "sticker collage" + ], + "allowed_new_layouts": [ + "comparison", + "risk", + "timeline", + "action_plan", + "case_evidence", + "metric_dashboard" + ], + "forbidden_mutations": [ + "new_palette", + "cross_family_components", + "fake_italic", + "new_decorative_motif", + "remote_font_dependency" + ], + "density_limits": "low", + "source_basis": { + "template_id": "bold-poster", + "design_signal_sha256": "9e35cd2eec4fb7fa43a8a3b0e9a00f9a332c9eec743de4e803b16f2fe0c606e4", + "class_name_count": 76 + } + }, "semantic_fit": { "best_for": [ "Anything that should land like a magazine cover: brand manifestos", @@ -4015,15 +4731,60 @@ "screenshot_benchmarks": [ { "path": "beautiful-html-templates/screenshots/bold-poster-1.png", - "role": "reference" + "role": "cover_reference", + "slide_number": 1, + "why_selected": "README gallery cover reference for bold-poster: Editorial poster aesthetic with massive Shrikhand display and a single fire-engine red accent.", + "visual_targets": [ + "palette", + "type_scale", + "chrome", + "density", + "layout_balance", + "grid" + ], + "acceptance_use": [ + "matcher_thumbnail", + "visual_qa", + "few_shot_reference" + ] }, { "path": "beautiful-html-templates/screenshots/bold-poster-4.png", - "role": "reference" + "role": "mid_deck_reference", + "slide_number": 4, + "why_selected": "README gallery mid deck reference for bold-poster: Editorial poster aesthetic with massive Shrikhand display and a single fire-engine red accent.", + "visual_targets": [ + "palette", + "type_scale", + "chrome", + "density", + "layout_balance", + "grid" + ], + "acceptance_use": [ + "matcher_thumbnail", + "visual_qa", + "few_shot_reference" + ] }, { "path": "beautiful-html-templates/screenshots/bold-poster-8.png", - "role": "reference" + "role": "late_deck_reference", + "slide_number": 8, + "why_selected": "README gallery late deck reference for bold-poster: Editorial poster aesthetic with massive Shrikhand display and a single fire-engine red accent.", + "visual_targets": [ + "palette", + "type_scale", + "chrome", + "density", + "layout_balance", + "grid" + ], + "acceptance_use": [ + "matcher_thumbnail", + "visual_qa", + "few_shot_reference" + ] } ], "density": "low" @@ -4728,8 +5489,8 @@ "source_template_html": "beautiful-html-templates/templates/broadside/template.html", "source_screenshots": [ "beautiful-html-templates/screenshots/broadside-1.png", - "beautiful-html-templates/screenshots/broadside-13.png", - "beautiful-html-templates/screenshots/broadside-4.png" + "beautiful-html-templates/screenshots/broadside-4.png", + "beautiful-html-templates/screenshots/broadside-13.png" ], "reference_screenshot": "beautiful-html-templates/screenshots/broadside-1.png", "reference_svg": "", @@ -4818,6 +5579,119 @@ "mono": "system-mono" } }, + "cjk_policy": { + "strategy": "replace_family_whole_element", + "display_font_cn": "Noto Serif SC", + "body_font_cn": "Noto Sans SC", + "mono_font_policy": "latin_only_or_system_mono", + "runtime_font_policy": "system_font_only_no_remote_dependency", + "runtime_font_stack": [ + "system-sans-cjk", + "system-sans-cjk-heavy", + "system-sans-cjk-regular", + "system-mono" + ], + "emphasis_policy": "color_or_weight_only", + "italic_policy": "color_only_emphasis", + "letter_spacing_policy": "reset_letter_spacing_for_cjk_keep_latin_labels", + "mixed_run_spacing": "pangu_spacing", + "latin_accent_policy": "latin_only_allowed_when_semantic_annotation", + "known_degradation": "**No CDN Chinese face matches Barlow's monolithic grotesque + lowercase identity.** Barlow's distinctive choice in this system is lowercase-display at heavy weights — and CJK has no equivalent expressive lever. The system's \"protest-poster lowercase-shouting\" character softens to \"heavy-serif declarative.\" The two-register color system (dark / orange) and th", + "design_intent_font_pairing": [ + "Noto Serif SC", + "Noto Sans SC", + "LXGW WenKai", + "LXGW WenKai TC", + "霞鹜文楷 LXGW WenKai 400", + "霞鹜文楷 LXGW WenKai" + ], + "source_section_heading": "CJK & International Content", + "source_section_sha256": "bc5a9c92a0ffa781bee92f43caea190e136373726ebbc5e9fceae9d308a61119" + }, + "family_usage_policy": { + "closed_visual_system": true, + "cross_family_layout_mix_allowed": false, + "recolor_allowed": false, + "font_substitution_allowed": false, + "decorative_elements_policy": "identity_element_not_noise", + "extend_missing_layout_policy": { + "same_fonts": true, + "same_palette": true, + "same_spacing_rhythm": true, + "same_component_grammar": true, + "same_decorative_vocabulary": true, + "same_chrome": true + }, + "soft_matching_policy": { + "tone_first": true, + "occasion_is_soft_signal": true, + "avoid_for_is_soft_warning": true, + "taste_can_override_industry": true, + "formality_density_as_sanity_check": true + }, + "hard_rules": [ + "preserve_fonts_palette_grid_slide_classes_decorative_elements", + "do_not_recolor_without_explicit_brand_override", + "do_not_mix_template_families", + "extend_missing_layout_inside_same_family", + "do_not_strip_identity_decorations" + ], + "source": "beautiful-html-templates/AGENTS.md", + "source_sha256": "ed619bb7d956303024872f170b96e5270672a03cf40bdf7ce0abc3d8018c9d77" + }, + "extension_grammar": { + "layout_rhythm": "broadside: medium density, medium-high formality. Dark editorial canvas with a single fire orange accent and bilingual Latin/Chinese type stack.", + "spacing_rhythm": "Reuse source spacing tokens and grid gaps: {\"pad_x\": \"5.5vw\", \"pad_y\": \"5.5vh\", \"gap_lg\": \"3.5vh\", \"gap_md\": \"2vh\", \"gap_sm\": \"1vh\"}", + "component_grammar": [ + "panel-orange", + "stat-card", + "stat-label", + "stat-note", + "stat-value", + "statement-body", + "stats-grid" + ], + "chrome_rules": [ + "bar-x-label", + "broadside-top-chrome", + "compare-label", + "corner-label", + "label", + "pie-item-label", + "slide-chrome", + "stat-label" + ], + "decorative_vocabulary": [ + "grid", + "accent line", + "card panels", + "paper texture", + "poster blocks", + "quote mark", + "sticker collage" + ], + "allowed_new_layouts": [ + "comparison", + "risk", + "timeline", + "action_plan", + "case_evidence", + "metric_dashboard" + ], + "forbidden_mutations": [ + "new_palette", + "cross_family_components", + "fake_italic", + "new_decorative_motif", + "remote_font_dependency" + ], + "density_limits": "medium", + "source_basis": { + "template_id": "broadside", + "design_signal_sha256": "7c00cdcc6c8ea15a63f328a381c83731e47dfa42e72b6f4d950845aa902bbbea", + "class_name_count": 103 + } + }, "semantic_fit": { "best_for": [ "Anything that should land like a broadside newspaper headline: brand manifestos", @@ -5088,15 +5962,60 @@ "screenshot_benchmarks": [ { "path": "beautiful-html-templates/screenshots/broadside-1.png", - "role": "reference" - }, - { - "path": "beautiful-html-templates/screenshots/broadside-13.png", - "role": "reference" + "role": "cover_reference", + "slide_number": 1, + "why_selected": "README gallery cover reference for broadside: Dark editorial canvas with a single fire orange accent and bilingual Latin/Chinese type stack.", + "visual_targets": [ + "palette", + "type_scale", + "chrome", + "density", + "layout_balance", + "grid" + ], + "acceptance_use": [ + "matcher_thumbnail", + "visual_qa", + "few_shot_reference" + ] }, { "path": "beautiful-html-templates/screenshots/broadside-4.png", - "role": "reference" + "role": "mid_deck_reference", + "slide_number": 4, + "why_selected": "README gallery mid deck reference for broadside: Dark editorial canvas with a single fire orange accent and bilingual Latin/Chinese type stack.", + "visual_targets": [ + "palette", + "type_scale", + "chrome", + "density", + "layout_balance", + "grid" + ], + "acceptance_use": [ + "matcher_thumbnail", + "visual_qa", + "few_shot_reference" + ] + }, + { + "path": "beautiful-html-templates/screenshots/broadside-13.png", + "role": "late_deck_reference", + "slide_number": 13, + "why_selected": "README gallery late deck reference for broadside: Dark editorial canvas with a single fire orange accent and bilingual Latin/Chinese type stack.", + "visual_targets": [ + "palette", + "type_scale", + "chrome", + "density", + "layout_balance", + "grid" + ], + "acceptance_use": [ + "matcher_thumbnail", + "visual_qa", + "few_shot_reference" + ] } ], "density": "medium" @@ -5846,6 +6765,120 @@ "mono": "system-mono" } }, + "cjk_policy": { + "strategy": "replace_family_whole_element", + "display_font_cn": "LXGW WenKai TC", + "body_font_cn": "ZCOOL XiaoWei", + "mono_font_policy": "latin_only_or_system_mono", + "runtime_font_policy": "system_font_only_no_remote_dependency", + "runtime_font_stack": [ + "system-sans-cjk", + "system-sans-cjk-heavy", + "system-sans-cjk-regular", + "system-mono" + ], + "emphasis_policy": "color_or_weight_only", + "italic_policy": "weight_only_emphasis", + "letter_spacing_policy": "reset_letter_spacing_for_cjk_keep_latin_labels", + "mixed_run_spacing": "pangu_spacing", + "latin_accent_policy": "latin_only_allowed_when_semantic_annotation", + "known_degradation": "ZCOOL XiaoWei is a display face with limited weight axis (single weight) and a smaller glyph set than Noto family — exotic or technical Hanzi (rare surnames, classical characters, simplified-only variants outside GB2312) may fall back to system font. For Traditional Chinese decks, swap Yozai for `LXGW WenKai TC` (Google Fonts) which has fuller TC coverage an", + "design_intent_font_pairing": [ + "LXGW WenKai TC", + "ZCOOL XiaoWei", + "Yozai", + "悠哉字体 Yozai", + "站酷小薇体 ZCOOL XiaoWei" + ], + "source_section_heading": "CJK & International Content", + "source_section_sha256": "2f17e736d2e8ca2e42ea1611ac6356e6cadc9a7806eae1ebae9c2dcee98a4330" + }, + "family_usage_policy": { + "closed_visual_system": true, + "cross_family_layout_mix_allowed": false, + "recolor_allowed": false, + "font_substitution_allowed": false, + "decorative_elements_policy": "identity_element_not_noise", + "extend_missing_layout_policy": { + "same_fonts": true, + "same_palette": true, + "same_spacing_rhythm": true, + "same_component_grammar": true, + "same_decorative_vocabulary": true, + "same_chrome": true + }, + "soft_matching_policy": { + "tone_first": true, + "occasion_is_soft_signal": true, + "avoid_for_is_soft_warning": true, + "taste_can_override_industry": true, + "formality_density_as_sanity_check": true + }, + "hard_rules": [ + "preserve_fonts_palette_grid_slide_classes_decorative_elements", + "do_not_recolor_without_explicit_brand_override", + "do_not_mix_template_families", + "extend_missing_layout_inside_same_family", + "do_not_strip_identity_decorations" + ], + "source": "beautiful-html-templates/AGENTS.md", + "source_sha256": "ed619bb7d956303024872f170b96e5270672a03cf40bdf7ce0abc3d8018c9d77" + }, + "extension_grammar": { + "layout_rhythm": "capsule: medium density, medium-low formality. Modular pill-shaped cards on warm bone with a full pastel-pop palette.", + "spacing_rhythm": "Reuse source spacing tokens and grid gaps: {\"pad_lg\": \"3rem 4rem\", \"pad_md\": \"2rem\", \"gap_xl\": \"4rem\", \"gap_lg\": \"3rem\", \"gap_md\": \"2rem\", \"gap_sm\": \"1.5rem\", \"gap_xs\": \"0.75rem\", \"card_pad\": \"2.5rem 2rem\", \"pill_pad_lg\": \"1.5rem 3.5rem\", \"pill_pad_md\": \"1rem 2.5", + "component_grammar": [ + "__font_body", + "__font_display", + "card-icon", + "cards-grid", + "stat-bar", + "stat-label", + "stat-number", + "stat-pill", + "statement-box", + "stats-grid" + ], + "chrome_rules": [ + "chart-label", + "nav-dot", + "nav-dots", + "nav-hint", + "stat-label", + "stat-number", + "step-label" + ], + "decorative_vocabulary": [ + "grid", + "accent line", + "card panels", + "paper texture", + "poster blocks", + "quote mark", + "sticker collage" + ], + "allowed_new_layouts": [ + "comparison", + "risk", + "timeline", + "action_plan", + "case_evidence", + "metric_dashboard" + ], + "forbidden_mutations": [ + "new_palette", + "cross_family_components", + "fake_italic", + "new_decorative_motif", + "remote_font_dependency" + ], + "density_limits": "medium", + "source_basis": { + "template_id": "capsule", + "design_signal_sha256": "10261e9e75f6cf80794d8fd56db0ebf1fe3288e5c0e866216f0130055552f059", + "class_name_count": 84 + } + }, "semantic_fit": { "best_for": [ "Anything that should feel modular", @@ -6090,15 +7123,60 @@ "screenshot_benchmarks": [ { "path": "beautiful-html-templates/screenshots/capsule-1.png", - "role": "reference" + "role": "cover_reference", + "slide_number": 1, + "why_selected": "README gallery cover reference for capsule: Modular pill-shaped cards on warm bone with a full pastel-pop palette.", + "visual_targets": [ + "palette", + "type_scale", + "chrome", + "density", + "layout_balance", + "grid" + ], + "acceptance_use": [ + "matcher_thumbnail", + "visual_qa", + "few_shot_reference" + ] }, { "path": "beautiful-html-templates/screenshots/capsule-4.png", - "role": "reference" + "role": "mid_deck_reference", + "slide_number": 4, + "why_selected": "README gallery mid deck reference for capsule: Modular pill-shaped cards on warm bone with a full pastel-pop palette.", + "visual_targets": [ + "palette", + "type_scale", + "chrome", + "density", + "layout_balance", + "grid" + ], + "acceptance_use": [ + "matcher_thumbnail", + "visual_qa", + "few_shot_reference" + ] }, { "path": "beautiful-html-templates/screenshots/capsule-8.png", - "role": "reference" + "role": "late_deck_reference", + "slide_number": 8, + "why_selected": "README gallery late deck reference for capsule: Modular pill-shaped cards on warm bone with a full pastel-pop palette.", + "visual_targets": [ + "palette", + "type_scale", + "chrome", + "density", + "layout_balance", + "grid" + ], + "acceptance_use": [ + "matcher_thumbnail", + "visual_qa", + "few_shot_reference" + ] } ], "density": "medium" @@ -6838,6 +7916,115 @@ "mono": "system-mono" } }, + "cjk_policy": { + "strategy": "replace_family_whole_element", + "display_font_cn": "Noto Serif SC", + "body_font_cn": "Noto Serif SC", + "mono_font_policy": "latin_only_or_system_mono", + "runtime_font_policy": "system_font_only_no_remote_dependency", + "runtime_font_stack": [ + "system-sans-cjk", + "system-sans-cjk-heavy", + "system-sans-cjk-regular", + "system-mono" + ], + "emphasis_policy": "color_or_weight_only", + "italic_policy": "drop_italic", + "letter_spacing_policy": "reset_letter_spacing_for_cjk_keep_latin_labels", + "mixed_run_spacing": "pangu_spacing", + "latin_accent_policy": "latin_only_allowed_when_semantic_annotation", + "known_degradation": "Noto Serif SC is the only Hanzi serif loaded — there is no italic axis (Chinese type historically has no italic), so the rare italic Playfair `` moment loses its emphasis when the body falls through to NSC. Substitute a single-character span colored in `{colors.accent}` (taupe), or wrap the emphasized phrase in faint brackets 「」, to recover emphasis. NSC", + "design_intent_font_pairing": [ + "Noto Serif SC" + ], + "source_section_heading": "CJK & International Content", + "source_section_sha256": "e8e494632f44c006960e60b91217750deaa859ac9da28f96cc78faee86b621fe" + }, + "family_usage_policy": { + "closed_visual_system": true, + "cross_family_layout_mix_allowed": false, + "recolor_allowed": false, + "font_substitution_allowed": false, + "decorative_elements_policy": "identity_element_not_noise", + "extend_missing_layout_policy": { + "same_fonts": true, + "same_palette": true, + "same_spacing_rhythm": true, + "same_component_grammar": true, + "same_decorative_vocabulary": true, + "same_chrome": true + }, + "soft_matching_policy": { + "tone_first": true, + "occasion_is_soft_signal": true, + "avoid_for_is_soft_warning": true, + "taste_can_override_industry": true, + "formality_density_as_sanity_check": true + }, + "hard_rules": [ + "preserve_fonts_palette_grid_slide_classes_decorative_elements", + "do_not_recolor_without_explicit_brand_override", + "do_not_mix_template_families", + "extend_missing_layout_inside_same_family", + "do_not_strip_identity_decorations" + ], + "source": "beautiful-html-templates/AGENTS.md", + "source_sha256": "ed619bb7d956303024872f170b96e5270672a03cf40bdf7ce0abc3d8018c9d77" + }, + "extension_grammar": { + "layout_rhythm": "cartesian: low density, high formality. Quiet warm-neutral palette with classical Playfair serifs; tasteful and unhurried.", + "spacing_rhythm": "Reuse source spacing tokens and grid gaps: {\"pad_y\": \"4vh\", \"pad_x\": \"4vw\", \"gap_xl\": \"6vw\", \"gap_lg\": \"5vw\", \"gap_md\": \"3vw\", \"gap_sm\": \"2vh\", \"card_pad\": \"4vh 2vw\"}", + "component_grammar": [ + "__font_body", + "__font_display", + "card", + "card-icon", + "cards-grid", + "chart_axis_tick_color", + "chart_comparison_dash", + "chart_grid_color", + "chart_stroke_comparison", + "chart_stroke_primary" + ], + "chrome_rules": [ + "agenda-number", + "image-label", + "label", + "nav-arrow", + "nav-arrows", + "nav-dot", + "nav-dots" + ], + "decorative_vocabulary": [ + "grid", + "accent line", + "card panels", + "paper texture", + "poster blocks", + "quote mark" + ], + "allowed_new_layouts": [ + "comparison", + "risk", + "timeline", + "action_plan", + "case_evidence", + "metric_dashboard" + ], + "forbidden_mutations": [ + "new_palette", + "cross_family_components", + "fake_italic", + "new_decorative_motif", + "remote_font_dependency" + ], + "density_limits": "low", + "source_basis": { + "template_id": "cartesian", + "design_signal_sha256": "485f4c4397c984eec3052058621e735b07e921afbfac1f6fb65cd5a55d4bd651", + "class_name_count": 45 + } + }, "semantic_fit": { "best_for": [ "Anything that should feel quiet", @@ -7027,15 +8214,60 @@ "screenshot_benchmarks": [ { "path": "beautiful-html-templates/screenshots/cartesian-1.png", - "role": "reference" + "role": "cover_reference", + "slide_number": 1, + "why_selected": "README gallery cover reference for cartesian: Quiet warm-neutral palette with classical Playfair serifs; tasteful and unhurried.", + "visual_targets": [ + "palette", + "type_scale", + "chrome", + "density", + "layout_balance", + "grid" + ], + "acceptance_use": [ + "matcher_thumbnail", + "visual_qa", + "few_shot_reference" + ] }, { "path": "beautiful-html-templates/screenshots/cartesian-4.png", - "role": "reference" + "role": "mid_deck_reference", + "slide_number": 4, + "why_selected": "README gallery mid deck reference for cartesian: Quiet warm-neutral palette with classical Playfair serifs; tasteful and unhurried.", + "visual_targets": [ + "palette", + "type_scale", + "chrome", + "density", + "layout_balance", + "grid" + ], + "acceptance_use": [ + "matcher_thumbnail", + "visual_qa", + "few_shot_reference" + ] }, { "path": "beautiful-html-templates/screenshots/cartesian-8.png", - "role": "reference" + "role": "late_deck_reference", + "slide_number": 8, + "why_selected": "README gallery late deck reference for cartesian: Quiet warm-neutral palette with classical Playfair serifs; tasteful and unhurried.", + "visual_targets": [ + "palette", + "type_scale", + "chrome", + "density", + "layout_balance", + "grid" + ], + "acceptance_use": [ + "matcher_thumbnail", + "visual_qa", + "few_shot_reference" + ] } ], "density": "low" @@ -7832,6 +9064,113 @@ "mono": "system-mono" } }, + "cjk_policy": { + "strategy": "replace_family_whole_element", + "display_font_cn": "Noto Serif SC", + "body_font_cn": "Noto Serif SC", + "mono_font_policy": "latin_only_or_system_mono", + "runtime_font_policy": "system_font_only_no_remote_dependency", + "runtime_font_stack": [ + "system-sans-cjk", + "system-sans-cjk-heavy", + "system-sans-cjk-regular", + "system-mono" + ], + "emphasis_policy": "color_or_weight_only", + "italic_policy": "drop_italic", + "letter_spacing_policy": "reset_letter_spacing_for_cjk_keep_latin_labels", + "mixed_run_spacing": "pangu_spacing", + "latin_accent_policy": "latin_only_allowed_when_semantic_annotation", + "known_degradation": "Noto Serif SC has no italic axis (Chinese type historically has no italic), so the manifesto layout's italic-Newsreader-with-`.roman`-flip emphasis pattern collapses when content is Hanzi. Substitute a weight contrast (NSC 700 vs NSC 400) or a faint-cobalt tone (`{colors.ink-faint}`) to recover the emphasis register. Newsreader's optical-size axis (6..72) ha", + "design_intent_font_pairing": [ + "Noto Serif SC" + ], + "source_section_heading": "CJK & International Content", + "source_section_sha256": "531f6993aa2dc951c730e77ecff8b82e317e76129c8490496bfc8c24989b1641" + }, + "family_usage_policy": { + "closed_visual_system": true, + "cross_family_layout_mix_allowed": false, + "recolor_allowed": false, + "font_substitution_allowed": false, + "decorative_elements_policy": "identity_element_not_noise", + "extend_missing_layout_policy": { + "same_fonts": true, + "same_palette": true, + "same_spacing_rhythm": true, + "same_component_grammar": true, + "same_decorative_vocabulary": true, + "same_chrome": true + }, + "soft_matching_policy": { + "tone_first": true, + "occasion_is_soft_signal": true, + "avoid_for_is_soft_warning": true, + "taste_can_override_industry": true, + "formality_density_as_sanity_check": true + }, + "hard_rules": [ + "preserve_fonts_palette_grid_slide_classes_decorative_elements", + "do_not_recolor_without_explicit_brand_override", + "do_not_mix_template_families", + "extend_missing_layout_inside_same_family", + "do_not_strip_identity_decorations" + ], + "source": "beautiful-html-templates/AGENTS.md", + "source_sha256": "ed619bb7d956303024872f170b96e5270672a03cf40bdf7ce0abc3d8018c9d77" + }, + "extension_grammar": { + "layout_rhythm": "cobalt-grid: medium density, high formality. Electric cobalt serifs on a graph-paper canvas, anchored by stair-stepped pixel-glitch decorations and slim hairline rules.", + "spacing_rhythm": "Reuse source spacing tokens and grid gaps: {\"edge\": \"clamp(36px, 3.6vw, 80px)\", \"edge_inner\": \"clamp(60px, 8vw, 160px)\", \"pad_top\": \"clamp(76px, 8vh, 130px)\", \"pad_bottom\": \"clamp(100px, 10vh, 150px)\", \"gap_lg\": \"clamp(28px, 3vw, 56px)\", \"gap_md\": \"clamp(20px, 2.", + "component_grammar": [ + "__font_body", + "__font_display", + "__font_mono", + "s-chapter", + "s-colophon", + "s-cover", + "s-data", + "s-index", + "s-manifesto", + "s-quote" + ], + "chrome_rules": [ + "cfooter", + "col-footer", + "nav-hint", + "pagenum" + ], + "decorative_vocabulary": [ + "grid", + "accent line", + "paper texture", + "poster blocks", + "quote mark", + "sticker collage", + "pixel motif" + ], + "allowed_new_layouts": [ + "comparison", + "risk", + "timeline", + "action_plan", + "case_evidence", + "metric_dashboard" + ], + "forbidden_mutations": [ + "new_palette", + "cross_family_components", + "fake_italic", + "new_decorative_motif", + "remote_font_dependency" + ], + "density_limits": "medium", + "source_basis": { + "template_id": "cobalt-grid", + "design_signal_sha256": "59b47558ea75f54b14b3dd6bdf918ee4e5159cfefc4b82be8c60373cc519ad55", + "class_name_count": 75 + } + }, "semantic_fit": { "best_for": [ "Anything that should feel like a quietly serious design", @@ -8056,15 +9395,60 @@ "screenshot_benchmarks": [ { "path": "beautiful-html-templates/screenshots/cobalt-grid-1.png", - "role": "reference" + "role": "cover_reference", + "slide_number": 1, + "why_selected": "README gallery cover reference for cobalt-grid: Electric cobalt serifs on a graph-paper canvas, anchored by stair-stepped pixel-glitch decorations and slim hairline rules.", + "visual_targets": [ + "palette", + "type_scale", + "chrome", + "density", + "layout_balance", + "grid" + ], + "acceptance_use": [ + "matcher_thumbnail", + "visual_qa", + "few_shot_reference" + ] }, { "path": "beautiful-html-templates/screenshots/cobalt-grid-3.png", - "role": "reference" + "role": "mid_deck_reference", + "slide_number": 3, + "why_selected": "README gallery mid deck reference for cobalt-grid: Electric cobalt serifs on a graph-paper canvas, anchored by stair-stepped pixel-glitch decorations and slim hairline rules.", + "visual_targets": [ + "palette", + "type_scale", + "chrome", + "density", + "layout_balance", + "grid" + ], + "acceptance_use": [ + "matcher_thumbnail", + "visual_qa", + "few_shot_reference" + ] }, { "path": "beautiful-html-templates/screenshots/cobalt-grid-5.png", - "role": "reference" + "role": "late_deck_reference", + "slide_number": 5, + "why_selected": "README gallery late deck reference for cobalt-grid: Electric cobalt serifs on a graph-paper canvas, anchored by stair-stepped pixel-glitch decorations and slim hairline rules.", + "visual_targets": [ + "palette", + "type_scale", + "chrome", + "density", + "layout_balance", + "grid" + ], + "acceptance_use": [ + "matcher_thumbnail", + "visual_qa", + "few_shot_reference" + ] } ], "density": "medium" @@ -8822,6 +10206,119 @@ "mono": "system-mono" } }, + "cjk_policy": { + "strategy": "replace_family_whole_element", + "display_font_cn": "LXGW WenKai TC", + "body_font_cn": "ZCOOL XiaoWei", + "mono_font_policy": "latin_only_or_system_mono", + "runtime_font_policy": "system_font_only_no_remote_dependency", + "runtime_font_stack": [ + "system-sans-cjk", + "system-sans-cjk-heavy", + "system-sans-cjk-regular", + "system-mono" + ], + "emphasis_policy": "color_or_weight_only", + "italic_policy": "color_only_emphasis", + "letter_spacing_policy": "reset_letter_spacing_for_cjk_keep_latin_labels", + "mixed_run_spacing": "pangu_spacing", + "latin_accent_policy": "latin_only_allowed_when_semantic_annotation", + "known_degradation": "ZCOOL XiaoWei is a single-weight display face with limited glyph coverage compared to Noto family — exotic or technical Hanzi (rare surnames, classical characters, simplified-only variants outside GB2312) may fall back to system font. For Traditional Chinese decks, swap Yozai for `LXGW WenKai TC` (Google Fonts) which has fuller TC coverage. Bebas Neue's narr", + "design_intent_font_pairing": [ + "LXGW WenKai TC", + "ZCOOL XiaoWei", + "Yozai", + "悠哉字体 Yozai", + "站酷小薇体 ZCOOL XiaoWei" + ], + "source_section_heading": "CJK & International Content", + "source_section_sha256": "9f0b4053b8aae2e02683ca89d4d6c6613a308fbacb022aa6b901e823aef2703b" + }, + "family_usage_policy": { + "closed_visual_system": true, + "cross_family_layout_mix_allowed": false, + "recolor_allowed": false, + "font_substitution_allowed": false, + "decorative_elements_policy": "identity_element_not_noise", + "extend_missing_layout_policy": { + "same_fonts": true, + "same_palette": true, + "same_spacing_rhythm": true, + "same_component_grammar": true, + "same_decorative_vocabulary": true, + "same_chrome": true + }, + "soft_matching_policy": { + "tone_first": true, + "occasion_is_soft_signal": true, + "avoid_for_is_soft_warning": true, + "taste_can_override_industry": true, + "formality_density_as_sanity_check": true + }, + "hard_rules": [ + "preserve_fonts_palette_grid_slide_classes_decorative_elements", + "do_not_recolor_without_explicit_brand_override", + "do_not_mix_template_families", + "extend_missing_layout_inside_same_family", + "do_not_strip_identity_decorations" + ], + "source": "beautiful-html-templates/AGENTS.md", + "source_sha256": "ed619bb7d956303024872f170b96e5270672a03cf40bdf7ce0abc3d8018c9d77" + }, + "extension_grammar": { + "layout_rhythm": "coral: medium density, medium formality. Cream and coral on near-black, set in oversized Bebas Neue.", + "spacing_rhythm": "Reuse source spacing tokens and grid gaps: {\"pad_y\": \"clamp(40px, 6vh, 80px)\", \"pad_x\": \"clamp(40px, 8vw, 100px)\", \"pad_y_tight\": \"clamp(28px, 4.5vh, 60px)\", \"pad_col\": \"clamp(32px, 4vw, 60px)\", \"gap_grid\": \"32px\", \"gap_md\": \"40px\", \"card_pad\": \"clamp(24px, 3vh, ", + "component_grammar": [ + "__font_body", + "__font_display", + "card-icon", + "card-stat", + "card-text", + "card-title", + "stat-label", + "stat-number" + ], + "chrome_rules": [ + "contact-label", + "item-label", + "label", + "meta-label", + "nav-arrow", + "nav-arrows", + "nav-dots", + "number" + ], + "decorative_vocabulary": [ + "grid", + "accent line", + "card panels", + "paper texture", + "poster blocks", + "quote mark", + "sticker collage" + ], + "allowed_new_layouts": [ + "comparison", + "risk", + "timeline", + "action_plan", + "case_evidence", + "metric_dashboard" + ], + "forbidden_mutations": [ + "new_palette", + "cross_family_components", + "fake_italic", + "new_decorative_motif", + "remote_font_dependency" + ], + "density_limits": "medium", + "source_basis": { + "template_id": "coral", + "design_signal_sha256": "795fbb37386cb2c9dc39b0aeb06ec2e22c94751e1e890fad65daa527073f87d6", + "class_name_count": 95 + } + }, "semantic_fit": { "best_for": [ "Anything that should feel warm-graphic and editorial: fashion", @@ -9055,15 +10552,60 @@ "screenshot_benchmarks": [ { "path": "beautiful-html-templates/screenshots/coral-1.png", - "role": "reference" + "role": "cover_reference", + "slide_number": 1, + "why_selected": "README gallery cover reference for coral: Cream and coral on near-black, set in oversized Bebas Neue.", + "visual_targets": [ + "palette", + "type_scale", + "chrome", + "density", + "layout_balance", + "grid" + ], + "acceptance_use": [ + "matcher_thumbnail", + "visual_qa", + "few_shot_reference" + ] }, { "path": "beautiful-html-templates/screenshots/coral-4.png", - "role": "reference" + "role": "mid_deck_reference", + "slide_number": 4, + "why_selected": "README gallery mid deck reference for coral: Cream and coral on near-black, set in oversized Bebas Neue.", + "visual_targets": [ + "palette", + "type_scale", + "chrome", + "density", + "layout_balance", + "grid" + ], + "acceptance_use": [ + "matcher_thumbnail", + "visual_qa", + "few_shot_reference" + ] }, { "path": "beautiful-html-templates/screenshots/coral-8.png", - "role": "reference" + "role": "late_deck_reference", + "slide_number": 8, + "why_selected": "README gallery late deck reference for coral: Cream and coral on near-black, set in oversized Bebas Neue.", + "visual_targets": [ + "palette", + "type_scale", + "chrome", + "density", + "layout_balance", + "grid" + ], + "acceptance_use": [ + "matcher_thumbnail", + "visual_qa", + "few_shot_reference" + ] } ], "density": "medium" @@ -9762,6 +11304,111 @@ "mono": "system-mono" } }, + "cjk_policy": { + "strategy": "replace_family_whole_element", + "display_font_cn": "Noto Serif SC", + "body_font_cn": "Noto Serif SC", + "mono_font_policy": "latin_only_or_system_mono", + "runtime_font_policy": "system_font_only_no_remote_dependency", + "runtime_font_stack": [ + "system-sans-cjk", + "system-sans-cjk-heavy", + "system-sans-cjk-regular", + "system-mono" + ], + "emphasis_policy": "color_or_weight_only", + "italic_policy": "drop_italic", + "letter_spacing_policy": "reset_letter_spacing_for_cjk_keep_latin_labels", + "mixed_run_spacing": "pangu_spacing", + "latin_accent_policy": "latin_only_allowed_when_semantic_annotation", + "known_degradation": "**Heavy Latin display has no exact CJK equivalent.** Archivo Black's brutalist density at 220px is the system's signature — Noto Serif SC 900 is the heaviest commonly available Hanzi weight, but it reads as a literary serif rather than a poster-grotesk. Chinese decks built with Creative Mode will feel ~30% less \"punk-zine\" than the Latin original; compensate", + "design_intent_font_pairing": [ + "Noto Serif SC" + ], + "source_section_heading": "CJK & International Content", + "source_section_sha256": "a48ea7b52d2f6118516e83bceb0c35c6719fb50b584dd444d3e32234f77f4ed2" + }, + "family_usage_policy": { + "closed_visual_system": true, + "cross_family_layout_mix_allowed": false, + "recolor_allowed": false, + "font_substitution_allowed": false, + "decorative_elements_policy": "identity_element_not_noise", + "extend_missing_layout_policy": { + "same_fonts": true, + "same_palette": true, + "same_spacing_rhythm": true, + "same_component_grammar": true, + "same_decorative_vocabulary": true, + "same_chrome": true + }, + "soft_matching_policy": { + "tone_first": true, + "occasion_is_soft_signal": true, + "avoid_for_is_soft_warning": true, + "taste_can_override_industry": true, + "formality_density_as_sanity_check": true + }, + "hard_rules": [ + "preserve_fonts_palette_grid_slide_classes_decorative_elements", + "do_not_recolor_without_explicit_brand_override", + "do_not_mix_template_families", + "extend_missing_layout_inside_same_family", + "do_not_strip_identity_decorations" + ], + "source": "beautiful-html-templates/AGENTS.md", + "source_sha256": "ed619bb7d956303024872f170b96e5270672a03cf40bdf7ce0abc3d8018c9d77" + }, + "extension_grammar": { + "layout_rhythm": "creative-mode: medium-high density, medium formality. Cream paper canvas with confident multi-color (green, pink, orange, yellow) accents and Archivo Black display.", + "spacing_rhythm": "Reuse source spacing tokens and grid gaps: {\"slide_gutter\": \"96px\", \"chrome_gutter\": \"64px\", \"grid_gap\": \"28px\", \"cell_pad\": \"32px\", \"step_pad\": \"28px\", \"topbar_top\": \"48px\", \"meta_bottom\": \"40px\", \"table_cell_pad\": \"18px 26px\"}", + "component_grammar": [ + "__font_body", + "__font_display", + "__font_mono", + "s-1", + "s-2", + "s-3", + "s-4" + ], + "chrome_rules": [ + "badge", + "label", + "label-off", + "label-on", + "stamp" + ], + "decorative_vocabulary": [ + "grid", + "accent line", + "card panels", + "paper texture", + "poster blocks", + "quote mark", + "sticker collage" + ], + "allowed_new_layouts": [ + "comparison", + "risk", + "timeline", + "action_plan", + "case_evidence", + "metric_dashboard" + ], + "forbidden_mutations": [ + "new_palette", + "cross_family_components", + "fake_italic", + "new_decorative_motif", + "remote_font_dependency" + ], + "density_limits": "medium-high", + "source_basis": { + "template_id": "creative-mode", + "design_signal_sha256": "f361c22edc6724d7c447bb864465ae748d07e3e83b262fe471a5b63e54e2f231", + "class_name_count": 80 + } + }, "semantic_fit": { "best_for": [ "Anything that should feel design-led and confident: creative agency pitches", @@ -9993,15 +11640,60 @@ "screenshot_benchmarks": [ { "path": "beautiful-html-templates/screenshots/creative-mode-1.png", - "role": "reference" + "role": "cover_reference", + "slide_number": 1, + "why_selected": "README gallery cover reference for creative-mode: Cream paper canvas with confident multi-color (green, pink, orange, yellow) accents and Archivo Black display.", + "visual_targets": [ + "palette", + "type_scale", + "chrome", + "density", + "layout_balance", + "grid" + ], + "acceptance_use": [ + "matcher_thumbnail", + "visual_qa", + "few_shot_reference" + ] }, { "path": "beautiful-html-templates/screenshots/creative-mode-4.png", - "role": "reference" + "role": "mid_deck_reference", + "slide_number": 4, + "why_selected": "README gallery mid deck reference for creative-mode: Cream paper canvas with confident multi-color (green, pink, orange, yellow) accents and Archivo Black display.", + "visual_targets": [ + "palette", + "type_scale", + "chrome", + "density", + "layout_balance", + "grid" + ], + "acceptance_use": [ + "matcher_thumbnail", + "visual_qa", + "few_shot_reference" + ] }, { "path": "beautiful-html-templates/screenshots/creative-mode-6.png", - "role": "reference" + "role": "late_deck_reference", + "slide_number": 6, + "why_selected": "README gallery late deck reference for creative-mode: Cream paper canvas with confident multi-color (green, pink, orange, yellow) accents and Archivo Black display.", + "visual_targets": [ + "palette", + "type_scale", + "chrome", + "density", + "layout_balance", + "grid" + ], + "acceptance_use": [ + "matcher_thumbnail", + "visual_qa", + "few_shot_reference" + ] } ], "density": "medium-high" @@ -10700,6 +12392,108 @@ "mono": "system-mono" } }, + "cjk_policy": { + "strategy": "replace_family_whole_element", + "display_font_cn": "LXGW WenKai TC", + "body_font_cn": "ZCOOL XiaoWei", + "mono_font_policy": "latin_only_or_system_mono", + "runtime_font_policy": "system_font_only_no_remote_dependency", + "runtime_font_stack": [ + "system-sans-cjk", + "system-sans-cjk-heavy", + "system-sans-cjk-regular", + "system-mono" + ], + "emphasis_policy": "color_or_weight_only", + "italic_policy": "drop_italic", + "letter_spacing_policy": "reset_letter_spacing_for_cjk_keep_latin_labels", + "mixed_run_spacing": "pangu_spacing", + "latin_accent_policy": "latin_only_allowed_when_semantic_annotation", + "known_degradation": "ZCOOL XiaoWei is a single-weight display face with limited glyph coverage compared to Noto family — exotic or technical Hanzi (rare surnames, classical characters, simplified-only variants outside GB2312) may fall back to system font. For Traditional Chinese decks, swap Yozai for `LXGW WenKai TC` (Google Fonts) which has fuller TC coverage and a similar frie", + "design_intent_font_pairing": [ + "LXGW WenKai TC", + "ZCOOL XiaoWei", + "Yozai", + "悠哉字体 Yozai", + "站酷小薇体 ZCOOL XiaoWei" + ], + "source_section_heading": "CJK & International Content", + "source_section_sha256": "bb21243ac23ea7ef57bd3c3fa500c5c52f8568eb3586e42b03757a9fdd51756f" + }, + "family_usage_policy": { + "closed_visual_system": true, + "cross_family_layout_mix_allowed": false, + "recolor_allowed": false, + "font_substitution_allowed": false, + "decorative_elements_policy": "identity_element_not_noise", + "extend_missing_layout_policy": { + "same_fonts": true, + "same_palette": true, + "same_spacing_rhythm": true, + "same_component_grammar": true, + "same_decorative_vocabulary": true, + "same_chrome": true + }, + "soft_matching_policy": { + "tone_first": true, + "occasion_is_soft_signal": true, + "avoid_for_is_soft_warning": true, + "taste_can_override_industry": true, + "formality_density_as_sanity_check": true + }, + "hard_rules": [ + "preserve_fonts_palette_grid_slide_classes_decorative_elements", + "do_not_recolor_without_explicit_brand_override", + "do_not_mix_template_families", + "extend_missing_layout_inside_same_family", + "do_not_strip_identity_decorations" + ], + "source": "beautiful-html-templates/AGENTS.md", + "source_sha256": "ed619bb7d956303024872f170b96e5270672a03cf40bdf7ce0abc3d8018c9d77" + }, + "extension_grammar": { + "layout_rhythm": "daisy-days: medium density, low formality. Cheerful pastel deck with hand-drawn daisies, stars, and rainbows. Friendly, soft, and warm.", + "spacing_rhythm": "Reuse source spacing tokens and grid gaps: {\"pad_slide\": \"40px 60px\", \"pad_card_lg\": \"48px 56px\", \"pad_card_md\": \"32px 40px\", \"pad_card_sm\": \"16px 24px\", \"gap_grid_lg\": \"28px\", \"gap_grid_md\": \"24px\", \"gap_grid_sm\": \"14px\", \"radius\": \"20px\", \"radius_lg\": \"28px\", \"", + "component_grammar": [ + "__font_body", + "__font_display", + "card-icon", + "cards-grid" + ], + "chrome_rules": [ + "nav-dot", + "nav-dots" + ], + "decorative_vocabulary": [ + "grid", + "accent line", + "card panels", + "poster blocks", + "quote mark", + "sticker collage" + ], + "allowed_new_layouts": [ + "comparison", + "risk", + "timeline", + "action_plan", + "case_evidence", + "metric_dashboard" + ], + "forbidden_mutations": [ + "new_palette", + "cross_family_components", + "fake_italic", + "new_decorative_motif", + "remote_font_dependency" + ], + "density_limits": "medium", + "source_basis": { + "template_id": "daisy-days", + "design_signal_sha256": "3588d74c555e7b7824e9e326ab55d5d53f59abc3ae89aaf3893a91a4536ef959", + "class_name_count": 98 + } + }, "semantic_fit": { "best_for": [ "Anything that should feel friendly", @@ -10954,15 +12748,60 @@ "screenshot_benchmarks": [ { "path": "beautiful-html-templates/screenshots/daisy-days-1.png", - "role": "reference" + "role": "cover_reference", + "slide_number": 1, + "why_selected": "README gallery cover reference for daisy-days: Cheerful pastel deck with hand-drawn daisies, stars, and rainbows. Friendly, soft, and warm.", + "visual_targets": [ + "palette", + "type_scale", + "chrome", + "density", + "layout_balance", + "grid" + ], + "acceptance_use": [ + "matcher_thumbnail", + "visual_qa", + "few_shot_reference" + ] }, { "path": "beautiful-html-templates/screenshots/daisy-days-4.png", - "role": "reference" + "role": "mid_deck_reference", + "slide_number": 4, + "why_selected": "README gallery mid deck reference for daisy-days: Cheerful pastel deck with hand-drawn daisies, stars, and rainbows. Friendly, soft, and warm.", + "visual_targets": [ + "palette", + "type_scale", + "chrome", + "density", + "layout_balance", + "grid" + ], + "acceptance_use": [ + "matcher_thumbnail", + "visual_qa", + "few_shot_reference" + ] }, { "path": "beautiful-html-templates/screenshots/daisy-days-8.png", - "role": "reference" + "role": "late_deck_reference", + "slide_number": 8, + "why_selected": "README gallery late deck reference for daisy-days: Cheerful pastel deck with hand-drawn daisies, stars, and rainbows. Friendly, soft, and warm.", + "visual_targets": [ + "palette", + "type_scale", + "chrome", + "density", + "layout_balance", + "grid" + ], + "acceptance_use": [ + "matcher_thumbnail", + "visual_qa", + "few_shot_reference" + ] } ], "density": "medium" @@ -11700,6 +13539,111 @@ "mono": "system-mono" } }, + "cjk_policy": { + "strategy": "replace_family_whole_element", + "display_font_cn": "Noto Serif SC", + "body_font_cn": "Noto Sans SC", + "mono_font_policy": "latin_only_or_system_mono", + "runtime_font_policy": "system_font_only_no_remote_dependency", + "runtime_font_stack": [ + "system-sans-cjk", + "system-sans-cjk-heavy", + "system-sans-cjk-regular", + "system-mono" + ], + "emphasis_policy": "color_or_weight_only", + "italic_policy": "color_only_emphasis", + "letter_spacing_policy": "reset_letter_spacing_for_cjk_keep_latin_labels", + "mixed_run_spacing": "pangu_spacing", + "latin_accent_policy": "latin_only_allowed_when_semantic_annotation", + "known_degradation": "LXGW WenKai's brushwork warmth is its strength at large display sizes, but at body scale (26–32px) the same brushwork reads slightly noisy. The system bumps body to Noto Serif SC (a cleaner Mincho) to avoid this, but the visual handoff between a 96px LXGW WenKai headline and a 30px Noto Serif SC paragraph below it is the system's biggest CJK seam — the two f", + "design_intent_font_pairing": [ + "Noto Serif SC", + "Noto Sans SC", + "LXGW WenKai", + "LXGW WenKai TC", + "LXGW WenKai sits slightly higher than Source Serif", + "LXGW WenKai TC is the version served on Google Fonts" + ], + "source_section_heading": "CJK & International Content", + "source_section_sha256": "1943fb9c543adcddd9fba5dbf6434c94adc112539a47971f5a67ad7a27b68f16" + }, + "family_usage_policy": { + "closed_visual_system": true, + "cross_family_layout_mix_allowed": false, + "recolor_allowed": false, + "font_substitution_allowed": false, + "decorative_elements_policy": "identity_element_not_noise", + "extend_missing_layout_policy": { + "same_fonts": true, + "same_palette": true, + "same_spacing_rhythm": true, + "same_component_grammar": true, + "same_decorative_vocabulary": true, + "same_chrome": true + }, + "soft_matching_policy": { + "tone_first": true, + "occasion_is_soft_signal": true, + "avoid_for_is_soft_warning": true, + "taste_can_override_industry": true, + "formality_density_as_sanity_check": true + }, + "hard_rules": [ + "preserve_fonts_palette_grid_slide_classes_decorative_elements", + "do_not_recolor_without_explicit_brand_override", + "do_not_mix_template_families", + "extend_missing_layout_inside_same_family", + "do_not_strip_identity_decorations" + ], + "source": "beautiful-html-templates/AGENTS.md", + "source_sha256": "ed619bb7d956303024872f170b96e5270672a03cf40bdf7ce0abc3d8018c9d77" + }, + "extension_grammar": { + "layout_rhythm": "editorial-forest: medium density, medium formality. Forest green, dusty pink, and warm cream meet Source Serif 4 in a quiet, intentional quarterly-review deck.", + "spacing_rhythm": "Reuse source spacing tokens and grid gaps: {\"slide_pad_default\": \"96px 120px\", \"slide_pad_narrow\": \"100px 120px\", \"slide_pad_wide\": \"100px 140px\", \"slide_pad_statement\": \"130px 160px\", \"grid_gap_cards\": \"28\", \"grid_gap_topics\": \"24\", \"grid_gap_kpi\": \"60\", \"rule_w", + "component_grammar": [ + "statement", + "stats" + ], + "chrome_rules": [ + "eyebrow", + "label", + "xlabel", + "xlabel-row" + ], + "decorative_vocabulary": [ + "grid", + "accent line", + "card panels", + "paper texture", + "window chrome", + "poster blocks", + "quote mark", + "sticker collage" + ], + "allowed_new_layouts": [ + "comparison", + "risk", + "timeline", + "action_plan", + "case_evidence", + "metric_dashboard" + ], + "forbidden_mutations": [ + "new_palette", + "cross_family_components", + "fake_italic", + "new_decorative_motif", + "remote_font_dependency" + ], + "density_limits": "medium", + "source_basis": { + "template_id": "editorial-forest", + "design_signal_sha256": "e26e2625d4035644e7feb44236f2800d40813050da2e5c3d83b7dbf50fca0b73", + "class_name_count": 56 + } + }, "semantic_fit": { "best_for": [ "Anything that should feel like a considered editorial — quarterly reviews", @@ -11902,15 +13846,60 @@ "screenshot_benchmarks": [ { "path": "beautiful-html-templates/screenshots/editorial-forest-1.png", - "role": "reference" + "role": "cover_reference", + "slide_number": 1, + "why_selected": "README gallery cover reference for editorial-forest: Forest green, dusty pink, and warm cream meet Source Serif 4 in a quiet, intentional quarterly-review deck.", + "visual_targets": [ + "palette", + "type_scale", + "chrome", + "density", + "layout_balance", + "grid" + ], + "acceptance_use": [ + "matcher_thumbnail", + "visual_qa", + "few_shot_reference" + ] }, { "path": "beautiful-html-templates/screenshots/editorial-forest-2.png", - "role": "reference" + "role": "mid_deck_reference", + "slide_number": 2, + "why_selected": "README gallery mid deck reference for editorial-forest: Forest green, dusty pink, and warm cream meet Source Serif 4 in a quiet, intentional quarterly-review deck.", + "visual_targets": [ + "palette", + "type_scale", + "chrome", + "density", + "layout_balance", + "grid" + ], + "acceptance_use": [ + "matcher_thumbnail", + "visual_qa", + "few_shot_reference" + ] }, { "path": "beautiful-html-templates/screenshots/editorial-forest-5.png", - "role": "reference" + "role": "late_deck_reference", + "slide_number": 5, + "why_selected": "README gallery late deck reference for editorial-forest: Forest green, dusty pink, and warm cream meet Source Serif 4 in a quiet, intentional quarterly-review deck.", + "visual_targets": [ + "palette", + "type_scale", + "chrome", + "density", + "layout_balance", + "grid" + ], + "acceptance_use": [ + "matcher_thumbnail", + "visual_qa", + "few_shot_reference" + ] } ], "density": "medium" @@ -12615,8 +14604,8 @@ "source_template_html": "beautiful-html-templates/templates/editorial-tri-tone/template.html", "source_screenshots": [ "beautiful-html-templates/screenshots/editorial-tri-tone-1.png", - "beautiful-html-templates/screenshots/editorial-tri-tone-3.png", - "beautiful-html-templates/screenshots/editorial-tri-tone-4.png" + "beautiful-html-templates/screenshots/editorial-tri-tone-4.png", + "beautiful-html-templates/screenshots/editorial-tri-tone-3.png" ], "reference_screenshot": "beautiful-html-templates/screenshots/editorial-tri-tone-1.png", "reference_svg": "", @@ -12665,6 +14654,115 @@ "mono": "system-mono" } }, + "cjk_policy": { + "strategy": "replace_family_whole_element", + "display_font_cn": "Noto Sans SC", + "body_font_cn": "Noto Serif SC", + "mono_font_policy": "latin_only_or_system_mono", + "runtime_font_policy": "system_font_only_no_remote_dependency", + "runtime_font_stack": [ + "system-sans-cjk", + "system-sans-cjk-heavy", + "system-sans-cjk-regular", + "system-mono" + ], + "emphasis_policy": "color_or_weight_only", + "italic_policy": "drop_italic", + "letter_spacing_policy": "reset_letter_spacing_for_cjk_keep_latin_labels", + "mixed_run_spacing": "pangu_spacing", + "latin_accent_policy": "latin_only_allowed_when_semantic_annotation", + "known_degradation": "ZCOOL XiaoWei is the right aesthetic match for the em-switch role, but it ships as **weight 400 only with no italic cut**. Chinese has no italic concept (slanted Han glyphs read as broken, not emphasized), so the lack of italic is fine — but the visual softness contrast that Instrument Serif italic provides in Latin (a slanted, more flowing letterform) canno", + "design_intent_font_pairing": [ + "Noto Sans SC", + "Noto Serif SC", + "LXGW WenKai", + "LXGW WenKai TC", + "ZCOOL XiaoWei", + "霞鹜文楷 LXGW WenKai" + ], + "source_section_heading": "CJK & International Content", + "source_section_sha256": "6c0971e51e3079eb53ee3a065d68c60824ac439da3d2acce960945fe0230d851" + }, + "family_usage_policy": { + "closed_visual_system": true, + "cross_family_layout_mix_allowed": false, + "recolor_allowed": false, + "font_substitution_allowed": false, + "decorative_elements_policy": "identity_element_not_noise", + "extend_missing_layout_policy": { + "same_fonts": true, + "same_palette": true, + "same_spacing_rhythm": true, + "same_component_grammar": true, + "same_decorative_vocabulary": true, + "same_chrome": true + }, + "soft_matching_policy": { + "tone_first": true, + "occasion_is_soft_signal": true, + "avoid_for_is_soft_warning": true, + "taste_can_override_industry": true, + "formality_density_as_sanity_check": true + }, + "hard_rules": [ + "preserve_fonts_palette_grid_slide_classes_decorative_elements", + "do_not_recolor_without_explicit_brand_override", + "do_not_mix_template_families", + "extend_missing_layout_inside_same_family", + "do_not_strip_identity_decorations" + ], + "source": "beautiful-html-templates/AGENTS.md", + "source_sha256": "ed619bb7d956303024872f170b96e5270672a03cf40bdf7ce0abc3d8018c9d77" + }, + "extension_grammar": { + "layout_rhythm": "editorial-tri-tone: medium density, medium-high formality. Three-color editorial system: dusty pink, mustard cream, and deep burgundy, set in Bricolage + Instrument Serif.", + "spacing_rhythm": "Reuse source spacing tokens and grid gaps: {\"slide_pad\": \"96px\", \"chrome_gutter\": \"64px\", \"section_gap\": \"48px\", \"card_pad\": \"28px 28px 30px\", \"chart_pad\": \"48px 48px 56px\", \"footer_bottom\": \"36px\", \"grid_gap\": \"24px\", \"endorsement_pad\": \"20px 0\"}", + "component_grammar": [ + "card", + "color", + "font_family", + "font_style", + "s-chart", + "s-closer", + "s-cover", + "s-grid", + "s-manifesto", + "s-quote" + ], + "chrome_rules": [ + "label" + ], + "decorative_vocabulary": [ + "grid", + "accent line", + "card panels", + "window chrome", + "poster blocks", + "quote mark", + "sticker collage" + ], + "allowed_new_layouts": [ + "comparison", + "risk", + "timeline", + "action_plan", + "case_evidence", + "metric_dashboard" + ], + "forbidden_mutations": [ + "new_palette", + "cross_family_components", + "fake_italic", + "new_decorative_motif", + "remote_font_dependency" + ], + "density_limits": "medium", + "source_basis": { + "template_id": "editorial-tri-tone", + "design_signal_sha256": "aa9e7afe84a36cb800f1130d143a5c4b11a214ce1cf8286182b75bbc282b1f52", + "class_name_count": 69 + } + }, "semantic_fit": { "best_for": [ "Anything that should feel like a fashion-magazine spread: editorial pitches", @@ -12864,15 +14962,60 @@ "screenshot_benchmarks": [ { "path": "beautiful-html-templates/screenshots/editorial-tri-tone-1.png", - "role": "reference" - }, - { - "path": "beautiful-html-templates/screenshots/editorial-tri-tone-3.png", - "role": "reference" + "role": "cover_reference", + "slide_number": 1, + "why_selected": "README gallery cover reference for editorial-tri-tone: Three-color editorial system: dusty pink, mustard cream, and deep burgundy, set in Bricolage + Instrument Serif.", + "visual_targets": [ + "palette", + "type_scale", + "chrome", + "density", + "layout_balance", + "grid" + ], + "acceptance_use": [ + "matcher_thumbnail", + "visual_qa", + "few_shot_reference" + ] }, { "path": "beautiful-html-templates/screenshots/editorial-tri-tone-4.png", - "role": "reference" + "role": "mid_deck_reference", + "slide_number": 4, + "why_selected": "README gallery mid deck reference for editorial-tri-tone: Three-color editorial system: dusty pink, mustard cream, and deep burgundy, set in Bricolage + Instrument Serif.", + "visual_targets": [ + "palette", + "type_scale", + "chrome", + "density", + "layout_balance", + "grid" + ], + "acceptance_use": [ + "matcher_thumbnail", + "visual_qa", + "few_shot_reference" + ] + }, + { + "path": "beautiful-html-templates/screenshots/editorial-tri-tone-3.png", + "role": "late_deck_reference", + "slide_number": 3, + "why_selected": "README gallery late deck reference for editorial-tri-tone: Three-color editorial system: dusty pink, mustard cream, and deep burgundy, set in Bricolage + Instrument Serif.", + "visual_targets": [ + "palette", + "type_scale", + "chrome", + "density", + "layout_balance", + "grid" + ], + "acceptance_use": [ + "matcher_thumbnail", + "visual_qa", + "few_shot_reference" + ] } ], "density": "medium" @@ -13570,6 +15713,109 @@ "mono": "system-mono" } }, + "cjk_policy": { + "strategy": "replace_family_whole_element", + "display_font_cn": "Noto Serif SC", + "body_font_cn": "Noto Sans SC", + "mono_font_policy": "latin_only_or_system_mono", + "runtime_font_policy": "system_font_only_no_remote_dependency", + "runtime_font_stack": [ + "system-sans-cjk", + "system-sans-cjk-heavy", + "system-sans-cjk-regular", + "system-mono" + ], + "emphasis_policy": "color_or_weight_only", + "italic_policy": "color_only_emphasis", + "letter_spacing_policy": "reset_letter_spacing_for_cjk_keep_latin_labels", + "mixed_run_spacing": "pangu_spacing", + "latin_accent_policy": "latin_only_allowed_when_semantic_annotation", + "known_degradation": "The system's commitment to Bodoni Moda weight 900 at 460px (jumbo numerals on inverse navy panels) is the hardest to translate — there is no Chinese face on the Google Fonts CDN that delivers Bodoni 900's optical heaviness at that scale. Noto Serif SC at weight 900 is the closest, but the contrast profile of Han glyphs at 460px reads visually heavier than Bo", + "design_intent_font_pairing": [ + "Noto Serif SC", + "Noto Sans SC", + "LXGW WenKai", + "LXGW WenKai TC", + "LXGW WenKai or Noto Serif SC", + "LXGW WenKai TC is the version on Google Fonts" + ], + "source_section_heading": "CJK & International Content", + "source_section_sha256": "088b64297ccb611ebf86b4144ff3ff3ca458e6051670825b6517b12d9b99da4a" + }, + "family_usage_policy": { + "closed_visual_system": true, + "cross_family_layout_mix_allowed": false, + "recolor_allowed": false, + "font_substitution_allowed": false, + "decorative_elements_policy": "identity_element_not_noise", + "extend_missing_layout_policy": { + "same_fonts": true, + "same_palette": true, + "same_spacing_rhythm": true, + "same_component_grammar": true, + "same_decorative_vocabulary": true, + "same_chrome": true + }, + "soft_matching_policy": { + "tone_first": true, + "occasion_is_soft_signal": true, + "avoid_for_is_soft_warning": true, + "taste_can_override_industry": true, + "formality_density_as_sanity_check": true + }, + "hard_rules": [ + "preserve_fonts_palette_grid_slide_classes_decorative_elements", + "do_not_recolor_without_explicit_brand_override", + "do_not_mix_template_families", + "extend_missing_layout_inside_same_family", + "do_not_strip_identity_decorations" + ], + "source": "beautiful-html-templates/AGENTS.md", + "source_sha256": "ed619bb7d956303024872f170b96e5270672a03cf40bdf7ce0abc3d8018c9d77" + }, + "extension_grammar": { + "layout_rhythm": "emerald-editorial: medium density, medium-high formality. A magazine-cover business deck: emerald + navy + paper, double-rule masthead ornaments, and a bold Bodoni-style display serif.", + "spacing_rhythm": "Reuse source spacing tokens and grid gaps: {\"pad_default\": \"110px 110px 70px\", \"pad_cover\": \"56px 110px\", \"pad_closing\": \"80px 110px\", \"pad_statement\": \"110px 110px 70px\", \"masthead_inset\": \"56px 80px\", \"rule_thick\": \"4px\", \"rule_thicker\": \"5px\", \"rule_thin\": \"2p", + "component_grammar": [ + "stat", + "stats" + ], + "chrome_rules": [ + "s2-eyebrow", + "s6-eyebrow", + "s7-eyebrow" + ], + "decorative_vocabulary": [ + "grid", + "accent line", + "card panels", + "paper texture", + "poster blocks", + "quote mark", + "sticker collage" + ], + "allowed_new_layouts": [ + "comparison", + "risk", + "timeline", + "action_plan", + "case_evidence", + "metric_dashboard" + ], + "forbidden_mutations": [ + "new_palette", + "cross_family_components", + "fake_italic", + "new_decorative_motif", + "remote_font_dependency" + ], + "density_limits": "medium", + "source_basis": { + "template_id": "emerald-editorial", + "design_signal_sha256": "bf47953c2db3adf338957cdf1e4de1184e408193fbde00387270886cdfb031d6", + "class_name_count": 90 + } + }, "semantic_fit": { "best_for": [ "Anything that should feel like the front of a serious magazine", @@ -13804,15 +16050,60 @@ "screenshot_benchmarks": [ { "path": "beautiful-html-templates/screenshots/emerald-editorial-1.png", - "role": "reference" + "role": "cover_reference", + "slide_number": 1, + "why_selected": "README gallery cover reference for emerald-editorial: A magazine-cover business deck: emerald + navy + paper, double-rule masthead ornaments, and a bold Bodoni-style display serif.", + "visual_targets": [ + "palette", + "type_scale", + "chrome", + "density", + "layout_balance", + "grid" + ], + "acceptance_use": [ + "matcher_thumbnail", + "visual_qa", + "few_shot_reference" + ] }, { "path": "beautiful-html-templates/screenshots/emerald-editorial-3.png", - "role": "reference" + "role": "mid_deck_reference", + "slide_number": 3, + "why_selected": "README gallery mid deck reference for emerald-editorial: A magazine-cover business deck: emerald + navy + paper, double-rule masthead ornaments, and a bold Bodoni-style display serif.", + "visual_targets": [ + "palette", + "type_scale", + "chrome", + "density", + "layout_balance", + "grid" + ], + "acceptance_use": [ + "matcher_thumbnail", + "visual_qa", + "few_shot_reference" + ] }, { "path": "beautiful-html-templates/screenshots/emerald-editorial-6.png", - "role": "reference" + "role": "late_deck_reference", + "slide_number": 6, + "why_selected": "README gallery late deck reference for emerald-editorial: A magazine-cover business deck: emerald + navy + paper, double-rule masthead ornaments, and a bold Bodoni-style display serif.", + "visual_targets": [ + "palette", + "type_scale", + "chrome", + "density", + "layout_balance", + "grid" + ], + "acceptance_use": [ + "matcher_thumbnail", + "visual_qa", + "few_shot_reference" + ] } ], "density": "medium" @@ -14511,6 +16802,113 @@ "mono": "system-mono" } }, + "cjk_policy": { + "strategy": "replace_family_whole_element", + "display_font_cn": "Noto Serif SC", + "body_font_cn": "Noto Sans SC", + "mono_font_policy": "latin_only_or_system_mono", + "runtime_font_policy": "system_font_only_no_remote_dependency", + "runtime_font_stack": [ + "system-sans-cjk", + "system-sans-cjk-heavy", + "system-sans-cjk-regular", + "system-mono" + ], + "emphasis_policy": "color_or_weight_only", + "italic_policy": "drop_italic", + "letter_spacing_policy": "reset_letter_spacing_for_cjk_keep_latin_labels", + "mixed_run_spacing": "pangu_spacing", + "latin_accent_policy": "latin_only_allowed_when_semantic_annotation", + "known_degradation": "The system's signature `` italic-coral treatment is the hardest piece to translate: **Chinese has no italic concept** — slanted Han glyphs read as broken, not as emphasis. The current Grove CSS depends on the browser's default `` styling (italic) plus a CSS color rule for the coral. In Chinese, the italic does nothing visually, so the emphasis collap", + "design_intent_font_pairing": [ + "Noto Serif SC", + "Noto Sans SC", + "LXGW WenKai", + "LXGW WenKai as the preferred CJK display face ahead of Noto Serif SC", + "LXGW WenKai TC", + "LXGW WenKai and Playfair Display both sit at similar optical baselines" + ], + "source_section_heading": "CJK & International Content", + "source_section_sha256": "3fa7fab3a4e7d592250d221acb2eecad53fabcd0059aab0d0db9e0dcd951ceef" + }, + "family_usage_policy": { + "closed_visual_system": true, + "cross_family_layout_mix_allowed": false, + "recolor_allowed": false, + "font_substitution_allowed": false, + "decorative_elements_policy": "identity_element_not_noise", + "extend_missing_layout_policy": { + "same_fonts": true, + "same_palette": true, + "same_spacing_rhythm": true, + "same_component_grammar": true, + "same_decorative_vocabulary": true, + "same_chrome": true + }, + "soft_matching_policy": { + "tone_first": true, + "occasion_is_soft_signal": true, + "avoid_for_is_soft_warning": true, + "taste_can_override_industry": true, + "formality_density_as_sanity_check": true + }, + "hard_rules": [ + "preserve_fonts_palette_grid_slide_classes_decorative_elements", + "do_not_recolor_without_explicit_brand_override", + "do_not_mix_template_families", + "extend_missing_layout_inside_same_family", + "do_not_strip_identity_decorations" + ], + "source": "beautiful-html-templates/AGENTS.md", + "source_sha256": "ed619bb7d956303024872f170b96e5270672a03cf40bdf7ce0abc3d8018c9d77" + }, + "extension_grammar": { + "layout_rhythm": "grove: medium density, medium-high formality. Forest-green canvas with cream type, classical Playfair serifs, and a single rust accent.", + "spacing_rhythm": "Reuse source spacing tokens and grid gaps: {\"pad_x\": \"8vw\", \"pad_y\": \"6.5vh\", \"pad_quote_x\": \"calc(8vw * 1.1)\", \"pad_quote_y\": \"calc(6.5vh * 1.2)\", \"gap_lg\": \"4.5vh\", \"gap_md\": \"2.8vh\", \"gap_sm\": \"1.4vh\", \"rule_short\": \"36px\"}", + "component_grammar": [ + "color", + "font_style", + "statement-body", + "stats-row" + ], + "chrome_rules": [ + "bar-x-label", + "compare-label", + "grove-stat-label", + "label", + "slide-chrome" + ], + "decorative_vocabulary": [ + "grid", + "accent line", + "card panels", + "paper texture", + "window chrome", + "poster blocks", + "quote mark" + ], + "allowed_new_layouts": [ + "comparison", + "risk", + "timeline", + "action_plan", + "case_evidence", + "metric_dashboard" + ], + "forbidden_mutations": [ + "new_palette", + "cross_family_components", + "fake_italic", + "new_decorative_motif", + "remote_font_dependency" + ], + "density_limits": "medium", + "source_basis": { + "template_id": "grove", + "design_signal_sha256": "dc6b2cb5dfe935cd6ff8de9407f9cb73be8a2703a5a44ddc0b267bce5f7aae26", + "class_name_count": 58 + } + }, "semantic_fit": { "best_for": [ "Anything that should feel organic", @@ -14752,15 +17150,60 @@ "screenshot_benchmarks": [ { "path": "beautiful-html-templates/screenshots/grove-1.png", - "role": "reference" + "role": "cover_reference", + "slide_number": 1, + "why_selected": "README gallery cover reference for grove: Forest-green canvas with cream type, classical Playfair serifs, and a single rust accent.", + "visual_targets": [ + "palette", + "type_scale", + "chrome", + "density", + "layout_balance", + "grid" + ], + "acceptance_use": [ + "matcher_thumbnail", + "visual_qa", + "few_shot_reference" + ] }, { "path": "beautiful-html-templates/screenshots/grove-4.png", - "role": "reference" + "role": "mid_deck_reference", + "slide_number": 4, + "why_selected": "README gallery mid deck reference for grove: Forest-green canvas with cream type, classical Playfair serifs, and a single rust accent.", + "visual_targets": [ + "palette", + "type_scale", + "chrome", + "density", + "layout_balance", + "grid" + ], + "acceptance_use": [ + "matcher_thumbnail", + "visual_qa", + "few_shot_reference" + ] }, { "path": "beautiful-html-templates/screenshots/grove-8.png", - "role": "reference" + "role": "late_deck_reference", + "slide_number": 8, + "why_selected": "README gallery late deck reference for grove: Forest-green canvas with cream type, classical Playfair serifs, and a single rust accent.", + "visual_targets": [ + "palette", + "type_scale", + "chrome", + "density", + "layout_balance", + "grid" + ], + "acceptance_use": [ + "matcher_thumbnail", + "visual_qa", + "few_shot_reference" + ] } ], "density": "medium" @@ -15500,6 +17943,114 @@ "mono": "system-mono" } }, + "cjk_policy": { + "strategy": "replace_family_whole_element", + "display_font_cn": "Noto Serif SC", + "body_font_cn": "Noto Serif SC", + "mono_font_policy": "latin_only_or_system_mono", + "runtime_font_policy": "system_font_only_no_remote_dependency", + "runtime_font_stack": [ + "system-sans-cjk", + "system-sans-cjk-heavy", + "system-sans-cjk-regular", + "system-mono" + ], + "emphasis_policy": "color_or_weight_only", + "italic_policy": "drop_italic", + "letter_spacing_policy": "reset_letter_spacing_for_cjk_keep_latin_labels", + "mixed_run_spacing": "pangu_spacing", + "latin_accent_policy": "latin_only_allowed_when_semantic_annotation", + "known_degradation": "The Fraunces italic-default body voice is one of Long Table's most distinctive typographic moves in Latin — italic Mincho-style serif body that gives the system its lyrical, hand-written warmth. Chinese has no equivalent: there is no commonly-available \"italic Mincho\" face on the Google Fonts CDN, and slanted Han glyphs read as broken regardless. The Chinese", + "design_intent_font_pairing": [ + "Noto Serif SC" + ], + "source_section_heading": "CJK & International Content", + "source_section_sha256": "9cc53f4b19ce367aac9fdfb5eb01bac9165ffc7e8a308431dfb901915228a8d6" + }, + "family_usage_policy": { + "closed_visual_system": true, + "cross_family_layout_mix_allowed": false, + "recolor_allowed": false, + "font_substitution_allowed": false, + "decorative_elements_policy": "identity_element_not_noise", + "extend_missing_layout_policy": { + "same_fonts": true, + "same_palette": true, + "same_spacing_rhythm": true, + "same_component_grammar": true, + "same_decorative_vocabulary": true, + "same_chrome": true + }, + "soft_matching_policy": { + "tone_first": true, + "occasion_is_soft_signal": true, + "avoid_for_is_soft_warning": true, + "taste_can_override_industry": true, + "formality_density_as_sanity_check": true + }, + "hard_rules": [ + "preserve_fonts_palette_grid_slide_classes_decorative_elements", + "do_not_recolor_without_explicit_brand_override", + "do_not_mix_template_families", + "extend_missing_layout_inside_same_family", + "do_not_strip_identity_decorations" + ], + "source": "beautiful-html-templates/AGENTS.md", + "source_sha256": "ed619bb7d956303024872f170b96e5270672a03cf40bdf7ce0abc3d8018c9d77" + }, + "extension_grammar": { + "layout_rhythm": "long-table: medium density, medium formality. Warm cream and rust-red supper-club aesthetic with bold uppercase grotesk headlines, Fraunces serifs, and pill-shaped outlined buttons.", + "spacing_rhythm": "Reuse source spacing tokens and grid gaps: {\"slide_pad_h_default\": \"clamp(60px, 5vw, 110px)\", \"slide_pad_h_wide\": \"clamp(80px, 7vw, 160px)\", \"slide_pad_h_narrow\": \"clamp(120px, 12vw, 280px)\", \"slide_pad_top_default\": \"clamp(96px, 10vh, 160px)\", \"slide_pad_top_cov", + "component_grammar": [ + "card", + "card-top", + "s-cal", + "s-closing", + "s-cover", + "s-featured", + "s-index", + "s-manifesto", + "s-menu", + "s-quote" + ], + "chrome_rules": [ + "ed-badge", + "ed-label", + "footer-line", + "nav-hint", + "pagenum" + ], + "decorative_vocabulary": [ + "grid", + "accent line", + "card panels", + "paper texture", + "poster blocks", + "quote mark", + "sticker collage" + ], + "allowed_new_layouts": [ + "comparison", + "risk", + "timeline", + "action_plan", + "case_evidence", + "metric_dashboard" + ], + "forbidden_mutations": [ + "new_palette", + "cross_family_components", + "fake_italic", + "new_decorative_motif", + "remote_font_dependency" + ], + "density_limits": "medium", + "source_basis": { + "template_id": "long-table", + "design_signal_sha256": "9d0aae48cef8f83559d5143ac454347cc1c7e438b3cd7d07842a965274671ff5", + "class_name_count": 77 + } + }, "semantic_fit": { "best_for": [ "Anything that should feel like a warm", @@ -15729,15 +18280,60 @@ "screenshot_benchmarks": [ { "path": "beautiful-html-templates/screenshots/long-table-1.png", - "role": "reference" + "role": "cover_reference", + "slide_number": 1, + "why_selected": "README gallery cover reference for long-table: Warm cream and rust-red supper-club aesthetic with bold uppercase grotesk headlines, Fraunces serifs, and pill-shaped outlined buttons.", + "visual_targets": [ + "palette", + "type_scale", + "chrome", + "density", + "layout_balance", + "grid" + ], + "acceptance_use": [ + "matcher_thumbnail", + "visual_qa", + "few_shot_reference" + ] }, { "path": "beautiful-html-templates/screenshots/long-table-3.png", - "role": "reference" + "role": "mid_deck_reference", + "slide_number": 3, + "why_selected": "README gallery mid deck reference for long-table: Warm cream and rust-red supper-club aesthetic with bold uppercase grotesk headlines, Fraunces serifs, and pill-shaped outlined buttons.", + "visual_targets": [ + "palette", + "type_scale", + "chrome", + "density", + "layout_balance", + "grid" + ], + "acceptance_use": [ + "matcher_thumbnail", + "visual_qa", + "few_shot_reference" + ] }, { "path": "beautiful-html-templates/screenshots/long-table-7.png", - "role": "reference" + "role": "late_deck_reference", + "slide_number": 7, + "why_selected": "README gallery late deck reference for long-table: Warm cream and rust-red supper-club aesthetic with bold uppercase grotesk headlines, Fraunces serifs, and pill-shaped outlined buttons.", + "visual_targets": [ + "palette", + "type_scale", + "chrome", + "density", + "layout_balance", + "grid" + ], + "acceptance_use": [ + "matcher_thumbnail", + "visual_qa", + "few_shot_reference" + ] } ], "density": "medium" @@ -16491,6 +19087,110 @@ "mono": "system-mono" } }, + "cjk_policy": { + "strategy": "replace_family_whole_element", + "display_font_cn": "Noto Serif SC", + "body_font_cn": "Noto Sans SC", + "mono_font_policy": "latin_only_or_system_mono", + "runtime_font_policy": "system_font_only_no_remote_dependency", + "runtime_font_stack": [ + "system-sans-cjk", + "system-sans-cjk-heavy", + "system-sans-cjk-regular", + "system-mono" + ], + "emphasis_policy": "color_or_weight_only", + "italic_policy": "drop_italic", + "letter_spacing_policy": "reset_letter_spacing_for_cjk_keep_latin_labels", + "mixed_run_spacing": "pangu_spacing", + "latin_accent_policy": "latin_only_allowed_when_semantic_annotation", + "known_degradation": "The Bricolage Grotesque \"heavy, rounded grotesque with mechanical character\" is one of Mat's most distinctive typographic moves in Latin — it's what gives the system its industrial-product-page voice. Chinese has no exact equivalent: Noto Serif SC at weight 700 provides structural mass but reads as more traditional / literary than Bricolage's rounded moderni", + "design_intent_font_pairing": [ + "Noto Serif SC", + "Noto Sans SC" + ], + "source_section_heading": "CJK & International Content", + "source_section_sha256": "100a2f15bc7c887da7af8bdac97512612946e64891bd73ad605f3b0beeb6c067" + }, + "family_usage_policy": { + "closed_visual_system": true, + "cross_family_layout_mix_allowed": false, + "recolor_allowed": false, + "font_substitution_allowed": false, + "decorative_elements_policy": "identity_element_not_noise", + "extend_missing_layout_policy": { + "same_fonts": true, + "same_palette": true, + "same_spacing_rhythm": true, + "same_component_grammar": true, + "same_decorative_vocabulary": true, + "same_chrome": true + }, + "soft_matching_policy": { + "tone_first": true, + "occasion_is_soft_signal": true, + "avoid_for_is_soft_warning": true, + "taste_can_override_industry": true, + "formality_density_as_sanity_check": true + }, + "hard_rules": [ + "preserve_fonts_palette_grid_slide_classes_decorative_elements", + "do_not_recolor_without_explicit_brand_override", + "do_not_mix_template_families", + "extend_missing_layout_inside_same_family", + "do_not_strip_identity_decorations" + ], + "source": "beautiful-html-templates/AGENTS.md", + "source_sha256": "ed619bb7d956303024872f170b96e5270672a03cf40bdf7ce0abc3d8018c9d77" + }, + "extension_grammar": { + "layout_rhythm": "mat: medium density, medium formality. Dark sage canvas with bone paper and burnt-orange accent; mid-century modern with wood undertones.", + "spacing_rhythm": "Reuse source spacing tokens and grid gaps: {\"pad_x\": \"5.5vw\", \"pad_y\": \"5.5vh\", \"gap_lg\": \"4.5vh\", \"gap_md\": \"2.8vh\", \"gap_sm\": \"1.4vh\"}", + "component_grammar": [ + "title_block", + "section_label", + "metric_card", + "finding_callout", + "evidence_table", + "comparison_matrix" + ], + "chrome_rules": [ + "bar-x-label", + "compare-label", + "label", + "mat-stat-label", + "slide-chrome" + ], + "decorative_vocabulary": [ + "grid", + "accent line", + "card panels", + "paper texture", + "poster blocks", + "quote mark" + ], + "allowed_new_layouts": [ + "comparison", + "risk", + "timeline", + "action_plan", + "case_evidence", + "metric_dashboard" + ], + "forbidden_mutations": [ + "new_palette", + "cross_family_components", + "fake_italic", + "new_decorative_motif", + "remote_font_dependency" + ], + "density_limits": "medium", + "source_basis": { + "template_id": "mat", + "design_signal_sha256": "486ea359d1075aff092a22a3c00a7cc0dac93e1ef080975353800320578b370f", + "class_name_count": 65 + } + }, "semantic_fit": { "best_for": [ "Anything that should feel mid-century", @@ -16738,15 +19438,60 @@ "screenshot_benchmarks": [ { "path": "beautiful-html-templates/screenshots/mat-1.png", - "role": "reference" + "role": "cover_reference", + "slide_number": 1, + "why_selected": "README gallery cover reference for mat: Dark sage canvas with bone paper and burnt-orange accent; mid-century modern with wood undertones.", + "visual_targets": [ + "palette", + "type_scale", + "chrome", + "density", + "layout_balance", + "grid" + ], + "acceptance_use": [ + "matcher_thumbnail", + "visual_qa", + "few_shot_reference" + ] }, { "path": "beautiful-html-templates/screenshots/mat-4.png", - "role": "reference" + "role": "mid_deck_reference", + "slide_number": 4, + "why_selected": "README gallery mid deck reference for mat: Dark sage canvas with bone paper and burnt-orange accent; mid-century modern with wood undertones.", + "visual_targets": [ + "palette", + "type_scale", + "chrome", + "density", + "layout_balance", + "grid" + ], + "acceptance_use": [ + "matcher_thumbnail", + "visual_qa", + "few_shot_reference" + ] }, { "path": "beautiful-html-templates/screenshots/mat-8.png", - "role": "reference" + "role": "late_deck_reference", + "slide_number": 8, + "why_selected": "README gallery late deck reference for mat: Dark sage canvas with bone paper and burnt-orange accent; mid-century modern with wood undertones.", + "visual_targets": [ + "palette", + "type_scale", + "chrome", + "density", + "layout_balance", + "grid" + ], + "acceptance_use": [ + "matcher_thumbnail", + "visual_qa", + "few_shot_reference" + ] } ], "density": "medium" @@ -17394,8 +20139,8 @@ "source_template_html": "beautiful-html-templates/templates/monochrome/template.html", "source_screenshots": [ "beautiful-html-templates/screenshots/monochrome-1.png", - "beautiful-html-templates/screenshots/monochrome-12.png", - "beautiful-html-templates/screenshots/monochrome-4.png" + "beautiful-html-templates/screenshots/monochrome-4.png", + "beautiful-html-templates/screenshots/monochrome-12.png" ], "reference_screenshot": "beautiful-html-templates/screenshots/monochrome-1.png", "reference_svg": "", @@ -17487,6 +20232,114 @@ "mono": "system-mono" } }, + "cjk_policy": { + "strategy": "replace_family_whole_element", + "display_font_cn": "Noto Sans SC", + "body_font_cn": "Noto Serif SC", + "mono_font_policy": "latin_only_or_system_mono", + "runtime_font_policy": "system_font_only_no_remote_dependency", + "runtime_font_stack": [ + "system-sans-cjk", + "system-sans-cjk-heavy", + "system-sans-cjk-regular", + "system-mono" + ], + "emphasis_policy": "color_or_weight_only", + "italic_policy": "drop_italic", + "letter_spacing_policy": "reset_letter_spacing_for_cjk_keep_latin_labels", + "mixed_run_spacing": "pangu_spacing", + "latin_accent_policy": "latin_only_allowed_when_semantic_annotation", + "known_degradation": "The 8vw horizontal padding (the most generous in the library) was tuned for Latin's narrower glyph widths. Chinese characters are roughly square and consume more horizontal space at the same point size. Long Chinese headlines that would fit on one line in English may wrap to two. Reduce display headline sizes by ~15% (Jost 8.5vw → Noto Sans SC 7.2vw) when th", + "design_intent_font_pairing": [ + "Noto Sans SC", + "Noto Serif SC" + ], + "source_section_heading": "CJK & International Content", + "source_section_sha256": "b156f146eda8d20d4a123aab2aa7fd033bb50bb7b86600ddcec407fc8350d1f7" + }, + "family_usage_policy": { + "closed_visual_system": true, + "cross_family_layout_mix_allowed": false, + "recolor_allowed": false, + "font_substitution_allowed": false, + "decorative_elements_policy": "identity_element_not_noise", + "extend_missing_layout_policy": { + "same_fonts": true, + "same_palette": true, + "same_spacing_rhythm": true, + "same_component_grammar": true, + "same_decorative_vocabulary": true, + "same_chrome": true + }, + "soft_matching_policy": { + "tone_first": true, + "occasion_is_soft_signal": true, + "avoid_for_is_soft_warning": true, + "taste_can_override_industry": true, + "formality_density_as_sanity_check": true + }, + "hard_rules": [ + "preserve_fonts_palette_grid_slide_classes_decorative_elements", + "do_not_recolor_without_explicit_brand_override", + "do_not_mix_template_families", + "extend_missing_layout_inside_same_family", + "do_not_strip_identity_decorations" + ], + "source": "beautiful-html-templates/AGENTS.md", + "source_sha256": "ed619bb7d956303024872f170b96e5270672a03cf40bdf7ce0abc3d8018c9d77" + }, + "extension_grammar": { + "layout_rhythm": "monochrome: high density, high formality. Ivory ledger paper with all-black type; Lora serif headlines, Jost body, no color at all.", + "spacing_rhythm": "Reuse source spacing tokens and grid gaps: {\"pad_x\": \"8vw\", \"pad_y\": \"6vh\", \"gap_lg\": \"5vh\", \"gap_md\": \"3vh\", \"gap_sm\": \"1.5vh\"}", + "component_grammar": [ + "stat-card", + "stat-label", + "stat-note", + "stat-value", + "statement-body", + "stats-grid" + ], + "chrome_rules": [ + "bar-x-label", + "compare-label", + "label", + "pie-item-label", + "sidebar-label", + "slide-chrome", + "stat-label" + ], + "decorative_vocabulary": [ + "grid", + "accent line", + "card panels", + "paper texture", + "poster blocks", + "quote mark", + "sticker collage", + "pixel motif" + ], + "allowed_new_layouts": [ + "comparison", + "risk", + "timeline", + "action_plan", + "case_evidence", + "metric_dashboard" + ], + "forbidden_mutations": [ + "new_palette", + "cross_family_components", + "fake_italic", + "new_decorative_motif", + "remote_font_dependency" + ], + "density_limits": "high", + "source_basis": { + "template_id": "monochrome", + "design_signal_sha256": "c9d1e232dd402cf04fcd5e7edac41b462a1933aec5623a0c50f8377b99594163", + "class_name_count": 100 + } + }, "semantic_fit": { "best_for": [ "Anything that should feel like a hand-typeset ledger: user research synthesis", @@ -17761,15 +20614,60 @@ "screenshot_benchmarks": [ { "path": "beautiful-html-templates/screenshots/monochrome-1.png", - "role": "reference" - }, - { - "path": "beautiful-html-templates/screenshots/monochrome-12.png", - "role": "reference" + "role": "cover_reference", + "slide_number": 1, + "why_selected": "README gallery cover reference for monochrome: Ivory ledger paper with all-black type; Lora serif headlines, Jost body, no color at all.", + "visual_targets": [ + "palette", + "type_scale", + "chrome", + "density", + "layout_balance", + "grid" + ], + "acceptance_use": [ + "matcher_thumbnail", + "visual_qa", + "few_shot_reference" + ] }, { "path": "beautiful-html-templates/screenshots/monochrome-4.png", - "role": "reference" + "role": "mid_deck_reference", + "slide_number": 4, + "why_selected": "README gallery mid deck reference for monochrome: Ivory ledger paper with all-black type; Lora serif headlines, Jost body, no color at all.", + "visual_targets": [ + "palette", + "type_scale", + "chrome", + "density", + "layout_balance", + "grid" + ], + "acceptance_use": [ + "matcher_thumbnail", + "visual_qa", + "few_shot_reference" + ] + }, + { + "path": "beautiful-html-templates/screenshots/monochrome-12.png", + "role": "late_deck_reference", + "slide_number": 12, + "why_selected": "README gallery late deck reference for monochrome: Ivory ledger paper with all-black type; Lora serif headlines, Jost body, no color at all.", + "visual_targets": [ + "palette", + "type_scale", + "chrome", + "density", + "layout_balance", + "grid" + ], + "acceptance_use": [ + "matcher_thumbnail", + "visual_qa", + "few_shot_reference" + ] } ], "density": "high" @@ -18564,6 +21462,113 @@ "mono": "system-mono" } }, + "cjk_policy": { + "strategy": "replace_family_whole_element", + "display_font_cn": "Noto Sans SC", + "body_font_cn": "Noto Sans SC", + "mono_font_policy": "latin_only_or_system_mono", + "runtime_font_policy": "system_font_only_no_remote_dependency", + "runtime_font_stack": [ + "system-sans-cjk", + "system-sans-cjk-heavy", + "system-sans-cjk-regular", + "system-mono" + ], + "emphasis_policy": "color_or_weight_only", + "italic_policy": "drop_italic", + "letter_spacing_policy": "reset_letter_spacing_for_cjk_keep_latin_labels", + "mixed_run_spacing": "pangu_spacing", + "latin_accent_policy": "latin_only_allowed_when_semantic_annotation", + "known_degradation": "The negative letter-spacing (-0.005 to -0.05em) scales with display size in this system and is part of the \"brutalist compressed\" signature. **Removing it for Chinese characters breaks visual parity with Latin slides in a mixed deck.** Accept this: pure-CJK slides will read as slightly less compressed than pure-Latin slides. Don't try to compensate by tighte", + "design_intent_font_pairing": [ + "Noto Sans SC" + ], + "source_section_heading": "CJK & International Content", + "source_section_sha256": "d23f764ecbab63a3f5f6ef3cc72f9e32401a8a7c84601690105461d3c69045e8" + }, + "family_usage_policy": { + "closed_visual_system": true, + "cross_family_layout_mix_allowed": false, + "recolor_allowed": false, + "font_substitution_allowed": false, + "decorative_elements_policy": "identity_element_not_noise", + "extend_missing_layout_policy": { + "same_fonts": true, + "same_palette": true, + "same_spacing_rhythm": true, + "same_component_grammar": true, + "same_decorative_vocabulary": true, + "same_chrome": true + }, + "soft_matching_policy": { + "tone_first": true, + "occasion_is_soft_signal": true, + "avoid_for_is_soft_warning": true, + "taste_can_override_industry": true, + "formality_density_as_sanity_check": true + }, + "hard_rules": [ + "preserve_fonts_palette_grid_slide_classes_decorative_elements", + "do_not_recolor_without_explicit_brand_override", + "do_not_mix_template_families", + "extend_missing_layout_inside_same_family", + "do_not_strip_identity_decorations" + ], + "source": "beautiful-html-templates/AGENTS.md", + "source_sha256": "ed619bb7d956303024872f170b96e5270672a03cf40bdf7ce0abc3d8018c9d77" + }, + "extension_grammar": { + "layout_rhythm": "neo-grid-bold: high density, medium formality. Editorial neo-brutalism with a single neon yellow accent on off-white paper.", + "spacing_rhythm": "Reuse source spacing tokens and grid gaps: {\"frame_inset\": \"40px\", \"grid_gap\": \"12px\", \"grid_gap_lg\": \"18px\", \"card_pad_sm\": \"24px 28px\", \"card_pad_md\": \"28px 32px\", \"card_pad_lg\": \"36px 32px\", \"card_pad_xl\": \"40px 44px\"}", + "component_grammar": [ + "card", + "panel-cap", + "panel-mid", + "panel-photo-l", + "panel-photo-r", + "panel-titletile", + "s-chart", + "s-chart2", + "s-consult", + "s-cover" + ], + "chrome_rules": [ + "label", + "pagenum", + "row-label", + "yearlabel" + ], + "decorative_vocabulary": [ + "grid", + "accent line", + "card panels", + "paper texture", + "poster blocks", + "quote mark", + "sticker collage" + ], + "allowed_new_layouts": [ + "comparison", + "risk", + "timeline", + "action_plan", + "case_evidence", + "metric_dashboard" + ], + "forbidden_mutations": [ + "new_palette", + "cross_family_components", + "fake_italic", + "new_decorative_motif", + "remote_font_dependency" + ], + "density_limits": "high", + "source_basis": { + "template_id": "neo-grid-bold", + "design_signal_sha256": "627ae09fcb29c165929d4501e3b996fe2b646fe2ed1c491730f0adf9e8486413", + "class_name_count": 102 + } + }, "semantic_fit": { "best_for": [ "Anything that should feel confident and editorial-graphic: design-led pitches", @@ -18807,15 +21812,60 @@ "screenshot_benchmarks": [ { "path": "beautiful-html-templates/screenshots/neo-grid-bold-1.png", - "role": "reference" + "role": "cover_reference", + "slide_number": 1, + "why_selected": "README gallery cover reference for neo-grid-bold: Editorial neo-brutalism with a single neon yellow accent on off-white paper.", + "visual_targets": [ + "palette", + "type_scale", + "chrome", + "density", + "layout_balance", + "grid" + ], + "acceptance_use": [ + "matcher_thumbnail", + "visual_qa", + "few_shot_reference" + ] }, { "path": "beautiful-html-templates/screenshots/neo-grid-bold-3.png", - "role": "reference" + "role": "mid_deck_reference", + "slide_number": 3, + "why_selected": "README gallery mid deck reference for neo-grid-bold: Editorial neo-brutalism with a single neon yellow accent on off-white paper.", + "visual_targets": [ + "palette", + "type_scale", + "chrome", + "density", + "layout_balance", + "grid" + ], + "acceptance_use": [ + "matcher_thumbnail", + "visual_qa", + "few_shot_reference" + ] }, { "path": "beautiful-html-templates/screenshots/neo-grid-bold-8.png", - "role": "reference" + "role": "late_deck_reference", + "slide_number": 8, + "why_selected": "README gallery late deck reference for neo-grid-bold: Editorial neo-brutalism with a single neon yellow accent on off-white paper.", + "visual_targets": [ + "palette", + "type_scale", + "chrome", + "density", + "layout_balance", + "grid" + ], + "acceptance_use": [ + "matcher_thumbnail", + "visual_qa", + "few_shot_reference" + ] } ], "density": "high" @@ -19564,6 +22614,111 @@ "mono": "system-mono" } }, + "cjk_policy": { + "strategy": "replace_family_whole_element", + "display_font_cn": "Noto Serif SC", + "body_font_cn": "Noto Sans SC", + "mono_font_policy": "latin_only_or_system_mono", + "runtime_font_policy": "system_font_only_no_remote_dependency", + "runtime_font_stack": [ + "system-sans-cjk", + "system-sans-cjk-heavy", + "system-sans-cjk-regular", + "system-mono" + ], + "emphasis_policy": "color_or_weight_only", + "italic_policy": "color_only_emphasis", + "letter_spacing_policy": "reset_letter_spacing_for_cjk_keep_latin_labels", + "mixed_run_spacing": "pangu_spacing", + "latin_accent_policy": "latin_only_allowed_when_semantic_annotation", + "known_degradation": "**Caveat Brush has no acceptable Chinese equivalent.** The \"human interrupt\" voice is structurally absent in a pure-CJK People's Platform deck. The two workarounds (drop the interrupt entirely; use Latin-in-Chinese for the script moments) are both visible aesthetic compromises — the populist-poster system loses one of its three voices when forced into pure C", + "design_intent_font_pairing": [ + "Noto Serif SC", + "Noto Sans SC" + ], + "source_section_heading": "CJK & International Content", + "source_section_sha256": "9665acd47d0f6576554ddec531a9925a0b578a9cef2fc7e62946fbd34ac72378" + }, + "family_usage_policy": { + "closed_visual_system": true, + "cross_family_layout_mix_allowed": false, + "recolor_allowed": false, + "font_substitution_allowed": false, + "decorative_elements_policy": "identity_element_not_noise", + "extend_missing_layout_policy": { + "same_fonts": true, + "same_palette": true, + "same_spacing_rhythm": true, + "same_component_grammar": true, + "same_decorative_vocabulary": true, + "same_chrome": true + }, + "soft_matching_policy": { + "tone_first": true, + "occasion_is_soft_signal": true, + "avoid_for_is_soft_warning": true, + "taste_can_override_industry": true, + "formality_density_as_sanity_check": true + }, + "hard_rules": [ + "preserve_fonts_palette_grid_slide_classes_decorative_elements", + "do_not_recolor_without_explicit_brand_override", + "do_not_mix_template_families", + "extend_missing_layout_inside_same_family", + "do_not_strip_identity_decorations" + ], + "source": "beautiful-html-templates/AGENTS.md", + "source_sha256": "ed619bb7d956303024872f170b96e5270672a03cf40bdf7ce0abc3d8018c9d77" + }, + "extension_grammar": { + "layout_rhythm": "peoples-platform: medium-high density, medium-low formality. Activist poster energy: blue, orange, red on cream, with Alfa Slab + Caveat Brush.", + "spacing_rhythm": "Reuse source spacing tokens and grid gaps: {\"slide_gutter\": \"90px\", \"content_gutter\": \"120px\", \"topbar_height\": \"90px\", \"section_border\": \"6px\", \"inner_border\": \"3px\", \"grid_gap_lg\": \"90px\", \"grid_gap_md\": \"30px\", \"frame_inset\": \"48px\"}", + "component_grammar": [ + "s-close", + "s-compare", + "s-cover", + "s-manifesto", + "s-pillars", + "s-platform", + "s-quote", + "s-stat", + "s-timeline", + "s-toc" + ], + "chrome_rules": [ + "label", + "stamp" + ], + "decorative_vocabulary": [ + "grid", + "accent line", + "card panels", + "paper texture", + "poster blocks", + "quote mark" + ], + "allowed_new_layouts": [ + "comparison", + "risk", + "timeline", + "action_plan", + "case_evidence", + "metric_dashboard" + ], + "forbidden_mutations": [ + "new_palette", + "cross_family_components", + "fake_italic", + "new_decorative_motif", + "remote_font_dependency" + ], + "density_limits": "medium-high", + "source_basis": { + "template_id": "peoples-platform", + "design_signal_sha256": "d77a6bc566e60367e2c812f699d6838d67e71e5e17aa890ca87fcbad19277f0d", + "class_name_count": 75 + } + }, "semantic_fit": { "best_for": [ "Anything that should feel honest", @@ -19784,15 +22939,60 @@ "screenshot_benchmarks": [ { "path": "beautiful-html-templates/screenshots/peoples-platform-1.png", - "role": "reference" + "role": "cover_reference", + "slide_number": 1, + "why_selected": "README gallery cover reference for peoples-platform: Activist poster energy: blue, orange, red on cream, with Alfa Slab + Caveat Brush.", + "visual_targets": [ + "palette", + "type_scale", + "chrome", + "density", + "layout_balance", + "grid" + ], + "acceptance_use": [ + "matcher_thumbnail", + "visual_qa", + "few_shot_reference" + ] }, { "path": "beautiful-html-templates/screenshots/peoples-platform-4.png", - "role": "reference" + "role": "mid_deck_reference", + "slide_number": 4, + "why_selected": "README gallery mid deck reference for peoples-platform: Activist poster energy: blue, orange, red on cream, with Alfa Slab + Caveat Brush.", + "visual_targets": [ + "palette", + "type_scale", + "chrome", + "density", + "layout_balance", + "grid" + ], + "acceptance_use": [ + "matcher_thumbnail", + "visual_qa", + "few_shot_reference" + ] }, { "path": "beautiful-html-templates/screenshots/peoples-platform-8.png", - "role": "reference" + "role": "late_deck_reference", + "slide_number": 8, + "why_selected": "README gallery late deck reference for peoples-platform: Activist poster energy: blue, orange, red on cream, with Alfa Slab + Caveat Brush.", + "visual_targets": [ + "palette", + "type_scale", + "chrome", + "density", + "layout_balance", + "grid" + ], + "acceptance_use": [ + "matcher_thumbnail", + "visual_qa", + "few_shot_reference" + ] } ], "density": "medium-high" @@ -20534,6 +23734,115 @@ "mono": "system-mono" } }, + "cjk_policy": { + "strategy": "replace_family_whole_element", + "display_font_cn": "LXGW WenKai", + "body_font_cn": "LXGW WenKai body", + "mono_font_policy": "latin_only_or_system_mono", + "runtime_font_policy": "system_font_only_no_remote_dependency", + "runtime_font_stack": [ + "system-sans-cjk", + "system-sans-cjk-heavy", + "system-sans-cjk-regular", + "system-mono" + ], + "emphasis_policy": "color_or_weight_only", + "italic_policy": "weight_only_emphasis", + "letter_spacing_policy": "reset_letter_spacing_for_cjk_keep_latin_labels", + "mixed_run_spacing": "pangu_spacing", + "latin_accent_policy": "latin_only_allowed_when_semantic_annotation", + "known_degradation": "Long Cang and LXGW WenKai are visually adjacent — both carry handwritten kaishu DNA. The three-voice editorial pairing (print / handwritten / archival) collapses into a two-voice pairing in pure Chinese (handwritten-display / handwritten-body / archival-Latin-only). This is not a bug — pure-Chinese decks in Pin & Paper read as more uniformly hand-touched tha", + "design_intent_font_pairing": [ + "LXGW WenKai", + "LXGW WenKai body", + "LXGW WenKai are visually adjacent", + "霞鹜文楷 LXGW WenKai" + ], + "source_section_heading": "CJK & International Content", + "source_section_sha256": "899cc60f29b1d9277e471d1275e3a31941deef2fe840bd3112fcf29a588ee267" + }, + "family_usage_policy": { + "closed_visual_system": true, + "cross_family_layout_mix_allowed": false, + "recolor_allowed": false, + "font_substitution_allowed": false, + "decorative_elements_policy": "identity_element_not_noise", + "extend_missing_layout_policy": { + "same_fonts": true, + "same_palette": true, + "same_spacing_rhythm": true, + "same_component_grammar": true, + "same_decorative_vocabulary": true, + "same_chrome": true + }, + "soft_matching_policy": { + "tone_first": true, + "occasion_is_soft_signal": true, + "avoid_for_is_soft_warning": true, + "taste_can_override_industry": true, + "formality_density_as_sanity_check": true + }, + "hard_rules": [ + "preserve_fonts_palette_grid_slide_classes_decorative_elements", + "do_not_recolor_without_explicit_brand_override", + "do_not_mix_template_families", + "extend_missing_layout_inside_same_family", + "do_not_strip_identity_decorations" + ], + "source": "beautiful-html-templates/AGENTS.md", + "source_sha256": "ed619bb7d956303024872f170b96e5270672a03cf40bdf7ce0abc3d8018c9d77" + }, + "extension_grammar": { + "layout_rhythm": "pin-and-paper: medium density, medium formality. Yellow paper with safety-pin illustrations, ink-blue handwritten Caveat, paper-grain texture.", + "spacing_rhythm": "Reuse source spacing tokens and grid gaps: {\"pad_edge\": \"64px\", \"pad_top\": \"110px\", \"pad_bottom\": \"90px\", \"card_pad_md\": \"28px 28px 24px\", \"card_pad_lg\": \"32px 22px 22px\", \"card_pad_xl\": \"36px 28px 28px\", \"card_pad_quote\": \"60px 80px\", \"grid_gap_sm\": \"22px\", \"gri", + "component_grammar": [ + "card", + "panel", + "s-agenda", + "s-chart", + "s-cover", + "s-cta", + "s-matrix", + "s-notes", + "s-notice", + "s-process" + ], + "chrome_rules": [ + "footer", + "label", + "row-label" + ], + "decorative_vocabulary": [ + "grid", + "accent line", + "card panels", + "paper texture", + "poster blocks", + "quote mark", + "sticker collage" + ], + "allowed_new_layouts": [ + "comparison", + "risk", + "timeline", + "action_plan", + "case_evidence", + "metric_dashboard" + ], + "forbidden_mutations": [ + "new_palette", + "cross_family_components", + "fake_italic", + "new_decorative_motif", + "remote_font_dependency" + ], + "density_limits": "medium", + "source_basis": { + "template_id": "pin-and-paper", + "design_signal_sha256": "eec890ff29da0426e131778284446b92710c7f3052cc03b71e9a43a5bf6cbae2", + "class_name_count": 77 + } + }, "semantic_fit": { "best_for": [ "Anything that should feel hand-crafted", @@ -20769,15 +24078,60 @@ "screenshot_benchmarks": [ { "path": "beautiful-html-templates/screenshots/pin-and-paper-1.png", - "role": "reference" + "role": "cover_reference", + "slide_number": 1, + "why_selected": "README gallery cover reference for pin-and-paper: Yellow paper with safety-pin illustrations, ink-blue handwritten Caveat, paper-grain texture.", + "visual_targets": [ + "palette", + "type_scale", + "chrome", + "density", + "layout_balance", + "grid" + ], + "acceptance_use": [ + "matcher_thumbnail", + "visual_qa", + "few_shot_reference" + ] }, { "path": "beautiful-html-templates/screenshots/pin-and-paper-11.png", - "role": "reference" + "role": "mid_deck_reference", + "slide_number": 11, + "why_selected": "README gallery mid deck reference for pin-and-paper: Yellow paper with safety-pin illustrations, ink-blue handwritten Caveat, paper-grain texture.", + "visual_targets": [ + "palette", + "type_scale", + "chrome", + "density", + "layout_balance", + "grid" + ], + "acceptance_use": [ + "matcher_thumbnail", + "visual_qa", + "few_shot_reference" + ] }, { "path": "beautiful-html-templates/screenshots/pin-and-paper-3.png", - "role": "reference" + "role": "late_deck_reference", + "slide_number": 3, + "why_selected": "README gallery late deck reference for pin-and-paper: Yellow paper with safety-pin illustrations, ink-blue handwritten Caveat, paper-grain texture.", + "visual_targets": [ + "palette", + "type_scale", + "chrome", + "density", + "layout_balance", + "grid" + ], + "acceptance_use": [ + "matcher_thumbnail", + "visual_qa", + "few_shot_reference" + ] } ], "density": "medium" @@ -21535,6 +24889,116 @@ "mono": "system-mono" } }, + "cjk_policy": { + "strategy": "replace_family_whole_element", + "display_font_cn": "Noto Serif SC", + "body_font_cn": "Noto Sans SC", + "mono_font_policy": "latin_only_or_system_mono", + "runtime_font_policy": "system_font_only_no_remote_dependency", + "runtime_font_stack": [ + "system-sans-cjk", + "system-sans-cjk-heavy", + "system-sans-cjk-regular", + "system-mono" + ], + "emphasis_policy": "color_or_weight_only", + "italic_policy": "color_only_emphasis", + "letter_spacing_policy": "reset_letter_spacing_for_cjk_keep_latin_labels", + "mixed_run_spacing": "pangu_spacing", + "latin_accent_policy": "latin_only_allowed_when_semantic_annotation", + "known_degradation": "DM Serif Display's \"single weight\" is misleading: it's a high-contrast display serif that reads as visually heavy at any size. The Chinese equivalent heaviness lives at Noto Serif SC **weight 900**, not weight 400 — using weight 400 for display will make Chinese headlines look limp and disconnected from the bold pink callouts. The system's reliance on size f", + "design_intent_font_pairing": [ + "Noto Serif SC", + "Noto Sans SC", + "ZCOOL XiaoWei", + "站酷小薇体 ZCOOL XiaoWei" + ], + "source_section_heading": "CJK & International Content", + "source_section_sha256": "0771c0c27a23602d30dcffd7bbdeac35717eede0d9eff113db75009cba677f9f" + }, + "family_usage_policy": { + "closed_visual_system": true, + "cross_family_layout_mix_allowed": false, + "recolor_allowed": false, + "font_substitution_allowed": false, + "decorative_elements_policy": "identity_element_not_noise", + "extend_missing_layout_policy": { + "same_fonts": true, + "same_palette": true, + "same_spacing_rhythm": true, + "same_component_grammar": true, + "same_decorative_vocabulary": true, + "same_chrome": true + }, + "soft_matching_policy": { + "tone_first": true, + "occasion_is_soft_signal": true, + "avoid_for_is_soft_warning": true, + "taste_can_override_industry": true, + "formality_density_as_sanity_check": true + }, + "hard_rules": [ + "preserve_fonts_palette_grid_slide_classes_decorative_elements", + "do_not_recolor_without_explicit_brand_override", + "do_not_mix_template_families", + "extend_missing_layout_inside_same_family", + "do_not_strip_identity_decorations" + ], + "source": "beautiful-html-templates/AGENTS.md", + "source_sha256": "ed619bb7d956303024872f170b96e5270672a03cf40bdf7ce0abc3d8018c9d77" + }, + "extension_grammar": { + "layout_rhythm": "pink-script: low density, medium-high formality. Black canvas, hot pink accent, pearl-cream paper, DM Serif Display headlines: late-night editorial luxury.", + "spacing_rhythm": "Reuse source spacing tokens and grid gaps: {\"edge_x\": \"60px\", \"edge_top_chrome\": \"60px\", \"edge_bottom_chrome\": \"60px\", \"content_top\": \"140px\", \"content_bottom\": \"140px\", \"inner_frame_inset\": \"36px\"}", + "component_grammar": [ + "s-chart", + "s-cover", + "s-cta", + "s-matrix", + "s-process", + "s-quote", + "s-section", + "s-stats", + "s-toc", + "stat" + ], + "chrome_rules": [ + "footer", + "label", + "label-l", + "pageno" + ], + "decorative_vocabulary": [ + "grid", + "accent line", + "card panels", + "paper texture", + "poster blocks", + "quote mark", + "sticker collage" + ], + "allowed_new_layouts": [ + "comparison", + "risk", + "timeline", + "action_plan", + "case_evidence", + "metric_dashboard" + ], + "forbidden_mutations": [ + "new_palette", + "cross_family_components", + "fake_italic", + "new_decorative_motif", + "remote_font_dependency" + ], + "density_limits": "low", + "source_basis": { + "template_id": "pink-script", + "design_signal_sha256": "f1584ed1704b5f61a8e3330632a93e36f1cd2e2fca8cc8eb39ecfd2204f0a7f9", + "class_name_count": 72 + } + }, "semantic_fit": { "best_for": [ "Anything that should feel nocturnal", @@ -21758,15 +25222,60 @@ "screenshot_benchmarks": [ { "path": "beautiful-html-templates/screenshots/pink-script-1.png", - "role": "reference" + "role": "cover_reference", + "slide_number": 1, + "why_selected": "README gallery cover reference for pink-script: Black canvas, hot pink accent, pearl-cream paper, DM Serif Display headlines: late-night editorial luxury.", + "visual_targets": [ + "palette", + "type_scale", + "chrome", + "density", + "layout_balance", + "grid" + ], + "acceptance_use": [ + "matcher_thumbnail", + "visual_qa", + "few_shot_reference" + ] }, { "path": "beautiful-html-templates/screenshots/pink-script-4.png", - "role": "reference" + "role": "mid_deck_reference", + "slide_number": 4, + "why_selected": "README gallery mid deck reference for pink-script: Black canvas, hot pink accent, pearl-cream paper, DM Serif Display headlines: late-night editorial luxury.", + "visual_targets": [ + "palette", + "type_scale", + "chrome", + "density", + "layout_balance", + "grid" + ], + "acceptance_use": [ + "matcher_thumbnail", + "visual_qa", + "few_shot_reference" + ] }, { "path": "beautiful-html-templates/screenshots/pink-script-8.png", - "role": "reference" + "role": "late_deck_reference", + "slide_number": 8, + "why_selected": "README gallery late deck reference for pink-script: Black canvas, hot pink accent, pearl-cream paper, DM Serif Display headlines: late-night editorial luxury.", + "visual_targets": [ + "palette", + "type_scale", + "chrome", + "density", + "layout_balance", + "grid" + ], + "acceptance_use": [ + "matcher_thumbnail", + "visual_qa", + "few_shot_reference" + ] } ], "density": "low" @@ -22465,6 +25974,113 @@ "mono": "system-mono" } }, + "cjk_policy": { + "strategy": "replace_family_whole_element", + "display_font_cn": "ZCOOL KuaiLe", + "body_font_cn": "Yozai", + "mono_font_policy": "latin_only_or_system_mono", + "runtime_font_policy": "system_font_only_no_remote_dependency", + "runtime_font_stack": [ + "system-sans-cjk", + "system-sans-cjk-heavy", + "system-sans-cjk-regular", + "system-mono" + ], + "emphasis_policy": "color_or_weight_only", + "italic_policy": "drop_italic", + "letter_spacing_policy": "reset_letter_spacing_for_cjk_keep_latin_labels", + "mixed_run_spacing": "pangu_spacing", + "latin_accent_policy": "latin_only_allowed_when_semantic_annotation", + "known_degradation": "ZCOOL KuaiLe and Yozai are both single-weight faces (400). The system's reliance on weight contrast (Syne 700 vs 800 for sub-display hierarchy; Space Grotesk 400 vs 500 vs 600 for label hierarchy) collapses to size-only hierarchy in pure Chinese. This is not a meaningful loss — Playful's hierarchy is primarily size-driven anyway, and the missing weight steps", + "design_intent_font_pairing": [ + "ZCOOL KuaiLe", + "Yozai", + "悠哉字体 Yozai", + "站酷快乐体 ZCOOL KuaiLe" + ], + "source_section_heading": "CJK & International Content", + "source_section_sha256": "3296eb614f6bba2bf2c9bd727c196988b202573605c8da309cf7affd436f4b2a" + }, + "family_usage_policy": { + "closed_visual_system": true, + "cross_family_layout_mix_allowed": false, + "recolor_allowed": false, + "font_substitution_allowed": false, + "decorative_elements_policy": "identity_element_not_noise", + "extend_missing_layout_policy": { + "same_fonts": true, + "same_palette": true, + "same_spacing_rhythm": true, + "same_component_grammar": true, + "same_decorative_vocabulary": true, + "same_chrome": true + }, + "soft_matching_policy": { + "tone_first": true, + "occasion_is_soft_signal": true, + "avoid_for_is_soft_warning": true, + "taste_can_override_industry": true, + "formality_density_as_sanity_check": true + }, + "hard_rules": [ + "preserve_fonts_palette_grid_slide_classes_decorative_elements", + "do_not_recolor_without_explicit_brand_override", + "do_not_mix_template_families", + "extend_missing_layout_inside_same_family", + "do_not_strip_identity_decorations" + ], + "source": "beautiful-html-templates/AGENTS.md", + "source_sha256": "ed619bb7d956303024872f170b96e5270672a03cf40bdf7ce0abc3d8018c9d77" + }, + "extension_grammar": { + "layout_rhythm": "playful: medium density, low formality. Sun-warm peach background with Syne display: a friendly indie launch deck.", + "spacing_rhythm": "Reuse source spacing tokens and grid gaps: {\"pad_slide_lg\": \"4rem 5rem\", \"pad_slide_md\": \"3rem 4rem\", \"pad_card_lg\": \"2rem 3rem\", \"pad_card_md\": \"1.5rem\", \"gap_lg\": \"3rem\", \"gap_md\": \"2rem\", \"gap_sm\": \"1.5rem\"}", + "component_grammar": [ + "stat-item", + "stat-label", + "stat-num", + "stats-grid", + "stats-title" + ], + "chrome_rules": [ + "bar-label", + "label", + "nav-btn", + "nav-controls", + "section-label", + "stat-label" + ], + "decorative_vocabulary": [ + "grid", + "accent line", + "card panels", + "paper texture", + "poster blocks", + "quote mark", + "sticker collage" + ], + "allowed_new_layouts": [ + "comparison", + "risk", + "timeline", + "action_plan", + "case_evidence", + "metric_dashboard" + ], + "forbidden_mutations": [ + "new_palette", + "cross_family_components", + "fake_italic", + "new_decorative_motif", + "remote_font_dependency" + ], + "density_limits": "medium", + "source_basis": { + "template_id": "playful", + "design_signal_sha256": "dae01d28353d170787e1c6c5fbf705965c34e9c3681b2e2b316f0e8f375a9e4b", + "class_name_count": 88 + } + }, "semantic_fit": { "best_for": [ "Anything that should feel warm", @@ -22685,15 +26301,60 @@ "screenshot_benchmarks": [ { "path": "beautiful-html-templates/screenshots/playful-1.png", - "role": "reference" + "role": "cover_reference", + "slide_number": 1, + "why_selected": "README gallery cover reference for playful: Sun-warm peach background with Syne display: a friendly indie launch deck.", + "visual_targets": [ + "palette", + "type_scale", + "chrome", + "density", + "layout_balance", + "grid" + ], + "acceptance_use": [ + "matcher_thumbnail", + "visual_qa", + "few_shot_reference" + ] }, { "path": "beautiful-html-templates/screenshots/playful-6.png", - "role": "reference" + "role": "mid_deck_reference", + "slide_number": 6, + "why_selected": "README gallery mid deck reference for playful: Sun-warm peach background with Syne display: a friendly indie launch deck.", + "visual_targets": [ + "palette", + "type_scale", + "chrome", + "density", + "layout_balance", + "grid" + ], + "acceptance_use": [ + "matcher_thumbnail", + "visual_qa", + "few_shot_reference" + ] }, { "path": "beautiful-html-templates/screenshots/playful-8.png", - "role": "reference" + "role": "late_deck_reference", + "slide_number": 8, + "why_selected": "README gallery late deck reference for playful: Sun-warm peach background with Syne display: a friendly indie launch deck.", + "visual_targets": [ + "palette", + "type_scale", + "chrome", + "density", + "layout_balance", + "grid" + ], + "acceptance_use": [ + "matcher_thumbnail", + "visual_qa", + "few_shot_reference" + ] } ], "density": "medium" @@ -23436,6 +27097,110 @@ "mono": "system-mono" } }, + "cjk_policy": { + "strategy": "replace_family_whole_element", + "display_font_cn": "Noto Sans SC", + "body_font_cn": "PingFang SC", + "mono_font_policy": "latin_only_or_system_mono", + "runtime_font_policy": "system_font_only_no_remote_dependency", + "runtime_font_stack": [ + "system-sans-cjk", + "system-sans-cjk-heavy", + "system-sans-cjk-regular", + "system-mono" + ], + "emphasis_policy": "color_or_weight_only", + "italic_policy": "drop_italic", + "letter_spacing_policy": "reset_letter_spacing_for_cjk_keep_latin_labels", + "mixed_run_spacing": "pangu_spacing", + "latin_accent_policy": "latin_only_allowed_when_semantic_annotation", + "known_degradation": "Raw Grid's whole aesthetic argument is \"this is the user's actual system font, not a downloaded display face.\" Loading Noto Sans SC technically violates that purity — but there is no acceptable substitute. macOS ships PingFang SC and Windows ships Microsoft YaHei, but the two render at noticeably different weights at \"900,\" and the digital-native aesthetic d", + "design_intent_font_pairing": [ + "Noto Sans SC", + "PingFang SC", + "Microsoft YaHei" + ], + "source_section_heading": "CJK & International Content", + "source_section_sha256": "cbcdcce1a20c0efa9433397e2edcae733f6f0f06d0c24514175b17d0412012b9" + }, + "family_usage_policy": { + "closed_visual_system": true, + "cross_family_layout_mix_allowed": false, + "recolor_allowed": false, + "font_substitution_allowed": false, + "decorative_elements_policy": "identity_element_not_noise", + "extend_missing_layout_policy": { + "same_fonts": true, + "same_palette": true, + "same_spacing_rhythm": true, + "same_component_grammar": true, + "same_decorative_vocabulary": true, + "same_chrome": true + }, + "soft_matching_policy": { + "tone_first": true, + "occasion_is_soft_signal": true, + "avoid_for_is_soft_warning": true, + "taste_can_override_industry": true, + "formality_density_as_sanity_check": true + }, + "hard_rules": [ + "preserve_fonts_palette_grid_slide_classes_decorative_elements", + "do_not_recolor_without_explicit_brand_override", + "do_not_mix_template_families", + "extend_missing_layout_inside_same_family", + "do_not_strip_identity_decorations" + ], + "source": "beautiful-html-templates/AGENTS.md", + "source_sha256": "ed619bb7d956303024872f170b96e5270672a03cf40bdf7ce0abc3d8018c9d77" + }, + "extension_grammar": { + "layout_rhythm": "raw-grid: high density, medium-low formality. Neo-brutalist deck with thick borders, offset shadows, and a pink/sage/ink palette.", + "spacing_rhythm": "Reuse source spacing tokens and grid gaps: {\"pad_lg\": \"clamp(32px, 4vw, 64px)\", \"pad_md\": \"clamp(20px, 2.5vw, 40px)\", \"pad_sm\": \"clamp(12px, 1.5vw, 20px)\", \"gap_lg\": \"clamp(24px, 3vw, 48px)\", \"gap_md\": \"clamp(16px, 2vw, 32px)\", \"gap_sm\": \"clamp(8px, 1vw, 16px)\"}", + "component_grammar": [ + "donut_stroke_width", + "donut_track_stroke_width" + ], + "chrome_rules": [ + "label", + "s3-bar-label", + "s3-stat-label", + "s3-stat-number", + "s5-badge", + "s7-donut-label", + "t-number" + ], + "decorative_vocabulary": [ + "grid", + "accent line", + "card panels", + "paper texture", + "poster blocks", + "quote mark", + "sticker collage" + ], + "allowed_new_layouts": [ + "comparison", + "risk", + "timeline", + "action_plan", + "case_evidence", + "metric_dashboard" + ], + "forbidden_mutations": [ + "new_palette", + "cross_family_components", + "fake_italic", + "new_decorative_motif", + "remote_font_dependency" + ], + "density_limits": "high", + "source_basis": { + "template_id": "raw-grid", + "design_signal_sha256": "5069d9443775e834512ae1206aa41ce67dd21634c2dfab58e95780ec07018bc4", + "class_name_count": 97 + } + }, "semantic_fit": { "best_for": [ "Anything that should feel direct and graphic-confident: founder pitches", @@ -23674,15 +27439,60 @@ "screenshot_benchmarks": [ { "path": "beautiful-html-templates/screenshots/raw-grid-1.png", - "role": "reference" + "role": "cover_reference", + "slide_number": 1, + "why_selected": "README gallery cover reference for raw-grid: Neo-brutalist deck with thick borders, offset shadows, and a pink/sage/ink palette.", + "visual_targets": [ + "palette", + "type_scale", + "chrome", + "density", + "layout_balance", + "grid" + ], + "acceptance_use": [ + "matcher_thumbnail", + "visual_qa", + "few_shot_reference" + ] }, { "path": "beautiful-html-templates/screenshots/raw-grid-4.png", - "role": "reference" + "role": "mid_deck_reference", + "slide_number": 4, + "why_selected": "README gallery mid deck reference for raw-grid: Neo-brutalist deck with thick borders, offset shadows, and a pink/sage/ink palette.", + "visual_targets": [ + "palette", + "type_scale", + "chrome", + "density", + "layout_balance", + "grid" + ], + "acceptance_use": [ + "matcher_thumbnail", + "visual_qa", + "few_shot_reference" + ] }, { "path": "beautiful-html-templates/screenshots/raw-grid-8.png", - "role": "reference" + "role": "late_deck_reference", + "slide_number": 8, + "why_selected": "README gallery late deck reference for raw-grid: Neo-brutalist deck with thick borders, offset shadows, and a pink/sage/ink palette.", + "visual_targets": [ + "palette", + "type_scale", + "chrome", + "density", + "layout_balance", + "grid" + ], + "acceptance_use": [ + "matcher_thumbnail", + "visual_qa", + "few_shot_reference" + ] } ], "density": "high" @@ -24481,6 +28291,103 @@ "mono": "system-mono" } }, + "cjk_policy": { + "strategy": "replace_family_whole_element", + "display_font_cn": "Noto Sans SC", + "body_font_cn": "SimSun", + "mono_font_policy": "latin_only_or_system_mono", + "runtime_font_policy": "system_font_only_no_remote_dependency", + "runtime_font_stack": [ + "system-sans-cjk", + "system-sans-cjk-heavy", + "system-sans-cjk-regular", + "system-mono" + ], + "emphasis_policy": "color_or_weight_only", + "italic_policy": "color_only_emphasis", + "letter_spacing_policy": "reset_letter_spacing_for_cjk_keep_latin_labels", + "mixed_run_spacing": "pangu_spacing", + "latin_accent_policy": "latin_only_allowed_when_semantic_annotation", + "known_degradation": "The two nostalgic accent fonts (Press Start 2P, VT323) are fundamentally Latin-only — they exist as 8-bit pixel and CRT terminal callbacks to an era when CJK rendering required specialized bitmap fonts that have no modern web equivalent. If a deck needs a pixel display moment in Chinese, the only honest option is to use Noto Sans SC at large size and let go ", + "design_intent_font_pairing": [ + "Noto Sans SC", + "SimSun" + ], + "source_section_heading": "CJK & International Content", + "source_section_sha256": "72119916d5bbfb65c60647a6e110230781604ea9126ea4b56d959aabeb176869" + }, + "family_usage_policy": { + "closed_visual_system": true, + "cross_family_layout_mix_allowed": false, + "recolor_allowed": false, + "font_substitution_allowed": false, + "decorative_elements_policy": "identity_element_not_noise", + "extend_missing_layout_policy": { + "same_fonts": true, + "same_palette": true, + "same_spacing_rhythm": true, + "same_component_grammar": true, + "same_decorative_vocabulary": true, + "same_chrome": true + }, + "soft_matching_policy": { + "tone_first": true, + "occasion_is_soft_signal": true, + "avoid_for_is_soft_warning": true, + "taste_can_override_industry": true, + "formality_density_as_sanity_check": true + }, + "hard_rules": [ + "preserve_fonts_palette_grid_slide_classes_decorative_elements", + "do_not_recolor_without_explicit_brand_override", + "do_not_mix_template_families", + "extend_missing_layout_inside_same_family", + "do_not_strip_identity_decorations" + ], + "source": "beautiful-html-templates/AGENTS.md", + "source_sha256": "ed619bb7d956303024872f170b96e5270672a03cf40bdf7ce0abc3d8018c9d77" + }, + "extension_grammar": { + "layout_rhythm": "retro-windows: medium density, low formality. Windows 95 chrome: gray title bars, MS Sans Serif, pixel typography, full nostalgia.", + "spacing_rhythm": "Reuse source spacing tokens and grid gaps: {\"slide_pad\": \"24px 32px 44px 32px\", \"win_body_pad\": \"20px 24px 24px 24px\", \"panel_pad\": \"16px\", \"group_box_pad\": \"20px 18px 16px 18px\", \"panel_sunken_pad\": \"12px\", \"gap_1\": \"6px\", \"gap_2\": \"10px\", \"gap_3\": \"16px\", \"gap_", + "component_grammar": [ + "panel-raised", + "panel-sunken" + ], + "chrome_rules": [ + "nav-dots", + "nav-hint" + ], + "decorative_vocabulary": [ + "grid", + "accent line", + "card panels", + "window chrome", + "poster blocks", + "pixel motif" + ], + "allowed_new_layouts": [ + "comparison", + "risk", + "timeline", + "action_plan", + "case_evidence", + "metric_dashboard" + ], + "forbidden_mutations": [ + "new_palette", + "cross_family_components", + "fake_italic", + "new_decorative_motif", + "remote_font_dependency" + ], + "density_limits": "medium", + "source_basis": { + "template_id": "retro-windows", + "design_signal_sha256": "879cb13215271b5e4f0bcaed0e55cef01b06ea89ba314493256279f1e4cbbbf7", + "class_name_count": 70 + } + }, "semantic_fit": { "best_for": [ "Anything that should feel knowingly nostalgic: retro gaming", @@ -24709,15 +28616,60 @@ "screenshot_benchmarks": [ { "path": "beautiful-html-templates/screenshots/retro-windows-1.png", - "role": "reference" + "role": "cover_reference", + "slide_number": 1, + "why_selected": "README gallery cover reference for retro-windows: Windows 95 chrome: gray title bars, MS Sans Serif, pixel typography, full nostalgia.", + "visual_targets": [ + "palette", + "type_scale", + "chrome", + "density", + "layout_balance", + "grid" + ], + "acceptance_use": [ + "matcher_thumbnail", + "visual_qa", + "few_shot_reference" + ] }, { "path": "beautiful-html-templates/screenshots/retro-windows-4.png", - "role": "reference" + "role": "mid_deck_reference", + "slide_number": 4, + "why_selected": "README gallery mid deck reference for retro-windows: Windows 95 chrome: gray title bars, MS Sans Serif, pixel typography, full nostalgia.", + "visual_targets": [ + "palette", + "type_scale", + "chrome", + "density", + "layout_balance", + "grid" + ], + "acceptance_use": [ + "matcher_thumbnail", + "visual_qa", + "few_shot_reference" + ] }, { "path": "beautiful-html-templates/screenshots/retro-windows-8.png", - "role": "reference" + "role": "late_deck_reference", + "slide_number": 8, + "why_selected": "README gallery late deck reference for retro-windows: Windows 95 chrome: gray title bars, MS Sans Serif, pixel typography, full nostalgia.", + "visual_targets": [ + "palette", + "type_scale", + "chrome", + "density", + "layout_balance", + "grid" + ], + "acceptance_use": [ + "matcher_thumbnail", + "visual_qa", + "few_shot_reference" + ] } ], "density": "medium" @@ -25475,6 +29427,113 @@ "mono": "system-mono" } }, + "cjk_policy": { + "strategy": "replace_family_whole_element", + "display_font_cn": "Noto Serif SC", + "body_font_cn": "Noto Sans SC", + "mono_font_policy": "latin_only_or_system_mono", + "runtime_font_policy": "system_font_only_no_remote_dependency", + "runtime_font_stack": [ + "system-sans-cjk", + "system-sans-cjk-heavy", + "system-sans-cjk-regular", + "system-mono" + ], + "emphasis_policy": "color_or_weight_only", + "italic_policy": "drop_italic", + "letter_spacing_policy": "reset_letter_spacing_for_cjk_keep_latin_labels", + "mixed_run_spacing": "pangu_spacing", + "latin_accent_policy": "latin_only_allowed_when_semantic_annotation", + "known_degradation": "The system's three-face contrast (Bebas display + Space Grotesk body + Caveat hand-script) is a Latin-typographic argument; collapsing it to a single CJK serif loses one rhythm and gains another. The decision to use a serif (Noto Serif SC) rather than a sans (Noto Sans SC) is deliberate — the zine's mid-century printed-press lineage maps better to Chinese se", + "design_intent_font_pairing": [ + "Noto Serif SC", + "Noto Sans SC" + ], + "source_section_heading": "CJK & International Content", + "source_section_sha256": "dca325b7b0cab435682fe7e4ca085edd8f4e6184dd92231d9f65a4fac5222f76" + }, + "family_usage_policy": { + "closed_visual_system": true, + "cross_family_layout_mix_allowed": false, + "recolor_allowed": false, + "font_substitution_allowed": false, + "decorative_elements_policy": "identity_element_not_noise", + "extend_missing_layout_policy": { + "same_fonts": true, + "same_palette": true, + "same_spacing_rhythm": true, + "same_component_grammar": true, + "same_decorative_vocabulary": true, + "same_chrome": true + }, + "soft_matching_policy": { + "tone_first": true, + "occasion_is_soft_signal": true, + "avoid_for_is_soft_warning": true, + "taste_can_override_industry": true, + "formality_density_as_sanity_check": true + }, + "hard_rules": [ + "preserve_fonts_palette_grid_slide_classes_decorative_elements", + "do_not_recolor_without_explicit_brand_override", + "do_not_mix_template_families", + "extend_missing_layout_inside_same_family", + "do_not_strip_identity_decorations" + ], + "source": "beautiful-html-templates/AGENTS.md", + "source_sha256": "ed619bb7d956303024872f170b96e5270672a03cf40bdf7ce0abc3d8018c9d77" + }, + "extension_grammar": { + "layout_rhythm": "retro-zine: medium density, medium-low formality. Beige paper with green accent and Bebas Neue + Caveat: a riso-printed zine in HTML form.", + "spacing_rhythm": "Reuse source spacing tokens and grid gaps: {\"slide_pad\": \"60px\", \"slide_pad_wide\": \"60px 80px\", \"card_pad_lg\": \"48px\", \"card_pad_md\": \"32px\", \"card_pad_sm\": \"24px\", \"gap_lg\": \"60px\", \"gap_md\": \"40px\", \"gap_sm\": \"24px\"}", + "component_grammar": [ + "statement-author", + "statement-line-bottom", + "statement-line-top", + "statement-quote" + ], + "chrome_rules": [ + "closing-label", + "grid-box-label", + "hero-label", + "nav-hint", + "num-label", + "rsvp-stamp", + "slide-numbers", + "split-label" + ], + "decorative_vocabulary": [ + "grid", + "accent line", + "card panels", + "paper texture", + "window chrome", + "poster blocks", + "quote mark", + "sticker collage" + ], + "allowed_new_layouts": [ + "comparison", + "risk", + "timeline", + "action_plan", + "case_evidence", + "metric_dashboard" + ], + "forbidden_mutations": [ + "new_palette", + "cross_family_components", + "fake_italic", + "new_decorative_motif", + "remote_font_dependency" + ], + "density_limits": "medium", + "source_basis": { + "template_id": "retro-zine", + "design_signal_sha256": "c483842bbb1f306f40cf385ad070abe9b27535459c172840795d3dd7f7bc5373", + "class_name_count": 74 + } + }, "semantic_fit": { "best_for": [ "Anything that should feel printed", @@ -25686,15 +29745,60 @@ "screenshot_benchmarks": [ { "path": "beautiful-html-templates/screenshots/retro-zine-1.png", - "role": "reference" + "role": "cover_reference", + "slide_number": 1, + "why_selected": "README gallery cover reference for retro-zine: Beige paper with green accent and Bebas Neue + Caveat: a riso-printed zine in HTML form.", + "visual_targets": [ + "palette", + "type_scale", + "chrome", + "density", + "layout_balance", + "grid" + ], + "acceptance_use": [ + "matcher_thumbnail", + "visual_qa", + "few_shot_reference" + ] }, { "path": "beautiful-html-templates/screenshots/retro-zine-4.png", - "role": "reference" + "role": "mid_deck_reference", + "slide_number": 4, + "why_selected": "README gallery mid deck reference for retro-zine: Beige paper with green accent and Bebas Neue + Caveat: a riso-printed zine in HTML form.", + "visual_targets": [ + "palette", + "type_scale", + "chrome", + "density", + "layout_balance", + "grid" + ], + "acceptance_use": [ + "matcher_thumbnail", + "visual_qa", + "few_shot_reference" + ] }, { "path": "beautiful-html-templates/screenshots/retro-zine-8.png", - "role": "reference" + "role": "late_deck_reference", + "slide_number": 8, + "why_selected": "README gallery late deck reference for retro-zine: Beige paper with green accent and Bebas Neue + Caveat: a riso-printed zine in HTML form.", + "visual_targets": [ + "palette", + "type_scale", + "chrome", + "density", + "layout_balance", + "grid" + ], + "acceptance_use": [ + "matcher_thumbnail", + "visual_qa", + "few_shot_reference" + ] } ], "density": "medium" @@ -26436,6 +30540,121 @@ "mono": "system-mono" } }, + "cjk_policy": { + "strategy": "replace_family_whole_element", + "display_font_cn": "Noto Sans JP", + "body_font_cn": "LXGW WenKai", + "mono_font_policy": "latin_only_or_system_mono", + "runtime_font_policy": "system_font_only_no_remote_dependency", + "runtime_font_stack": [ + "system-sans-cjk", + "system-sans-cjk-heavy", + "system-sans-cjk-regular", + "system-mono" + ], + "emphasis_policy": "color_or_weight_only", + "italic_policy": "drop_italic", + "letter_spacing_policy": "reset_letter_spacing_for_cjk_keep_latin_labels", + "mixed_run_spacing": "pangu_spacing", + "latin_accent_policy": "latin_only_allowed_when_semantic_annotation", + "known_degradation": "ZCOOL XiaoWei is a single-weight face — there is no 900-equivalent. The Big Shoulders 900-weight loudness that defines the Latin display voice cannot be exactly matched. Compensate by reserving CJK display for moments where the soft elegance is welcome (cover spreads, quote slides) rather than where pure brutalist weight is needed (hero stats). For hero nume", + "design_intent_font_pairing": [ + "Noto Sans JP", + "LXGW WenKai", + "LXGW WenKai are both Google", + "LXGW WenKai inline", + "LXGW WenKai for these characters so they read as Chinese rather than as a Japane", + "ZCOOL XiaoWei" + ], + "source_section_heading": "CJK & International Content", + "source_section_sha256": "a257011c2005d705898e16b70bf7220dd8fbd46c1cf955d555cbb7cffb7ed3bd" + }, + "family_usage_policy": { + "closed_visual_system": true, + "cross_family_layout_mix_allowed": false, + "recolor_allowed": false, + "font_substitution_allowed": false, + "decorative_elements_policy": "identity_element_not_noise", + "extend_missing_layout_policy": { + "same_fonts": true, + "same_palette": true, + "same_spacing_rhythm": true, + "same_component_grammar": true, + "same_decorative_vocabulary": true, + "same_chrome": true + }, + "soft_matching_policy": { + "tone_first": true, + "occasion_is_soft_signal": true, + "avoid_for_is_soft_warning": true, + "taste_can_override_industry": true, + "formality_density_as_sanity_check": true + }, + "hard_rules": [ + "preserve_fonts_palette_grid_slide_classes_decorative_elements", + "do_not_recolor_without_explicit_brand_override", + "do_not_mix_template_families", + "extend_missing_layout_inside_same_family", + "do_not_strip_identity_decorations" + ], + "source": "beautiful-html-templates/AGENTS.md", + "source_sha256": "ed619bb7d956303024872f170b96e5270672a03cf40bdf7ce0abc3d8018c9d77" + }, + "extension_grammar": { + "layout_rhythm": "sakura-chroma: medium density, low formality. Vintage Japanese cassette-package aesthetic: cream paper, diagonal rainbow ribbons, condensed bold type, JIS-style spec checkboxes.", + "spacing_rhythm": "Reuse source spacing tokens and grid gaps: {\"frame_inset\": \"clamp(36px, 3.6vw, 72px)\", \"frame_inset_bottom\": \"clamp(72px, 7vh, 110px)\", \"topbar_gap\": \"clamp(12px, 1.4vh, 22px)\", \"card_pad_x\": \"clamp(14px, 1.4vw, 20px)\", \"card_pad_y\": \"clamp(16px, 1.7vw, 24px)\", \"", + "component_grammar": [ + "card", + "s-cal", + "s-catalogue", + "s-colophon", + "s-cover", + "s-data", + "s-manifesto", + "s-quote", + "s-stripe", + "stat" + ], + "chrome_rules": [ + "cfooter", + "col-footer", + "nav-hint", + "pagenum", + "red-stamp", + "stamp" + ], + "decorative_vocabulary": [ + "grid", + "accent line", + "card panels", + "paper texture", + "window chrome", + "poster blocks", + "quote mark", + "sticker collage" + ], + "allowed_new_layouts": [ + "comparison", + "risk", + "timeline", + "action_plan", + "case_evidence", + "metric_dashboard" + ], + "forbidden_mutations": [ + "new_palette", + "cross_family_components", + "fake_italic", + "new_decorative_motif", + "remote_font_dependency" + ], + "density_limits": "medium", + "source_basis": { + "template_id": "sakura-chroma", + "design_signal_sha256": "766521d882dee7db713d60811947d20422e4b645fd70bc2e066f8571cbaee42e", + "class_name_count": 118 + } + }, "semantic_fit": { "best_for": [ "Anything that should feel like a vintage Japanese cassette package or a TDK", @@ -26705,15 +30924,60 @@ "screenshot_benchmarks": [ { "path": "beautiful-html-templates/screenshots/sakura-chroma-1.png", - "role": "reference" + "role": "cover_reference", + "slide_number": 1, + "why_selected": "README gallery cover reference for sakura-chroma: Vintage Japanese cassette-package aesthetic: cream paper, diagonal rainbow ribbons, condensed bold type, JIS-style spec checkboxes.", + "visual_targets": [ + "palette", + "type_scale", + "chrome", + "density", + "layout_balance", + "grid" + ], + "acceptance_use": [ + "matcher_thumbnail", + "visual_qa", + "few_shot_reference" + ] }, { "path": "beautiful-html-templates/screenshots/sakura-chroma-3.png", - "role": "reference" + "role": "mid_deck_reference", + "slide_number": 3, + "why_selected": "README gallery mid deck reference for sakura-chroma: Vintage Japanese cassette-package aesthetic: cream paper, diagonal rainbow ribbons, condensed bold type, JIS-style spec checkboxes.", + "visual_targets": [ + "palette", + "type_scale", + "chrome", + "density", + "layout_balance", + "grid" + ], + "acceptance_use": [ + "matcher_thumbnail", + "visual_qa", + "few_shot_reference" + ] }, { "path": "beautiful-html-templates/screenshots/sakura-chroma-4.png", - "role": "reference" + "role": "late_deck_reference", + "slide_number": 4, + "why_selected": "README gallery late deck reference for sakura-chroma: Vintage Japanese cassette-package aesthetic: cream paper, diagonal rainbow ribbons, condensed bold type, JIS-style spec checkboxes.", + "visual_targets": [ + "palette", + "type_scale", + "chrome", + "density", + "layout_balance", + "grid" + ], + "acceptance_use": [ + "matcher_thumbnail", + "visual_qa", + "few_shot_reference" + ] } ], "density": "medium" @@ -27471,6 +31735,111 @@ "mono": "system-mono" } }, + "cjk_policy": { + "strategy": "replace_family_whole_element", + "display_font_cn": "ZCOOL KuaiLe", + "body_font_cn": "Yozai", + "mono_font_policy": "latin_only_or_system_mono", + "runtime_font_policy": "system_font_only_no_remote_dependency", + "runtime_font_stack": [ + "system-sans-cjk", + "system-sans-cjk-heavy", + "system-sans-cjk-regular", + "system-mono" + ], + "emphasis_policy": "color_or_weight_only", + "italic_policy": "color_only_emphasis", + "letter_spacing_policy": "reset_letter_spacing_for_cjk_keep_latin_labels", + "mixed_run_spacing": "pangu_spacing", + "latin_accent_policy": "latin_only_allowed_when_semantic_annotation", + "known_degradation": "Caveat — the system's most distinctive voice (the casual ballpoint hand-script that anchors every personal note) — has no CJK equivalent. There are handwritten-style Chinese web fonts (悠果手写体, 站酷庆科黄油体), but the cultural register of casual cursive handwriting differs sharply between Latin and CJK traditions, and no Chinese face will read as \"the same voice as ", + "design_intent_font_pairing": [ + "ZCOOL KuaiLe", + "Yozai", + "悠哉字体 Yozai", + "站酷快乐体 ZCOOL KuaiLe", + "站酷快乐体", + "站酷庆科黄油体" + ], + "source_section_heading": "CJK & International Content", + "source_section_sha256": "febacdb3b79be938a1c1036962364f5c34a8fc75755c3b06edde563fec920dcc" + }, + "family_usage_policy": { + "closed_visual_system": true, + "cross_family_layout_mix_allowed": false, + "recolor_allowed": false, + "font_substitution_allowed": false, + "decorative_elements_policy": "identity_element_not_noise", + "extend_missing_layout_policy": { + "same_fonts": true, + "same_palette": true, + "same_spacing_rhythm": true, + "same_component_grammar": true, + "same_decorative_vocabulary": true, + "same_chrome": true + }, + "soft_matching_policy": { + "tone_first": true, + "occasion_is_soft_signal": true, + "avoid_for_is_soft_warning": true, + "taste_can_override_industry": true, + "formality_density_as_sanity_check": true + }, + "hard_rules": [ + "preserve_fonts_palette_grid_slide_classes_decorative_elements", + "do_not_recolor_without_explicit_brand_override", + "do_not_mix_template_families", + "extend_missing_layout_inside_same_family", + "do_not_strip_identity_decorations" + ], + "source": "beautiful-html-templates/AGENTS.md", + "source_sha256": "ed619bb7d956303024872f170b96e5270672a03cf40bdf7ce0abc3d8018c9d77" + }, + "extension_grammar": { + "layout_rhythm": "scatterbrain: high density, low formality. Post-it inspired: pastel sticky notes, Caveat handwriting, Shrikhand and Zilla Slab type stack.", + "spacing_rhythm": "Reuse source spacing tokens and grid gaps: {\"slide_pad\": \"3rem\", \"post_it_pad_lg\": \"3rem 4rem\", \"post_it_pad_md\": \"2.5rem\", \"post_it_pad_sm\": \"1.5rem\", \"post_it_pad_statement\": \"3.5rem 4rem\", \"gap_lg\": \"3rem\", \"gap_md\": \"2.5rem\", \"gap_sm\": \"2rem\"}", + "component_grammar": [ + "stat-label", + "stat-row", + "stat-value", + "statement-layout", + "statement-postit" + ], + "chrome_rules": [ + "label", + "phase-label", + "stat-label" + ], + "decorative_vocabulary": [ + "grid", + "accent line", + "card panels", + "paper texture", + "poster blocks", + "sticker collage" + ], + "allowed_new_layouts": [ + "comparison", + "risk", + "timeline", + "action_plan", + "case_evidence", + "metric_dashboard" + ], + "forbidden_mutations": [ + "new_palette", + "cross_family_components", + "fake_italic", + "new_decorative_motif", + "remote_font_dependency" + ], + "density_limits": "high", + "source_basis": { + "template_id": "scatterbrain", + "design_signal_sha256": "b9dc27649f3e0e15856278d0530901d4d7d918e56aca8c6e5d463cd551ef809b", + "class_name_count": 75 + } + }, "semantic_fit": { "best_for": [ "Anything that should feel like a designer's whiteboard: brainstorms", @@ -27704,15 +32073,60 @@ "screenshot_benchmarks": [ { "path": "beautiful-html-templates/screenshots/scatterbrain-1.png", - "role": "reference" + "role": "cover_reference", + "slide_number": 1, + "why_selected": "README gallery cover reference for scatterbrain: Post-it inspired: pastel sticky notes, Caveat handwriting, Shrikhand and Zilla Slab type stack.", + "visual_targets": [ + "palette", + "type_scale", + "chrome", + "density", + "layout_balance", + "grid" + ], + "acceptance_use": [ + "matcher_thumbnail", + "visual_qa", + "few_shot_reference" + ] }, { "path": "beautiful-html-templates/screenshots/scatterbrain-4.png", - "role": "reference" + "role": "mid_deck_reference", + "slide_number": 4, + "why_selected": "README gallery mid deck reference for scatterbrain: Post-it inspired: pastel sticky notes, Caveat handwriting, Shrikhand and Zilla Slab type stack.", + "visual_targets": [ + "palette", + "type_scale", + "chrome", + "density", + "layout_balance", + "grid" + ], + "acceptance_use": [ + "matcher_thumbnail", + "visual_qa", + "few_shot_reference" + ] }, { "path": "beautiful-html-templates/screenshots/scatterbrain-8.png", - "role": "reference" + "role": "late_deck_reference", + "slide_number": 8, + "why_selected": "README gallery late deck reference for scatterbrain: Post-it inspired: pastel sticky notes, Caveat handwriting, Shrikhand and Zilla Slab type stack.", + "visual_targets": [ + "palette", + "type_scale", + "chrome", + "density", + "layout_balance", + "grid" + ], + "acceptance_use": [ + "matcher_thumbnail", + "visual_qa", + "few_shot_reference" + ] } ], "density": "high" @@ -28452,6 +32866,119 @@ "mono": "system-mono" } }, + "cjk_policy": { + "strategy": "replace_family_whole_element", + "display_font_cn": "Noto Sans SC", + "body_font_cn": "Noto Serif SC", + "mono_font_policy": "latin_only_or_system_mono", + "runtime_font_policy": "system_font_only_no_remote_dependency", + "runtime_font_stack": [ + "system-sans-cjk", + "system-sans-cjk-heavy", + "system-sans-cjk-regular", + "system-mono" + ], + "emphasis_policy": "color_or_weight_only", + "italic_policy": "drop_italic", + "letter_spacing_policy": "reset_letter_spacing_for_cjk_keep_latin_labels", + "mixed_run_spacing": "pangu_spacing", + "latin_accent_policy": "latin_only_allowed_when_semantic_annotation", + "known_degradation": "The system's most distinctive typographic treatment (roman + italic-gold mid-sentence inside Source Serif 4 headlines) is fundamentally a Latin-typographic move that does not translate. Neither Noto Serif SC nor Noto Sans SC ships an italic axis, and inventing one via CSS `font-style: italic` produces an oblique/slanted glyph that reads as broken rather than", + "design_intent_font_pairing": [ + "Noto Sans SC", + "Noto Serif SC" + ], + "source_section_heading": "CJK & International Content", + "source_section_sha256": "63e59eb164dd465d55114602076e2bac6aa477ec9a023f6c686e0493d3e3bc39" + }, + "family_usage_policy": { + "closed_visual_system": true, + "cross_family_layout_mix_allowed": false, + "recolor_allowed": false, + "font_substitution_allowed": false, + "decorative_elements_policy": "identity_element_not_noise", + "extend_missing_layout_policy": { + "same_fonts": true, + "same_palette": true, + "same_spacing_rhythm": true, + "same_component_grammar": true, + "same_decorative_vocabulary": true, + "same_chrome": true + }, + "soft_matching_policy": { + "tone_first": true, + "occasion_is_soft_signal": true, + "avoid_for_is_soft_warning": true, + "taste_can_override_industry": true, + "formality_density_as_sanity_check": true + }, + "hard_rules": [ + "preserve_fonts_palette_grid_slide_classes_decorative_elements", + "do_not_recolor_without_explicit_brand_override", + "do_not_mix_template_families", + "extend_missing_layout_inside_same_family", + "do_not_strip_identity_decorations" + ], + "source": "beautiful-html-templates/AGENTS.md", + "source_sha256": "ed619bb7d956303024872f170b96e5270672a03cf40bdf7ce0abc3d8018c9d77" + }, + "extension_grammar": { + "layout_rhythm": "signal: high density, high formality. Deep navy canvas with bone paper and a single muted-gold accent; institutional with quiet weight.", + "spacing_rhythm": "Reuse source spacing tokens and grid gaps: {\"pad_x\": \"7.5vw\", \"pad_y\": \"5.5vh\", \"gap_lg\": \"4vh\", \"gap_md\": \"2.5vh\", \"gap_sm\": \"1.2vh\", \"grid_cell\": \"80px\"}", + "component_grammar": [ + "stat-4", + "stat-4-cell", + "stat-4-label", + "stat-4-val", + "stat-card", + "stat-label", + "stat-note", + "stat-value", + "statement-body", + "stats-grid" + ], + "chrome_rules": [ + "bar-x-label", + "compare-label", + "editorial-stamp", + "label", + "pie-item-label", + "slide-chrome", + "stat-4-label", + "stat-label" + ], + "decorative_vocabulary": [ + "grid", + "accent line", + "card panels", + "paper texture", + "window chrome", + "poster blocks", + "quote mark", + "sticker collage" + ], + "allowed_new_layouts": [ + "comparison", + "risk", + "timeline", + "action_plan", + "case_evidence", + "metric_dashboard" + ], + "forbidden_mutations": [ + "new_palette", + "cross_family_components", + "fake_italic", + "new_decorative_motif", + "remote_font_dependency" + ], + "density_limits": "high", + "source_basis": { + "template_id": "signal", + "design_signal_sha256": "2d65a9e3349e7a3f163d7b839d8aa77e6e8d7993dd06ccfeb6498f7a170abb02", + "class_name_count": 117 + } + }, "semantic_fit": { "best_for": [ "Anything that should feel weighty", @@ -28745,15 +33272,60 @@ "screenshot_benchmarks": [ { "path": "beautiful-html-templates/screenshots/signal-1.png", - "role": "reference" + "role": "cover_reference", + "slide_number": 1, + "why_selected": "README gallery cover reference for signal: Deep navy canvas with bone paper and a single muted-gold accent; institutional with quiet weight.", + "visual_targets": [ + "palette", + "type_scale", + "chrome", + "density", + "layout_balance", + "grid" + ], + "acceptance_use": [ + "matcher_thumbnail", + "visual_qa", + "few_shot_reference" + ] }, { "path": "beautiful-html-templates/screenshots/signal-18.png", - "role": "reference" + "role": "mid_deck_reference", + "slide_number": 18, + "why_selected": "README gallery mid deck reference for signal: Deep navy canvas with bone paper and a single muted-gold accent; institutional with quiet weight.", + "visual_targets": [ + "palette", + "type_scale", + "chrome", + "density", + "layout_balance", + "grid" + ], + "acceptance_use": [ + "matcher_thumbnail", + "visual_qa", + "few_shot_reference" + ] }, { "path": "beautiful-html-templates/screenshots/signal-8.png", - "role": "reference" + "role": "late_deck_reference", + "slide_number": 8, + "why_selected": "README gallery late deck reference for signal: Deep navy canvas with bone paper and a single muted-gold accent; institutional with quiet weight.", + "visual_targets": [ + "palette", + "type_scale", + "chrome", + "density", + "layout_balance", + "grid" + ], + "acceptance_use": [ + "matcher_thumbnail", + "visual_qa", + "few_shot_reference" + ] } ], "density": "high" @@ -29455,11 +34027,11 @@ "source_design_md": "beautiful-html-templates/templates/soft-editorial/design.md", "source_template_html": "beautiful-html-templates/templates/soft-editorial/template.html", "source_screenshots": [ - "beautiful-html-templates/screenshots/soft-editorial-10.png", "beautiful-html-templates/screenshots/soft-editorial-4.png", - "beautiful-html-templates/screenshots/soft-editorial-6.png" + "beautiful-html-templates/screenshots/soft-editorial-6.png", + "beautiful-html-templates/screenshots/soft-editorial-10.png" ], - "reference_screenshot": "beautiful-html-templates/screenshots/soft-editorial-10.png", + "reference_screenshot": "beautiful-html-templates/screenshots/soft-editorial-4.png", "reference_svg": "", "receipt": "", "inventory_item_ids": [ @@ -29507,6 +34079,119 @@ "mono": "system-mono" } }, + "cjk_policy": { + "strategy": "replace_family_whole_element", + "display_font_cn": "Noto Serif SC", + "body_font_cn": "Noto Sans SC", + "mono_font_policy": "latin_only_or_system_mono", + "runtime_font_policy": "system_font_only_no_remote_dependency", + "runtime_font_stack": [ + "system-sans-cjk", + "system-sans-cjk-heavy", + "system-sans-cjk-regular", + "system-mono" + ], + "emphasis_policy": "color_or_weight_only", + "italic_policy": "drop_italic", + "letter_spacing_policy": "reset_letter_spacing_for_cjk_keep_latin_labels", + "mixed_run_spacing": "pangu_spacing", + "latin_accent_policy": "latin_only_allowed_when_semantic_annotation", + "known_degradation": "LXGW WenKai has only a single weight (regular). The system's signature \"weight drop\" inside headlines (Cormorant 500 → italic 400) cannot be reproduced in CJK. Substitute with a color shift to `{colors.ink-soft}` for emphasis, or accept that Chinese headlines read as one consistent weight.", + "design_intent_font_pairing": [ + "Noto Serif SC", + "Noto Sans SC", + "LXGW WenKai", + "LXGW WenKai TC", + "LXGW WenKai is a hand", + "LXGW WenKai has no true italic" + ], + "source_section_heading": "CJK & International Content", + "source_section_sha256": "b57f26e5c042ce9af7466a2ff5a428cd1dd668d8fe750b683921eef395940d9a" + }, + "family_usage_policy": { + "closed_visual_system": true, + "cross_family_layout_mix_allowed": false, + "recolor_allowed": false, + "font_substitution_allowed": false, + "decorative_elements_policy": "identity_element_not_noise", + "extend_missing_layout_policy": { + "same_fonts": true, + "same_palette": true, + "same_spacing_rhythm": true, + "same_component_grammar": true, + "same_decorative_vocabulary": true, + "same_chrome": true + }, + "soft_matching_policy": { + "tone_first": true, + "occasion_is_soft_signal": true, + "avoid_for_is_soft_warning": true, + "taste_can_override_industry": true, + "formality_density_as_sanity_check": true + }, + "hard_rules": [ + "preserve_fonts_palette_grid_slide_classes_decorative_elements", + "do_not_recolor_without_explicit_brand_override", + "do_not_mix_template_families", + "extend_missing_layout_inside_same_family", + "do_not_strip_identity_decorations" + ], + "source": "beautiful-html-templates/AGENTS.md", + "source_sha256": "ed619bb7d956303024872f170b96e5270672a03cf40bdf7ce0abc3d8018c9d77" + }, + "extension_grammar": { + "layout_rhythm": "soft-editorial: low density, high formality. Cormorant Garamond serif on warm paper with sage, blush, and lemon accents.", + "spacing_rhythm": "Reuse source spacing tokens and grid gaps: {\"pad_outer\": \"80px\", \"pad_top\": \"60px\", \"pad_bottom\": \"50px\", \"card_pad_lg\": \"64px 48px\", \"card_pad_md\": \"48px 52px\", \"card_pad_sm\": \"28px 30px\", \"gap_cards\": \"28px\", \"gap_cards_lg\": \"36px\", \"gap_stack\": \"36px\"}", + "component_grammar": [ + "card", + "panel", + "s-chart", + "s-closer", + "s-consult", + "s-cover", + "s-foreword", + "s-insights", + "s-matrix", + "s-method" + ], + "chrome_rules": [ + "eyebrow", + "footer", + "pagedot", + "row-label", + "s-numbers" + ], + "decorative_vocabulary": [ + "grid", + "accent line", + "card panels", + "paper texture", + "poster blocks", + "quote mark", + "sticker collage" + ], + "allowed_new_layouts": [ + "comparison", + "risk", + "timeline", + "action_plan", + "case_evidence", + "metric_dashboard" + ], + "forbidden_mutations": [ + "new_palette", + "cross_family_components", + "fake_italic", + "new_decorative_motif", + "remote_font_dependency" + ], + "density_limits": "low", + "source_basis": { + "template_id": "soft-editorial", + "design_signal_sha256": "954d6f57e6b4e9dbb7cade4de9f0cac85df0e7472a3bc4f49e4335cde8800488", + "class_name_count": 86 + } + }, "semantic_fit": { "best_for": [ "Anything that should feel literary", @@ -29734,17 +34419,62 @@ } ], "screenshot_benchmarks": [ - { - "path": "beautiful-html-templates/screenshots/soft-editorial-10.png", - "role": "reference" - }, { "path": "beautiful-html-templates/screenshots/soft-editorial-4.png", - "role": "reference" + "role": "cover_reference", + "slide_number": 4, + "why_selected": "README gallery cover reference for soft-editorial: Cormorant Garamond serif on warm paper with sage, blush, and lemon accents.", + "visual_targets": [ + "palette", + "type_scale", + "chrome", + "density", + "layout_balance", + "grid" + ], + "acceptance_use": [ + "matcher_thumbnail", + "visual_qa", + "few_shot_reference" + ] }, { "path": "beautiful-html-templates/screenshots/soft-editorial-6.png", - "role": "reference" + "role": "mid_deck_reference", + "slide_number": 6, + "why_selected": "README gallery mid deck reference for soft-editorial: Cormorant Garamond serif on warm paper with sage, blush, and lemon accents.", + "visual_targets": [ + "palette", + "type_scale", + "chrome", + "density", + "layout_balance", + "grid" + ], + "acceptance_use": [ + "matcher_thumbnail", + "visual_qa", + "few_shot_reference" + ] + }, + { + "path": "beautiful-html-templates/screenshots/soft-editorial-10.png", + "role": "late_deck_reference", + "slide_number": 10, + "why_selected": "README gallery late deck reference for soft-editorial: Cormorant Garamond serif on warm paper with sage, blush, and lemon accents.", + "visual_targets": [ + "palette", + "type_scale", + "chrome", + "density", + "layout_balance", + "grid" + ], + "acceptance_use": [ + "matcher_thumbnail", + "visual_qa", + "few_shot_reference" + ] } ], "density": "low" @@ -30443,6 +35173,113 @@ "mono": "system-mono" } }, + "cjk_policy": { + "strategy": "replace_family_whole_element", + "display_font_cn": "Noto Serif SC", + "body_font_cn": "Noto Sans SC", + "mono_font_policy": "latin_only_or_system_mono", + "runtime_font_policy": "system_font_only_no_remote_dependency", + "runtime_font_stack": [ + "system-sans-cjk", + "system-sans-cjk-heavy", + "system-sans-cjk-regular", + "system-mono" + ], + "emphasis_policy": "color_or_weight_only", + "italic_policy": "weight_only_emphasis", + "letter_spacing_policy": "reset_letter_spacing_for_cjk_keep_latin_labels", + "mixed_run_spacing": "pangu_spacing", + "latin_accent_policy": "latin_only_allowed_when_semantic_annotation", + "known_degradation": "Barlow Condensed has no condensed CJK equivalent. The system's uppercase-heavy-condensed-tracked chrome aesthetic cannot be reproduced; Noto Sans SC 900 is the closest fallback but lacks the condensed proportion. Accept that Chinese chrome will feel slightly wider than Latin chrome.", + "design_intent_font_pairing": [ + "Noto Serif SC", + "Noto Sans SC" + ], + "source_section_heading": "CJK & International Content", + "source_section_sha256": "40d2e5f8d19a7e4b92a0b303517621629e6ec647168832db0c3207fe8e0ecde5" + }, + "family_usage_policy": { + "closed_visual_system": true, + "cross_family_layout_mix_allowed": false, + "recolor_allowed": false, + "font_substitution_allowed": false, + "decorative_elements_policy": "identity_element_not_noise", + "extend_missing_layout_policy": { + "same_fonts": true, + "same_palette": true, + "same_spacing_rhythm": true, + "same_component_grammar": true, + "same_decorative_vocabulary": true, + "same_chrome": true + }, + "soft_matching_policy": { + "tone_first": true, + "occasion_is_soft_signal": true, + "avoid_for_is_soft_warning": true, + "taste_can_override_industry": true, + "formality_density_as_sanity_check": true + }, + "hard_rules": [ + "preserve_fonts_palette_grid_slide_classes_decorative_elements", + "do_not_recolor_without_explicit_brand_override", + "do_not_mix_template_families", + "extend_missing_layout_inside_same_family", + "do_not_strip_identity_decorations" + ], + "source": "beautiful-html-templates/AGENTS.md", + "source_sha256": "ed619bb7d956303024872f170b96e5270672a03cf40bdf7ce0abc3d8018c9d77" + }, + "extension_grammar": { + "layout_rhythm": "stencil-tablet: medium density, medium-high formality. Bone paper with stencil-cut headlines and a six-color earth palette: archaeology meets brand.", + "spacing_rhythm": "Reuse source spacing tokens and grid gaps: {\"pad_outer\": \"64px\", \"pad_top\": \"48px\", \"pad_bottom\": \"36px\", \"card_pad\": \"24px 22px to 38px 32px\", \"gap_card\": \"22px to 28px\", \"radius_card\": \"22px\", \"radius_card_lg\": \"26px\", \"radius_action\": \"22px\", \"radius_pill\": \"9", + "component_grammar": [ + "card", + "panel", + "s-agenda", + "s-chart", + "s-consult", + "s-cover", + "s-cta", + "s-matrix", + "s-princ", + "s-process" + ], + "chrome_rules": [ + "footer", + "label", + "row-label" + ], + "decorative_vocabulary": [ + "grid", + "accent line", + "card panels", + "paper texture", + "window chrome", + "poster blocks", + "quote mark" + ], + "allowed_new_layouts": [ + "comparison", + "risk", + "timeline", + "action_plan", + "case_evidence", + "metric_dashboard" + ], + "forbidden_mutations": [ + "new_palette", + "cross_family_components", + "fake_italic", + "new_decorative_motif", + "remote_font_dependency" + ], + "density_limits": "medium", + "source_basis": { + "template_id": "stencil-tablet", + "design_signal_sha256": "72a44481c88458349b062500d4609c9af2c43b1bb01b6a69727772a8c6d78880", + "class_name_count": 82 + } + }, "semantic_fit": { "best_for": [ "Anything that should feel archival", @@ -30669,15 +35506,60 @@ "screenshot_benchmarks": [ { "path": "beautiful-html-templates/screenshots/stencil-tablet-1.png", - "role": "reference" + "role": "cover_reference", + "slide_number": 1, + "why_selected": "README gallery cover reference for stencil-tablet: Bone paper with stencil-cut headlines and a six-color earth palette: archaeology meets brand.", + "visual_targets": [ + "palette", + "type_scale", + "chrome", + "density", + "layout_balance", + "grid" + ], + "acceptance_use": [ + "matcher_thumbnail", + "visual_qa", + "few_shot_reference" + ] }, { "path": "beautiful-html-templates/screenshots/stencil-tablet-3.png", - "role": "reference" + "role": "mid_deck_reference", + "slide_number": 3, + "why_selected": "README gallery mid deck reference for stencil-tablet: Bone paper with stencil-cut headlines and a six-color earth palette: archaeology meets brand.", + "visual_targets": [ + "palette", + "type_scale", + "chrome", + "density", + "layout_balance", + "grid" + ], + "acceptance_use": [ + "matcher_thumbnail", + "visual_qa", + "few_shot_reference" + ] }, { "path": "beautiful-html-templates/screenshots/stencil-tablet-8.png", - "role": "reference" + "role": "late_deck_reference", + "slide_number": 8, + "why_selected": "README gallery late deck reference for stencil-tablet: Bone paper with stencil-cut headlines and a six-color earth palette: archaeology meets brand.", + "visual_targets": [ + "palette", + "type_scale", + "chrome", + "density", + "layout_balance", + "grid" + ], + "acceptance_use": [ + "matcher_thumbnail", + "visual_qa", + "few_shot_reference" + ] } ], "density": "medium" @@ -31418,6 +36300,112 @@ "mono": "system-mono" } }, + "cjk_policy": { + "strategy": "replace_family_whole_element", + "display_font_cn": "Noto Serif SC", + "body_font_cn": "Noto Sans SC", + "mono_font_policy": "latin_only_or_system_mono", + "runtime_font_policy": "system_font_only_no_remote_dependency", + "runtime_font_stack": [ + "system-sans-cjk", + "system-sans-cjk-heavy", + "system-sans-cjk-regular", + "system-mono" + ], + "emphasis_policy": "color_or_weight_only", + "italic_policy": "weight_only_emphasis", + "letter_spacing_policy": "reset_letter_spacing_for_cjk_keep_latin_labels", + "mixed_run_spacing": "pangu_spacing", + "latin_accent_policy": "latin_only_allowed_when_semantic_annotation", + "known_degradation": "The \"uppercase + negative tracking + weight 900\" formula that defines the system cannot be reproduced in CJK. Chinese gets weight 700 (the heaviest NSC weight), no case transformation, and zero tracking. The system loses ~30% of its Latin character in pure-Chinese mode.", + "design_intent_font_pairing": [ + "Noto Serif SC", + "Noto Sans SC" + ], + "source_section_heading": "CJK & International Content", + "source_section_sha256": "99c8689230ec2a54954f913d160e14beec448bccfa40e95138ffab4db7210624" + }, + "family_usage_policy": { + "closed_visual_system": true, + "cross_family_layout_mix_allowed": false, + "recolor_allowed": false, + "font_substitution_allowed": false, + "decorative_elements_policy": "identity_element_not_noise", + "extend_missing_layout_policy": { + "same_fonts": true, + "same_palette": true, + "same_spacing_rhythm": true, + "same_component_grammar": true, + "same_decorative_vocabulary": true, + "same_chrome": true + }, + "soft_matching_policy": { + "tone_first": true, + "occasion_is_soft_signal": true, + "avoid_for_is_soft_warning": true, + "taste_can_override_industry": true, + "formality_density_as_sanity_check": true + }, + "hard_rules": [ + "preserve_fonts_palette_grid_slide_classes_decorative_elements", + "do_not_recolor_without_explicit_brand_override", + "do_not_mix_template_families", + "extend_missing_layout_inside_same_family", + "do_not_strip_identity_decorations" + ], + "source": "beautiful-html-templates/AGENTS.md", + "source_sha256": "ed619bb7d956303024872f170b96e5270672a03cf40bdf7ce0abc3d8018c9d77" + }, + "extension_grammar": { + "layout_rhythm": "studio: medium density, medium formality. Black canvas with electric-yellow type; high-voltage design studio aesthetic.", + "spacing_rhythm": "Reuse source spacing tokens and grid gaps: {\"pad_x\": \"5vw\", \"pad_y\": \"5vh\", \"gap_lg\": \"3.5vh\", \"gap_md\": \"2vh\", \"gap_sm\": \"1vh\"}", + "component_grammar": [ + "stat-card", + "stat-label", + "stat-note", + "stat-value", + "statement-body", + "stats-grid" + ], + "chrome_rules": [ + "bar-x-label", + "compare-label", + "cover-footer", + "cover-footer-col", + "label", + "slide-chrome", + "stat-label" + ], + "decorative_vocabulary": [ + "grid", + "accent line", + "card panels", + "paper texture", + "poster blocks", + "quote mark" + ], + "allowed_new_layouts": [ + "comparison", + "risk", + "timeline", + "action_plan", + "case_evidence", + "metric_dashboard" + ], + "forbidden_mutations": [ + "new_palette", + "cross_family_components", + "fake_italic", + "new_decorative_motif", + "remote_font_dependency" + ], + "density_limits": "medium", + "source_basis": { + "template_id": "studio", + "design_signal_sha256": "5d587ab0bb90d2576bd25334b1b946df63171f11d909234eec0965af3c027657", + "class_name_count": 60 + } + }, "semantic_fit": { "best_for": [ "Anything that should feel electric and design-led: studio credentials", @@ -31651,15 +36639,60 @@ "screenshot_benchmarks": [ { "path": "beautiful-html-templates/screenshots/studio-1.png", - "role": "reference" + "role": "cover_reference", + "slide_number": 1, + "why_selected": "README gallery cover reference for studio: Black canvas with electric-yellow type; high-voltage design studio aesthetic.", + "visual_targets": [ + "palette", + "type_scale", + "chrome", + "density", + "layout_balance", + "grid" + ], + "acceptance_use": [ + "matcher_thumbnail", + "visual_qa", + "few_shot_reference" + ] }, { "path": "beautiful-html-templates/screenshots/studio-4.png", - "role": "reference" + "role": "mid_deck_reference", + "slide_number": 4, + "why_selected": "README gallery mid deck reference for studio: Black canvas with electric-yellow type; high-voltage design studio aesthetic.", + "visual_targets": [ + "palette", + "type_scale", + "chrome", + "density", + "layout_balance", + "grid" + ], + "acceptance_use": [ + "matcher_thumbnail", + "visual_qa", + "few_shot_reference" + ] }, { "path": "beautiful-html-templates/screenshots/studio-8.png", - "role": "reference" + "role": "late_deck_reference", + "slide_number": 8, + "why_selected": "README gallery late deck reference for studio: Black canvas with electric-yellow type; high-voltage design studio aesthetic.", + "visual_targets": [ + "palette", + "type_scale", + "chrome", + "density", + "layout_balance", + "grid" + ], + "acceptance_use": [ + "matcher_thumbnail", + "visual_qa", + "few_shot_reference" + ] } ], "density": "medium" @@ -32415,6 +37448,110 @@ "mono": "system-mono" } }, + "cjk_policy": { + "strategy": "replace_family_whole_element", + "display_font_cn": "Noto Serif SC", + "body_font_cn": "LXGW WenKai", + "mono_font_policy": "latin_only_or_system_mono", + "runtime_font_policy": "system_font_only_no_remote_dependency", + "runtime_font_stack": [ + "system-sans-cjk", + "system-sans-cjk-heavy", + "system-sans-cjk-regular", + "system-mono" + ], + "emphasis_policy": "color_or_weight_only", + "italic_policy": "drop_italic", + "letter_spacing_policy": "reset_letter_spacing_for_cjk_keep_latin_labels", + "mixed_run_spacing": "pangu_spacing", + "latin_accent_policy": "latin_only_allowed_when_semantic_annotation", + "known_degradation": "LXGW WenKai has only a single weight (regular). The system's h3 (weight 500 italic) cannot step up in weight in CJK — the visual hierarchy step must come from size alone (h2 4vw → h3 2.4vw). For decks that need stronger sub-headline emphasis, consider NSC 500 as an h3 alternate.", + "design_intent_font_pairing": [ + "Noto Serif SC", + "LXGW WenKai", + "LXGW WenKai TC", + "LXGW WenKai or NSC at the same teal color", + "LXGW WenKai preserves both registers", + "LXGW WenKai TC is the Traditional Chinese cut on Google Fonts" + ], + "source_section_heading": "CJK & International Content", + "source_section_sha256": "20e7baf08986811ea6fdfd1c1e197ea719c2573e3c0cdf31bca95fbb7ad9f024" + }, + "family_usage_policy": { + "closed_visual_system": true, + "cross_family_layout_mix_allowed": false, + "recolor_allowed": false, + "font_substitution_allowed": false, + "decorative_elements_policy": "identity_element_not_noise", + "extend_missing_layout_policy": { + "same_fonts": true, + "same_palette": true, + "same_spacing_rhythm": true, + "same_component_grammar": true, + "same_decorative_vocabulary": true, + "same_chrome": true + }, + "soft_matching_policy": { + "tone_first": true, + "occasion_is_soft_signal": true, + "avoid_for_is_soft_warning": true, + "taste_can_override_industry": true, + "formality_density_as_sanity_check": true + }, + "hard_rules": [ + "preserve_fonts_palette_grid_slide_classes_decorative_elements", + "do_not_recolor_without_explicit_brand_override", + "do_not_mix_template_families", + "extend_missing_layout_inside_same_family", + "do_not_strip_identity_decorations" + ], + "source": "beautiful-html-templates/AGENTS.md", + "source_sha256": "ed619bb7d956303024872f170b96e5270672a03cf40bdf7ce0abc3d8018c9d77" + }, + "extension_grammar": { + "layout_rhythm": "vellum: low density, high formality. Deep navy canvas with warm-yellow Cormorant serifs and a single dusty teal accent. A quiet, scholarly aesthetic.", + "spacing_rhythm": "Reuse source spacing tokens and grid gaps: {\"pad_x\": \"6vw\", \"pad_y\": \"6vh\", \"gap_lg\": \"5vh\", \"gap_md\": \"3vh\", \"gap_sm\": \"1.5vh\"}", + "component_grammar": [ + "stats-row" + ], + "chrome_rules": [ + "bar-x-label", + "compare-label", + "label", + "pin-stat-label", + "slide-chrome" + ], + "decorative_vocabulary": [ + "grid", + "accent line", + "card panels", + "paper texture", + "poster blocks", + "quote mark", + "sticker collage" + ], + "allowed_new_layouts": [ + "comparison", + "risk", + "timeline", + "action_plan", + "case_evidence", + "metric_dashboard" + ], + "forbidden_mutations": [ + "new_palette", + "cross_family_components", + "fake_italic", + "new_decorative_motif", + "remote_font_dependency" + ], + "density_limits": "low", + "source_basis": { + "template_id": "vellum", + "design_signal_sha256": "602d219d5551ef7a1767d7ce55eeeeae981760471fef47feba5b07dd38704fc6", + "class_name_count": 49 + } + }, "semantic_fit": { "best_for": [ "Anything that should feel scholarly", @@ -32634,15 +37771,60 @@ "screenshot_benchmarks": [ { "path": "beautiful-html-templates/screenshots/vellum-1.png", - "role": "reference" + "role": "cover_reference", + "slide_number": 1, + "why_selected": "README gallery cover reference for vellum: Deep navy canvas with warm-yellow Cormorant serifs and a single dusty teal accent. A quiet, scholarly aesthetic.", + "visual_targets": [ + "palette", + "type_scale", + "chrome", + "density", + "layout_balance", + "grid" + ], + "acceptance_use": [ + "matcher_thumbnail", + "visual_qa", + "few_shot_reference" + ] }, { "path": "beautiful-html-templates/screenshots/vellum-4.png", - "role": "reference" + "role": "mid_deck_reference", + "slide_number": 4, + "why_selected": "README gallery mid deck reference for vellum: Deep navy canvas with warm-yellow Cormorant serifs and a single dusty teal accent. A quiet, scholarly aesthetic.", + "visual_targets": [ + "palette", + "type_scale", + "chrome", + "density", + "layout_balance", + "grid" + ], + "acceptance_use": [ + "matcher_thumbnail", + "visual_qa", + "few_shot_reference" + ] }, { "path": "beautiful-html-templates/screenshots/vellum-8.png", - "role": "reference" + "role": "late_deck_reference", + "slide_number": 8, + "why_selected": "README gallery late deck reference for vellum: Deep navy canvas with warm-yellow Cormorant serifs and a single dusty teal accent. A quiet, scholarly aesthetic.", + "visual_targets": [ + "palette", + "type_scale", + "chrome", + "density", + "layout_balance", + "grid" + ], + "acceptance_use": [ + "matcher_thumbnail", + "visual_qa", + "few_shot_reference" + ] } ], "density": "low" diff --git a/skills/lark-slides/references/beautiful-html-template-families.schema.json b/skills/lark-slides/references/beautiful-html-template-families.schema.json index 4cf1c8b68..4e40a0f9a 100644 --- a/skills/lark-slides/references/beautiful-html-template-families.schema.json +++ b/skills/lark-slides/references/beautiful-html-template-families.schema.json @@ -28,6 +28,9 @@ "claim_level", "runtime_policy", "font_policy", + "cjk_policy", + "family_usage_policy", + "extension_grammar", "semantic_fit", "design_tokens", "visual_dna", @@ -60,6 +63,62 @@ "required": ["fallback_stack", "font_role_map"], "additionalProperties": true }, + "cjk_policy": { + "type": "object", + "required": [ + "strategy", + "display_font_cn", + "body_font_cn", + "runtime_font_policy", + "emphasis_policy", + "italic_policy", + "letter_spacing_policy", + "mixed_run_spacing", + "known_degradation", + "source_section_sha256" + ], + "additionalProperties": true, + "properties": { + "runtime_font_policy": {"const": "system_font_only_no_remote_dependency"}, + "mixed_run_spacing": {"enum": ["pangu_spacing", "none_required"]} + } + }, + "family_usage_policy": { + "type": "object", + "required": [ + "closed_visual_system", + "cross_family_layout_mix_allowed", + "recolor_allowed", + "font_substitution_allowed", + "extend_missing_layout_policy" + ], + "additionalProperties": true, + "properties": { + "closed_visual_system": {"const": true}, + "cross_family_layout_mix_allowed": {"const": false}, + "recolor_allowed": {"const": false}, + "font_substitution_allowed": {"const": false}, + "extend_missing_layout_policy": { + "type": "object", + "required": ["same_fonts", "same_palette", "same_spacing_rhythm", "same_component_grammar", "same_decorative_vocabulary", "same_chrome"], + "additionalProperties": true + } + } + }, + "extension_grammar": { + "type": "object", + "required": [ + "layout_rhythm", + "spacing_rhythm", + "component_grammar", + "chrome_rules", + "decorative_vocabulary", + "allowed_new_layouts", + "forbidden_mutations", + "source_basis" + ], + "additionalProperties": true + }, "semantic_fit": { "type": "object", "required": ["best_for", "industries", "tones", "avoid_when"], @@ -75,6 +134,21 @@ "required": ["palette_roles", "typography_roles", "decorative_motifs", "visual_effects", "screenshot_benchmarks"], "additionalProperties": true, "properties": { + "screenshot_benchmarks": { + "type": "array", + "minItems": 3, + "items": { + "type": "object", + "required": ["path", "role", "slide_number", "why_selected", "visual_targets", "acceptance_use"], + "additionalProperties": true, + "properties": { + "role": {"enum": ["cover_reference", "mid_deck_reference", "late_deck_reference"]}, + "slide_number": {"type": "integer", "minimum": 1}, + "visual_targets": {"type": "array", "minItems": 1, "items": {"type": "string"}}, + "acceptance_use": {"type": "array", "minItems": 1, "items": {"type": "string"}} + } + } + }, "visual_effects": { "type": "array", "items": { diff --git a/skills/lark-slides/references/beautiful-template-issue-codes.json b/skills/lark-slides/references/beautiful-template-issue-codes.json index 15429f64a..407b75896 100644 --- a/skills/lark-slides/references/beautiful-template-issue-codes.json +++ b/skills/lark-slides/references/beautiful-template-issue-codes.json @@ -11,5 +11,16 @@ "live_submit_missing_file_token", "unowned_decorative_primitive", "decorative_motif_overuse" + ], + "phase_1_knowledge_absorption": [ + "cross_family_layout_mix", + "missing_extension_grammar", + "remote_font_dependency", + "cjk_fake_italic", + "cjk_letter_spacing_inherited", + "cjk_mixed_run_spacing_missing", + "family_recolor_without_override", + "source_inventoried_claim_escalation", + "missing_screenshot_benchmark_role" ] } diff --git a/skills/lark-slides/scripts/beautiful_template_asset_extractor.py b/skills/lark-slides/scripts/beautiful_template_asset_extractor.py index 8aebc15eb..8a1162d5d 100644 --- a/skills/lark-slides/scripts/beautiful_template_asset_extractor.py +++ b/skills/lark-slides/scripts/beautiful_template_asset_extractor.py @@ -337,6 +337,235 @@ def screenshot_paths(source_root: Path, slug: str) -> list[str]: return [f"beautiful-html-templates/screenshots/{path.name}" for path in matches[:3]] +def readme_gallery_by_slug(source_root: Path) -> dict[str, list[str]]: + readme = source_root / "README.md" + if not readme.exists(): + return {} + by_slug: dict[str, list[str]] = {} + for match in re.finditer(r"\./screenshots/([a-z0-9-]+-\d+\.png)", readme.read_text(encoding="utf-8")): + name = match.group(1) + slug = re.sub(r"-\d+\.png$", "", name) + by_slug.setdefault(slug, []).append(f"beautiful-html-templates/screenshots/{name}") + return {slug: paths[:3] for slug, paths in by_slug.items() if paths} + + +def screenshot_slide_number(path: str) -> int: + match = re.search(r"-(\d+)\.png$", path) + return int(match.group(1)) if match else 0 + + +def screenshot_benchmarks(source_root: Path, slug: str, template_json: dict[str, Any], visual_targets: list[str], gallery_by_slug: dict[str, list[str]]) -> list[dict[str, Any]]: + paths = gallery_by_slug.get(slug) or screenshot_paths(source_root, slug) + roles = ["cover_reference", "mid_deck_reference", "late_deck_reference"] + tagline = str(template_json.get("tagline") or template_json.get("description") or template_json.get("best_for") or slug) + out: list[dict[str, Any]] = [] + for index, path in enumerate(paths[:3]): + role = roles[index] if index < len(roles) else "reference" + out.append( + { + "path": path, + "role": role, + "slide_number": screenshot_slide_number(path), + "why_selected": f"README gallery {role.replace('_', ' ')} for {slug}: {tagline[:180]}", + "visual_targets": visual_targets[:6] or ["palette", "type_scale", "chrome", "density", "layout_balance"], + "acceptance_use": ["matcher_thumbnail", "visual_qa", "few_shot_reference"], + } + ) + return out + + +def markdown_section(markdown: str, heading: str) -> str: + lines = markdown.splitlines() + start: int | None = None + start_level = 0 + for index, line in enumerate(lines): + match = re.match(r"^(#{2,6})\s+(.+?)\s*$", line) + if not match: + continue + if match.group(2).strip().lower() == heading.lower(): + start = index + start_level = len(match.group(1)) + break + if start is None: + return "" + end = len(lines) + for index in range(start + 1, len(lines)): + match = re.match(r"^(#{2,6})\s+", lines[index]) + if match and len(match.group(1)) <= start_level: + end = index + break + return "\n".join(lines[start:end]).strip() + + +def first_section_paragraph(section: str, heading: str) -> str: + subsection = markdown_section(section, heading) + if not subsection: + return "" + chunks = [] + for raw in subsection.splitlines()[1:]: + line = raw.strip() + if not line or line.startswith("#") or line.startswith("|") or line.startswith("```"): + continue + if line.startswith("- "): + line = line[2:].strip() + chunks.append(line) + if len(" ".join(chunks)) > 240: + break + return " ".join(chunks)[:360] + + +CJK_FONT_PATTERNS = [ + r"Noto\s+(?:Sans|Serif)\s+(?:SC|TC|JP|CJK)", + r"Source\s+Han\s+(?:Sans|Serif)", + r"LXGW\s+[A-Za-z ]+", + r"ZCOOL\s+[A-Za-z]+", + r"PingFang\s+SC", + r"Microsoft\s+YaHei", + r"SimHei", + r"SimSun", + r"Yozai", + r"悠哉字体\s*Yozai", + r"霞鹜[^|,,。))`*]+", + r"站酷[^|,,。))`*]+", +] + + +def clean_font_name(value: str) -> str: + cleaned = re.sub(r"[`*_\"'()()\[\]]", "", value).strip() + cleaned = re.sub(r"\s+", " ", cleaned) + return cleaned[:80] + + +def cjk_font_candidates(cjk_section: str) -> list[str]: + candidates: list[str] = [] + for pattern in CJK_FONT_PATTERNS: + for match in re.finditer(pattern, cjk_section, flags=re.IGNORECASE): + name = clean_font_name(match.group(0)) + if name and name.lower() not in {item.lower() for item in candidates}: + candidates.append(name) + return candidates + + +def classify_italic_policy(cjk_section: str, full_design: str) -> str: + text = f"{cjk_section}\n{full_design}".lower() + if re.search(r"never italic|no italic|drop italic|italic does not exist|fake italic|oblique", text): + return "drop_italic" + if re.search(r"color shift|color-only|color only|emphasis.*color", text): + return "color_only_emphasis" + if re.search(r"weight|bold", text): + return "weight_only_emphasis" + return "latin_only" + + +def classify_letter_spacing_policy(cjk_section: str) -> str: + text = cjk_section.lower() + if re.search(r"letter-spacing|tracking|tracked|uppercase|text-transform", text): + return "reset_letter_spacing_for_cjk_keep_latin_labels" + return "reset_letter_spacing_for_cjk" + + +def extract_cjk_policy(design_md: str, template_json: dict[str, Any]) -> dict[str, Any]: + cjk_section = markdown_section(design_md, "CJK & International Content") + fonts = cjk_font_candidates(cjk_section) + display_font = fonts[0] if fonts else "Noto Sans SC" + body_font = fonts[1] if len(fonts) > 1 else display_font + known_gap = first_section_paragraph(cjk_section, "Known CJK Gap") or first_section_paragraph(cjk_section, "Aesthetic Notes") + if not known_gap: + known_gap = "Preserve the family rhythm while replacing unsafe remote CJK font loading with SVGlide system font roles." + italic_policy = classify_italic_policy(cjk_section, design_md) + emphasis_policy = "color_or_weight_only" if italic_policy != "latin_only" else "latin_only_emphasis" + return { + "strategy": "replace_family_whole_element" if fonts else "single_cjk_family_all_roles", + "display_font_cn": display_font, + "body_font_cn": body_font, + "mono_font_policy": "latin_only_or_system_mono", + "runtime_font_policy": "system_font_only_no_remote_dependency", + "runtime_font_stack": ["system-sans-cjk", "system-sans-cjk-heavy", "system-sans-cjk-regular", "system-mono"], + "emphasis_policy": emphasis_policy, + "italic_policy": italic_policy, + "letter_spacing_policy": classify_letter_spacing_policy(cjk_section), + "mixed_run_spacing": "pangu_spacing" if re.search(r"Pangu|盘古", cjk_section, re.IGNORECASE) else "none_required", + "latin_accent_policy": "latin_only_allowed_when_semantic_annotation", + "known_degradation": known_gap, + "design_intent_font_pairing": fonts[:6], + "source_section_heading": "CJK & International Content", + "source_section_sha256": hashlib.sha256(cjk_section.encode("utf-8")).hexdigest(), + } + + +def extract_family_usage_policy(agents_md: str) -> dict[str, Any]: + return { + "closed_visual_system": True, + "cross_family_layout_mix_allowed": False, + "recolor_allowed": False, + "font_substitution_allowed": False, + "decorative_elements_policy": "identity_element_not_noise", + "extend_missing_layout_policy": { + "same_fonts": True, + "same_palette": True, + "same_spacing_rhythm": True, + "same_component_grammar": True, + "same_decorative_vocabulary": True, + "same_chrome": True, + }, + "soft_matching_policy": { + "tone_first": True, + "occasion_is_soft_signal": True, + "avoid_for_is_soft_warning": True, + "taste_can_override_industry": True, + "formality_density_as_sanity_check": True, + }, + "hard_rules": [ + "preserve_fonts_palette_grid_slide_classes_decorative_elements", + "do_not_recolor_without_explicit_brand_override", + "do_not_mix_template_families", + "extend_missing_layout_inside_same_family", + "do_not_strip_identity_decorations", + ], + "source": "beautiful-html-templates/AGENTS.md", + "source_sha256": hashlib.sha256(agents_md.encode("utf-8")).hexdigest(), + } + + +def extract_extension_grammar( + slug: str, + template_json: dict[str, Any], + design_blocks: dict[str, dict[str, str]], + class_names: list[str], + combined_text: str, +) -> dict[str, Any]: + density = str(template_json.get("density") or "medium") + formality = str(template_json.get("formality") or "medium") + tagline = str(template_json.get("tagline") or template_json.get("description") or template_json.get("best_for") or slug) + component_tokens = sorted( + { + token + for token in ( + list(design_blocks.get("components", {}).keys()) + + [name.removeprefix("layout-") for name in class_names if name.startswith(("layout-", "s-", "card", "panel", "stat"))] + ) + if token + } + ) + chrome = [name for name in class_names if re.search(r"footer|page|number|chrome|label|eyebrow|nav|badge|stamp", name)] + motifs = classify_decorative_motifs(combined_text) + return { + "layout_rhythm": f"{slug}: {density} density, {formality} formality. {tagline[:180]}", + "spacing_rhythm": "Reuse source spacing tokens and grid gaps: " + json.dumps(design_blocks.get("spacing", {}), ensure_ascii=False)[:220], + "component_grammar": component_tokens[:10] or DEFAULT_COMPONENTS[:6], + "chrome_rules": chrome[:8] or ["preserve family header/footer labels", "preserve page-number rhythm", "no unrelated chrome"], + "decorative_vocabulary": motifs, + "allowed_new_layouts": ["comparison", "risk", "timeline", "action_plan", "case_evidence", "metric_dashboard"], + "forbidden_mutations": ["new_palette", "cross_family_components", "fake_italic", "new_decorative_motif", "remote_font_dependency"], + "density_limits": density, + "source_basis": { + "template_id": slug, + "design_signal_sha256": hashlib.sha256(combined_text[:12000].encode("utf-8")).hexdigest(), + "class_name_count": len(class_names), + }, + } + + def variant_record(variant_id: str) -> dict[str, Any]: role_map = { "cover": ["cover"], @@ -378,6 +607,8 @@ def extract_family( slug: str, inventory_by_slug: dict[str, list[dict[str, Any]]] | None = None, absorptions_by_slug: dict[str, list[dict[str, Any]]] | None = None, + agents_md: str = "", + gallery_by_slug: dict[str, list[str]] | None = None, ) -> dict[str, Any]: template_dir = source_root / "templates" / slug template_json = load_json(template_dir / "template.json") @@ -417,8 +648,9 @@ def extract_family( css_tokens = css_variables(template_html) class_names = css_class_names(template_html) layout_variants = html_layout_variants(template_html) - screenshots = screenshot_paths(source_root, slug) + screenshots = (gallery_by_slug or {}).get(slug) or screenshot_paths(source_root, slug) palette_roles = palette_roles_from_tokens(palette, design_blocks.get("colors", {}), css_tokens) + visual_targets = ["palette", "type_scale", "chrome", "density", "layout_balance"] + classify_decorative_motifs(combined)[:2] return { "template_id": slug, "source": { @@ -456,6 +688,9 @@ def extract_family( "mono": "system-mono", }, }, + "cjk_policy": extract_cjk_policy(design_md, template_json), + "family_usage_policy": extract_family_usage_policy(agents_md), + "extension_grammar": extract_extension_grammar(slug, template_json, design_blocks, class_names, combined), "semantic_fit": { "best_for": words(template_json.get("best_for")) or words(template_json.get("occasion")), "industries": classify_industries(combined), @@ -485,7 +720,7 @@ def extract_family( }, "decorative_motifs": classify_decorative_motifs(combined), "visual_effects": classify_visual_effects(combined), - "screenshot_benchmarks": [{"path": path, "role": "reference"} for path in screenshots], + "screenshot_benchmarks": screenshot_benchmarks(source_root, slug, template_json, visual_targets, gallery_by_slug or {}), "density": str(template_json.get("density") or "medium"), }, "svglide_mapping": { @@ -509,6 +744,8 @@ def extract_registry(source_root: str | None = None) -> dict[str, Any]: slugs = sorted(str(item.get("slug")) for item in templates if item.get("slug")) inventory_by_slug = load_inventory_by_slug() absorptions_by_slug = load_absorptions_by_slug() + agents_md = (root / "AGENTS.md").read_text(encoding="utf-8") if (root / "AGENTS.md").exists() else "" + gallery_by_slug = readme_gallery_by_slug(root) return { "version": "beautiful-html-template-families/v1", "source": { @@ -518,7 +755,7 @@ def extract_registry(source_root: str | None = None) -> dict[str, Any]: "inventory_item_count": sum(len(items) for items in inventory_by_slug.values()), "absorbed_family_count": len(absorptions_by_slug), }, - "families": [extract_family(root, slug, inventory_by_slug, absorptions_by_slug) for slug in slugs], + "families": [extract_family(root, slug, inventory_by_slug, absorptions_by_slug, agents_md, gallery_by_slug) for slug in slugs], } diff --git a/skills/lark-slides/scripts/beautiful_template_e2e_dry_run.py b/skills/lark-slides/scripts/beautiful_template_e2e_dry_run.py index 9c3793013..09b53f26f 100644 --- a/skills/lark-slides/scripts/beautiful_template_e2e_dry_run.py +++ b/skills/lark-slides/scripts/beautiful_template_e2e_dry_run.py @@ -5,6 +5,7 @@ from __future__ import annotations import argparse +import hashlib import json from html import escape from pathlib import Path @@ -27,6 +28,28 @@ RECIPES = [ ("spotlight_annotation", "annotation", ["spotlight", "annotation"], ["typography"]), ("brand_system", "brand", ["typography", "geometric_shape"], ["typography"]), ] +M15_POLICY_CODES = [ + "cross_family_layout_mix", + "missing_extension_grammar", + "remote_font_dependency", + "cjk_fake_italic", + "cjk_letter_spacing_inherited", + "cjk_mixed_run_spacing_missing", + "family_recolor_without_override", + "source_inventoried_claim_escalation", + "missing_screenshot_benchmark_role", +] + + +def sha256_payload(value: Any) -> str: + blob = json.dumps(value, ensure_ascii=False, sort_keys=True, separators=(",", ":")).encode("utf-8") + return "sha256:" + hashlib.sha256(blob).hexdigest() + + +def benchmark_roles(family: dict[str, Any]) -> list[str]: + visual_dna = family.get("visual_dna") if isinstance(family.get("visual_dna"), dict) else {} + benchmarks = visual_dna.get("screenshot_benchmarks") if isinstance(visual_dna.get("screenshot_benchmarks"), list) else [] + return [str(item.get("role")) for item in benchmarks if isinstance(item, dict) and item.get("role")] def style_plan_fields(case_id: str) -> dict[str, Any]: @@ -158,12 +181,15 @@ def run_case(case_id: str, query: str, out_dir: Path, include_images: bool) -> d case_dir = out_dir / case_id case_dir.mkdir(parents=True, exist_ok=True) matched_plan = beautiful_template_matcher.plan_with_template_family(query, page_count=10) + selected_family_id = matched_plan["template_family_selection"]["selected_template_id"] + selected_family = beautiful_template_matcher.load_family(selected_family_id) slides: list[dict[str, Any]] = [] svg_paths: list[str] = [] for raw_slide in matched_plan["slides"]: page = int(raw_slide["page"]) include_image = include_images and page in {1, 7} slide, svg = make_slide(page, raw_slide["template_variant"], raw_slide.get("semantic_blocks", []), raw_slide["component_selection"], include_image) + slide["template_family_id"] = selected_family_id svg_path = case_dir / f"page-{page:03d}.svg" svg_path.write_text(svg, encoding="utf-8") svg_paths.append(str(svg_path)) @@ -183,11 +209,19 @@ def run_case(case_id: str, query: str, out_dir: Path, include_images: bool) -> d required_slots = sum(len(svg_preflight.required_image_slots(slide)) for slide in slides) rendered_images = sum(file.get("visual_primitives", {}).get("counts", {}).get("image", 0) for file in preflight["files"]) issues = preflight.get("plan", {}).get("issues", []) + [issue for file in preflight["files"] for issue in file.get("issues", [])] + issue_codes = {issue.get("code") for issue in issues if isinstance(issue, dict)} receipt = { "version": "beautiful-template-e2e-dry-run/v1", "case_id": case_id, "query": query, "selected_template_id": matched_plan["template_family_selection"]["selected_template_id"], + "selected_template_family": selected_family_id, + "claim_level": selected_family.get("claim_level"), + "cjk_policy_hash": sha256_payload(selected_family.get("cjk_policy")), + "family_usage_policy_hash": sha256_payload(selected_family.get("family_usage_policy")), + "extension_grammar_hash": sha256_payload(selected_family.get("extension_grammar")), + "benchmark_roles": benchmark_roles(selected_family), + "preflight_policy_checks": {code: ("failed" if code in issue_codes else "passed") for code in M15_POLICY_CODES}, "candidate_template_ids": matched_plan["template_family_selection"]["candidate_template_ids"], "slide_count": len(slides), "template_variant_count": len({slide["template_variant"] for slide in slides}), @@ -227,8 +261,23 @@ def run_all(out_dir: Path = DEFAULT_OUT_DIR) -> dict[str, Any]: def main() -> int: parser = argparse.ArgumentParser(description="Run beautiful template matcher-to-preflight dry-run fixtures.") parser.add_argument("--out-dir", default=str(DEFAULT_OUT_DIR)) + parser.add_argument("--query", default=None) + parser.add_argument("--case-id", default="ad-hoc") + parser.add_argument("--dry-run", action="store_true") + parser.add_argument("--include-images", action="store_true") args = parser.parse_args() - summary = run_all(Path(args.out_dir)) + if args.query: + receipt = run_case(args.case_id, args.query, Path(args.out_dir), include_images=args.include_images) + summary = { + "version": "beautiful-template-e2e-dry-run-summary/v1", + "status": receipt["status"], + "receipt_count": 1, + "receipts": [receipt], + } + Path(args.out_dir).mkdir(parents=True, exist_ok=True) + (Path(args.out_dir) / "summary.json").write_text(json.dumps(summary, ensure_ascii=False, indent=2) + "\n", encoding="utf-8") + else: + summary = run_all(Path(args.out_dir)) print(json.dumps(summary, ensure_ascii=False, indent=2)) return 0 if summary["status"] == "passed" else 1 diff --git a/skills/lark-slides/scripts/beautiful_template_knowledge_absorption_test.py b/skills/lark-slides/scripts/beautiful_template_knowledge_absorption_test.py new file mode 100644 index 000000000..9d5f0592b --- /dev/null +++ b/skills/lark-slides/scripts/beautiful_template_knowledge_absorption_test.py @@ -0,0 +1,345 @@ +# Copyright (c) 2026 Lark Technologies Pte. Ltd. +# SPDX-License-Identifier: MIT +from __future__ import annotations + +import json +import sys +import tempfile +import unittest +from pathlib import Path + +sys.path.insert(0, str(Path(__file__).resolve().parent)) + +import beautiful_template_asset_extractor +import beautiful_template_e2e_dry_run +import beautiful_template_matcher +import svglide_prompt_planner +import svglide_quality_gate +import svglide_theme_template_selector +import svg_preflight + + +REFERENCES_DIR = Path(__file__).resolve().parent.parent / "references" +SOURCE_ROOT = Path("/Users/bytedance/bd-projects/beautiful-html-templates") +REQUIRED_M15_CODES = { + "cross_family_layout_mix", + "missing_extension_grammar", + "remote_font_dependency", + "cjk_fake_italic", + "cjk_letter_spacing_inherited", + "cjk_mixed_run_spacing_missing", + "family_recolor_without_override", + "source_inventoried_claim_escalation", + "missing_screenshot_benchmark_role", +} +REQUIRED_BENCHMARK_ROLES = {"cover_reference", "mid_deck_reference", "late_deck_reference"} + + +def load_json(name: str) -> dict: + return json.loads((REFERENCES_DIR / name).read_text(encoding="utf-8")) + + +def family_by_id(registry: dict) -> dict[str, dict]: + return {family["template_id"]: family for family in registry["families"]} + + +def all_issue_codes(payload: object) -> set[str]: + codes: set[str] = set() + if isinstance(payload, dict): + for key, value in payload.items(): + if key in {"code", "id"} and isinstance(value, str): + codes.add(value) + elif isinstance(value, str) and key.endswith("codes"): + codes.add(value) + else: + codes.update(all_issue_codes(value)) + elif isinstance(payload, list): + for item in payload: + if isinstance(item, str): + codes.add(item) + else: + codes.update(all_issue_codes(item)) + return codes + + +def issue_codes(result: dict) -> set[str]: + codes: set[str] = set() + for issue in result.get("issues", []): + if isinstance(issue, dict) and issue.get("code"): + codes.add(issue["code"]) + return codes + + +class BeautifulTemplateKnowledgeAbsorptionTest(unittest.TestCase): + def test_issue_codes_freeze_m15_contract(self) -> None: + codes = all_issue_codes(load_json("beautiful-template-issue-codes.json")) + self.assertTrue(REQUIRED_M15_CODES <= codes, REQUIRED_M15_CODES - codes) + + def test_all_families_have_cjk_policy_usage_policy_and_extension_grammar(self) -> None: + registry = load_json("beautiful-html-template-families.json") + self.assertEqual(len(registry["families"]), 34) + cjk_signatures: set[str] = set() + extension_signatures: set[str] = set() + for family in registry["families"]: + with self.subTest(family=family["template_id"]): + cjk = family.get("cjk_policy") + usage = family.get("family_usage_policy") + grammar = family.get("extension_grammar") + self.assertIsInstance(cjk, dict) + self.assertIsInstance(usage, dict) + self.assertIsInstance(grammar, dict) + for key in [ + "strategy", + "display_font_cn", + "body_font_cn", + "runtime_font_policy", + "emphasis_policy", + "italic_policy", + "letter_spacing_policy", + "mixed_run_spacing", + "known_degradation", + "source_section_sha256", + ]: + self.assertTrue(cjk.get(key), f"{family['template_id']} missing cjk_policy.{key}") + self.assertEqual(cjk["runtime_font_policy"], "system_font_only_no_remote_dependency") + self.assertTrue(usage.get("closed_visual_system")) + self.assertFalse(usage.get("cross_family_layout_mix_allowed")) + self.assertFalse(usage.get("recolor_allowed")) + self.assertFalse(usage.get("font_substitution_allowed")) + self.assertTrue(usage.get("extend_missing_layout_policy", {}).get("same_component_grammar")) + for key in [ + "layout_rhythm", + "spacing_rhythm", + "component_grammar", + "chrome_rules", + "decorative_vocabulary", + "allowed_new_layouts", + "forbidden_mutations", + "source_basis", + ]: + self.assertTrue(grammar.get(key), f"{family['template_id']} missing extension_grammar.{key}") + cjk_signatures.add(json.dumps(cjk, sort_keys=True, ensure_ascii=False)) + extension_signatures.add(json.dumps(grammar, sort_keys=True, ensure_ascii=False)) + self.assertGreaterEqual(len(cjk_signatures), 20) + self.assertGreaterEqual(len(extension_signatures), 20) + + def test_screenshot_benchmarks_have_cover_mid_late_roles(self) -> None: + for family in load_json("beautiful-html-template-families.json")["families"]: + benchmarks = family["visual_dna"]["screenshot_benchmarks"] + roles = {item.get("role") for item in benchmarks} + with self.subTest(family=family["template_id"]): + self.assertEqual(roles, REQUIRED_BENCHMARK_ROLES) + for item in benchmarks: + self.assertRegex(item["path"], rf"beautiful-html-templates/screenshots/{family['template_id']}-\d+\.png") + self.assertIsInstance(item.get("slide_number"), int) + self.assertGreater(item["slide_number"], 0) + self.assertTrue(item.get("why_selected")) + self.assertTrue(item.get("visual_targets")) + self.assertTrue(item.get("acceptance_use")) + self.assertNotEqual(item.get("role"), "reference") + + def test_cjk_policy_contains_no_remote_font_runtime_dependency(self) -> None: + registry = load_json("beautiful-html-template-families.json") + for family in registry["families"]: + cjk = family["cjk_policy"] + runtime_blob = json.dumps( + { + "runtime_font_policy": cjk.get("runtime_font_policy"), + "runtime_font_stack": cjk.get("runtime_font_stack"), + "font_role_map": family.get("font_policy", {}).get("font_role_map"), + }, + ensure_ascii=False, + ) + with self.subTest(family=family["template_id"]): + self.assertNotIn("fonts.googleapis.com", runtime_blob) + self.assertNotIn("@font-face", runtime_blob) + self.assertNotIn("http://", runtime_blob) + self.assertNotIn("https://", runtime_blob) + + def test_source_inventoried_families_do_not_claim_absorbed(self) -> None: + for family in load_json("beautiful-html-template-families.json")["families"]: + if family["status"] == "source_inventoried": + self.assertEqual(family["claim_level"], "source_inventory_only", family["template_id"]) + self.assertFalse(family.get("svglide_mapping", {}).get("svglide_asset_ids"), family["template_id"]) + + def test_extractor_reads_cjk_sections_from_all_design_md(self) -> None: + registry = beautiful_template_asset_extractor.extract_registry() + self.assertEqual(len(registry["families"]), 34) + for family in registry["families"]: + with self.subTest(family=family["template_id"]): + cjk = family.get("cjk_policy", {}) + self.assertEqual(cjk.get("source_section_heading"), "CJK & International Content") + self.assertTrue(cjk.get("source_section_sha256")) + self.assertIn(cjk.get("mixed_run_spacing"), {"pangu_spacing", "none_required"}) + self.assertIn("letter", cjk.get("letter_spacing_policy", "")) + self.assertTrue(cjk.get("known_degradation")) + + def test_extractor_assigns_screenshot_benchmark_roles(self) -> None: + registry = beautiful_template_asset_extractor.extract_registry() + for family in registry["families"]: + roles = {item.get("role") for item in family["visual_dna"]["screenshot_benchmarks"]} + self.assertEqual(roles, REQUIRED_BENCHMARK_ROLES, family["template_id"]) + + def test_matcher_outputs_policy_summaries_without_claim_escalation(self) -> None: + result = beautiful_template_matcher.match_templates("内部业务复盘,管理层阅读,有指标、问题、原因、后续动作", limit=5) + self.assertGreaterEqual(len(result["matches"]), 3) + for match in result["matches"]: + with self.subTest(match=match["template_id"]): + self.assertIn(match.get("claim_level"), {"svglide_absorbed", "source_inventory_only"}) + self.assertTrue(match.get("family_usage_policy_summary")) + self.assertTrue(match.get("cjk_policy_summary")) + self.assertTrue(match.get("extension_grammar_summary")) + self.assertEqual(set(match.get("benchmark_roles", [])), REQUIRED_BENCHMARK_ROLES) + if match.get("status") == "source_inventoried": + self.assertEqual(match["claim_level"], "source_inventory_only") + + def test_prompt_context_includes_policy_summaries(self) -> None: + templates = svglide_prompt_planner.template_registry_bundle() + self.assertTrue(templates) + sample = next((item for item in templates if item.get("source_template_id")), None) + self.assertIsNotNone(sample) + for key in [ + "source_template_id", + "claim_level", + "family_usage_policy_summary", + "cjk_policy_summary", + "extension_grammar_summary", + "benchmark_roles", + ]: + self.assertIn(key, sample) + family_context = svglide_prompt_planner.template_family_policy_context_bundle() + self.assertEqual(len(family_context), 34) + + def test_theme_template_selector_preserves_policy_fields(self) -> None: + templates = [ + item + for item in svglide_theme_template_selector.load_template_registry().get("templates", []) + if isinstance(item, dict) and item.get("source_template_id") + ] + self.assertTrue(templates) + scored = svglide_theme_template_selector.score_template({}, templates[0], brief="内部复盘") + for key in [ + "source_template_id", + "claim_level", + "family_usage_policy_summary", + "cjk_policy_summary", + "extension_grammar_summary", + "benchmark_roles", + ]: + self.assertIn(key, scored) + + def test_quality_gate_blocks_m15_preflight_codes(self) -> None: + with tempfile.TemporaryDirectory() as tmpdir: + project = Path(tmpdir) + check_path = project / "06-check/preflight.json" + check_path.parent.mkdir(parents=True, exist_ok=True) + check_path.write_text( + json.dumps( + { + "summary": {"error_count": 0}, + "plan": {"issues": [{"level": "error", "code": "cross_family_layout_mix"}]}, + }, + ensure_ascii=False, + ) + + "\n", + encoding="utf-8", + ) + check = svglide_quality_gate.load_check(project, "preflight", Path("06-check/preflight.json"), required=True, profile="production") + codes = {issue["code"] for issue in check["issues"]} + self.assertIn("m15_policy_gate_failed", codes) + + def test_preflight_rejects_family_usage_misuse(self) -> None: + plan = { + "output_mode": "svglide-svg", + "page_count": 1, + "template_family_selection": { + "enabled": True, + "source": "beautiful-html-template-families", + "selected_template_id": "blue-professional", + "claim_level": "svglide_absorbed", + "palette_override": {"primary": "#ff0000"}, + }, + "slides": [ + { + "page": 1, + "title": "复盘", + "template_family_id": "studio", + "template_variant": "custom_risk_board", + "variant_source": "generated_extension", + "semantic_blocks": [{"block_id": "title_1", "type": "title", "content": "复盘"}], + "component_selection": [{"component_id": "title_block", "binds": ["title_1"]}], + "asset_strategy": {"strategy_id": "structured_fallback", "no_fake_data": True}, + "asset_contract": "none_required", + "risk_flags": [], + "source_policy": "prompt only", + "content_density_contract": "medium-density structured template page", + } + ], + } + codes = issue_codes(svg_preflight.lint_plan(plan)) + self.assertIn("cross_family_layout_mix", codes) + self.assertIn("missing_extension_grammar", codes) + self.assertIn("family_recolor_without_override", codes) + + def test_preflight_rejects_source_inventoried_claim_escalation(self) -> None: + plan = { + "output_mode": "svglide-svg", + "page_count": 1, + "template_family_selection": { + "enabled": True, + "source": "beautiful-html-template-families", + "selected_template_id": "8-bit-orbit", + "claim_level": "svglide_absorbed", + }, + "slides": [ + { + "page": 1, + "title": "Demo", + "template_variant": "cover", + "semantic_blocks": [{"block_id": "title_1", "type": "title", "content": "Demo"}], + "component_selection": [{"component_id": "title_block", "binds": ["title_1"]}], + "asset_strategy": {"strategy_id": "structured_fallback", "no_fake_data": True}, + "asset_contract": "none_required", + "risk_flags": [], + "source_policy": "prompt only", + "content_density_contract": "medium-density structured template page", + } + ], + } + self.assertIn("source_inventoried_claim_escalation", issue_codes(svg_preflight.lint_plan(plan))) + + def test_preflight_rejects_cjk_fake_italic_and_letter_spacing(self) -> None: + svg = """ + + +
内部复盘 AI 产品 2026
+
+
""" + codes = issue_codes(svg_preflight.lint_svg(svg)) + self.assertIn("cjk_fake_italic", codes) + self.assertIn("cjk_letter_spacing_inherited", codes) + + def test_dry_run_receipt_records_policy_hashes_and_preflight_checks(self) -> None: + with tempfile.TemporaryDirectory() as tmpdir: + summary = beautiful_template_e2e_dry_run.run_all(Path(tmpdir)) + self.assertEqual(summary["status"], "passed") + for receipt in summary["receipts"]: + with self.subTest(case=receipt["case_id"]): + self.assertTrue(receipt.get("selected_template_family")) + self.assertTrue(receipt.get("claim_level")) + self.assertRegex(receipt.get("cjk_policy_hash", ""), r"^sha256:[0-9a-f]{64}$") + self.assertRegex(receipt.get("family_usage_policy_hash", ""), r"^sha256:[0-9a-f]{64}$") + self.assertRegex(receipt.get("extension_grammar_hash", ""), r"^sha256:[0-9a-f]{64}$") + self.assertEqual(set(receipt.get("benchmark_roles", [])), REQUIRED_BENCHMARK_ROLES) + checks = receipt.get("preflight_policy_checks", {}) + for code in [ + "cross_family_layout_mix", + "cjk_fake_italic", + "cjk_letter_spacing_inherited", + "family_recolor_without_override", + ]: + self.assertEqual(checks.get(code), "passed") + + +if __name__ == "__main__": + unittest.main() diff --git a/skills/lark-slides/scripts/beautiful_template_matcher.py b/skills/lark-slides/scripts/beautiful_template_matcher.py index dbbb880b3..f2a9e6388 100644 --- a/skills/lark-slides/scripts/beautiful_template_matcher.py +++ b/skills/lark-slides/scripts/beautiful_template_matcher.py @@ -19,7 +19,7 @@ COMPONENT_REGISTRY_PATH = REFERENCES_DIR / "component-registry.json" ASSET_STRATEGY_PATH = REFERENCES_DIR / "asset-strategy-registry.json" -INTERNAL_REVIEW_RE = re.compile(r"复盘|经营|季度|管理层|指标|问题|原因|后续|review|business", re.IGNORECASE) +INTERNAL_REVIEW_RE = re.compile(r"复盘|经营|管理层|指标|问题|原因|后续|review|business", re.IGNORECASE) CULTURE_EVENT_RE = re.compile(r"艺术|展|活动|海报|文化|青年|poster|exhibition|biennale", re.IGNORECASE) COMPANY_PRODUCT_RE = re.compile(r"公司|产品|竞品|MiniMax|智谱|brand|company|product|logo|screenshot", re.IGNORECASE) QUANTIFIED_RE = re.compile(r"\d+|同比|环比|增长|下降|占比|排名|trend|share|%|KPI", re.IGNORECASE) @@ -80,6 +80,42 @@ def normalize_text(value: Any) -> str: return str(value or "") +def policy_summary(value: Any, keys: list[str]) -> dict[str, Any]: + if not isinstance(value, dict): + return {} + return {key: value.get(key) for key in keys if value.get(key) not in (None, "", [])} + + +def cjk_policy_summary(family: dict[str, Any]) -> dict[str, Any]: + return policy_summary( + family.get("cjk_policy"), + ["strategy", "display_font_cn", "body_font_cn", "runtime_font_policy", "italic_policy", "letter_spacing_policy", "mixed_run_spacing"], + ) + + +def family_usage_policy_summary(family: dict[str, Any]) -> dict[str, Any]: + return policy_summary( + family.get("family_usage_policy"), + ["closed_visual_system", "cross_family_layout_mix_allowed", "recolor_allowed", "font_substitution_allowed", "decorative_elements_policy"], + ) + + +def extension_grammar_summary(family: dict[str, Any]) -> dict[str, Any]: + grammar = family.get("extension_grammar") if isinstance(family.get("extension_grammar"), dict) else {} + return { + "layout_rhythm": grammar.get("layout_rhythm"), + "component_grammar": grammar.get("component_grammar", [])[:6] if isinstance(grammar.get("component_grammar"), list) else grammar.get("component_grammar"), + "decorative_vocabulary": grammar.get("decorative_vocabulary", [])[:6] if isinstance(grammar.get("decorative_vocabulary"), list) else grammar.get("decorative_vocabulary"), + "forbidden_mutations": grammar.get("forbidden_mutations", [])[:6] if isinstance(grammar.get("forbidden_mutations"), list) else grammar.get("forbidden_mutations"), + } + + +def benchmark_roles(family: dict[str, Any]) -> list[str]: + visual_dna = family.get("visual_dna") if isinstance(family.get("visual_dna"), dict) else {} + benchmarks = visual_dna.get("screenshot_benchmarks") if isinstance(visual_dna.get("screenshot_benchmarks"), list) else [] + return [str(item.get("role")) for item in benchmarks if isinstance(item, dict) and item.get("role")] + + def query_signals(query: str) -> dict[str, Any]: needs: list[str] = [] tones: list[str] = [] @@ -148,6 +184,9 @@ def family_score(query: str, signals: dict[str, Any], family: dict[str, Any]) -> if pattern.search(query) and template_id in boosts: score += boosts[template_id] reasons.append(reason) + if family.get("claim_level") == "source_inventory_only": + score -= 0.03 + reasons.append("source inventory only; requires contract compile before absorbed claim") avoid_text = normalize_text(semantic_fit.get("avoid_when")) if avoid_text and token_overlap_score(query, avoid_text) > 0: score -= 0.3 @@ -297,11 +336,17 @@ def match_templates(query: str, limit: int = 3, page_count: int | None = None, r matches.append( { "template_id": family.get("template_id"), + "status": family.get("status"), + "claim_level": family.get("claim_level"), "score": round(score, 4), "reasons": reasons, "recommended_variants": variants, "component_hints": family.get("component_candidates", [])[:6], "asset_strategy_hints": ["chart_when_quantified", "real_image_required", "structured_fallback"], + "family_usage_policy_summary": family_usage_policy_summary(family), + "cjk_policy_summary": cjk_policy_summary(family), + "extension_grammar_summary": extension_grammar_summary(family), + "benchmark_roles": benchmark_roles(family), } ) return {"query_signals": signals, "matches": matches} @@ -309,8 +354,9 @@ def match_templates(query: str, limit: int = 3, page_count: int | None = None, r def plan_with_template_family(query: str, page_count: int = 10) -> dict[str, Any]: result = match_templates(query, limit=3, page_count=page_count) - selected = result["matches"][0]["template_id"] - variants = result["matches"][0]["recommended_variants"] + selected_match = result["matches"][0] + selected = selected_match["template_id"] + variants = selected_match["recommended_variants"] if not variants: variants = ["cover", "agenda", "context_overview", "comparison", "action_plan", "closing"] slides = [] @@ -320,6 +366,7 @@ def plan_with_template_family(query: str, page_count: int = 10) -> dict[str, Any slides.append( { "page": index + 1, + "template_family_id": selected, "template_variant": variant, "semantic_blocks": blocks, "component_selection": select_components(blocks), @@ -334,7 +381,12 @@ def plan_with_template_family(query: str, page_count: int = 10) -> dict[str, Any "source": "beautiful-html-template-families", "selected_template_id": selected, "candidate_template_ids": [item["template_id"] for item in result["matches"]], - "selection_reason": "; ".join(result["matches"][0]["reasons"]), + "selection_reason": "; ".join(selected_match["reasons"]), + "claim_level": selected_match.get("claim_level"), + "family_usage_policy_summary": selected_match.get("family_usage_policy_summary"), + "cjk_policy_summary": selected_match.get("cjk_policy_summary"), + "extension_grammar_summary": selected_match.get("extension_grammar_summary"), + "benchmark_roles": selected_match.get("benchmark_roles"), }, "slides": slides, } diff --git a/skills/lark-slides/scripts/beautiful_template_runtime.py b/skills/lark-slides/scripts/beautiful_template_runtime.py index 1770c2911..d6d98a8dd 100644 --- a/skills/lark-slides/scripts/beautiful_template_runtime.py +++ b/skills/lark-slides/scripts/beautiful_template_runtime.py @@ -121,6 +121,62 @@ def normalized_formality(value: Any) -> str: return raw if raw in FORMALITY_VALUES else "medium" +def policy_summary(value: Any, keys: list[str]) -> dict[str, Any]: + if not isinstance(value, dict): + return {} + return {key: value.get(key) for key in keys if value.get(key) not in (None, "", [])} + + +def family_usage_policy_summary(family: dict[str, Any]) -> dict[str, Any]: + return policy_summary( + family.get("family_usage_policy"), + ["closed_visual_system", "cross_family_layout_mix_allowed", "recolor_allowed", "font_substitution_allowed", "decorative_elements_policy"], + ) + + +def cjk_policy_summary(family: dict[str, Any]) -> dict[str, Any]: + return policy_summary( + family.get("cjk_policy"), + ["strategy", "display_font_cn", "body_font_cn", "runtime_font_policy", "italic_policy", "letter_spacing_policy", "mixed_run_spacing"], + ) + + +def extension_grammar_summary(family: dict[str, Any]) -> dict[str, Any]: + grammar = family.get("extension_grammar") if isinstance(family.get("extension_grammar"), dict) else {} + return { + "layout_rhythm": grammar.get("layout_rhythm"), + "component_grammar": grammar.get("component_grammar", [])[:6] if isinstance(grammar.get("component_grammar"), list) else grammar.get("component_grammar"), + "decorative_vocabulary": grammar.get("decorative_vocabulary", [])[:6] if isinstance(grammar.get("decorative_vocabulary"), list) else grammar.get("decorative_vocabulary"), + "forbidden_mutations": grammar.get("forbidden_mutations", [])[:6] if isinstance(grammar.get("forbidden_mutations"), list) else grammar.get("forbidden_mutations"), + } + + +def benchmark_roles(family: dict[str, Any]) -> list[str]: + visual_dna = family.get("visual_dna") if isinstance(family.get("visual_dna"), dict) else {} + benchmarks = visual_dna.get("screenshot_benchmarks") if isinstance(visual_dna.get("screenshot_benchmarks"), list) else [] + return [str(item.get("role")) for item in benchmarks if isinstance(item, dict) and item.get("role")] + + +def family_policy_context(limit: int | None = None) -> list[dict[str, Any]]: + records: list[dict[str, Any]] = [] + for family in families()[: limit or None]: + template_id = family.get("template_id") + if not isinstance(template_id, str) or not template_id: + continue + records.append( + { + "source_template_id": template_id, + "status": family.get("status"), + "claim_level": family.get("claim_level"), + "family_usage_policy_summary": family_usage_policy_summary(family), + "cjk_policy_summary": cjk_policy_summary(family), + "extension_grammar_summary": extension_grammar_summary(family), + "benchmark_roles": benchmark_roles(family), + } + ) + return records + + def template_registry() -> dict[str, Any]: theme_ids = all_theme_ids() records: list[dict[str, Any]] = [] @@ -163,6 +219,17 @@ def template_registry() -> dict[str, Any]: "decorative_elements": visual_dna.get("decorative_motifs") or visual_dna.get("motifs") or [], }, } + if family: + record.update( + { + "source_template_id": family.get("template_id"), + "claim_level": family.get("claim_level"), + "family_usage_policy_summary": family_usage_policy_summary(family), + "cjk_policy_summary": cjk_policy_summary(family), + "extension_grammar_summary": extension_grammar_summary(family), + "benchmark_roles": benchmark_roles(family), + } + ) record.update(TEMPLATE_OVERRIDES.get(template_id, {})) records.append(record) return {"version": "svglide-template-registry/generated-from-beautiful-family-v1", "templates": records} diff --git a/skills/lark-slides/scripts/svg_preflight.py b/skills/lark-slides/scripts/svg_preflight.py index d51ec6d34..6a1cb203b 100644 --- a/skills/lark-slides/scripts/svg_preflight.py +++ b/skills/lark-slides/scripts/svg_preflight.py @@ -38,9 +38,13 @@ PATH_NUMBER_RE = re.compile(r"[-+]?(?:\d+\.?\d*|\.\d+)(?:[eE][-+]?\d+)?") BASE64URL_RE = re.compile(r"^[A-Za-z0-9_-]+$") SHA256_HASH_RE = re.compile(r"^sha256:[0-9a-fA-F]{64}$") FONT_SHORTHAND_RE = re.compile(r"(^|;)\s*font\s*:", re.IGNORECASE) +FONT_STYLE_ITALIC_RE = re.compile(r"font-style\s*:\s*(italic|oblique)\b", re.IGNORECASE) +LETTER_SPACING_RE = re.compile(r"letter-spacing\s*:\s*([^;]+)", re.IGNORECASE) +REMOTE_FONT_DEPENDENCY_RE = re.compile(r"(@font-face|fonts\.googleapis\.com|fonts\.gstatic\.com|https?://)", re.IGNORECASE) STYLE_IMAGE_OPACITY_RE = re.compile(r"(^|;)\s*opacity\s*:", re.IGNORECASE) STYLE_STROKE_WIDTH_RE = re.compile(r"(^|;)\s*stroke-width\s*:", re.IGNORECASE) STYLE_STROKE_DASHARRAY_RE = re.compile(r"(^|;)\s*stroke-dasharray\s*:", re.IGNORECASE) +CJK_TEXT_RE = re.compile(r"[\u3400-\u9fff]") RGB_RE = re.compile(r"rgba?\(([^)]+)\)", re.IGNORECASE) FONT_SIZE_RE = re.compile(r"font-size\s*:\s*([0-9.]+)px?", re.IGNORECASE) KEY_PATH_RE = re.compile(r"(critical|flow|journey|loop|main|path|rail|route|spine|timeline)", re.IGNORECASE) @@ -1437,6 +1441,18 @@ def validate_styles(root: ET.Element) -> list[dict[str, Any]]: issues: list[dict[str, Any]] = [] for element in root.iter(): style = get_attr(element, "style") or "" + text = "".join(element.itertext()) + has_cjk = bool(CJK_TEXT_RE.search(text)) + if style and REMOTE_FONT_DEPENDENCY_RE.search(style): + issues.append( + issue( + "error", + "remote_font_dependency", + "SVG style must not depend on remote font loading", + element, + "Use SVGlide system font roles; keep Google/webfont names only as design intent metadata.", + ) + ) if FONT_SHORTHAND_RE.search(style): issues.append( issue( @@ -1447,6 +1463,33 @@ def validate_styles(root: ET.Element) -> list[dict[str, Any]]: "Use explicit font-size, font-weight, font-family, color, line-height, and text-align properties.", ) ) + font_style = textify(get_attr(element, "font-style") or "") + if has_cjk and (FONT_STYLE_ITALIC_RE.search(style) or normalize_name(font_style) in {"italic", "oblique"}): + issues.append( + issue( + "error", + "cjk_fake_italic", + "CJK text must not use fake italic or oblique styling", + element, + "Use color, weight, underline, or a family-specific emphasis treatment instead of synthetic CJK italic.", + ) + ) + letter_spacing = get_attr(element, "letter-spacing") + match = LETTER_SPACING_RE.search(style) + if match: + letter_spacing = match.group(1) + if has_cjk and letter_spacing and normalize_name(letter_spacing) not in {"0", "0px", "normal", "unset", "initial"}: + parsed = parse_number(letter_spacing) + if parsed is None or abs(parsed) > 0.01: + issues.append( + issue( + "error", + "cjk_letter_spacing_inherited", + "CJK text must reset inherited Latin tracking/letter-spacing", + element, + "Set letter-spacing:0 for CJK runs; keep tracking only on Latin labels when explicitly needed.", + ) + ) name = local_name(element.tag) if name in {"circle", "ellipse"} and (get_attr(element, "stroke-width") is not None or STYLE_STROKE_WIDTH_RE.search(style)): issues.append( @@ -1751,6 +1794,180 @@ def is_template_family_route_plan(plan: dict[str, Any]) -> bool: return isinstance(selection, dict) and boolish(selection.get("enabled"), default=False) +def beautiful_family_by_id() -> dict[str, dict[str, Any]]: + return {textify(family.get("template_id")).strip(): family for family in beautiful_template_runtime.families() if textify(family.get("template_id")).strip()} + + +def selected_template_family_id(plan: dict[str, Any]) -> str: + selection = nested_dict(plan.get("template_family_selection")) + return textify(selection.get("selected_template_id") or selection.get("template_id") or selection.get("family_id")).strip() + + +def selected_template_family(plan: dict[str, Any]) -> dict[str, Any] | None: + selected = selected_template_family_id(plan) + if not selected: + return None + families_by_id = beautiful_family_by_id() + family = families_by_id.get(selected) + if family: + return family + normalized = normalize_name(selected) + for template_id, candidate in families_by_id.items(): + if normalize_name(template_id) == normalized: + return candidate + return None + + +def slide_template_family_id(slide: dict[str, Any]) -> str: + for key in ["template_family_id", "family_id", "template_source_id", "source_template_id"]: + value = textify(slide.get(key)).strip() + if value: + return value + selection = nested_dict(slide.get("template_family_selection")) + return textify(selection.get("selected_template_id") or selection.get("template_id") or selection.get("family_id")).strip() + + +def family_variant_ids(family: dict[str, Any]) -> set[str]: + variants = family.get("variants") if isinstance(family.get("variants"), list) else [] + return {textify(item.get("variant_id")).strip() for item in variants if isinstance(item, dict) and textify(item.get("variant_id")).strip()} + + +def slide_requires_extension_grammar(slide: dict[str, Any], family: dict[str, Any]) -> bool: + variant = textify(slide.get("template_variant")).strip() + variant_source = normalize_name(slide.get("variant_source") or slide.get("layout_source")) + if variant_source in {"generated_extension", "custom", "from_scratch", "manual_extension", "derived_extension"}: + return True + return variant.startswith("custom_") + + +def slide_has_extension_grammar_ref(slide: dict[str, Any]) -> bool: + for key in ["extension_grammar_ref", "extension_grammar_applied", "extension_grammar", "template_extension_grammar"]: + value = slide.get(key) + if isinstance(value, bool): + if value: + return True + elif textify(value).strip(): + return True + return False + + +def selection_requests_recolor(plan: dict[str, Any]) -> bool: + selection = nested_dict(plan.get("template_family_selection")) + for key in ["palette_override", "recolor_override", "color_override", "theme_override"]: + value = selection.get(key) or plan.get(key) + if value not in (None, "", {}, []): + return True + return False + + +def selection_allows_recolor(plan: dict[str, Any]) -> bool: + selection = nested_dict(plan.get("template_family_selection")) + for source in [selection, plan]: + if boolish(source.get("allow_family_recolor") or source.get("brand_palette_override") or source.get("brand_override"), default=False): + return True + reason = textify(source.get("brand_override_reason") or source.get("recolor_reason")).strip() + if reason: + return True + return False + + +def validate_template_family_policy(plan: dict[str, Any]) -> list[dict[str, Any]]: + issues: list[dict[str, Any]] = [] + family = selected_template_family(plan) + selection = nested_dict(plan.get("template_family_selection")) + selected = selected_template_family_id(plan) + if not family: + return issues + + if family.get("claim_level") == "source_inventory_only" and selection.get("claim_level") == "svglide_absorbed": + issues.append( + plan_issue( + "error", + "source_inventoried_claim_escalation", + f'template family "{selected}" is source_inventory_only but planner claims svglide_absorbed', + None, + "Keep claim_level=source_inventory_only until the family has real SVGlide absorption provenance.", + ) + ) + + usage = family.get("family_usage_policy") if isinstance(family.get("family_usage_policy"), dict) else {} + if selection_requests_recolor(plan) and not selection_allows_recolor(plan) and usage.get("recolor_allowed") is False: + issues.append( + plan_issue( + "error", + "family_recolor_without_override", + f'template family "{selected}" forbids default recolor without explicit brand override', + None, + "Remove the palette/recolor override or mark an explicit brand override with a reason.", + ) + ) + + cjk_policy = family.get("cjk_policy") if isinstance(family.get("cjk_policy"), dict) else {} + if not cjk_policy.get("mixed_run_spacing"): + issues.append( + plan_issue( + "error", + "cjk_mixed_run_spacing_missing", + f'template family "{selected}" does not declare mixed-run CJK/Latin spacing policy', + None, + "Extract mixed_run_spacing from design.md before using the family.", + ) + ) + if cjk_policy.get("runtime_font_policy") not in {"system_font_only_no_remote_dependency", None}: + issues.append( + plan_issue( + "error", + "remote_font_dependency", + f'template family "{selected}" declares a runtime font dependency that SVGlide cannot rely on', + None, + "Use system CJK font roles in SVGlide runtime; keep webfont names as design intent only.", + ) + ) + + visual_dna = family.get("visual_dna") if isinstance(family.get("visual_dna"), dict) else {} + benchmarks = visual_dna.get("screenshot_benchmarks") if isinstance(visual_dna.get("screenshot_benchmarks"), list) else [] + roles = {textify(item.get("role")) for item in benchmarks if isinstance(item, dict)} + required_roles = {"cover_reference", "mid_deck_reference", "late_deck_reference"} + if roles != required_roles: + issues.append( + plan_issue( + "error", + "missing_screenshot_benchmark_role", + f'template family "{selected}" screenshot_benchmarks must include cover/mid/late roles', + None, + "Use README gallery order and real screenshot paths; do not invent benchmark roles.", + ) + ) + + slides = plan.get("slides") if isinstance(plan.get("slides"), list) else [] + for slide in slides: + if not isinstance(slide, dict): + continue + visual_plan = slide_visual_plan(slide) + slide_family_id = slide_template_family_id(visual_plan) + if slide_family_id and slide_family_id != selected and normalize_name(slide_family_id) != normalize_name(selected): + issues.append( + plan_issue( + "error", + "cross_family_layout_mix", + f'slide uses template family "{slide_family_id}" while deck selected "{selected}"', + slide, + "Keep one template family per deck unless the user explicitly starts a new deck.", + ) + ) + if slide_requires_extension_grammar(visual_plan, family) and not slide_has_extension_grammar_ref(visual_plan): + issues.append( + plan_issue( + "error", + "missing_extension_grammar", + "generated or custom template_family slide must cite the selected family's extension_grammar", + slide, + "Attach extension_grammar_ref/extension_grammar_applied when extending missing layouts.", + ) + ) + return issues + + def slide_visual_plan(slide: dict[str, Any]) -> dict[str, Any]: visual_plan = slide.get("visual_plan") if isinstance(visual_plan, dict): @@ -2460,6 +2677,7 @@ def lint_plan(plan: dict[str, Any], path: str = "") -> dict[str, Any]: "Use one of: " + ", ".join(sorted(family_ids)), ) ) + issues.extend(validate_template_family_policy(plan)) deck_preset_id = deck_style_preset_id(plan) deck_style_system = style_system(plan) asset_contract_lookup = asset_contracts_by_id(plan) diff --git a/skills/lark-slides/scripts/svglide_prompt_planner.py b/skills/lark-slides/scripts/svglide_prompt_planner.py index 0792b7bc8..6d45578d7 100644 --- a/skills/lark-slides/scripts/svglide_prompt_planner.py +++ b/skills/lark-slides/scripts/svglide_prompt_planner.py @@ -178,11 +178,21 @@ def template_registry_bundle() -> list[dict[str, Any]]: "max_items": item.get("max_items"), "text_budget": item.get("text_budget"), "supported_theme_ids": item.get("supported_theme_ids"), + "source_template_id": item.get("source_template_id"), + "claim_level": item.get("claim_level"), + "family_usage_policy_summary": item.get("family_usage_policy_summary"), + "cjk_policy_summary": item.get("cjk_policy_summary"), + "extension_grammar_summary": item.get("extension_grammar_summary"), + "benchmark_roles": item.get("benchmark_roles"), } ) return result +def template_family_policy_context_bundle() -> list[dict[str, Any]]: + return beautiful_template_runtime.family_policy_context() + + def load_selection_context(project: Path | None = None) -> dict[str, Any]: if project is None: return {} @@ -204,6 +214,7 @@ def load_selection_context(project: Path | None = None) -> dict[str, Any]: def load_context(project: Path | None = None) -> dict[str, Any]: context = { "templates": template_registry_bundle(), + "template_family_policy_context": template_family_policy_context_bundle(), "themes": theme_registry_bundle(), "layout_archetypes": read_json(repo_path("skills/lark-slides/references/svglide-layout-archetypes.json")), "component_registry": beautiful_template_runtime.component_registry(), diff --git a/skills/lark-slides/scripts/svglide_quality_gate.py b/skills/lark-slides/scripts/svglide_quality_gate.py index 6430c1683..1d2afdff7 100644 --- a/skills/lark-slides/scripts/svglide_quality_gate.py +++ b/skills/lark-slides/scripts/svglide_quality_gate.py @@ -66,6 +66,17 @@ BLOCKED_ASSET_SOURCE_REFS = {"local-generated-preview-asset"} BLOCKED_ASSET_KINDS = {"generated_image", "ai_image"} BLOCKED_ASSET_LICENSES = {"preview_unverified"} INTERNAL_ASSET_SCHEMES = {"internal"} +M15_POLICY_CODES = { + "cross_family_layout_mix", + "missing_extension_grammar", + "remote_font_dependency", + "cjk_fake_italic", + "cjk_letter_spacing_inherited", + "cjk_mixed_run_spacing_missing", + "family_recolor_without_override", + "source_inventoried_claim_escalation", + "missing_screenshot_benchmark_role", +} ASSET_METADATA_KEYS = { "asset_id", "asset_kind", @@ -272,6 +283,20 @@ def error_count_from_payload(payload: Any) -> int | None: return raw +def collect_issue_codes(payload: Any) -> set[str]: + codes: set[str] = set() + if isinstance(payload, dict): + code = payload.get("code") + if isinstance(code, str): + codes.add(code) + for value in payload.values(): + codes.update(collect_issue_codes(value)) + elif isinstance(payload, list): + for item in payload: + codes.update(collect_issue_codes(item)) + return codes + + def list_waivers(payload: Any) -> list[Any]: if not isinstance(payload, dict): return [] @@ -900,6 +925,11 @@ def load_check(project: Path, name: str, rel: Path, *, required: bool, profile: check["error_count"] = error_count check["action"] = action check["waivers"] = waivers + if name == "preflight": + m15_codes = sorted(M15_POLICY_CODES & collect_issue_codes(payload)) + if m15_codes: + check["issues"].append(issue("m15_policy_gate_failed", "preflight contains M15 policy blocker(s): " + ", ".join(m15_codes))) + return check if error_count > 0: check["issues"].append(issue("check_has_errors", f"summary.error_count is {error_count}")) return check diff --git a/skills/lark-slides/scripts/svglide_theme_template_selector.py b/skills/lark-slides/scripts/svglide_theme_template_selector.py index 3dad595d1..5ae1cd696 100644 --- a/skills/lark-slides/scripts/svglide_theme_template_selector.py +++ b/skills/lark-slides/scripts/svglide_theme_template_selector.py @@ -282,6 +282,16 @@ def score_template(signals: dict[str, Any], template: dict[str, Any], *, brief: scored["rejection_reasons"].append("template_mismatch:summary_not_process") scored["score"] = score scored["template_id"] = template_id + for key in [ + "source_template_id", + "claim_level", + "family_usage_policy_summary", + "cjk_policy_summary", + "extension_grammar_summary", + "benchmark_roles", + ]: + if template.get(key) not in (None, "", [], {}): + scored[key] = template.get(key) scored["selection_reason"] = list(scored.get("matched_signals", []))[:6] return scored