diff --git a/examples/gallery.json b/examples/gallery.json index 976ca98..299ccc3 100644 --- a/examples/gallery.json +++ b/examples/gallery.json @@ -86,7 +86,8 @@ "tags": [ "mesh", "bmesh" - ] + ], + "featured_rank": 7 }, { "name": "shader-node-group", @@ -170,7 +171,8 @@ "tags": [ "constraints", "animation" - ] + ], + "featured_rank": 3 }, { "name": "color-attribute-wheel", @@ -183,7 +185,8 @@ "mesh", "materials", "attributes" - ] + ], + "featured_rank": 8 }, { "name": "parent-inverse-orrery", @@ -219,7 +222,8 @@ "tags": [ "armature", "depsgraph" - ] + ], + "featured_rank": 6 }, { "name": "text-version-stamp", @@ -368,7 +372,8 @@ "tags": [ "rendering", "objects" - ] + ], + "featured_rank": 4 }, { "name": "collision-hull-proxy", @@ -380,7 +385,8 @@ "tags": [ "bmesh", "mesh" - ] + ], + "featured_rank": 5 }, { "name": "custom-normals-shade", @@ -456,7 +462,8 @@ "tags": [ "bmesh", "mesh" - ] + ], + "featured_rank": 2 }, { "name": "car-mirror-symmetry", @@ -468,7 +475,8 @@ "tags": [ "modifiers", "depsgraph" - ] + ], + "featured_rank": 1 }, { "name": "attribute-domain-shear", diff --git a/scripts/site/build_site.py b/scripts/site/build_site.py index 13ae6ed..c56e4c6 100644 --- a/scripts/site/build_site.py +++ b/scripts/site/build_site.py @@ -250,6 +250,16 @@ def load_examples(repo_root: Path) -> list[dict]: return examples +def pick_featured(examples: list[dict]) -> list[dict]: + """Landing-page showcase subset: entries carrying a ``featured_rank`` + integer in gallery.json, sorted by rank. Returns [] when nothing is + curated; the template then falls back to the full list.""" + return sorted( + (ex for ex in examples if isinstance(ex.get("featured_rank"), int)), + key=lambda ex: ex["featured_rank"], + ) + + def load_mcp_tools(repo_root: Path) -> list[dict]: mcp_file = repo_root / "mcp-tools.json" if not mcp_file.is_file(): @@ -365,6 +375,7 @@ def main(): skills = parse_skills(repo_root) rules = parse_rules(repo_root) examples = load_examples(repo_root) + featured = pick_featured(examples) mcp_tools = load_mcp_tools(repo_root) mcp_grouped = group_by_category(mcp_tools) changelog = parse_changelog(repo_root) @@ -378,6 +389,8 @@ def main(): "rule_count": len(rules), "examples": examples, "example_count": len(examples), + "featured_examples": featured, + "featured_count": len(featured), "snippet_count": len(plugin.get("snippets", [])), "template_count": len(plugin.get("templates", [])), # basenames for display: snippets/foo-bar.py -> foo-bar diff --git a/scripts/site/template.html.j2 b/scripts/site/template.html.j2 index 5e14880..eb3c4c7 100644 --- a/scripts/site/template.html.j2 +++ b/scripts/site/template.html.j2 @@ -153,6 +153,11 @@ text-overflow: ellipsis; } .panel-cta { display: inline-block; margin-top: 1.25rem; font-weight: 500; font-size: 0.9rem; color: var(--select); } .panel-cta:hover { text-decoration: underline; } + /* featured subset: gallery link is the section's primary call to action */ + .cta-row { margin: -0.25rem 0 1.5rem; } + .btn-cta { display: inline-block; background: var(--select); color: #1a1b1e; font-weight: 500; + font-size: 0.92rem; border-radius: 4px; padding: 0.55rem 1.15rem; transition: filter 0.15s; } + .btn-cta:hover { filter: brightness(1.12); } /* skills */ .skill-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 0.4rem 2.25rem; } @@ -284,19 +289,21 @@
{% if examples %} + {% set shown = featured_examples if featured_examples else examples %}
Render Result - {{ example_count }} frames + {% if featured_examples %}{{ featured_count }} of {% endif %}{{ example_count }} frames

Every render here is a CI artifact.

These aren't mockups. Each example runs headless on Blender 4.5 LTS and 5.1 in the smoke workflow, asserts its own correctness, and exits non-zero if the API drifted. The render is what the code produced.

+

Browse all {{ example_count }} examples in the gallery →

- {% for ex in examples %} + {% for ex in shown %} {{ ex.name }} render