diff --git a/docs/gallery/DESIGN_NOTES.md b/docs/gallery/DESIGN_NOTES.md index a0f6718..ff9858a 100644 --- a/docs/gallery/DESIGN_NOTES.md +++ b/docs/gallery/DESIGN_NOTES.md @@ -1,48 +1,31 @@ -# Gallery design direction — prototype for the Option-2 fleet facelift - -This local gallery (`docs/gallery/`, generated by `scripts/build_gallery.py` from -`examples/gallery.json`) is the **deliberate prototype** for the eventual shared-template -facelift tracked in [Developer-Tools-Directory#86](https://github.com/TMHSDigital/Developer-Tools-Directory/issues/86) -and the ROADMAP "Fleet Pages examples support" candidate. The markup here is throwaway on -migration; the **data** (`gallery.json`) and the **visual direction** below are what carry over. - -## Tokens (aligned to the fleet landing page so the two never clash) - -| Token | Dark | Light | Notes | -| --- | --- | --- | --- | -| `--bg` | `#0d1117` | `#f6f8fa` | matches landing's GitHub-dark base | -| `--surface` | `#161b22` | `#ffffff` | card background | -| `--surface-2` | `#1c2128` | `#f0f2f5` | toggle / inline code | -| `--border` | `#30363d` | `#d0d7de` | | -| `--text` | `#e6edf3` | `#1f2328` | | -| `--text-dim` | `#8b949e` | `#656d76` | secondary text | -| `--accent` / `--accent-light` | `#7c3aed` / `#a78bfa` | same | from `site.json`; shared with landing | -| `--radius` / `--radius-lg` | `8px` / `12px` | — | cards use `-lg` | -| font | `'Inter', system-ui…` | — | landing ships the Inter webfont; the prototype uses the same stack and falls back to system sans (no coupling to the fleet font files) | - -## Type scale -- Page title `h1`: `clamp(1.9rem, 4vw, 2.6rem)`, `letter-spacing: -0.02em` — fluid hero. -- Card title `h2`: `1.22rem`. -- Body: `1rem` / `line-height: 1.6`; secondary `0.9rem`; tag `0.68rem` uppercase. - -## Layout -- Container `max-width: 1080px`, centered, `1.25rem` side padding. -- Grid: **1 column** mobile → **2 columns at ≥720px**, `align-items: stretch` so paired cards share a row height. -- **Heroes are a uniform 16:9** (`aspect-ratio: 16/9; object-fit: cover`). This was a deliberate revision: the first cut used mixed aspects (8:3 swatch panorama + 16:9 stills) with `align-items: start`, which — confirmed by headless screenshots — left a ragged empty gap under the short card on desktop. The swatch hero was re-rendered at 16:9 so all three share an aspect; with uniform heroes `object-fit: cover` no longer crops anything. Keep new heroes 16:9. -- Card is a flex column; the "View example" link is pinned to the bottom (`margin-top: auto`) so footers align across a row. Hover lifts `-3px` with an accent-tinted border and soft shadow. - -## Theme -- Tri-state **auto / light / dark** mirroring the landing: `data-theme` on ``, persisted in `localStorage['theme']` — **the same key the landing uses**, so a visitor's choice carries across both pages. -- FOUC guard runs before first paint. `theme-color` meta per scheme. Toggle cycles auto→light→dark with a sun/moon glyph and an accurate `aria-label`. - -## Navigation / discoverability -- The landing→gallery link is **template-blocked** (the landing nav is fleet-generated). The gallery compensates with self-sufficient outbound nav: a top-bar **back link to the landing** (`../`) and a **GitHub repo link**, plus per-card links to each example on GitHub. A visitor who arrives via the README or a direct link can always navigate out. - -## Accessibility -- Skip-to-content link; `:focus-visible` outlines (accent, 2px); `prefers-reduced-motion` disables hover transform + smooth scroll; descriptive `alt` per hero ("``"); single `h1`, card titles as `h2`. - -## What the fleet template should adopt (not the markup, the direction) -1. The token set above as CSS variables, light/dark parity with the existing landing palette. -2. An **Examples grid** section reading `gallery.json` (per-entry `name/dir/teaches/witnessesFix/hero/preview`), cards styled as here. -3. A **nav link to the gallery** (closes the landing→gallery cross-link gap — impossible today without a template edit). -4. Standardize heroes at **16:9** with `object-fit: cover` and `align-items: stretch` for an even grid; pin card footers (`margin-top: auto`). (Supersedes the first cut's mixed-aspect/`align-items: start` approach, which read as ragged — see Layout.) +# Site design — the Blender viewport system + +The whole site (landing page `docs/index.html` via `scripts/site/`, gallery +`docs/gallery/` via `scripts/build_gallery.py`) shares one design system: the +site reads as a Blender viewport session. This replaced the earlier purple +fleet-template look (2026-07-03); the previous plan to upstream that look into +the shared template was dropped — the fleet template only scaffolds new tools, +and each tool's site evolves independently after that. + +## Vocabulary + +- **Conceit**: topbar = Blender's topbar, footer = its status bar, sections = + its panels (caret + mono label headers), hero = a viewport with a + perspective grid floor, red-X/green-Y origin lines, and HUD overlays in the + corners (mode, axis gizmo, statistics overlay with the pack counts, render + status `smoke-gated · exit 0`). +- **Color**: Blender panel grays (`#1a1b1e` bg, `#222327` panel, `#3a3b40` + border). ONE accent: selection orange `#ff8c19` (Blender's selected-object + outline; cards use it as a hover outline). Axis colors + `#ff3352 / #8bdc00 / #2890ff` appear only in the gizmo and grid origin + lines — they encode, never decorate. Dark only; there is no theme toggle. +- **Type**: Barlow Condensed 600 uppercase for display; Inter for body; + JetBrains Mono for every HUD label, stat, name, and chip. Fonts are + self-hosted in `scripts/site/fonts/` and deployed to `docs/fonts/` by the + landing build — gallery pages reference them at `../fonts/` / `../../fonts/`. +- **Copy**: benefit-led headers ("Every render here is a CI artifact"), the + smoke-gate claim is the headline thesis. + +Keep both builders in this system when editing either; the tokens are +duplicated (template.html.j2 and build_gallery.py SHELL) — change them in +both places. diff --git a/docs/gallery/depsgraph-export/index.html b/docs/gallery/depsgraph-export/index.html index 12dfcc6..49537b7 100644 --- a/docs/gallery/depsgraph-export/index.html +++ b/docs/gallery/depsgraph-export/index.html @@ -7,8 +7,7 @@ - - + @@ -18,90 +17,85 @@ - - @@ -168,7 +166,6 @@ Examples Gallery
GitHub -
@@ -263,28 +260,13 @@

Source

depsgraph-export render, full size
- Generated from examples/gallery.json by scripts/build_gallery.py. -  •  CC-BY-NC-ND-4.0 +
+ generated from examples/gallery.json + CC-BY-NC-ND-4.0 + exit 0 +
@@ -168,7 +166,6 @@ Examples Gallery
GitHub -
@@ -337,28 +334,13 @@

Source

gn-sdf-remesh render, full size
- Generated from examples/gallery.json by scripts/build_gallery.py. -  •  CC-BY-NC-ND-4.0 +
+ generated from examples/gallery.json + CC-BY-NC-ND-4.0 + exit 0 +
@@ -168,7 +166,6 @@ Blender Developer Tools
GitHub -
@@ -233,28 +230,13 @@

depsgraph-export

- Generated from examples/gallery.json by scripts/build_gallery.py. -  •  CC-BY-NC-ND-4.0 +
+ generated from examples/gallery.json + CC-BY-NC-ND-4.0 + exit 0 +
@@ -168,7 +166,6 @@ Examples Gallery
GitHub -
@@ -435,28 +432,13 @@

Source

swatch-grid render, full size
- Generated from examples/gallery.json by scripts/build_gallery.py. -  •  CC-BY-NC-ND-4.0 +
+ generated from examples/gallery.json + CC-BY-NC-ND-4.0 + exit 0 +
@@ -168,7 +166,6 @@ Examples Gallery
GitHub -
@@ -339,28 +336,13 @@

Source

turntable render, full size
- Generated from examples/gallery.json by scripts/build_gallery.py. -  •  CC-BY-NC-ND-4.0 +
+ generated from examples/gallery.json + CC-BY-NC-ND-4.0 + exit 0 +
@@ -210,33 +208,17 @@ __BACKLABEL__
GitHub -
__CONTENT__
- Generated from examples/gallery.json by scripts/build_gallery.py. -  •  CC-BY-NC-ND-4.0 +
+ generated from examples/gallery.json + CC-BY-NC-ND-4.0 + exit 0 +
diff --git a/scripts/site/build_site.py b/scripts/site/build_site.py index 389c524..13ae6ed 100644 --- a/scripts/site/build_site.py +++ b/scripts/site/build_site.py @@ -80,6 +80,14 @@ def _extract_trigger_section(body: str) -> list[str]: return triggers +def _truncate_words(text: str, limit: int) -> str: + """Cut *text* at a word boundary under *limit* chars, with an ellipsis.""" + if len(text) <= limit: + return text + cut = text[:limit].rsplit(" ", 1)[0].rstrip(",;:") + return cut + "…" + + def parse_skills(repo_root: Path) -> list[dict]: skills_dir = repo_root / "skills" if not skills_dir.is_dir(): @@ -97,7 +105,7 @@ def parse_skills(repo_root: Path) -> list[dict]: name = meta.get("name", "").replace("-", " ").replace("_", " ").title() if not name: name = skill_dir.name.replace("-", " ").replace("_", " ").title() - description = meta.get("description", "")[:200] + description = _truncate_words(meta.get("description", ""), 200) if not description: for line in body.splitlines(): @@ -154,7 +162,7 @@ def parse_rules(repo_root: Path) -> list[dict]: key, _, val = stripped.partition(":") key_lower = key.strip().lower() if key_lower == "description": - description = val.strip()[:200] + description = _truncate_words(val.strip(), 200) elif key_lower in ("globs", "scope"): scope = val.strip() continue @@ -163,6 +171,7 @@ def parse_rules(repo_root: Path) -> list[dict]: results.append({ "name": name, + "slug": rule_file.stem, "description": description, "scope": scope, }) @@ -371,6 +380,15 @@ def main(): "example_count": len(examples), "snippet_count": len(plugin.get("snippets", [])), "template_count": len(plugin.get("templates", [])), + # basenames for display: snippets/foo-bar.py -> foo-bar + "snippets": [ + {"name": p.split("/")[-1].removesuffix(".py"), "path": p} + for p in plugin.get("snippets", []) + ], + "templates": [ + {"name": p.split("/")[-1], "path": p} + for p in plugin.get("templates", []) + ], "mcp_tools": mcp_tools, "mcp_tool_count": len(mcp_tools), "mcp_grouped": mcp_grouped, diff --git a/scripts/site/fonts/barlow-condensed-500.woff2 b/scripts/site/fonts/barlow-condensed-500.woff2 new file mode 100644 index 0000000..e30e239 Binary files /dev/null and b/scripts/site/fonts/barlow-condensed-500.woff2 differ diff --git a/scripts/site/fonts/barlow-condensed-600.woff2 b/scripts/site/fonts/barlow-condensed-600.woff2 new file mode 100644 index 0000000..da60c9a Binary files /dev/null and b/scripts/site/fonts/barlow-condensed-600.woff2 differ diff --git a/scripts/site/template.html.j2 b/scripts/site/template.html.j2 index a94313a..5e14880 100644 --- a/scripts/site/template.html.j2 +++ b/scripts/site/template.html.j2 @@ -1,887 +1,461 @@ - - - {% set og_image = site.ogImage | default('https://tmhsdigital.github.io/Developer-Tools-Directory/assets/logo.png', true) %} - {{ plugin.displayName }} + + + {{ plugin.displayName }} — Blender Python that actually runs {% if site.canonical %}{% endif %} - - + {% if site.favicon %}{% endif %} + + + {% if site.canonical %}{% endif %} - + {% set og_image = site.ogImage | default('', true) %} + {% if og_image %}{% endif %} - + - - {% if site.favicon %}{% endif %} - - - + {% if og_image %}{% endif %} + - - - - + -
+ +
+
+ - -
-
- {% if plugin.logo %}{% endif %} -

{{ plugin.displayName }}

-

{{ plugin.description }}

-
- {% if skill_count %}
0
Skills
{% endif %} - {% if rule_count %}
0
Rules
{% endif %} - {% if mcp_tool_count %}
0
MCP Tools
{% endif %} - {% if snippet_count %}
0
Snippets
{% endif %} - {% if template_count %}
0
Templates
{% endif %} - {% if example_count %}
0
Examples
{% endif %} + - {% if site.compatibility %} -
- {% if site.compatibility.cursor %} - - - Cursor {{ site.compatibility.cursor }} - - {% endif %} - {% if site.compatibility.os %} - - - {{ site.compatibility.os | join(' / ') }} - - {% endif %} - {% if site.compatibility.node %} - - - Node {{ site.compatibility.node }} - - {% endif %} - {% if site.compatibility.claude %} - - - {{ site.compatibility.claude }} - - {% endif %} + - {% endif %} - -
- - - GitHub - - {% if site.links.npm %} - - - npm - - {% endif %} +
+ {% if skill_count %}Skills0{% endif %} + {% if rule_count %}Rules0{% endif %} + {% if snippet_count %}Snippets0{% endif %} + {% if template_count %}Templates0{% endif %} + {% if example_count %}Examples0{% endif %} +
+
+ smoke-gated on 4.5 LTS + 5.1 · exit 0
- {% if site.quickStart %} -
-
{{ site.quickStart.title | default('Get started') }}
-
{{ site.quickStart.command }}
- +
+

Blender Python
that actually runs.

+

Skills, rules, snippets, and starter templates that teach Cursor and Claude Code + the bpy that works — + every pattern executed headless on Blender 4.5 LTS and 5.1 before it ships.

+
+
$ git clone {{ site.links.github | default(plugin.repository) }}
+ +
+
- {% endif %} -
-
+
+
- -
+
- - {% if skills %} -
-
-

Skills

- {{ skill_count }} -
- -
+ {% if examples %} +
+
+ + Render Result + {{ example_count }} frames
-
- Skills list -
- {% for skill in skills %} -
- - {{ skill.name }} - {{ skill.description }} - -
- {% if skill.triggers %} -
- Triggers -
    {% for t in skill.triggers %}
  • {{ t }}
  • {% endfor %}
-
- {% endif %} - {% if skill.tools %} -
- MCP Tools -
{% for tool in skill.tools %}{{ tool }}{% endfor %}
-
- {% endif %} - {{ skill.category }} +
+

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.

+
+ {% for ex in examples %} + + {{ ex.name }} render +
+ {{ ex.name }} + {{ ex.teaches }}
-
+ {% endfor %}
-
-
- {% endif %} - - - {% if rules %} -
-
-

Rules

- {{ rule_count }} -
- -
+ Open the gallery — code, README, and full-size renders →
-
- Rules list -
- - - - {% for rule in rules %} - - - - - - {% endfor %} - -
NameScopeDescription
{{ rule.name }}{{ rule.scope }}{{ rule.description }}
-
-
{% endif %} - - {% if examples %} -
-
-

Examples

- {{ example_count }} - + {% if skills %} +
+
+ + Skills + {{ skill_count }} loaded
-
{% endif %} - - {% if mcp_tools %} -
-
-

MCP Tools

- {{ mcp_tool_count }} - {% if mcp_grouped | length > 1 %} -
- -
- {% endif %} -
-
- - - / -
+ {% if rules %} +
+
+ + Rules + {{ rule_count }} active
- {% if mcp_grouped | length > 1 %} - {% for category, tools in mcp_grouped.items() %} -
- {{ category }} {{ tools | length }} -
- - - - {% for tool in tools %} - - - - - {% endfor %} - -
NameDescription
{{ tool.name }}{{ tool.description }}
-
-
- {% endfor %} - {% else %} - - +
+

Anti-patterns, caught before they ship.

+

Always-on guardrails for the failure modes that make Blender Python look right + and run wrong: ops in loops, leaked bmesh, deprecated context dicts, per-vertex Python loops.

+
NameDescription
+ - {% for tool in mcp_tools %} - - - + {% for rule in rules %} + + + + {% endfor %}
RuleScopeFlags
{{ tool.name }}{{ tool.description }}
{{ rule.slug | default(rule.name) }}{{ rule.scope }}{{ rule.description }}
- {% endif %} -
- {% endif %} - - - {% if site.installSteps %} -
-
-

Installation

-
- -
-
- Installation steps -
-
    - {% for step in site.installSteps %} -
  1. {{ step | safe }}
  2. - {% endfor %} -
-
-
{% endif %} - - {% if has_changelog %} -
-
-

Changelog

-
- -
+ {% if snippets %} +
+
+ + Snippets + {{ snippet_count }} patterns
-
- Recent changelog -
- {% for entry in changelog %} -
- v{{ entry.version }} - {% if entry.date %}{{ entry.date }}{% endif %} - {% for sec in entry.sections %} -
{{ sec.heading }}
-
    - {% for item in sec.entries %}
  • {{ item }}
  • {% endfor %} -
- {% endfor %} -
+
+

Canonical patterns, five to fifty lines.

+

Standalone, paste-ready answers to the questions that come up every session: + the right way to create and delete objects, read bulk vertex data, bind properties, bridge + the 4.x/5.x API boundary.

+
+ {% for sn in snippets %} + {{ sn.name }} {% endfor %} - View full changelog on GitHub →
-
+ {% if templates %} +

Plus {{ template_count }} starter templates: + {% for t in templates %}{{ t.name }}{% if not loop.last %} and {% endif %}{% endfor %} + — a complete Extensions-Platform add-on and a headless batch job with CI exit codes.

+ {% endif %} +
{% endif %} - - {% if site.relatedTools %} -
- - -
- - - - - diff --git a/site.json b/site.json index de14af7..da80091 100644 --- a/site.json +++ b/site.json @@ -1,8 +1,4 @@ { - "accent": "#7c3aed", - "accentLight": "#a78bfa", - "heroGradientFrom": "#0d1117", - "heroGradientTo": "#161b22", "canonical": "https://tmhsdigital.github.io/Blender-Developer-Tools/", "favicon": "assets/favicon.svg", "ogImage": "https://tmhsdigital.github.io/Blender-Developer-Tools/gallery/assets/swatch-grid-hero.webp",