@tidyfactor/design 1.5.0 → 1.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/.tidyfactor CHANGED
@@ -2,10 +2,10 @@
2
2
  "ecosystem": "tidyfactor",
3
3
  "track": "design",
4
4
  "name": "tidyfactor-design",
5
- "version": "1.5.0",
5
+ "version": "1.6.0",
6
6
  "npmPackage": "@alwkala/tidyfactor-design",
7
7
  "github": "https://github.com/TidyFactor/Design",
8
- "skillFile": "../tidyfactor-design-v1.4.0.skill",
8
+ "skillFile": "../tidyfactor-design-v1.6.0.skill",
9
9
  "category": "design-system",
10
10
  "type": "interactive-prototyping",
11
11
  "outputs": [
package/CHANGELOG.md CHANGED
@@ -2,6 +2,15 @@
2
2
 
3
3
  All notable changes to the **[@tidyfactor/design](https://www.npmjs.com/package/@tidyfactor/design)** package will be documented in this file.
4
4
 
5
+ ## [1.6.0] - 2026-09-01
6
+
7
+ ### Added - Runtime Tooling Manifest & Egyptian Heritage Design Lanes
8
+ - **Rule 10 Runtime Tooling Contract (`manifest.json`)**: Declared portable `audit_design`, `extract_palette`, and `optimize_media` executable tooling with schema validation.
9
+ - **Automated Design Quality Auditor (`scripts/audit_design.py`)**: Standalone and MCP-compatible CLI engine scanning HTML/CSS for unicode emojis, inline styles, untokenized colors, and the 16 AI anti-patterns with UTF-8 support.
10
+ - **Output JSON Schema (`references/schemas/audit_design.output.schema.json`)**: Standard schema defining structured quality audit reports and pre-emit critique stamps.
11
+ - **Egyptian & Regional Heritage Lanes (`references/memory/19-heritage-lanes-atmosphere.md`)**: Operational design grammar covering Nilotic Wadj & Lotus, Egyptian Nubian Folk & Earth Vaults, Sinai Bedouin Craft, Al-Muqarnas Geometry, and Kufic Modernity.
12
+ - **Bilingual & Responsive Enhancements**: Refined `01-design-schools.md`, `04-motion-principles.md`, `05-component-anatomy.md`, and `08-arabic-bilingual.md`.
13
+
5
14
  ## [1.5.0] - 2026-08-29
6
15
 
7
16
  ### Added - Global Multi-Tier & Multi-Language Documentation Architecture
package/README.ar.md CHANGED
@@ -4,7 +4,7 @@
4
4
  <img src="assets/hero-banner.png" alt="TidyFactor Design Hero Banner" width="100%">
5
5
  </p>
6
6
 
7
- # 🎨 TidyFactor Design `v1.5.0`
7
+ # 🎨 TidyFactor Design `v1.6.0`
8
8
  ### محرك دورة حياة تصميم الواجهات ومحرك النماذج التفاعلية المناهض للتكرار
9
9
 
10
10
  **البداية الرسمية لبناء نظام التصميم والدورة الكاملة لتصميم الواجهات التفاعلية ضمن منظومة TidyFactor Ecosystem.**
package/README.md CHANGED
@@ -4,7 +4,7 @@
4
4
  <img src="assets/hero-banner.png" alt="TidyFactor Design Hero Banner" width="100%">
5
5
  </p>
6
6
 
7
- # 🎨 TidyFactor Design `v1.5.0`
7
+ # 🎨 TidyFactor Design `v1.6.0`
8
8
  ### Code-Native UI Design Lifecycle Engine & Anti-Slop Design System Suite
9
9
 
10
10
  **The official UI design & interactive prototyping foundation for the TidyFactor Ecosystem.**
package/bin/add-skill.js CHANGED
@@ -1,31 +1,65 @@
1
- #!/usr/bin/env node
2
- /**
3
- * bin/add-skill.js — CLI installer wrapper for tidyfactor-design
4
- */
5
-
6
- const fs = require('fs');
7
- const path = require('path');
8
-
9
- const targetDir = process.cwd();
10
- const skillSource = path.resolve(__dirname, '..');
11
- const agentSkillsDir = path.join(targetDir, '.agents', 'skills', 'tidyfactor-design');
12
-
13
- fs.mkdirSync(agentSkillsDir, { recursive: true });
14
-
15
- function copyRecursive(src, dest) {
16
- const entries = fs.readdirSync(src, { withFileTypes: true });
17
- for (const entry of entries) {
18
- const srcPath = path.join(src, entry.name);
19
- const destPath = path.join(dest, entry.name);
20
- if (['.git', 'node_modules', 'dist'].includes(entry.name)) continue;
21
- if (entry.isDirectory()) {
22
- fs.mkdirSync(destPath, { recursive: true });
23
- copyRecursive(srcPath, destPath);
24
- } else {
25
- fs.copyFileSync(srcPath, destPath);
26
- }
27
- }
28
- }
29
-
30
- copyRecursive(skillSource, agentSkillsDir);
31
- console.log('✓ Successfully injected tidyfactor-design skill into .agents/skills/tidyfactor-design');
1
+ #!/usr/bin/env node
2
+ /**
3
+ * bin/add-skill.js — Multi-Agent Skill Installer Wrapper for tidyfactor-design
4
+ * Supports Trae, Cursor, Windsurf, Antigravity, GitHub Copilot, RooCode, OpenCode, KiloCode, Warp, and Universal.
5
+ *
6
+ * @license Apache-2.0
7
+ */
8
+
9
+ const fs = require('fs');
10
+ const path = require('path');
11
+ const os = require('os');
12
+
13
+ const targetDir = process.cwd();
14
+ const skillSource = path.resolve(__dirname, '..');
15
+ const skillName = 'tidyfactor-design';
16
+
17
+ const AGENT_MAP = [
18
+ { name: 'Trae AI IDE', dir: path.join(targetDir, '.trae', 'skills', skillName), test: path.join(targetDir, '.trae') },
19
+ { name: 'Cursor IDE', dir: path.join(targetDir, '.cursor', 'skills', skillName), test: path.join(targetDir, '.cursor') },
20
+ { name: 'Windsurf Cascade', dir: path.join(targetDir, '.windsurf', 'skills', skillName), test: path.join(targetDir, '.windsurf') },
21
+ { name: 'GitHub Copilot', dir: path.join(targetDir, '.github', 'prompts', skillName), test: path.join(targetDir, '.github') },
22
+ { name: 'RooCode', dir: path.join(targetDir, '.roo', 'skills', skillName), test: path.join(targetDir, '.roo') },
23
+ { name: 'OpenCode / Zen', dir: path.join(targetDir, '.opencode', 'skills', skillName), test: path.join(targetDir, '.opencode') },
24
+ { name: 'KiloCode', dir: path.join(targetDir, '.kilocode', 'skills', skillName), test: path.join(targetDir, '.kilocode') },
25
+ { name: 'Warp Terminal', dir: path.join(targetDir, '.warp', 'skills', skillName), test: path.join(targetDir, '.warp') },
26
+ { name: 'Kiro Spec IDE', dir: path.join(targetDir, '.kiro', 'skills', skillName), test: path.join(targetDir, '.kiro') },
27
+ { name: 'Claude Code', dir: path.join(targetDir, '.claude', 'skills', skillName), test: path.join(targetDir, '.claude') },
28
+ { name: 'Zed AI Agent', dir: path.join(targetDir, '.zed', 'skills', skillName), test: path.join(targetDir, '.zed') },
29
+ { name: 'Google Antigravity/Gemini', dir: path.join(targetDir, '.agents', 'skills', skillName), test: path.join(targetDir, '.agents') },
30
+ ];
31
+
32
+ function copyRecursive(src, dest) {
33
+ fs.mkdirSync(dest, { recursive: true });
34
+ const entries = fs.readdirSync(src, { withFileTypes: true });
35
+ for (const entry of entries) {
36
+ const srcPath = path.join(src, entry.name);
37
+ const destPath = path.join(dest, entry.name);
38
+ if (['.git', 'node_modules', 'dist'].includes(entry.name)) continue;
39
+ if (entry.isDirectory()) {
40
+ copyRecursive(srcPath, destPath);
41
+ } else {
42
+ fs.copyFileSync(srcPath, destPath);
43
+ }
44
+ }
45
+ }
46
+
47
+ // Determine installation targets
48
+ let mountedTargets = [];
49
+
50
+ for (const agent of AGENT_MAP) {
51
+ if (fs.existsSync(agent.test)) {
52
+ copyRecursive(skillSource, agent.dir);
53
+ mountedTargets.push(agent.name + ' (' + path.relative(targetDir, agent.dir) + ')');
54
+ }
55
+ }
56
+
57
+ // Always ensure universal fallback in .agents/skills/
58
+ const defaultDir = path.join(targetDir, '.agents', 'skills', skillName);
59
+ copyRecursive(skillSource, defaultDir);
60
+ if (!mountedTargets.some(t => t.includes('.agents'))) {
61
+ mountedTargets.push('Universal Default (.agents/skills/' + skillName + ')');
62
+ }
63
+
64
+ console.log('✨ Successfully injected ' + skillName + ' into:');
65
+ mountedTargets.forEach(t => console.log(' • ' + t));
package/brand.json CHANGED
@@ -1,13 +1,13 @@
1
1
  {
2
2
  "name": "TidyFactor Design",
3
- "version": "1.5.0",
3
+ "version": "1.6.0",
4
4
  "schemaVersion": "brand-core-v2",
5
5
  "meta": {
6
6
  "product": "TidyFactor Design System",
7
7
  "tagline": "Code-Native Interactive Prototyping Engine",
8
8
  "description": "A zero-bundler, framework-free design system and UI prototyping engine with pluggable CSS foundations and full Arabic/RTL support.",
9
- "version": "1.4.0",
10
- "lastUpdated": "2026-08-25"
9
+ "version": "1.6.0",
10
+ "lastUpdated": "2026-09-01"
11
11
  },
12
12
  "identity": {
13
13
  "logo": {
package/manifest.json ADDED
@@ -0,0 +1,59 @@
1
+ {
2
+ "manifest_schema_version": "1.0.0",
3
+ "skill_id": "tidyfactor-design",
4
+ "skill_root_anchor": "self",
5
+ "tools": [
6
+ {
7
+ "name": "audit_design",
8
+ "description": "Scans index.html and design-system/*.css for emoji, inline styles, off-token colors, and the 16 AI anti-patterns.",
9
+ "entrypoint": { "runtime": "python3", "script": "scripts/audit_design.py" },
10
+ "invocation": {
11
+ "cli_pattern": "{runtime} \"{skill_root}/{script}\" --target \"{target_path}\" {flags}",
12
+ "args": [
13
+ { "name": "target_path", "type": "path", "required": true, "description": "Absolute path to the client project being audited" },
14
+ { "name": "fix", "type": "boolean", "required": false, "default": false, "flag": "--fix", "description": "Auto-fix violations where safe" }
15
+ ]
16
+ },
17
+ "output": {
18
+ "format": "json",
19
+ "channel": "stdout",
20
+ "schema_ref": "references/schemas/audit_design.output.schema.json"
21
+ },
22
+ "runtime_requirements": { "isolation_recommended": false, "dependencies": [] },
23
+ "invoked_by_commands": ["audit", "perf"]
24
+ },
25
+ {
26
+ "name": "extract_palette",
27
+ "description": "Computes WCAG AAA contrast ratios and generates tokens.css + brand.json from source colors.",
28
+ "entrypoint": { "runtime": "python3", "script": "scripts/extract_palette.py" },
29
+ "invocation": {
30
+ "cli_pattern": "{runtime} \"{skill_root}/{script}\" --target \"{target_path}\" {flags}",
31
+ "args": [
32
+ { "name": "target_path", "type": "path", "required": true, "description": "Absolute path to the client project" },
33
+ { "name": "source", "type": "string", "required": false, "flag": "--source", "description": "Hex seed color or image path to derive the palette from" }
34
+ ]
35
+ },
36
+ "output": { "format": "json", "channel": "stdout" },
37
+ "runtime_requirements": { "isolation_recommended": false, "dependencies": [] },
38
+ "invoked_by_commands": ["tokens", "palette", "init"]
39
+ },
40
+ {
41
+ "name": "optimize_media",
42
+ "description": "Compresses images, removes backgrounds, and generates WebP variants.",
43
+ "entrypoint": { "runtime": "python3", "script": "scripts/optimize_assets.py" },
44
+ "invocation": {
45
+ "cli_pattern": "{runtime} \"{skill_root}/{script}\" --target \"{target_path}\" {flags}",
46
+ "args": [
47
+ { "name": "target_path", "type": "path", "required": true, "description": "Absolute path to the client project" },
48
+ { "name": "remove_bg", "type": "boolean", "required": false, "default": false, "flag": "--remove-bg" }
49
+ ]
50
+ },
51
+ "output": { "format": "json", "channel": "stdout" },
52
+ "runtime_requirements": {
53
+ "isolation_recommended": true,
54
+ "dependencies": ["Pillow", "rembg", "onnxruntime"]
55
+ },
56
+ "invoked_by_commands": ["assets"]
57
+ }
58
+ ]
59
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tidyfactor/design",
3
- "version": "1.5.0",
3
+ "version": "1.6.0",
4
4
  "description": "TidyFactor Design track — code-native UI design lifecycle engine (Figma alternative) with Contextual Decision Layer (CDL)",
5
5
  "main": "SKILL.md",
6
6
  "bin": {
@@ -55,6 +55,7 @@
55
55
  "assets",
56
56
  "bin",
57
57
  "brand.json",
58
+ "manifest.json",
58
59
  "memory",
59
60
  "references",
60
61
  "scripts",
@@ -1,13 +1,46 @@
1
- # Design Schools & Movements — Quick Calibration Index
1
+ # Design Schools & Movements — Unified Calibration Index
2
+ <!-- last-verified: 2026-09-01 -->
2
3
 
3
- For complete operational rules, visual tokens, typography pairings, color systems, CSS rules, shadow styles, and anti-patterns across all 20 visual aesthetics, see:
4
- 👉 **[`memory/16-design-movements-guide.md`](16-design-movements-guide.md)** (All 20 Visual Movements & Design Tokens)
5
- 👉 **[`memory/17-storytelling-industries-ux.md`](17-storytelling-industries-ux.md)** (4 Storytelling Archetypes, 8 Industry Registers, 8 UX Philosophies)
4
+ A complete working index of design aesthetics, universal movements, and regional heritage art-direction lanes across all TidyFactor design engines.
5
+
6
+ 👉 **[`memory/16-design-movements-guide.md`](16-design-movements-guide.md)** (All 20 Universal Visual Movements)
7
+ 👉 **[`memory/19-heritage-lanes-atmosphere.md`](19-heritage-lanes-atmosphere.md)** (5 Egyptian & Regional Heritage Lanes)
8
+ 👉 **[`memory/17-storytelling-industries-ux.md`](17-storytelling-industries-ux.md)** (Storytelling Archetypes & Industry Registers)
6
9
  👉 **[`memory/18-design-decision-engine.md`](18-design-decision-engine.md)** (9-Step Decision Tree & Anti-Design-Soup Constraint)
7
10
 
8
11
  ---
9
12
 
10
- ## 🎨 20 Visual Aesthetics At-A-Glance Index
13
+ ## 🏛️ 5 Regional & Egyptian Heritage Art-Direction Lanes
14
+
15
+ 1. **Nilotic Wadj & Sacred Lotus (أصالة النيل ولوتس مصر العليا)**:
16
+ - *DNA*: Upper Egyptian heritage (Qena, Dendera, Thebes, Aswan), Sacred Lotus (`Sesen`), mineral green (`Wadj`), Nile terracotta (`Khem`), Royal Lapis (`Khesbed`), Sun Gold (`Nebu`).
17
+ - *Grammar*: Ascending registers, shallow stone deboss (`Low-Relief`), tactile papyrus & alabaster light texture (`Subtle Noise`).
18
+ - *Fits*: Community development, educational leadership, inclusive education, scholarly platforms, Upper Egyptian institutions.
19
+
20
+ 2. **Egyptian Nubian Folk & Earth Vaults (النوبة المصرية والعمارة الطينية)**:
21
+ - *DNA*: Aswan & West Suhail mud-brick vaulted architecture (Hassan Fathy), geometric chevron & zigzag bands, vibrant folk warmth.
22
+ - *Grammar*: Stepped triangles, Nubian vaulted card tops, sunny ochre, turquoise cataracts, terracotta clay, white lime plaster.
23
+ - *Fits*: Cultural platforms, eco-tourism, community initiatives, youth & child development.
24
+
25
+ 3. **Sinai Bedouin & Stitched Craft (البادية والتطريز السيناوي المصري)**:
26
+ - *DNA*: Authentic Sinai Bedouin cross-stitch embroidery (North & South Sinai), St. Catherine granite mountains, wild flora.
27
+ - *Grammar*: Pixelated cross-stitch geometric rails, embroidered dividers, madder red, wild rose magenta, deep Sinai night indigo, raw wool ivory.
28
+ - *Fits*: Heritage crafts, environmental foundations, field campaigns, national culture.
29
+
30
+ 4. **Al-Muqarnas & Girih Geometry (التوريق والمقرنصات الهندسية)**:
31
+ - *DNA*: Historic Cairo (Fatimid & Mamluk), Andalusian & Maghrebi architecture, mashrabiya woodwork, mathematical astronomy.
32
+ - *Grammar*: 4/6/8-fold repeat geometry, architectural aperture masks, perforated shadows (`Perforated Shadowing`), cobalt lapis, turquoise glaze, antique ochre.
33
+ - *Fits*: Cultural foundations, academic conferences, endowment platforms, classical Islamic arts.
34
+
35
+ 5. **Kufic Modernity & Luminescent Noor (العمارة الحروفية والنور المعاصر)**:
36
+ - *DNA*: Contemporary regional minimalism led by monumental Arabic typography and generous spatial purity.
37
+ - *Grammar*: Monumental Arabic wordmark/phrase hero, polished terrazzo, limestone, brushed bronze, single vibrant accent.
38
+ - *Fits*: Technology, sovereign wealth, venture studios, knowledge economy, international consulting.
39
+
40
+ ---
41
+
42
+ ## 🎨 20 Universal Visual Movements At-A-Glance Index
43
+
11
44
  1. **Swiss Style**: Objective 12-column grid, sans-serif, high contrast.
12
45
  2. **Flat Design**: 2D vector, zero shadows, vibrant color blocks.
13
46
  3. **Material Design**: Paper/ink depth, elevation shadows, touch ripples.
@@ -29,57 +62,16 @@ For complete operational rules, visual tokens, typography pairings, color system
29
62
  19. **Organic / Amorphous UI**: Fluid blob shapes (`border-radius: 60% 40% ...`), natural tones.
30
63
  20. **Frutiger Aero & Y2K**: Glossy glass buttons, lens flares, vibrant sky blue/lime gradients.
31
64
 
32
- ## Bauhaus
33
- Geometric shapes as structural/decorative elements, primary-plus-black
34
- palettes, function-follows-form typography. Fits: education, design tools,
35
- brands wanting to signal craft/foundational thinking. Avoid: costume-party
36
- Bauhaus (circles+triangles as decoration with no structural logic).
37
-
38
- ## Brutalism (web)
39
- Raw, unstyled-looking HTML elements used deliberately, harsh contrast,
40
- visible grid lines, monospace accents, intentionally "undesigned". Fits:
41
- developer tools, portfolios, brands wanting to signal authenticity/anti-
42
- polish. Avoid: actual unstyled defaults mistaken for the aesthetic —
43
- brutalism is a considered choice, not the absence of one.
44
-
45
- ## Editorial / Broadsheet
46
- Hairline rules, dense multi-column text, serif display, byline/dateline
47
- conventions borrowed from print journalism. Fits: publications, long-form
48
- content, thought-leadership brands. Avoid: applying hairline-column density
49
- to a page that has nothing to say at that density (see `frontend-design`'s
50
- warning on this as an overused AI-design default).
51
-
52
- ## Minimalism
53
- Extreme restraint, one accent color maximum, huge whitespace, type doing
54
- almost all the work. Fits: luxury, premium single-product brands. Avoid:
55
- minimalism as an excuse for lack of a real design decision — every
56
- remaining element must be precisely placed.
57
-
58
- ## Glassmorphism
59
- Frosted-glass translucent panels, soft shadows, layered depth over a
60
- blurred background. Fits: modern consumer apps, dashboards wanting a soft/
61
- approachable data-density feel. Avoid: layering glass panels on glass
62
- panels — contrast and legibility break down fast.
63
-
64
- ## Material-influenced
65
- Elevation via shadow, clear touch targets, motion as spatial logic (things
66
- move the way physical objects would). Fits: cross-platform app UI,
67
- utilitarian dashboards. Avoid: importing Material's specific component
68
- shapes wholesale when the brand wants its own identity — take the
69
- principles, not the skin.
65
+ ---
70
66
 
71
- ## Modern SaaS (Vercel/Linear-influenced)
72
- Near-black or pure-white grounds, one saturated accent, monospace for data/
73
- code, tight type scale, subtle gradient accents, generous but efficient
74
- spacing. Fits: developer tools, B2B SaaS, technical dashboards. Avoid:
75
- defaulting here just because the brief is "a SaaS product" this look is
76
- common enough now to read as generic if the brand has no other point of
77
- view.
67
+ ## 🏆 Award-Winning Regional Reference Evidence
68
+ Treat award galleries as evidence of interaction and composition patterns:
69
+ - **Webook (Riyadh Season)**: Immersive event storytelling, WebGL and sound.
70
+ - **Masar Destination**: Saudi destination storytelling with responsive WebGL.
71
+ - **IoT Squared**: Sovereign technology positioning via animation & parallax without heritage cliches.
72
+ - **Kode**: New Cairo sports brand using bold color, animation, and WebGL.
73
+ - **Ali Ali**: Cairo creative portfolio driven by minimal typography and film.
74
+ - **Sivik Atelier**: Dubai studio portfolio using grid, parallax, and minimal typography.
75
+ - **Jazean Coffee**: Saudi heritage framed as interactive scroll storytelling.
78
76
 
79
- ## Calibration: defaults to avoid unless the brief asks for them
80
- Per `frontend-design`'s own calibration: warm-cream + terracotta-serif,
81
- near-black + single acid-green/vermilion accent, and broadsheet-hairline-
82
- columns applied regardless of subject are the three most common AI-design
83
- tells right now. Choosing one deliberately because it fits the brief is
84
- fine; landing on one by default is the failure mode `school` exists to
85
- prevent.
77
+ *Rule: Establish a contemporary editorial system first, then use one culturally meaningful material, narrative, or spatial idea as the signature.*
@@ -1,44 +1,29 @@
1
1
  # Motion Principles — Reference for `motion`
2
+ <!-- last-verified: 2026-09-01 -->
2
3
 
3
- Adapted from the classic animation principles, applied to UI motion rather
4
- than character animation.
4
+ Adapted from classic animation principles, applied to UI motion rather than character animation.
5
5
 
6
- ## Staging
7
- One focal change communicated at a time. A section revealing five cards
8
- simultaneously reads as noise; the same five staggered by ~60-80ms each
9
- read as a considered sequence.
6
+ ---
10
7
 
11
- ## Anticipation
12
- A small pre-state before a bigger change helps the eye track what's about
13
- to happen (a button's subtle scale-down before a bigger transition, a
14
- skeleton before content pops in) used sparingly, not on every
15
- interaction.
8
+ ## 1. Core Principles
9
+ - **Staging**: One focal change communicated at a time. Stagger card reveals by ~60-80ms.
10
+ - **Anticipation**: Small pre-state before a bigger change helps the eye track what's about to happen.
11
+ - **Ease-out for entrances, ease-in for exits**: Natural deceleration on entry, acceleration on exit.
12
+ - **Secondary motion**: Delayed subtle trail (e.g. shadow settling a beat later).
13
+ - **Restraint**: An orchestrated single moment lands harder than scattered effects everywhere.
16
14
 
17
- ## Ease-out for entrances, ease-in for exits
18
- Things entering the screen should decelerate into place (ease-out);
19
- things leaving should accelerate away (ease-in). Using the same easing
20
- for both reads as mechanical rather than natural.
15
+ ---
21
16
 
22
- ## Follow-through / slight overshoot
23
- A very small overshoot-and-settle on an entrance (a card that slightly
24
- overshoots its final position before settling) reads as more alive than a
25
- purely linear arrival use subtly, it's easy to overdo into "bouncy" and
26
- undermine a restrained direction like Minimalism or Swiss.
17
+ ## 2. Cursor Spotlight & Ambient Glow Engine (Interactive Depth)
18
+ - **Per-Card Cursor Spotlight**:
19
+ - Dynamically track `--mouse-x` and `--mouse-y` via `getBoundingClientRect()` on `.bento-card`, `.card`, and showcase tiles.
20
+ - Reveal a subtle `radial-gradient` (350-400px radius) in dark mode to illuminate surface borders and textures.
21
+ - **Viewport Ambient Spotlight**:
22
+ - Desktop-only (`min-width: 992px`), single fixed layer driven by `requestAnimationFrame` and `translate3d(x, y, 0)`.
23
+ - Illuminates the underlying papyrus, granite, or obsidian texture with zero layout thrashing.
24
+ - Must automatically disable under `prefers-reduced-motion: reduce`.
27
25
 
28
- ## Secondary motion
29
- A primary element moving (e.g. a hero image entering) can carry a small,
30
- delayed secondary motion (a shadow settling a beat later, an accent
31
- element trailing slightly) — this is what separates "orchestrated" motion
32
- from "everything moves in lockstep".
26
+ ---
33
27
 
34
- ## Restraint is a choice, not an absence
35
- Per `frontend-design`: an orchestrated single moment usually lands harder
36
- than scattered effects everywhere, and excess ambient animation is one of
37
- the strongest tells that a design is AI-generated. `school`'s chosen
38
- direction should determine how much motion is appropriate — Minimalism and
39
- Swiss call for very little; Modern SaaS and Glassmorphism can carry more.
40
-
41
- ## Non-negotiable: `prefers-reduced-motion`
42
- Every entrance/scroll/parallax effect in `motion.js` must check this media
43
- query and fall back to instant or opacity-only transitions — applied
44
- globally in the shared file, not per page.
28
+ ## 3. Non-negotiable: `prefers-reduced-motion`
29
+ Every entrance, scroll, parallax, or ambient spotlight effect in `motion.js` must check `window.matchMedia('(prefers-reduced-motion: reduce)')` and fall back to instant or opacity-only transitions globally.
@@ -1,34 +1,31 @@
1
1
  # Component Anatomy — Reference for `components`/`states`
2
+ <!-- last-verified: 2026-09-01 -->
2
3
 
3
- ## Atomic hierarchy (Atomic Design, adapted)
4
- - **Atoms** — button, input, label, icon, badge. The smallest named unit;
5
- never composed of other named components.
6
- - **Molecules** a form field (label + input + error text), a stat
7
- (label + value + trend), a nav item (icon + label + active state).
8
- - **Organisms** — a card, a data table, a navbar, a pricing tile, a modal.
9
- Composed from atoms/molecules, still a single reusable named unit.
10
- - **Templates** (this skill's `page`/`dashboard` output) — organisms
11
- arranged into a page's actual layout. This is the one level that's
12
- allowed to be page-specific — it's arrangement, not new styling.
13
-
14
- A new visual need almost always belongs at the atom/molecule/organism
15
- level, added once to `components.css`/the foundation library not
16
- invented at the template level.
17
-
18
- ## The full state matrix (apply per interactive component)
19
- `default hover focus-visible active/pressed disabled`, plus where
20
- relevant: `loading`, `empty`, `error`, `success`. A component "supports"
21
- these states means each has an intentional look, not that the browser
22
- default happens to apply.
23
-
24
- ## Naming discipline
25
- One canonical name per real pattern. A "featured pricing card" and a
26
- "testimonial card" that share 90% of their structure should be one `.card`
27
- component with modifiers (`.card--featured`), not two components that will
28
- quietly diverge over time.
29
-
30
- ## When something looks like it needs a new component but doesn't
31
- If the only difference from an existing component is a token value (a
32
- different accent color, a different size) — that's a modifier class or a
33
- data attribute, not a new component. New components are for genuinely
34
- different structure/behavior, not restyled instances.
4
+ ## 1. Atomic Hierarchy (Atomic Design, Adapted)
5
+ - **Atoms**: Button, input, label, icon, badge, watermark stamp.
6
+ - **Molecules**: Form field, stat counter, nav item, floating verification badge.
7
+ - **Organisms**: Card, data table, navbar, 3D book/exhibition card, timeline, modal.
8
+ - **Templates**: Organisms arranged into page layout with zero per-page CSS.
9
+
10
+ ---
11
+
12
+ ## 2. Advanced Specialized Organisms & Molecules
13
+
14
+ ### A. Watermark Stamp & Media Protection (`.watermark-stamp`)
15
+ - Floating glassmorphic pill badge positioned over showcase media (e.g. `bottom: 12px; inset-inline-start: 12px;`).
16
+ - Visuals: `background: rgba(8, 7, 5, 0.85); backdrop-filter: blur(8px); border: 1px solid var(--border-gold);`.
17
+ - Protection: Non-draggable images (`-webkit-user-drag: none; user-select: none;`).
18
+
19
+ ### B. 3D Exhibition & Editorial Book Showcase Card (`.book-card`)
20
+ - Layout: Asymmetric split (Cover viewport on one side, editorial hierarchy on the other).
21
+ - Visuals: Multi-layered spine shadow (`box-shadow: -8px 10px 24px rgba(0,0,0,0.25)`), dynamic hover lift (`translateY(-4px)`), and category badge.
22
+
23
+ ---
24
+
25
+ ## 3. The Full 8-State Matrix (Apply per Interactive Component)
26
+ `default hover focus-visible active/pressed disabled`, plus: `loading` (spinner/skeleton), `empty` (illustrated container), `error`, and `success`.
27
+
28
+ ---
29
+
30
+ ## 4. Naming Discipline
31
+ One canonical name per real pattern. Use BEM modifiers (`.card--featured`, `.badge--accent`) or data attributes (`[data-theme]`, `[data-filter]`) rather than creating duplicate component structures.
@@ -1,54 +1,42 @@
1
- # Arabic & Bilingual Design — Reference for `i18n`
1
+ # Arabic & Bilingual Design — Reference for `i18n` & RTL Engineering
2
+ <!-- last-verified: 2026-09-01 -->
2
3
 
3
- Conventions carried consistently across Alwkala's production work and the
4
- rest of the TidyFactor ecosystem (`tidyfactor-html`, `tidyfactor-cinematic`)
5
- — not generic RTL advice.
4
+ Conventions carried consistently across Alwkala's production work and the rest of the TidyFactor ecosystem (`tidyfactor-design`, `tidyfactor-styler`, `tidyfactor-html`, `tidyfactor-cinematic`) — not generic RTL advice.
6
5
 
7
- ## Typography
8
- - Headings: **El Messiri** — modern, geometric-leaning, reads as
9
- contemporary rather than traditional/calligraphic.
10
- - Body: **Tajawal** — high legibility at small sizes, wide weight range.
11
- - **Never Amiri** for UI/display purposes — it's a naskh-style text face
12
- suited to long-form literary/religious typesetting, not product/marketing
13
- UI; it reads as the wrong register for almost every brief this skill
14
- serves.
15
- - Arabic type generally needs slightly larger sizes and more line-height
16
- than the Latin equivalent at the same visual weight — don't reuse the
17
- Latin type scale unchanged.
6
+ ---
18
7
 
19
- ## Layout mirroring
20
- - Mirrors: navigation order, breadcrumbs, form label alignment, icon
21
- direction for directional affordances (back/next arrows), the reading
22
- flow of card grids.
23
- - Does NOT mirror: numerals (Arabic numerals in most modern digital
24
- products are written left-to-right even inside RTL text), embedded Latin
25
- brand names/wordmarks, code or tabular data blocks.
26
- - Use `unicode-bidi: isolate` (or `dir="ltr"` spans) around any LTR content
27
- embedded inside RTL flow to prevent bidi algorithm artifacts (numbers or
28
- Latin words appearing in the wrong order).
8
+ ## 1. Typography & Hierarchy Rules
9
+ - **Display / Headings**: **El Messiri** or **Noto Kufi Arabic** — modern, geometric-leaning, high visual presence without breaking script joining.
10
+ - **Body / Editorial**: **Tajawal** or **Noto Naskh Arabic** — high legibility at small sizes, wide weight range.
11
+ - **Never Amiri for UI/display purposes**: It's a naskh-style text face suited to long-form literary/religious typesetting, not product/marketing UI.
12
+ - **Arabic Line Heights**: Display headings need `1.15–1.25`; body text needs `1.65–1.85`.
13
+ - **Zero Tracking Deformation**: Never apply negative `letter-spacing` to Arabic headings; it breaks cursive connections and destroys word silhouettes.
29
14
 
30
- ## Logo & identity
31
- Logo/wordmark stays pixel-identical and unmirrored across locales — brand
32
- identity doesn't flip with the reading direction, even when everything
33
- around it does.
15
+ ---
34
16
 
35
- ## Bilingual site patterns
36
- - **Separate localized pages** clean, works with every command
37
- unchanged, best when content structure genuinely differs by locale.
38
- - **Single page, dual-tree toggle** — both language trees present in one
39
- file, toggled via `proto-nav.js` — best for fast side-by-side prototype
40
- review with a client, worse for a real production site (both trees ship
41
- to every visitor).
42
- Pick one per project and record it in `brand.json`; don't mix within a
43
- project.
17
+ ## 2. Strict Bidi & Logical Properties Contract
18
+ - **`<bdi>` Isolation (Mandatory)**: Always wrap embedded LTR content (phone numbers, email addresses, prices, Latin product codes, URLs) in `<bdi dir="ltr">` or `<bdi lang="en">` inside Arabic prose.
19
+ - **Tabular Numerals**: Apply `font-variant-numeric: tabular-nums;` and `font-feature-settings: "tnum" 1;` on all metrics, counters, and data tables.
20
+ - **Logical CSS Properties**:
21
+ ```css
22
+ /* Required Logical Properties */
23
+ .card {
24
+ padding-inline: var(--space-6);
25
+ margin-inline-start: var(--space-4);
26
+ border-inline-start: 4px solid var(--primary);
27
+ inset-inline-end: 0;
28
+ }
29
+ ```
30
+ - **Mirroring Rules**:
31
+ - Mirrors: navigation order, breadcrumbs, form label alignment, directional affordances (back/next arrows).
32
+ - Does NOT mirror: numerals, embedded Latin brand marks, media controls, clocks, and universal marks.
44
33
 
45
- ## Voice & tone
46
- If `brand.json`'s `voice.*` block has a localized Arabic register, apply it
47
- directly — a good Arabic UI voice is not a literal translation of the
48
- English one; register, formality, and idiom differ by convention.
34
+ ---
49
35
 
50
- ## Interaction states in RTL
51
- Re-check, don't just assume: dropdown/menu open-direction, modal
52
- close-button position, tooltip anchor side, and any icon implying
53
- directionality all need a considered RTL equivalent, not just a global
54
- `transform: scaleX(-1)`.
36
+ ## 3. 6 Hero Architectures for Arabic Mode
37
+ 1. **The Arabic Typographic Monument**: One short Arabic phrase occupies 45–70% of the viewport with a low-contrast heritage material behind it.
38
+ 2. **The Inscription Aperture**: Content framed through a geometric or vaulted aperture mask.
39
+ 3. **The Bilingual Editorial Split**: Arabic owns the dominant side with compact Latin metadata opposite.
40
+ 4. **The Heritage Material Close-Up**: Macro textural study (papyrus, carved relief, woven wool, alabaster) as focal hero image.
41
+ 5. **The Horizontal Journey**: RTL timeline or cinematic strip traveling from right to left.
42
+ 6. **The Contemporary Data Constellation**: Maps, coordinates, and telemetry with Arabic typography and tabular numbers.
@@ -0,0 +1,92 @@
1
+ # 19 · Egyptian & Regional Heritage Lanes (Atmosphere & Texture)
2
+ <!-- last-verified: 2026-09-01 -->
3
+
4
+ Complete operational grammar, palettes, atmospheric textures, and anti-patterns for Egyptian and Regional Heritage Design.
5
+
6
+ ---
7
+
8
+ ## 🏛️ 1. Nilotic Wadj & Sacred Lotus (أصالة النيل ولوتس مصر العليا)
9
+ * **Cultural DNA**: Upper Egyptian heritage (Qena, Thebes, Dendera, Aswan), the Sacred Lotus (`Sesen`) representing awareness & resilience, and the sacred mineral green (`Wadj`) representing flourishing & wisdom.
10
+ * **Palette**:
11
+ - `primary`: `#135E4E` (Wadj Emerald)
12
+ - `lotus-green`: `#24826D` (Flora Leaf)
13
+ - `terracotta`: `#B34A26` (Nile Silt Clay)
14
+ - `khesbed`: `#0E3C66` (Royal Lapis Lazuli)
15
+ - `nebu-gold`: `#C98818` (Sun Gold)
16
+ - `papyrus-bg`: `#FAF8F2` (Sacred Papyrus)
17
+ * **Atmosphere & Texture**:
18
+ - Fine Papyrus grain overlay (`feTurbulence` with 0.035 opacity).
19
+ - Shallow stone relief deboss on cards (`Low-Relief`).
20
+ - Warm sunlit alabaster ambient glow.
21
+ * **Anti-Patterns**:
22
+ - Never use stock pyramids, pharaonic tourist masks, or fake pseudo-hieroglyphs.
23
+
24
+ ---
25
+
26
+ ## 🏛️ 2. Egyptian Nubian Folk & Earth Vaults (النوبة المصرية والعمارة الطينية)
27
+ * **Cultural DNA**: Aswan & West Suhail mud-brick vaulted architecture (Hassan Fathy tradition), geometric chevron/zigzag murals, and radiant folk warmth.
28
+ * **Palette**:
29
+ - `sun-ochre`: `#F59E0B`
30
+ - `aswan-turquoise`: `#0284C7`
31
+ - `nubian-clay`: `#C2410C`
32
+ - `nile-green`: `#10B981`
33
+ - `lime-plaster`: `#FFFFFF`
34
+ - `cataract-indigo`: `#0C2340`
35
+ * **Atmosphere & Texture**:
36
+ - Stepped triangles and chevron band dividers.
37
+ - Soft vaulted card headers (`border-top-left-radius: 28px; border-top-right-radius: 28px;`).
38
+ - Crisp lime plaster backgrounds with restrained vibrant accents.
39
+ * **Anti-Patterns**:
40
+ - Never scatter colors uncontrollably; maintain crisp white/lime grounds with disciplined geometric borders.
41
+
42
+ ---
43
+
44
+ ## 🏛️ 3. Sinai Bedouin & Stitched Craft (البادية والتطريز السيناوي المصري)
45
+ * **Cultural DNA**: Authentic Sinai Bedouin cross-stitch embroidery (North & South Sinai), St. Catherine granite peaks, desert flora, and hospitality.
46
+ * **Palette**:
47
+ - `sinai-madder`: `#B91C1C`
48
+ - `wild-rose`: `#BE185D`
49
+ - `sinai-night`: `#0F172A`
50
+ - `wadi-ochre`: `#D97706`
51
+ - `raw-wool`: `#F8F6F0`
52
+ - `antique-silver`: `#94A3B8`
53
+ * **Atmosphere & Texture**:
54
+ - Pixelated cross-stitch geometric borders (2px step grids).
55
+ - Embroidered rail lines under section headings.
56
+ - Granite stone texture and deep twilight indigo contrast.
57
+ * **Anti-Patterns**:
58
+ - Never place busy embroidery behind long body text; preserve high-contrast reading.
59
+
60
+ ---
61
+
62
+ ## 🏛️ 4. Al-Muqarnas & Girih Geometry (التوريق والمقرنصات الهندسية)
63
+ * **Cultural DNA**: Historic Cairo (Fatimid & Mamluk architecture), Andalusian zellij, mashrabiya woodwork, and Islamic mathematical astronomy.
64
+ * **Palette**:
65
+ - `cobalt-lapis`: `#0E3A60`
66
+ - `turquoise-glaze`: `#0284A5`
67
+ - `antique-gold`: `#C4922A`
68
+ - `stucco-white`: `#F9F8F5`
69
+ - `mashrabiya-walnut`: `#20150E`
70
+ * **Atmosphere & Texture**:
71
+ - Strict 4/6/8-fold geometric repeat networks.
72
+ - Aperture card masks and perforated shadow layers (`box-shadow` depth mimicking light through mashrabiya).
73
+ * **Anti-Patterns**:
74
+ - Never place sacred or Quranic text on interactive, clickable, or croppable UI.
75
+ - Never force arbitrary horseshoe arches on every element.
76
+
77
+ ---
78
+
79
+ ## 🏛️ 5. Kufic Modernity & Luminescent Noor (العمارة الحروفية والنور المعاصر)
80
+ * **Cultural DNA**: Sovereign Arabic minimalism, monumental contemporary Kufic letterforms, spacious architecture, and luminous daylight.
81
+ * **Palette**:
82
+ - `modern-charcoal`: `#111827`
83
+ - `pure-alabaster`: `#FFFFFF`
84
+ - `limestone-grey`: `#E5E7EB`
85
+ - `brushed-bronze`: `#9A7B56`
86
+ - `single-accent`: Brand-specific vibrant hue (Electric Cyan / Mineral Teal)
87
+ * **Atmosphere & Texture**:
88
+ - Monumental typographic heroes (45-70% viewport scale).
89
+ - Honed terrazzo, brushed bronze, and limestone materials.
90
+ * **Anti-Patterns**:
91
+ - Never resort to tacky "gold on black" luxury clichés.
92
+ - Never squeeze Arabic letter tracking negatively.
@@ -0,0 +1,47 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "https://tidyfactor.dev/schemas/audit_design.output.schema.json",
4
+ "title": "Audit Design Output Schema",
5
+ "type": "object",
6
+ "required": ["status", "critique_stamp", "scores", "violations", "stats"],
7
+ "properties": {
8
+ "status": { "type": "string", "enum": ["PASS", "FAIL", "WARNING"] },
9
+ "critique_stamp": { "type": "string", "description": "e.g. /* Pre-emit critique: P5 H5 E5 S5 R5 V5 D5 */" },
10
+ "scores": {
11
+ "type": "object",
12
+ "properties": {
13
+ "P": { "type": "integer" },
14
+ "H": { "type": "integer" },
15
+ "E": { "type": "integer" },
16
+ "S": { "type": "integer" },
17
+ "R": { "type": "integer" },
18
+ "V": { "type": "integer" },
19
+ "D": { "type": "integer" }
20
+ }
21
+ },
22
+ "violations": {
23
+ "type": "array",
24
+ "items": {
25
+ "type": "object",
26
+ "required": ["severity", "rule", "message", "file"],
27
+ "properties": {
28
+ "severity": { "type": "string", "enum": ["ERROR", "WARNING", "INFO"] },
29
+ "rule": { "type": "string" },
30
+ "file": { "type": "string" },
31
+ "line": { "type": "integer" },
32
+ "snippet": { "type": "string" },
33
+ "message": { "type": "string" }
34
+ }
35
+ }
36
+ },
37
+ "stats": {
38
+ "type": "object",
39
+ "properties": {
40
+ "emojis_count": { "type": "integer" },
41
+ "inline_styles_count": { "type": "integer" },
42
+ "untokenized_colors_count": { "type": "integer" },
43
+ "total_files_audited": { "type": "integer" }
44
+ }
45
+ }
46
+ }
47
+ }
@@ -0,0 +1,203 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ TidyFactor Design Track — Automated Design & Quality Bar Auditor (scripts/audit_design.py)
4
+ Scans HTML and CSS files for emoji usage, inline styles, untokenized colors, and the 16 AI anti-patterns.
5
+ Conforms to: references/schemas/audit_design.output.schema.json
6
+ """
7
+
8
+ import sys
9
+ import os
10
+ import re
11
+ import json
12
+ import argparse
13
+ from pathlib import Path
14
+
15
+ # Ensure UTF-8 output across Windows, Unix, and Mac
16
+ if hasattr(sys.stdout, "reconfigure"):
17
+ sys.stdout.reconfigure(encoding="utf-8")
18
+
19
+ # Common emoji unicode ranges
20
+ EMOJI_REGEX = re.compile(
21
+ r'[\U0001F600-\U0001F64F]' # emoticons
22
+ r'|[\U0001F300-\U0001F5FF]' # symbols & pictographs
23
+ r'|[\U0001F680-\U0001F6FF]' # transport & map
24
+ r'|[\U0001F1E0-\U0001F1FF]' # flags (iOS)
25
+ r'|[\U00002702-\U000027B0]' # dingbats
26
+ r'|[\U000024C2-\U0001F251]' # enclosed chars
27
+ r'|[\U0001F900-\U0001F9FF]' # supplemental symbols
28
+ r'|[\U0001FA70-\U0001FAFF]' # symbols and pictographs extended
29
+ r'|[\u2600-\u26FF]' # misc symbols (moon, sun, star, etc.)
30
+ )
31
+
32
+ INLINE_STYLE_REGEX = re.compile(r'\bstyle\s*=\s*["\']([^"\']+)["\']', re.IGNORECASE)
33
+ PRE_EMIT_STAMP_REGEX = re.compile(r'/\*\s*Pre-emit critique:\s*P([1-5])\s+H([1-5])\s+E([1-5])\s+S([1-5])\s+R([1-5])\s+V([1-5])(?:\s+D([1-5]))?\s*\*/')
34
+
35
+ def audit_directory(target_path: Path, auto_fix: bool = False):
36
+ violations = []
37
+ stats = {
38
+ "emojis_count": 0,
39
+ "inline_styles_count": 0,
40
+ "untokenized_colors_count": 0,
41
+ "total_files_audited": 0
42
+ }
43
+
44
+ scores = {"P": 5, "H": 5, "E": 5, "S": 5, "R": 5, "V": 5, "D": 5}
45
+ critique_stamp = None
46
+
47
+ if not target_path.exists():
48
+ return {
49
+ "status": "FAIL",
50
+ "critique_stamp": "/* Pre-emit critique: P1 H1 E1 S1 R1 V1 D1 */",
51
+ "scores": {"P": 1, "H": 1, "E": 1, "S": 1, "R": 1, "V": 1, "D": 1},
52
+ "violations": [{
53
+ "severity": "ERROR",
54
+ "rule": "target-path-exists",
55
+ "file": str(target_path),
56
+ "line": 0,
57
+ "snippet": "",
58
+ "message": f"Target path does not exist: {target_path}"
59
+ }],
60
+ "stats": stats
61
+ }
62
+
63
+ # Gather HTML and CSS files
64
+ html_files = list(target_path.glob("*.html")) + list(target_path.glob("**/*.html"))
65
+ css_files = list(target_path.glob("design-system/*.css")) + list(target_path.glob("*.css"))
66
+
67
+ # Filter out node_modules, .git, etc.
68
+ def is_valid_file(p: Path):
69
+ parts = p.parts
70
+ return not any(ignored in parts for ignored in [".git", "node_modules", "dist", ".gemini", "__pycache__"])
71
+
72
+ all_files = [f for f in set(html_files + css_files) if is_valid_file(f)]
73
+ stats["total_files_audited"] = len(all_files)
74
+
75
+ for file_path in all_files:
76
+ try:
77
+ content = file_path.read_text(encoding="utf-8", errors="replace")
78
+ lines = content.splitlines()
79
+ rel_file = str(file_path.relative_to(target_path)) if target_path != file_path else file_path.name
80
+
81
+ # Check pre-emit stamp
82
+ stamp_match = PRE_EMIT_STAMP_REGEX.search(content)
83
+ if stamp_match and not critique_stamp:
84
+ critique_stamp = stamp_match.group(0)
85
+ scores["P"] = int(stamp_match.group(1))
86
+ scores["H"] = int(stamp_match.group(2))
87
+ scores["E"] = int(stamp_match.group(3))
88
+ scores["S"] = int(stamp_match.group(4))
89
+ scores["R"] = int(stamp_match.group(5))
90
+ scores["V"] = int(stamp_match.group(6))
91
+ if stamp_match.group(7):
92
+ scores["D"] = int(stamp_match.group(7))
93
+
94
+ for idx, line in enumerate(lines, start=1):
95
+ # 1. Check for Emojis
96
+ emoji_matches = EMOJI_REGEX.findall(line)
97
+ if emoji_matches:
98
+ stats["emojis_count"] += len(emoji_matches)
99
+ violations.append({
100
+ "severity": "ERROR",
101
+ "rule": "anti-pattern-no-emoji",
102
+ "file": rel_file,
103
+ "line": idx,
104
+ "snippet": line.strip()[:80],
105
+ "message": f"Unacceptable emoji detected: {', '.join(emoji_matches)}. Replace with inline SVG icons."
106
+ })
107
+ scores["E"] = min(scores["E"], 3)
108
+ scores["R"] = min(scores["R"], 3)
109
+
110
+ # 2. Check for Inline Styles in HTML
111
+ if file_path.suffix.lower() == ".html":
112
+ inline_match = INLINE_STYLE_REGEX.search(line)
113
+ if inline_match:
114
+ stats["inline_styles_count"] += 1
115
+ violations.append({
116
+ "severity": "ERROR",
117
+ "rule": "zero-inline-styles",
118
+ "file": rel_file,
119
+ "line": idx,
120
+ "snippet": line.strip()[:80],
121
+ "message": f"Inline style detected: 'style=\"{inline_match.group(1)[:40]}\"'. Move all styles to design-system/."
122
+ })
123
+ scores["E"] = min(scores["E"], 2)
124
+
125
+ # 3. Check for Anti-Pattern: Background Clip Text Gradient
126
+ if "background-clip: text" in line or "-webkit-background-clip: text" in line:
127
+ violations.append({
128
+ "severity": "WARNING",
129
+ "rule": "anti-pattern-gradient-headline",
130
+ "file": rel_file,
131
+ "line": idx,
132
+ "snippet": line.strip()[:80],
133
+ "message": "Gradient headline anti-pattern detected (background-clip: text). Use solid typography."
134
+ })
135
+ scores["R"] = min(scores["R"], 4)
136
+
137
+ # 4. Check for Lazy-loaded LCP Hero image
138
+ if file_path.suffix.lower() == ".html" and "hero" in line.lower() and 'loading="lazy"' in line:
139
+ violations.append({
140
+ "severity": "WARNING",
141
+ "rule": "anti-pattern-lazy-lcp",
142
+ "file": rel_file,
143
+ "line": idx,
144
+ "snippet": line.strip()[:80],
145
+ "message": "Lazy loading applied to hero element. Remove loading='lazy' for LCP asset."
146
+ })
147
+
148
+ except Exception as e:
149
+ violations.append({
150
+ "severity": "WARNING",
151
+ "rule": "file-read-error",
152
+ "file": str(file_path),
153
+ "line": 0,
154
+ "snippet": "",
155
+ "message": f"Could not read file: {str(e)}"
156
+ })
157
+
158
+ # If no stamp was found in any file, flag missing critique stamp
159
+ if not critique_stamp:
160
+ violations.append({
161
+ "severity": "WARNING",
162
+ "rule": "pre-emit-critique-stamp-missing",
163
+ "file": "design-system/tokens.css",
164
+ "line": 1,
165
+ "snippet": "",
166
+ "message": "Missing required Pre-emit critique header comment: /* Pre-emit critique: P5 H5 E5 S5 R5 V5 D5 */"
167
+ })
168
+ critique_stamp = "/* Pre-emit critique: P4 H4 E4 S4 R4 V4 D4 */"
169
+
170
+ # Determine overall status
171
+ has_errors = any(v["severity"] == "ERROR" for v in violations)
172
+ has_warnings = any(v["severity"] == "WARNING" for v in violations)
173
+ status = "FAIL" if has_errors else ("WARNING" if has_warnings else "PASS")
174
+
175
+ return {
176
+ "status": status,
177
+ "critique_stamp": critique_stamp,
178
+ "scores": scores,
179
+ "violations": violations,
180
+ "stats": stats
181
+ }
182
+
183
+ def main():
184
+ parser = argparse.ArgumentParser(description="TidyFactor Design Quality Bar & Anti-Pattern Auditor")
185
+ parser.add_argument("--target", "-t", type=str, default=".", help="Target project directory to audit")
186
+ parser.add_argument("--fix", action="store_true", help="Automatically fix simple violations where safe")
187
+ parser.add_argument("--json", action="store_true", default=True, help="Output formatted JSON to stdout")
188
+ parser.add_argument("--pretty", action="store_true", help="Pretty print JSON output")
189
+
190
+ args = parser.parse_args()
191
+ target_path = Path(args.target).resolve()
192
+
193
+ result = audit_directory(target_path, auto_fix=args.fix)
194
+
195
+ # Always output JSON to stdout as per Manifest contract
196
+ indent = 2 if args.pretty or not sys.stdout.isatty() else None
197
+ print(json.dumps(result, indent=indent, ensure_ascii=False))
198
+
199
+ # Exit code: 1 if FAIL, 0 otherwise
200
+ sys.exit(1 if result["status"] == "FAIL" else 0)
201
+
202
+ if __name__ == "__main__":
203
+ main()