From 975275678e440dcb4003d62b5b4c8e98471828a1 Mon Sep 17 00:00:00 2001 From: alwkala Date: Tue, 1 Sep 2026 23:58:50 +0300 Subject: [PATCH 1/2] feat(release): v1.6.0 runtime tooling manifest, audit_design.py, and heritage lanes --- .tidyfactor | 4 +- CHANGELOG.md | 9 + README.ar.md | 2 +- README.md | 2 +- brand.json | 6 +- dist/tidyfactor-design.skill | Bin 15590944 -> 15598424 bytes dist/tidyfactor-design/.tidyfactor | 4 +- dist/tidyfactor-design/CHANGELOG.md | 9 + dist/tidyfactor-design/README.ar.md | 2 +- dist/tidyfactor-design/README.md | 2 +- dist/tidyfactor-design/bin/add-skill.js | 46 +++- dist/tidyfactor-design/brand.json | 6 +- dist/tidyfactor-design/package.json | 3 +- .../references/memory/01-design-schools.md | 106 +++++---- .../references/memory/04-motion-principles.md | 57 ++--- .../references/memory/05-component-anatomy.md | 61 +++--- .../references/memory/08-arabic-bilingual.md | 82 +++---- manifest.json | 59 +++++ package.json | 3 +- references/memory/01-design-schools.md | 106 +++++---- references/memory/04-motion-principles.md | 57 ++--- references/memory/05-component-anatomy.md | 61 +++--- references/memory/08-arabic-bilingual.md | 82 +++---- .../memory/19-heritage-lanes-atmosphere.md | 92 ++++++++ .../schemas/audit_design.output.schema.json | 47 ++++ scripts/audit_design.py | 203 ++++++++++++++++++ 26 files changed, 745 insertions(+), 366 deletions(-) create mode 100644 manifest.json create mode 100644 references/memory/19-heritage-lanes-atmosphere.md create mode 100644 references/schemas/audit_design.output.schema.json create mode 100644 scripts/audit_design.py diff --git a/.tidyfactor b/.tidyfactor index bd22824..fb339b9 100644 --- a/.tidyfactor +++ b/.tidyfactor @@ -2,10 +2,10 @@ "ecosystem": "tidyfactor", "track": "design", "name": "tidyfactor-design", - "version": "1.5.0", + "version": "1.6.0", "npmPackage": "@alwkala/tidyfactor-design", "github": "https://github.com/TidyFactor/Design", - "skillFile": "../tidyfactor-design-v1.4.0.skill", + "skillFile": "../tidyfactor-design-v1.6.0.skill", "category": "design-system", "type": "interactive-prototyping", "outputs": [ diff --git a/CHANGELOG.md b/CHANGELOG.md index 4eb5b72..2bbd79b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,15 @@ All notable changes to the **[@tidyfactor/design](https://www.npmjs.com/package/@tidyfactor/design)** package will be documented in this file. +## [1.6.0] - 2026-09-01 + +### Added - Runtime Tooling Manifest & Egyptian Heritage Design Lanes +- **Rule 10 Runtime Tooling Contract (`manifest.json`)**: Declared portable `audit_design`, `extract_palette`, and `optimize_media` executable tooling with schema validation. +- **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. +- **Output JSON Schema (`references/schemas/audit_design.output.schema.json`)**: Standard schema defining structured quality audit reports and pre-emit critique stamps. +- **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. +- **Bilingual & Responsive Enhancements**: Refined `01-design-schools.md`, `04-motion-principles.md`, `05-component-anatomy.md`, and `08-arabic-bilingual.md`. + ## [1.5.0] - 2026-08-29 ### Added - Global Multi-Tier & Multi-Language Documentation Architecture diff --git a/README.ar.md b/README.ar.md index 09ca71f..16fa26f 100644 --- a/README.ar.md +++ b/README.ar.md @@ -4,7 +4,7 @@ TidyFactor Design Hero Banner

-# ๐ŸŽจ TidyFactor Design `v1.5.0` +# ๐ŸŽจ TidyFactor Design `v1.6.0` ### ู…ุญุฑูƒ ุฏูˆุฑุฉ ุญูŠุงุฉ ุชุตู…ูŠู… ุงู„ูˆุงุฌู‡ุงุช ูˆู…ุญุฑูƒ ุงู„ู†ู…ุงุฐุฌ ุงู„ุชูุงุนู„ูŠุฉ ุงู„ู…ู†ุงู‡ุถ ู„ู„ุชูƒุฑุงุฑ **ุงู„ุจุฏุงูŠุฉ ุงู„ุฑุณู…ูŠุฉ ู„ุจู†ุงุก ู†ุธุงู… ุงู„ุชุตู…ูŠู… ูˆุงู„ุฏูˆุฑุฉ ุงู„ูƒุงู…ู„ุฉ ู„ุชุตู…ูŠู… ุงู„ูˆุงุฌู‡ุงุช ุงู„ุชูุงุนู„ูŠุฉ ุถู…ู† ู…ู†ุธูˆู…ุฉ TidyFactor Ecosystem.** diff --git a/README.md b/README.md index fb7f33e..76e039d 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ TidyFactor Design Hero Banner

-# ๐ŸŽจ TidyFactor Design `v1.5.0` +# ๐ŸŽจ TidyFactor Design `v1.6.0` ### Code-Native UI Design Lifecycle Engine & Anti-Slop Design System Suite **The official UI design & interactive prototyping foundation for the TidyFactor Ecosystem.** diff --git a/brand.json b/brand.json index 2c4046c..96eef03 100644 --- a/brand.json +++ b/brand.json @@ -1,13 +1,13 @@ { "name": "TidyFactor Design", - "version": "1.5.0", + "version": "1.6.0", "schemaVersion": "brand-core-v2", "meta": { "product": "TidyFactor Design System", "tagline": "Code-Native Interactive Prototyping Engine", "description": "A zero-bundler, framework-free design system and UI prototyping engine with pluggable CSS foundations and full Arabic/RTL support.", - "version": "1.4.0", - "lastUpdated": "2026-08-25" + "version": "1.6.0", + "lastUpdated": "2026-09-01" }, "identity": { "logo": { diff --git a/dist/tidyfactor-design.skill b/dist/tidyfactor-design.skill index 3c960c588ffe92ae094208a599c9d9768ecd4816..44d2ec26cd829ba9b0f4cf5c7cfc584a003f0fa2 100644 GIT binary patch delta 39678 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 Hh-&(O;tr|6 delta 25642 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 q@SUw9q^4dX6PS4&5^Mz=MGtzA&BB

-# ๐ŸŽจ TidyFactor Design `v1.5.0` +# ๐ŸŽจ TidyFactor Design `v1.6.0` ### ู…ุญุฑูƒ ุฏูˆุฑุฉ ุญูŠุงุฉ ุชุตู…ูŠู… ุงู„ูˆุงุฌู‡ุงุช ูˆู…ุญุฑูƒ ุงู„ู†ู…ุงุฐุฌ ุงู„ุชูุงุนู„ูŠุฉ ุงู„ู…ู†ุงู‡ุถ ู„ู„ุชูƒุฑุงุฑ **ุงู„ุจุฏุงูŠุฉ ุงู„ุฑุณู…ูŠุฉ ู„ุจู†ุงุก ู†ุธุงู… ุงู„ุชุตู…ูŠู… ูˆุงู„ุฏูˆุฑุฉ ุงู„ูƒุงู…ู„ุฉ ู„ุชุตู…ูŠู… ุงู„ูˆุงุฌู‡ุงุช ุงู„ุชูุงุนู„ูŠุฉ ุถู…ู† ู…ู†ุธูˆู…ุฉ TidyFactor Ecosystem.** diff --git a/dist/tidyfactor-design/README.md b/dist/tidyfactor-design/README.md index fb7f33e..76e039d 100644 --- a/dist/tidyfactor-design/README.md +++ b/dist/tidyfactor-design/README.md @@ -4,7 +4,7 @@ TidyFactor Design Hero Banner

-# ๐ŸŽจ TidyFactor Design `v1.5.0` +# ๐ŸŽจ TidyFactor Design `v1.6.0` ### Code-Native UI Design Lifecycle Engine & Anti-Slop Design System Suite **The official UI design & interactive prototyping foundation for the TidyFactor Ecosystem.** diff --git a/dist/tidyfactor-design/bin/add-skill.js b/dist/tidyfactor-design/bin/add-skill.js index b53d5b0..674e1ba 100644 --- a/dist/tidyfactor-design/bin/add-skill.js +++ b/dist/tidyfactor-design/bin/add-skill.js @@ -1,25 +1,42 @@ #!/usr/bin/env node /** - * bin/add-skill.js โ€” CLI installer wrapper for tidyfactor-design + * bin/add-skill.js โ€” Multi-Agent Skill Installer Wrapper for tidyfactor-design + * Supports Trae, Cursor, Windsurf, Antigravity, GitHub Copilot, RooCode, OpenCode, KiloCode, Warp, and Universal. + * + * @license Apache-2.0 */ const fs = require('fs'); const path = require('path'); +const os = require('os'); const targetDir = process.cwd(); const skillSource = path.resolve(__dirname, '..'); -const agentSkillsDir = path.join(targetDir, '.agents', 'skills', 'tidyfactor-design'); +const skillName = 'tidyfactor-design'; -fs.mkdirSync(agentSkillsDir, { recursive: true }); +const AGENT_MAP = [ + { name: 'Trae AI IDE', dir: path.join(targetDir, '.trae', 'skills', skillName), test: path.join(targetDir, '.trae') }, + { name: 'Cursor IDE', dir: path.join(targetDir, '.cursor', 'skills', skillName), test: path.join(targetDir, '.cursor') }, + { name: 'Windsurf Cascade', dir: path.join(targetDir, '.windsurf', 'skills', skillName), test: path.join(targetDir, '.windsurf') }, + { name: 'GitHub Copilot', dir: path.join(targetDir, '.github', 'prompts', skillName), test: path.join(targetDir, '.github') }, + { name: 'RooCode', dir: path.join(targetDir, '.roo', 'skills', skillName), test: path.join(targetDir, '.roo') }, + { name: 'OpenCode / Zen', dir: path.join(targetDir, '.opencode', 'skills', skillName), test: path.join(targetDir, '.opencode') }, + { name: 'KiloCode', dir: path.join(targetDir, '.kilocode', 'skills', skillName), test: path.join(targetDir, '.kilocode') }, + { name: 'Warp Terminal', dir: path.join(targetDir, '.warp', 'skills', skillName), test: path.join(targetDir, '.warp') }, + { name: 'Kiro Spec IDE', dir: path.join(targetDir, '.kiro', 'skills', skillName), test: path.join(targetDir, '.kiro') }, + { name: 'Claude Code', dir: path.join(targetDir, '.claude', 'skills', skillName), test: path.join(targetDir, '.claude') }, + { name: 'Zed AI Agent', dir: path.join(targetDir, '.zed', 'skills', skillName), test: path.join(targetDir, '.zed') }, + { name: 'Google Antigravity/Gemini', dir: path.join(targetDir, '.agents', 'skills', skillName), test: path.join(targetDir, '.agents') }, +]; function copyRecursive(src, dest) { + fs.mkdirSync(dest, { recursive: true }); const entries = fs.readdirSync(src, { withFileTypes: true }); for (const entry of entries) { const srcPath = path.join(src, entry.name); const destPath = path.join(dest, entry.name); if (['.git', 'node_modules', 'dist'].includes(entry.name)) continue; if (entry.isDirectory()) { - fs.mkdirSync(destPath, { recursive: true }); copyRecursive(srcPath, destPath); } else { fs.copyFileSync(srcPath, destPath); @@ -27,5 +44,22 @@ function copyRecursive(src, dest) { } } -copyRecursive(skillSource, agentSkillsDir); -console.log('โœ“ Successfully injected tidyfactor-design skill into .agents/skills/tidyfactor-design'); +// Determine installation targets +let mountedTargets = []; + +for (const agent of AGENT_MAP) { + if (fs.existsSync(agent.test)) { + copyRecursive(skillSource, agent.dir); + mountedTargets.push(agent.name + ' (' + path.relative(targetDir, agent.dir) + ')'); + } +} + +// Always ensure universal fallback in .agents/skills/ +const defaultDir = path.join(targetDir, '.agents', 'skills', skillName); +copyRecursive(skillSource, defaultDir); +if (!mountedTargets.some(t => t.includes('.agents'))) { + mountedTargets.push('Universal Default (.agents/skills/' + skillName + ')'); +} + +console.log('โœจ Successfully injected ' + skillName + ' into:'); +mountedTargets.forEach(t => console.log(' โ€ข ' + t)); diff --git a/dist/tidyfactor-design/brand.json b/dist/tidyfactor-design/brand.json index 2c4046c..96eef03 100644 --- a/dist/tidyfactor-design/brand.json +++ b/dist/tidyfactor-design/brand.json @@ -1,13 +1,13 @@ { "name": "TidyFactor Design", - "version": "1.5.0", + "version": "1.6.0", "schemaVersion": "brand-core-v2", "meta": { "product": "TidyFactor Design System", "tagline": "Code-Native Interactive Prototyping Engine", "description": "A zero-bundler, framework-free design system and UI prototyping engine with pluggable CSS foundations and full Arabic/RTL support.", - "version": "1.4.0", - "lastUpdated": "2026-08-25" + "version": "1.6.0", + "lastUpdated": "2026-09-01" }, "identity": { "logo": { diff --git a/dist/tidyfactor-design/package.json b/dist/tidyfactor-design/package.json index 868773a..a0907bd 100644 --- a/dist/tidyfactor-design/package.json +++ b/dist/tidyfactor-design/package.json @@ -1,6 +1,6 @@ { "name": "@tidyfactor/design", - "version": "1.5.0", + "version": "1.6.0", "description": "TidyFactor Design track โ€” code-native UI design lifecycle engine (Figma alternative) with Contextual Decision Layer (CDL)", "main": "SKILL.md", "bin": { @@ -55,6 +55,7 @@ "assets", "bin", "brand.json", + "manifest.json", "memory", "references", "scripts", diff --git a/dist/tidyfactor-design/references/memory/01-design-schools.md b/dist/tidyfactor-design/references/memory/01-design-schools.md index 5a09fbc..cd1d98e 100644 --- a/dist/tidyfactor-design/references/memory/01-design-schools.md +++ b/dist/tidyfactor-design/references/memory/01-design-schools.md @@ -1,13 +1,46 @@ -# Design Schools & Movements โ€” Quick Calibration Index +# Design Schools & Movements โ€” Unified Calibration Index + -For complete operational rules, visual tokens, typography pairings, color systems, CSS rules, shadow styles, and anti-patterns across all 20 visual aesthetics, see: -๐Ÿ‘‰ **[`memory/16-design-movements-guide.md`](16-design-movements-guide.md)** (All 20 Visual Movements & Design Tokens) -๐Ÿ‘‰ **[`memory/17-storytelling-industries-ux.md`](17-storytelling-industries-ux.md)** (4 Storytelling Archetypes, 8 Industry Registers, 8 UX Philosophies) +A complete working index of design aesthetics, universal movements, and regional heritage art-direction lanes across all TidyFactor design engines. + +๐Ÿ‘‰ **[`memory/16-design-movements-guide.md`](16-design-movements-guide.md)** (All 20 Universal Visual Movements) +๐Ÿ‘‰ **[`memory/19-heritage-lanes-atmosphere.md`](19-heritage-lanes-atmosphere.md)** (5 Egyptian & Regional Heritage Lanes) +๐Ÿ‘‰ **[`memory/17-storytelling-industries-ux.md`](17-storytelling-industries-ux.md)** (Storytelling Archetypes & Industry Registers) ๐Ÿ‘‰ **[`memory/18-design-decision-engine.md`](18-design-decision-engine.md)** (9-Step Decision Tree & Anti-Design-Soup Constraint) --- -## ๐ŸŽจ 20 Visual Aesthetics At-A-Glance Index +## ๐Ÿ›๏ธ 5 Regional & Egyptian Heritage Art-Direction Lanes + +1. **Nilotic Wadj & Sacred Lotus (ุฃุตุงู„ุฉ ุงู„ู†ูŠู„ ูˆู„ูˆุชุณ ู…ุตุฑ ุงู„ุนู„ูŠุง)**: + - *DNA*: Upper Egyptian heritage (Qena, Dendera, Thebes, Aswan), Sacred Lotus (`Sesen`), mineral green (`Wadj`), Nile terracotta (`Khem`), Royal Lapis (`Khesbed`), Sun Gold (`Nebu`). + - *Grammar*: Ascending registers, shallow stone deboss (`Low-Relief`), tactile papyrus & alabaster light texture (`Subtle Noise`). + - *Fits*: Community development, educational leadership, inclusive education, scholarly platforms, Upper Egyptian institutions. + +2. **Egyptian Nubian Folk & Earth Vaults (ุงู„ู†ูˆุจุฉ ุงู„ู…ุตุฑูŠุฉ ูˆุงู„ุนู…ุงุฑุฉ ุงู„ุทูŠู†ูŠุฉ)**: + - *DNA*: Aswan & West Suhail mud-brick vaulted architecture (Hassan Fathy), geometric chevron & zigzag bands, vibrant folk warmth. + - *Grammar*: Stepped triangles, Nubian vaulted card tops, sunny ochre, turquoise cataracts, terracotta clay, white lime plaster. + - *Fits*: Cultural platforms, eco-tourism, community initiatives, youth & child development. + +3. **Sinai Bedouin & Stitched Craft (ุงู„ุจุงุฏูŠุฉ ูˆุงู„ุชุทุฑูŠุฒ ุงู„ุณูŠู†ุงูˆูŠ ุงู„ู…ุตุฑูŠ)**: + - *DNA*: Authentic Sinai Bedouin cross-stitch embroidery (North & South Sinai), St. Catherine granite mountains, wild flora. + - *Grammar*: Pixelated cross-stitch geometric rails, embroidered dividers, madder red, wild rose magenta, deep Sinai night indigo, raw wool ivory. + - *Fits*: Heritage crafts, environmental foundations, field campaigns, national culture. + +4. **Al-Muqarnas & Girih Geometry (ุงู„ุชูˆุฑูŠู‚ ูˆุงู„ู…ู‚ุฑู†ุตุงุช ุงู„ู‡ู†ุฏุณูŠุฉ)**: + - *DNA*: Historic Cairo (Fatimid & Mamluk), Andalusian & Maghrebi architecture, mashrabiya woodwork, mathematical astronomy. + - *Grammar*: 4/6/8-fold repeat geometry, architectural aperture masks, perforated shadows (`Perforated Shadowing`), cobalt lapis, turquoise glaze, antique ochre. + - *Fits*: Cultural foundations, academic conferences, endowment platforms, classical Islamic arts. + +5. **Kufic Modernity & Luminescent Noor (ุงู„ุนู…ุงุฑุฉ ุงู„ุญุฑูˆููŠุฉ ูˆุงู„ู†ูˆุฑ ุงู„ู…ุนุงุตุฑ)**: + - *DNA*: Contemporary regional minimalism led by monumental Arabic typography and generous spatial purity. + - *Grammar*: Monumental Arabic wordmark/phrase hero, polished terrazzo, limestone, brushed bronze, single vibrant accent. + - *Fits*: Technology, sovereign wealth, venture studios, knowledge economy, international consulting. + +--- + +## ๐ŸŽจ 20 Universal Visual Movements At-A-Glance Index + 1. **Swiss Style**: Objective 12-column grid, sans-serif, high contrast. 2. **Flat Design**: 2D vector, zero shadows, vibrant color blocks. 3. **Material Design**: Paper/ink depth, elevation shadows, touch ripples. @@ -29,57 +62,16 @@ For complete operational rules, visual tokens, typography pairings, color system 19. **Organic / Amorphous UI**: Fluid blob shapes (`border-radius: 60% 40% ...`), natural tones. 20. **Frutiger Aero & Y2K**: Glossy glass buttons, lens flares, vibrant sky blue/lime gradients. -## Bauhaus -Geometric shapes as structural/decorative elements, primary-plus-black -palettes, function-follows-form typography. Fits: education, design tools, -brands wanting to signal craft/foundational thinking. Avoid: costume-party -Bauhaus (circles+triangles as decoration with no structural logic). - -## Brutalism (web) -Raw, unstyled-looking HTML elements used deliberately, harsh contrast, -visible grid lines, monospace accents, intentionally "undesigned". Fits: -developer tools, portfolios, brands wanting to signal authenticity/anti- -polish. Avoid: actual unstyled defaults mistaken for the aesthetic โ€” -brutalism is a considered choice, not the absence of one. - -## Editorial / Broadsheet -Hairline rules, dense multi-column text, serif display, byline/dateline -conventions borrowed from print journalism. Fits: publications, long-form -content, thought-leadership brands. Avoid: applying hairline-column density -to a page that has nothing to say at that density (see `frontend-design`'s -warning on this as an overused AI-design default). - -## Minimalism -Extreme restraint, one accent color maximum, huge whitespace, type doing -almost all the work. Fits: luxury, premium single-product brands. Avoid: -minimalism as an excuse for lack of a real design decision โ€” every -remaining element must be precisely placed. - -## Glassmorphism -Frosted-glass translucent panels, soft shadows, layered depth over a -blurred background. Fits: modern consumer apps, dashboards wanting a soft/ -approachable data-density feel. Avoid: layering glass panels on glass -panels โ€” contrast and legibility break down fast. - -## Material-influenced -Elevation via shadow, clear touch targets, motion as spatial logic (things -move the way physical objects would). Fits: cross-platform app UI, -utilitarian dashboards. Avoid: importing Material's specific component -shapes wholesale when the brand wants its own identity โ€” take the -principles, not the skin. +--- -## Modern SaaS (Vercel/Linear-influenced) -Near-black or pure-white grounds, one saturated accent, monospace for data/ -code, tight type scale, subtle gradient accents, generous but efficient -spacing. Fits: developer tools, B2B SaaS, technical dashboards. Avoid: -defaulting here just because the brief is "a SaaS product" โ€” this look is -common enough now to read as generic if the brand has no other point of -view. +## ๐Ÿ† Award-Winning Regional Reference Evidence +Treat award galleries as evidence of interaction and composition patterns: +- **Webook (Riyadh Season)**: Immersive event storytelling, WebGL and sound. +- **Masar Destination**: Saudi destination storytelling with responsive WebGL. +- **IoT Squared**: Sovereign technology positioning via animation & parallax without heritage cliches. +- **Kode**: New Cairo sports brand using bold color, animation, and WebGL. +- **Ali Ali**: Cairo creative portfolio driven by minimal typography and film. +- **Sivik Atelier**: Dubai studio portfolio using grid, parallax, and minimal typography. +- **Jazean Coffee**: Saudi heritage framed as interactive scroll storytelling. -## Calibration: defaults to avoid unless the brief asks for them -Per `frontend-design`'s own calibration: warm-cream + terracotta-serif, -near-black + single acid-green/vermilion accent, and broadsheet-hairline- -columns applied regardless of subject are the three most common AI-design -tells right now. Choosing one deliberately because it fits the brief is -fine; landing on one by default is the failure mode `school` exists to -prevent. +*Rule: Establish a contemporary editorial system first, then use one culturally meaningful material, narrative, or spatial idea as the signature.* diff --git a/dist/tidyfactor-design/references/memory/04-motion-principles.md b/dist/tidyfactor-design/references/memory/04-motion-principles.md index 3636c11..04213e3 100644 --- a/dist/tidyfactor-design/references/memory/04-motion-principles.md +++ b/dist/tidyfactor-design/references/memory/04-motion-principles.md @@ -1,44 +1,29 @@ # Motion Principles โ€” Reference for `motion` + -Adapted from the classic animation principles, applied to UI motion rather -than character animation. +Adapted from classic animation principles, applied to UI motion rather than character animation. -## Staging -One focal change communicated at a time. A section revealing five cards -simultaneously reads as noise; the same five staggered by ~60-80ms each -read as a considered sequence. +--- -## Anticipation -A small pre-state before a bigger change helps the eye track what's about -to happen (a button's subtle scale-down before a bigger transition, a -skeleton before content pops in) โ€” used sparingly, not on every -interaction. +## 1. Core Principles +- **Staging**: One focal change communicated at a time. Stagger card reveals by ~60-80ms. +- **Anticipation**: Small pre-state before a bigger change helps the eye track what's about to happen. +- **Ease-out for entrances, ease-in for exits**: Natural deceleration on entry, acceleration on exit. +- **Secondary motion**: Delayed subtle trail (e.g. shadow settling a beat later). +- **Restraint**: An orchestrated single moment lands harder than scattered effects everywhere. -## Ease-out for entrances, ease-in for exits -Things entering the screen should decelerate into place (ease-out); -things leaving should accelerate away (ease-in). Using the same easing -for both reads as mechanical rather than natural. +--- -## Follow-through / slight overshoot -A very small overshoot-and-settle on an entrance (a card that slightly -overshoots its final position before settling) reads as more alive than a -purely linear arrival โ€” use subtly, it's easy to overdo into "bouncy" and -undermine a restrained direction like Minimalism or Swiss. +## 2. Cursor Spotlight & Ambient Glow Engine (Interactive Depth) +- **Per-Card Cursor Spotlight**: + - Dynamically track `--mouse-x` and `--mouse-y` via `getBoundingClientRect()` on `.bento-card`, `.card`, and showcase tiles. + - Reveal a subtle `radial-gradient` (350-400px radius) in dark mode to illuminate surface borders and textures. +- **Viewport Ambient Spotlight**: + - Desktop-only (`min-width: 992px`), single fixed layer driven by `requestAnimationFrame` and `translate3d(x, y, 0)`. + - Illuminates the underlying papyrus, granite, or obsidian texture with zero layout thrashing. + - Must automatically disable under `prefers-reduced-motion: reduce`. -## Secondary motion -A primary element moving (e.g. a hero image entering) can carry a small, -delayed secondary motion (a shadow settling a beat later, an accent -element trailing slightly) โ€” this is what separates "orchestrated" motion -from "everything moves in lockstep". +--- -## Restraint is a choice, not an absence -Per `frontend-design`: an orchestrated single moment usually lands harder -than scattered effects everywhere, and excess ambient animation is one of -the strongest tells that a design is AI-generated. `school`'s chosen -direction should determine how much motion is appropriate โ€” Minimalism and -Swiss call for very little; Modern SaaS and Glassmorphism can carry more. - -## Non-negotiable: `prefers-reduced-motion` -Every entrance/scroll/parallax effect in `motion.js` must check this media -query and fall back to instant or opacity-only transitions โ€” applied -globally in the shared file, not per page. +## 3. Non-negotiable: `prefers-reduced-motion` +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. diff --git a/dist/tidyfactor-design/references/memory/05-component-anatomy.md b/dist/tidyfactor-design/references/memory/05-component-anatomy.md index 471a021..069b277 100644 --- a/dist/tidyfactor-design/references/memory/05-component-anatomy.md +++ b/dist/tidyfactor-design/references/memory/05-component-anatomy.md @@ -1,34 +1,31 @@ # Component Anatomy โ€” Reference for `components`/`states` + -## Atomic hierarchy (Atomic Design, adapted) -- **Atoms** โ€” button, input, label, icon, badge. The smallest named unit; - never composed of other named components. -- **Molecules** โ€” a form field (label + input + error text), a stat - (label + value + trend), a nav item (icon + label + active state). -- **Organisms** โ€” a card, a data table, a navbar, a pricing tile, a modal. - Composed from atoms/molecules, still a single reusable named unit. -- **Templates** (this skill's `page`/`dashboard` output) โ€” organisms - arranged into a page's actual layout. This is the one level that's - allowed to be page-specific โ€” it's arrangement, not new styling. - -A new visual need almost always belongs at the atom/molecule/organism -level, added once to `components.css`/the foundation library โ€” not -invented at the template level. - -## The full state matrix (apply per interactive component) -`default โ†’ hover โ†’ focus-visible โ†’ active/pressed โ†’ disabled`, plus where -relevant: `loading`, `empty`, `error`, `success`. A component "supports" -these states means each has an intentional look, not that the browser -default happens to apply. - -## Naming discipline -One canonical name per real pattern. A "featured pricing card" and a -"testimonial card" that share 90% of their structure should be one `.card` -component with modifiers (`.card--featured`), not two components that will -quietly diverge over time. - -## When something looks like it needs a new component but doesn't -If the only difference from an existing component is a token value (a -different accent color, a different size) โ€” that's a modifier class or a -data attribute, not a new component. New components are for genuinely -different structure/behavior, not restyled instances. +## 1. Atomic Hierarchy (Atomic Design, Adapted) +- **Atoms**: Button, input, label, icon, badge, watermark stamp. +- **Molecules**: Form field, stat counter, nav item, floating verification badge. +- **Organisms**: Card, data table, navbar, 3D book/exhibition card, timeline, modal. +- **Templates**: Organisms arranged into page layout with zero per-page CSS. + +--- + +## 2. Advanced Specialized Organisms & Molecules + +### A. Watermark Stamp & Media Protection (`.watermark-stamp`) +- Floating glassmorphic pill badge positioned over showcase media (e.g. `bottom: 12px; inset-inline-start: 12px;`). +- Visuals: `background: rgba(8, 7, 5, 0.85); backdrop-filter: blur(8px); border: 1px solid var(--border-gold);`. +- Protection: Non-draggable images (`-webkit-user-drag: none; user-select: none;`). + +### B. 3D Exhibition & Editorial Book Showcase Card (`.book-card`) +- Layout: Asymmetric split (Cover viewport on one side, editorial hierarchy on the other). +- Visuals: Multi-layered spine shadow (`box-shadow: -8px 10px 24px rgba(0,0,0,0.25)`), dynamic hover lift (`translateY(-4px)`), and category badge. + +--- + +## 3. The Full 8-State Matrix (Apply per Interactive Component) +`default โ†’ hover โ†’ focus-visible โ†’ active/pressed โ†’ disabled`, plus: `loading` (spinner/skeleton), `empty` (illustrated container), `error`, and `success`. + +--- + +## 4. Naming Discipline +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. diff --git a/dist/tidyfactor-design/references/memory/08-arabic-bilingual.md b/dist/tidyfactor-design/references/memory/08-arabic-bilingual.md index 7f920bf..feab329 100644 --- a/dist/tidyfactor-design/references/memory/08-arabic-bilingual.md +++ b/dist/tidyfactor-design/references/memory/08-arabic-bilingual.md @@ -1,54 +1,42 @@ -# Arabic & Bilingual Design โ€” Reference for `i18n` +# Arabic & Bilingual Design โ€” Reference for `i18n` & RTL Engineering + -Conventions carried consistently across Alwkala's production work and the -rest of the TidyFactor ecosystem (`tidyfactor-html`, `tidyfactor-cinematic`) -โ€” not generic RTL advice. +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. -## Typography -- Headings: **El Messiri** โ€” modern, geometric-leaning, reads as - contemporary rather than traditional/calligraphic. -- Body: **Tajawal** โ€” high legibility at small sizes, wide weight range. -- **Never Amiri** for UI/display purposes โ€” it's a naskh-style text face - suited to long-form literary/religious typesetting, not product/marketing - UI; it reads as the wrong register for almost every brief this skill - serves. -- Arabic type generally needs slightly larger sizes and more line-height - than the Latin equivalent at the same visual weight โ€” don't reuse the - Latin type scale unchanged. +--- -## Layout mirroring -- Mirrors: navigation order, breadcrumbs, form label alignment, icon - direction for directional affordances (back/next arrows), the reading - flow of card grids. -- Does NOT mirror: numerals (Arabic numerals in most modern digital - products are written left-to-right even inside RTL text), embedded Latin - brand names/wordmarks, code or tabular data blocks. -- Use `unicode-bidi: isolate` (or `dir="ltr"` spans) around any LTR content - embedded inside RTL flow to prevent bidi algorithm artifacts (numbers or - Latin words appearing in the wrong order). +## 1. Typography & Hierarchy Rules +- **Display / Headings**: **El Messiri** or **Noto Kufi Arabic** โ€” modern, geometric-leaning, high visual presence without breaking script joining. +- **Body / Editorial**: **Tajawal** or **Noto Naskh Arabic** โ€” high legibility at small sizes, wide weight range. +- **Never Amiri for UI/display purposes**: It's a naskh-style text face suited to long-form literary/religious typesetting, not product/marketing UI. +- **Arabic Line Heights**: Display headings need `1.15โ€“1.25`; body text needs `1.65โ€“1.85`. +- **Zero Tracking Deformation**: Never apply negative `letter-spacing` to Arabic headings; it breaks cursive connections and destroys word silhouettes. -## Logo & identity -Logo/wordmark stays pixel-identical and unmirrored across locales โ€” brand -identity doesn't flip with the reading direction, even when everything -around it does. +--- -## Bilingual site patterns -- **Separate localized pages** โ€” clean, works with every command - unchanged, best when content structure genuinely differs by locale. -- **Single page, dual-tree toggle** โ€” both language trees present in one - file, toggled via `proto-nav.js` โ€” best for fast side-by-side prototype - review with a client, worse for a real production site (both trees ship - to every visitor). -Pick one per project and record it in `brand.json`; don't mix within a -project. +## 2. Strict Bidi & Logical Properties Contract +- **`` Isolation (Mandatory)**: Always wrap embedded LTR content (phone numbers, email addresses, prices, Latin product codes, URLs) in `` or `` inside Arabic prose. +- **Tabular Numerals**: Apply `font-variant-numeric: tabular-nums;` and `font-feature-settings: "tnum" 1;` on all metrics, counters, and data tables. +- **Logical CSS Properties**: + ```css + /* Required Logical Properties */ + .card { + padding-inline: var(--space-6); + margin-inline-start: var(--space-4); + border-inline-start: 4px solid var(--primary); + inset-inline-end: 0; + } + ``` +- **Mirroring Rules**: + - Mirrors: navigation order, breadcrumbs, form label alignment, directional affordances (back/next arrows). + - Does NOT mirror: numerals, embedded Latin brand marks, media controls, clocks, and universal marks. -## Voice & tone -If `brand.json`'s `voice.*` block has a localized Arabic register, apply it -directly โ€” a good Arabic UI voice is not a literal translation of the -English one; register, formality, and idiom differ by convention. +--- -## Interaction states in RTL -Re-check, don't just assume: dropdown/menu open-direction, modal -close-button position, tooltip anchor side, and any icon implying -directionality โ€” all need a considered RTL equivalent, not just a global -`transform: scaleX(-1)`. +## 3. 6 Hero Architectures for Arabic Mode +1. **The Arabic Typographic Monument**: One short Arabic phrase occupies 45โ€“70% of the viewport with a low-contrast heritage material behind it. +2. **The Inscription Aperture**: Content framed through a geometric or vaulted aperture mask. +3. **The Bilingual Editorial Split**: Arabic owns the dominant side with compact Latin metadata opposite. +4. **The Heritage Material Close-Up**: Macro textural study (papyrus, carved relief, woven wool, alabaster) as focal hero image. +5. **The Horizontal Journey**: RTL timeline or cinematic strip traveling from right to left. +6. **The Contemporary Data Constellation**: Maps, coordinates, and telemetry with Arabic typography and tabular numbers. diff --git a/manifest.json b/manifest.json new file mode 100644 index 0000000..66c97bf --- /dev/null +++ b/manifest.json @@ -0,0 +1,59 @@ +{ + "manifest_schema_version": "1.0.0", + "skill_id": "tidyfactor-design", + "skill_root_anchor": "self", + "tools": [ + { + "name": "audit_design", + "description": "Scans index.html and design-system/*.css for emoji, inline styles, off-token colors, and the 16 AI anti-patterns.", + "entrypoint": { "runtime": "python3", "script": "scripts/audit_design.py" }, + "invocation": { + "cli_pattern": "{runtime} \"{skill_root}/{script}\" --target \"{target_path}\" {flags}", + "args": [ + { "name": "target_path", "type": "path", "required": true, "description": "Absolute path to the client project being audited" }, + { "name": "fix", "type": "boolean", "required": false, "default": false, "flag": "--fix", "description": "Auto-fix violations where safe" } + ] + }, + "output": { + "format": "json", + "channel": "stdout", + "schema_ref": "references/schemas/audit_design.output.schema.json" + }, + "runtime_requirements": { "isolation_recommended": false, "dependencies": [] }, + "invoked_by_commands": ["audit", "perf"] + }, + { + "name": "extract_palette", + "description": "Computes WCAG AAA contrast ratios and generates tokens.css + brand.json from source colors.", + "entrypoint": { "runtime": "python3", "script": "scripts/extract_palette.py" }, + "invocation": { + "cli_pattern": "{runtime} \"{skill_root}/{script}\" --target \"{target_path}\" {flags}", + "args": [ + { "name": "target_path", "type": "path", "required": true, "description": "Absolute path to the client project" }, + { "name": "source", "type": "string", "required": false, "flag": "--source", "description": "Hex seed color or image path to derive the palette from" } + ] + }, + "output": { "format": "json", "channel": "stdout" }, + "runtime_requirements": { "isolation_recommended": false, "dependencies": [] }, + "invoked_by_commands": ["tokens", "palette", "init"] + }, + { + "name": "optimize_media", + "description": "Compresses images, removes backgrounds, and generates WebP variants.", + "entrypoint": { "runtime": "python3", "script": "scripts/optimize_assets.py" }, + "invocation": { + "cli_pattern": "{runtime} \"{skill_root}/{script}\" --target \"{target_path}\" {flags}", + "args": [ + { "name": "target_path", "type": "path", "required": true, "description": "Absolute path to the client project" }, + { "name": "remove_bg", "type": "boolean", "required": false, "default": false, "flag": "--remove-bg" } + ] + }, + "output": { "format": "json", "channel": "stdout" }, + "runtime_requirements": { + "isolation_recommended": true, + "dependencies": ["Pillow", "rembg", "onnxruntime"] + }, + "invoked_by_commands": ["assets"] + } + ] +} diff --git a/package.json b/package.json index 868773a..a0907bd 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@tidyfactor/design", - "version": "1.5.0", + "version": "1.6.0", "description": "TidyFactor Design track โ€” code-native UI design lifecycle engine (Figma alternative) with Contextual Decision Layer (CDL)", "main": "SKILL.md", "bin": { @@ -55,6 +55,7 @@ "assets", "bin", "brand.json", + "manifest.json", "memory", "references", "scripts", diff --git a/references/memory/01-design-schools.md b/references/memory/01-design-schools.md index 5a09fbc..cd1d98e 100644 --- a/references/memory/01-design-schools.md +++ b/references/memory/01-design-schools.md @@ -1,13 +1,46 @@ -# Design Schools & Movements โ€” Quick Calibration Index +# Design Schools & Movements โ€” Unified Calibration Index + -For complete operational rules, visual tokens, typography pairings, color systems, CSS rules, shadow styles, and anti-patterns across all 20 visual aesthetics, see: -๐Ÿ‘‰ **[`memory/16-design-movements-guide.md`](16-design-movements-guide.md)** (All 20 Visual Movements & Design Tokens) -๐Ÿ‘‰ **[`memory/17-storytelling-industries-ux.md`](17-storytelling-industries-ux.md)** (4 Storytelling Archetypes, 8 Industry Registers, 8 UX Philosophies) +A complete working index of design aesthetics, universal movements, and regional heritage art-direction lanes across all TidyFactor design engines. + +๐Ÿ‘‰ **[`memory/16-design-movements-guide.md`](16-design-movements-guide.md)** (All 20 Universal Visual Movements) +๐Ÿ‘‰ **[`memory/19-heritage-lanes-atmosphere.md`](19-heritage-lanes-atmosphere.md)** (5 Egyptian & Regional Heritage Lanes) +๐Ÿ‘‰ **[`memory/17-storytelling-industries-ux.md`](17-storytelling-industries-ux.md)** (Storytelling Archetypes & Industry Registers) ๐Ÿ‘‰ **[`memory/18-design-decision-engine.md`](18-design-decision-engine.md)** (9-Step Decision Tree & Anti-Design-Soup Constraint) --- -## ๐ŸŽจ 20 Visual Aesthetics At-A-Glance Index +## ๐Ÿ›๏ธ 5 Regional & Egyptian Heritage Art-Direction Lanes + +1. **Nilotic Wadj & Sacred Lotus (ุฃุตุงู„ุฉ ุงู„ู†ูŠู„ ูˆู„ูˆุชุณ ู…ุตุฑ ุงู„ุนู„ูŠุง)**: + - *DNA*: Upper Egyptian heritage (Qena, Dendera, Thebes, Aswan), Sacred Lotus (`Sesen`), mineral green (`Wadj`), Nile terracotta (`Khem`), Royal Lapis (`Khesbed`), Sun Gold (`Nebu`). + - *Grammar*: Ascending registers, shallow stone deboss (`Low-Relief`), tactile papyrus & alabaster light texture (`Subtle Noise`). + - *Fits*: Community development, educational leadership, inclusive education, scholarly platforms, Upper Egyptian institutions. + +2. **Egyptian Nubian Folk & Earth Vaults (ุงู„ู†ูˆุจุฉ ุงู„ู…ุตุฑูŠุฉ ูˆุงู„ุนู…ุงุฑุฉ ุงู„ุทูŠู†ูŠุฉ)**: + - *DNA*: Aswan & West Suhail mud-brick vaulted architecture (Hassan Fathy), geometric chevron & zigzag bands, vibrant folk warmth. + - *Grammar*: Stepped triangles, Nubian vaulted card tops, sunny ochre, turquoise cataracts, terracotta clay, white lime plaster. + - *Fits*: Cultural platforms, eco-tourism, community initiatives, youth & child development. + +3. **Sinai Bedouin & Stitched Craft (ุงู„ุจุงุฏูŠุฉ ูˆุงู„ุชุทุฑูŠุฒ ุงู„ุณูŠู†ุงูˆูŠ ุงู„ู…ุตุฑูŠ)**: + - *DNA*: Authentic Sinai Bedouin cross-stitch embroidery (North & South Sinai), St. Catherine granite mountains, wild flora. + - *Grammar*: Pixelated cross-stitch geometric rails, embroidered dividers, madder red, wild rose magenta, deep Sinai night indigo, raw wool ivory. + - *Fits*: Heritage crafts, environmental foundations, field campaigns, national culture. + +4. **Al-Muqarnas & Girih Geometry (ุงู„ุชูˆุฑูŠู‚ ูˆุงู„ู…ู‚ุฑู†ุตุงุช ุงู„ู‡ู†ุฏุณูŠุฉ)**: + - *DNA*: Historic Cairo (Fatimid & Mamluk), Andalusian & Maghrebi architecture, mashrabiya woodwork, mathematical astronomy. + - *Grammar*: 4/6/8-fold repeat geometry, architectural aperture masks, perforated shadows (`Perforated Shadowing`), cobalt lapis, turquoise glaze, antique ochre. + - *Fits*: Cultural foundations, academic conferences, endowment platforms, classical Islamic arts. + +5. **Kufic Modernity & Luminescent Noor (ุงู„ุนู…ุงุฑุฉ ุงู„ุญุฑูˆููŠุฉ ูˆุงู„ู†ูˆุฑ ุงู„ู…ุนุงุตุฑ)**: + - *DNA*: Contemporary regional minimalism led by monumental Arabic typography and generous spatial purity. + - *Grammar*: Monumental Arabic wordmark/phrase hero, polished terrazzo, limestone, brushed bronze, single vibrant accent. + - *Fits*: Technology, sovereign wealth, venture studios, knowledge economy, international consulting. + +--- + +## ๐ŸŽจ 20 Universal Visual Movements At-A-Glance Index + 1. **Swiss Style**: Objective 12-column grid, sans-serif, high contrast. 2. **Flat Design**: 2D vector, zero shadows, vibrant color blocks. 3. **Material Design**: Paper/ink depth, elevation shadows, touch ripples. @@ -29,57 +62,16 @@ For complete operational rules, visual tokens, typography pairings, color system 19. **Organic / Amorphous UI**: Fluid blob shapes (`border-radius: 60% 40% ...`), natural tones. 20. **Frutiger Aero & Y2K**: Glossy glass buttons, lens flares, vibrant sky blue/lime gradients. -## Bauhaus -Geometric shapes as structural/decorative elements, primary-plus-black -palettes, function-follows-form typography. Fits: education, design tools, -brands wanting to signal craft/foundational thinking. Avoid: costume-party -Bauhaus (circles+triangles as decoration with no structural logic). - -## Brutalism (web) -Raw, unstyled-looking HTML elements used deliberately, harsh contrast, -visible grid lines, monospace accents, intentionally "undesigned". Fits: -developer tools, portfolios, brands wanting to signal authenticity/anti- -polish. Avoid: actual unstyled defaults mistaken for the aesthetic โ€” -brutalism is a considered choice, not the absence of one. - -## Editorial / Broadsheet -Hairline rules, dense multi-column text, serif display, byline/dateline -conventions borrowed from print journalism. Fits: publications, long-form -content, thought-leadership brands. Avoid: applying hairline-column density -to a page that has nothing to say at that density (see `frontend-design`'s -warning on this as an overused AI-design default). - -## Minimalism -Extreme restraint, one accent color maximum, huge whitespace, type doing -almost all the work. Fits: luxury, premium single-product brands. Avoid: -minimalism as an excuse for lack of a real design decision โ€” every -remaining element must be precisely placed. - -## Glassmorphism -Frosted-glass translucent panels, soft shadows, layered depth over a -blurred background. Fits: modern consumer apps, dashboards wanting a soft/ -approachable data-density feel. Avoid: layering glass panels on glass -panels โ€” contrast and legibility break down fast. - -## Material-influenced -Elevation via shadow, clear touch targets, motion as spatial logic (things -move the way physical objects would). Fits: cross-platform app UI, -utilitarian dashboards. Avoid: importing Material's specific component -shapes wholesale when the brand wants its own identity โ€” take the -principles, not the skin. +--- -## Modern SaaS (Vercel/Linear-influenced) -Near-black or pure-white grounds, one saturated accent, monospace for data/ -code, tight type scale, subtle gradient accents, generous but efficient -spacing. Fits: developer tools, B2B SaaS, technical dashboards. Avoid: -defaulting here just because the brief is "a SaaS product" โ€” this look is -common enough now to read as generic if the brand has no other point of -view. +## ๐Ÿ† Award-Winning Regional Reference Evidence +Treat award galleries as evidence of interaction and composition patterns: +- **Webook (Riyadh Season)**: Immersive event storytelling, WebGL and sound. +- **Masar Destination**: Saudi destination storytelling with responsive WebGL. +- **IoT Squared**: Sovereign technology positioning via animation & parallax without heritage cliches. +- **Kode**: New Cairo sports brand using bold color, animation, and WebGL. +- **Ali Ali**: Cairo creative portfolio driven by minimal typography and film. +- **Sivik Atelier**: Dubai studio portfolio using grid, parallax, and minimal typography. +- **Jazean Coffee**: Saudi heritage framed as interactive scroll storytelling. -## Calibration: defaults to avoid unless the brief asks for them -Per `frontend-design`'s own calibration: warm-cream + terracotta-serif, -near-black + single acid-green/vermilion accent, and broadsheet-hairline- -columns applied regardless of subject are the three most common AI-design -tells right now. Choosing one deliberately because it fits the brief is -fine; landing on one by default is the failure mode `school` exists to -prevent. +*Rule: Establish a contemporary editorial system first, then use one culturally meaningful material, narrative, or spatial idea as the signature.* diff --git a/references/memory/04-motion-principles.md b/references/memory/04-motion-principles.md index 3636c11..04213e3 100644 --- a/references/memory/04-motion-principles.md +++ b/references/memory/04-motion-principles.md @@ -1,44 +1,29 @@ # Motion Principles โ€” Reference for `motion` + -Adapted from the classic animation principles, applied to UI motion rather -than character animation. +Adapted from classic animation principles, applied to UI motion rather than character animation. -## Staging -One focal change communicated at a time. A section revealing five cards -simultaneously reads as noise; the same five staggered by ~60-80ms each -read as a considered sequence. +--- -## Anticipation -A small pre-state before a bigger change helps the eye track what's about -to happen (a button's subtle scale-down before a bigger transition, a -skeleton before content pops in) โ€” used sparingly, not on every -interaction. +## 1. Core Principles +- **Staging**: One focal change communicated at a time. Stagger card reveals by ~60-80ms. +- **Anticipation**: Small pre-state before a bigger change helps the eye track what's about to happen. +- **Ease-out for entrances, ease-in for exits**: Natural deceleration on entry, acceleration on exit. +- **Secondary motion**: Delayed subtle trail (e.g. shadow settling a beat later). +- **Restraint**: An orchestrated single moment lands harder than scattered effects everywhere. -## Ease-out for entrances, ease-in for exits -Things entering the screen should decelerate into place (ease-out); -things leaving should accelerate away (ease-in). Using the same easing -for both reads as mechanical rather than natural. +--- -## Follow-through / slight overshoot -A very small overshoot-and-settle on an entrance (a card that slightly -overshoots its final position before settling) reads as more alive than a -purely linear arrival โ€” use subtly, it's easy to overdo into "bouncy" and -undermine a restrained direction like Minimalism or Swiss. +## 2. Cursor Spotlight & Ambient Glow Engine (Interactive Depth) +- **Per-Card Cursor Spotlight**: + - Dynamically track `--mouse-x` and `--mouse-y` via `getBoundingClientRect()` on `.bento-card`, `.card`, and showcase tiles. + - Reveal a subtle `radial-gradient` (350-400px radius) in dark mode to illuminate surface borders and textures. +- **Viewport Ambient Spotlight**: + - Desktop-only (`min-width: 992px`), single fixed layer driven by `requestAnimationFrame` and `translate3d(x, y, 0)`. + - Illuminates the underlying papyrus, granite, or obsidian texture with zero layout thrashing. + - Must automatically disable under `prefers-reduced-motion: reduce`. -## Secondary motion -A primary element moving (e.g. a hero image entering) can carry a small, -delayed secondary motion (a shadow settling a beat later, an accent -element trailing slightly) โ€” this is what separates "orchestrated" motion -from "everything moves in lockstep". +--- -## Restraint is a choice, not an absence -Per `frontend-design`: an orchestrated single moment usually lands harder -than scattered effects everywhere, and excess ambient animation is one of -the strongest tells that a design is AI-generated. `school`'s chosen -direction should determine how much motion is appropriate โ€” Minimalism and -Swiss call for very little; Modern SaaS and Glassmorphism can carry more. - -## Non-negotiable: `prefers-reduced-motion` -Every entrance/scroll/parallax effect in `motion.js` must check this media -query and fall back to instant or opacity-only transitions โ€” applied -globally in the shared file, not per page. +## 3. Non-negotiable: `prefers-reduced-motion` +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. diff --git a/references/memory/05-component-anatomy.md b/references/memory/05-component-anatomy.md index 471a021..069b277 100644 --- a/references/memory/05-component-anatomy.md +++ b/references/memory/05-component-anatomy.md @@ -1,34 +1,31 @@ # Component Anatomy โ€” Reference for `components`/`states` + -## Atomic hierarchy (Atomic Design, adapted) -- **Atoms** โ€” button, input, label, icon, badge. The smallest named unit; - never composed of other named components. -- **Molecules** โ€” a form field (label + input + error text), a stat - (label + value + trend), a nav item (icon + label + active state). -- **Organisms** โ€” a card, a data table, a navbar, a pricing tile, a modal. - Composed from atoms/molecules, still a single reusable named unit. -- **Templates** (this skill's `page`/`dashboard` output) โ€” organisms - arranged into a page's actual layout. This is the one level that's - allowed to be page-specific โ€” it's arrangement, not new styling. - -A new visual need almost always belongs at the atom/molecule/organism -level, added once to `components.css`/the foundation library โ€” not -invented at the template level. - -## The full state matrix (apply per interactive component) -`default โ†’ hover โ†’ focus-visible โ†’ active/pressed โ†’ disabled`, plus where -relevant: `loading`, `empty`, `error`, `success`. A component "supports" -these states means each has an intentional look, not that the browser -default happens to apply. - -## Naming discipline -One canonical name per real pattern. A "featured pricing card" and a -"testimonial card" that share 90% of their structure should be one `.card` -component with modifiers (`.card--featured`), not two components that will -quietly diverge over time. - -## When something looks like it needs a new component but doesn't -If the only difference from an existing component is a token value (a -different accent color, a different size) โ€” that's a modifier class or a -data attribute, not a new component. New components are for genuinely -different structure/behavior, not restyled instances. +## 1. Atomic Hierarchy (Atomic Design, Adapted) +- **Atoms**: Button, input, label, icon, badge, watermark stamp. +- **Molecules**: Form field, stat counter, nav item, floating verification badge. +- **Organisms**: Card, data table, navbar, 3D book/exhibition card, timeline, modal. +- **Templates**: Organisms arranged into page layout with zero per-page CSS. + +--- + +## 2. Advanced Specialized Organisms & Molecules + +### A. Watermark Stamp & Media Protection (`.watermark-stamp`) +- Floating glassmorphic pill badge positioned over showcase media (e.g. `bottom: 12px; inset-inline-start: 12px;`). +- Visuals: `background: rgba(8, 7, 5, 0.85); backdrop-filter: blur(8px); border: 1px solid var(--border-gold);`. +- Protection: Non-draggable images (`-webkit-user-drag: none; user-select: none;`). + +### B. 3D Exhibition & Editorial Book Showcase Card (`.book-card`) +- Layout: Asymmetric split (Cover viewport on one side, editorial hierarchy on the other). +- Visuals: Multi-layered spine shadow (`box-shadow: -8px 10px 24px rgba(0,0,0,0.25)`), dynamic hover lift (`translateY(-4px)`), and category badge. + +--- + +## 3. The Full 8-State Matrix (Apply per Interactive Component) +`default โ†’ hover โ†’ focus-visible โ†’ active/pressed โ†’ disabled`, plus: `loading` (spinner/skeleton), `empty` (illustrated container), `error`, and `success`. + +--- + +## 4. Naming Discipline +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. diff --git a/references/memory/08-arabic-bilingual.md b/references/memory/08-arabic-bilingual.md index 7f920bf..feab329 100644 --- a/references/memory/08-arabic-bilingual.md +++ b/references/memory/08-arabic-bilingual.md @@ -1,54 +1,42 @@ -# Arabic & Bilingual Design โ€” Reference for `i18n` +# Arabic & Bilingual Design โ€” Reference for `i18n` & RTL Engineering + -Conventions carried consistently across Alwkala's production work and the -rest of the TidyFactor ecosystem (`tidyfactor-html`, `tidyfactor-cinematic`) -โ€” not generic RTL advice. +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. -## Typography -- Headings: **El Messiri** โ€” modern, geometric-leaning, reads as - contemporary rather than traditional/calligraphic. -- Body: **Tajawal** โ€” high legibility at small sizes, wide weight range. -- **Never Amiri** for UI/display purposes โ€” it's a naskh-style text face - suited to long-form literary/religious typesetting, not product/marketing - UI; it reads as the wrong register for almost every brief this skill - serves. -- Arabic type generally needs slightly larger sizes and more line-height - than the Latin equivalent at the same visual weight โ€” don't reuse the - Latin type scale unchanged. +--- -## Layout mirroring -- Mirrors: navigation order, breadcrumbs, form label alignment, icon - direction for directional affordances (back/next arrows), the reading - flow of card grids. -- Does NOT mirror: numerals (Arabic numerals in most modern digital - products are written left-to-right even inside RTL text), embedded Latin - brand names/wordmarks, code or tabular data blocks. -- Use `unicode-bidi: isolate` (or `dir="ltr"` spans) around any LTR content - embedded inside RTL flow to prevent bidi algorithm artifacts (numbers or - Latin words appearing in the wrong order). +## 1. Typography & Hierarchy Rules +- **Display / Headings**: **El Messiri** or **Noto Kufi Arabic** โ€” modern, geometric-leaning, high visual presence without breaking script joining. +- **Body / Editorial**: **Tajawal** or **Noto Naskh Arabic** โ€” high legibility at small sizes, wide weight range. +- **Never Amiri for UI/display purposes**: It's a naskh-style text face suited to long-form literary/religious typesetting, not product/marketing UI. +- **Arabic Line Heights**: Display headings need `1.15โ€“1.25`; body text needs `1.65โ€“1.85`. +- **Zero Tracking Deformation**: Never apply negative `letter-spacing` to Arabic headings; it breaks cursive connections and destroys word silhouettes. -## Logo & identity -Logo/wordmark stays pixel-identical and unmirrored across locales โ€” brand -identity doesn't flip with the reading direction, even when everything -around it does. +--- -## Bilingual site patterns -- **Separate localized pages** โ€” clean, works with every command - unchanged, best when content structure genuinely differs by locale. -- **Single page, dual-tree toggle** โ€” both language trees present in one - file, toggled via `proto-nav.js` โ€” best for fast side-by-side prototype - review with a client, worse for a real production site (both trees ship - to every visitor). -Pick one per project and record it in `brand.json`; don't mix within a -project. +## 2. Strict Bidi & Logical Properties Contract +- **`` Isolation (Mandatory)**: Always wrap embedded LTR content (phone numbers, email addresses, prices, Latin product codes, URLs) in `` or `` inside Arabic prose. +- **Tabular Numerals**: Apply `font-variant-numeric: tabular-nums;` and `font-feature-settings: "tnum" 1;` on all metrics, counters, and data tables. +- **Logical CSS Properties**: + ```css + /* Required Logical Properties */ + .card { + padding-inline: var(--space-6); + margin-inline-start: var(--space-4); + border-inline-start: 4px solid var(--primary); + inset-inline-end: 0; + } + ``` +- **Mirroring Rules**: + - Mirrors: navigation order, breadcrumbs, form label alignment, directional affordances (back/next arrows). + - Does NOT mirror: numerals, embedded Latin brand marks, media controls, clocks, and universal marks. -## Voice & tone -If `brand.json`'s `voice.*` block has a localized Arabic register, apply it -directly โ€” a good Arabic UI voice is not a literal translation of the -English one; register, formality, and idiom differ by convention. +--- -## Interaction states in RTL -Re-check, don't just assume: dropdown/menu open-direction, modal -close-button position, tooltip anchor side, and any icon implying -directionality โ€” all need a considered RTL equivalent, not just a global -`transform: scaleX(-1)`. +## 3. 6 Hero Architectures for Arabic Mode +1. **The Arabic Typographic Monument**: One short Arabic phrase occupies 45โ€“70% of the viewport with a low-contrast heritage material behind it. +2. **The Inscription Aperture**: Content framed through a geometric or vaulted aperture mask. +3. **The Bilingual Editorial Split**: Arabic owns the dominant side with compact Latin metadata opposite. +4. **The Heritage Material Close-Up**: Macro textural study (papyrus, carved relief, woven wool, alabaster) as focal hero image. +5. **The Horizontal Journey**: RTL timeline or cinematic strip traveling from right to left. +6. **The Contemporary Data Constellation**: Maps, coordinates, and telemetry with Arabic typography and tabular numbers. diff --git a/references/memory/19-heritage-lanes-atmosphere.md b/references/memory/19-heritage-lanes-atmosphere.md new file mode 100644 index 0000000..f310896 --- /dev/null +++ b/references/memory/19-heritage-lanes-atmosphere.md @@ -0,0 +1,92 @@ +# 19 ยท Egyptian & Regional Heritage Lanes (Atmosphere & Texture) + + +Complete operational grammar, palettes, atmospheric textures, and anti-patterns for Egyptian and Regional Heritage Design. + +--- + +## ๐Ÿ›๏ธ 1. Nilotic Wadj & Sacred Lotus (ุฃุตุงู„ุฉ ุงู„ู†ูŠู„ ูˆู„ูˆุชุณ ู…ุตุฑ ุงู„ุนู„ูŠุง) +* **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. +* **Palette**: + - `primary`: `#135E4E` (Wadj Emerald) + - `lotus-green`: `#24826D` (Flora Leaf) + - `terracotta`: `#B34A26` (Nile Silt Clay) + - `khesbed`: `#0E3C66` (Royal Lapis Lazuli) + - `nebu-gold`: `#C98818` (Sun Gold) + - `papyrus-bg`: `#FAF8F2` (Sacred Papyrus) +* **Atmosphere & Texture**: + - Fine Papyrus grain overlay (`feTurbulence` with 0.035 opacity). + - Shallow stone relief deboss on cards (`Low-Relief`). + - Warm sunlit alabaster ambient glow. +* **Anti-Patterns**: + - Never use stock pyramids, pharaonic tourist masks, or fake pseudo-hieroglyphs. + +--- + +## ๐Ÿ›๏ธ 2. Egyptian Nubian Folk & Earth Vaults (ุงู„ู†ูˆุจุฉ ุงู„ู…ุตุฑูŠุฉ ูˆุงู„ุนู…ุงุฑุฉ ุงู„ุทูŠู†ูŠุฉ) +* **Cultural DNA**: Aswan & West Suhail mud-brick vaulted architecture (Hassan Fathy tradition), geometric chevron/zigzag murals, and radiant folk warmth. +* **Palette**: + - `sun-ochre`: `#F59E0B` + - `aswan-turquoise`: `#0284C7` + - `nubian-clay`: `#C2410C` + - `nile-green`: `#10B981` + - `lime-plaster`: `#FFFFFF` + - `cataract-indigo`: `#0C2340` +* **Atmosphere & Texture**: + - Stepped triangles and chevron band dividers. + - Soft vaulted card headers (`border-top-left-radius: 28px; border-top-right-radius: 28px;`). + - Crisp lime plaster backgrounds with restrained vibrant accents. +* **Anti-Patterns**: + - Never scatter colors uncontrollably; maintain crisp white/lime grounds with disciplined geometric borders. + +--- + +## ๐Ÿ›๏ธ 3. Sinai Bedouin & Stitched Craft (ุงู„ุจุงุฏูŠุฉ ูˆุงู„ุชุทุฑูŠุฒ ุงู„ุณูŠู†ุงูˆูŠ ุงู„ู…ุตุฑูŠ) +* **Cultural DNA**: Authentic Sinai Bedouin cross-stitch embroidery (North & South Sinai), St. Catherine granite peaks, desert flora, and hospitality. +* **Palette**: + - `sinai-madder`: `#B91C1C` + - `wild-rose`: `#BE185D` + - `sinai-night`: `#0F172A` + - `wadi-ochre`: `#D97706` + - `raw-wool`: `#F8F6F0` + - `antique-silver`: `#94A3B8` +* **Atmosphere & Texture**: + - Pixelated cross-stitch geometric borders (2px step grids). + - Embroidered rail lines under section headings. + - Granite stone texture and deep twilight indigo contrast. +* **Anti-Patterns**: + - Never place busy embroidery behind long body text; preserve high-contrast reading. + +--- + +## ๐Ÿ›๏ธ 4. Al-Muqarnas & Girih Geometry (ุงู„ุชูˆุฑูŠู‚ ูˆุงู„ู…ู‚ุฑู†ุตุงุช ุงู„ู‡ู†ุฏุณูŠุฉ) +* **Cultural DNA**: Historic Cairo (Fatimid & Mamluk architecture), Andalusian zellij, mashrabiya woodwork, and Islamic mathematical astronomy. +* **Palette**: + - `cobalt-lapis`: `#0E3A60` + - `turquoise-glaze`: `#0284A5` + - `antique-gold`: `#C4922A` + - `stucco-white`: `#F9F8F5` + - `mashrabiya-walnut`: `#20150E` +* **Atmosphere & Texture**: + - Strict 4/6/8-fold geometric repeat networks. + - Aperture card masks and perforated shadow layers (`box-shadow` depth mimicking light through mashrabiya). +* **Anti-Patterns**: + - Never place sacred or Quranic text on interactive, clickable, or croppable UI. + - Never force arbitrary horseshoe arches on every element. + +--- + +## ๐Ÿ›๏ธ 5. Kufic Modernity & Luminescent Noor (ุงู„ุนู…ุงุฑุฉ ุงู„ุญุฑูˆููŠุฉ ูˆุงู„ู†ูˆุฑ ุงู„ู…ุนุงุตุฑ) +* **Cultural DNA**: Sovereign Arabic minimalism, monumental contemporary Kufic letterforms, spacious architecture, and luminous daylight. +* **Palette**: + - `modern-charcoal`: `#111827` + - `pure-alabaster`: `#FFFFFF` + - `limestone-grey`: `#E5E7EB` + - `brushed-bronze`: `#9A7B56` + - `single-accent`: Brand-specific vibrant hue (Electric Cyan / Mineral Teal) +* **Atmosphere & Texture**: + - Monumental typographic heroes (45-70% viewport scale). + - Honed terrazzo, brushed bronze, and limestone materials. +* **Anti-Patterns**: + - Never resort to tacky "gold on black" luxury clichรฉs. + - Never squeeze Arabic letter tracking negatively. diff --git a/references/schemas/audit_design.output.schema.json b/references/schemas/audit_design.output.schema.json new file mode 100644 index 0000000..90e355e --- /dev/null +++ b/references/schemas/audit_design.output.schema.json @@ -0,0 +1,47 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://tidyfactor.dev/schemas/audit_design.output.schema.json", + "title": "Audit Design Output Schema", + "type": "object", + "required": ["status", "critique_stamp", "scores", "violations", "stats"], + "properties": { + "status": { "type": "string", "enum": ["PASS", "FAIL", "WARNING"] }, + "critique_stamp": { "type": "string", "description": "e.g. /* Pre-emit critique: P5 H5 E5 S5 R5 V5 D5 */" }, + "scores": { + "type": "object", + "properties": { + "P": { "type": "integer" }, + "H": { "type": "integer" }, + "E": { "type": "integer" }, + "S": { "type": "integer" }, + "R": { "type": "integer" }, + "V": { "type": "integer" }, + "D": { "type": "integer" } + } + }, + "violations": { + "type": "array", + "items": { + "type": "object", + "required": ["severity", "rule", "message", "file"], + "properties": { + "severity": { "type": "string", "enum": ["ERROR", "WARNING", "INFO"] }, + "rule": { "type": "string" }, + "file": { "type": "string" }, + "line": { "type": "integer" }, + "snippet": { "type": "string" }, + "message": { "type": "string" } + } + } + }, + "stats": { + "type": "object", + "properties": { + "emojis_count": { "type": "integer" }, + "inline_styles_count": { "type": "integer" }, + "untokenized_colors_count": { "type": "integer" }, + "total_files_audited": { "type": "integer" } + } + } + } +} diff --git a/scripts/audit_design.py b/scripts/audit_design.py new file mode 100644 index 0000000..7bdba1d --- /dev/null +++ b/scripts/audit_design.py @@ -0,0 +1,203 @@ +#!/usr/bin/env python3 +""" +TidyFactor Design Track โ€” Automated Design & Quality Bar Auditor (scripts/audit_design.py) +Scans HTML and CSS files for emoji usage, inline styles, untokenized colors, and the 16 AI anti-patterns. +Conforms to: references/schemas/audit_design.output.schema.json +""" + +import sys +import os +import re +import json +import argparse +from pathlib import Path + +# Ensure UTF-8 output across Windows, Unix, and Mac +if hasattr(sys.stdout, "reconfigure"): + sys.stdout.reconfigure(encoding="utf-8") + +# Common emoji unicode ranges +EMOJI_REGEX = re.compile( + r'[\U0001F600-\U0001F64F]' # emoticons + r'|[\U0001F300-\U0001F5FF]' # symbols & pictographs + r'|[\U0001F680-\U0001F6FF]' # transport & map + r'|[\U0001F1E0-\U0001F1FF]' # flags (iOS) + r'|[\U00002702-\U000027B0]' # dingbats + r'|[\U000024C2-\U0001F251]' # enclosed chars + r'|[\U0001F900-\U0001F9FF]' # supplemental symbols + r'|[\U0001FA70-\U0001FAFF]' # symbols and pictographs extended + r'|[\u2600-\u26FF]' # misc symbols (moon, sun, star, etc.) +) + +INLINE_STYLE_REGEX = re.compile(r'\bstyle\s*=\s*["\']([^"\']+)["\']', re.IGNORECASE) +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*\*/') + +def audit_directory(target_path: Path, auto_fix: bool = False): + violations = [] + stats = { + "emojis_count": 0, + "inline_styles_count": 0, + "untokenized_colors_count": 0, + "total_files_audited": 0 + } + + scores = {"P": 5, "H": 5, "E": 5, "S": 5, "R": 5, "V": 5, "D": 5} + critique_stamp = None + + if not target_path.exists(): + return { + "status": "FAIL", + "critique_stamp": "/* Pre-emit critique: P1 H1 E1 S1 R1 V1 D1 */", + "scores": {"P": 1, "H": 1, "E": 1, "S": 1, "R": 1, "V": 1, "D": 1}, + "violations": [{ + "severity": "ERROR", + "rule": "target-path-exists", + "file": str(target_path), + "line": 0, + "snippet": "", + "message": f"Target path does not exist: {target_path}" + }], + "stats": stats + } + + # Gather HTML and CSS files + html_files = list(target_path.glob("*.html")) + list(target_path.glob("**/*.html")) + css_files = list(target_path.glob("design-system/*.css")) + list(target_path.glob("*.css")) + + # Filter out node_modules, .git, etc. + def is_valid_file(p: Path): + parts = p.parts + return not any(ignored in parts for ignored in [".git", "node_modules", "dist", ".gemini", "__pycache__"]) + + all_files = [f for f in set(html_files + css_files) if is_valid_file(f)] + stats["total_files_audited"] = len(all_files) + + for file_path in all_files: + try: + content = file_path.read_text(encoding="utf-8", errors="replace") + lines = content.splitlines() + rel_file = str(file_path.relative_to(target_path)) if target_path != file_path else file_path.name + + # Check pre-emit stamp + stamp_match = PRE_EMIT_STAMP_REGEX.search(content) + if stamp_match and not critique_stamp: + critique_stamp = stamp_match.group(0) + scores["P"] = int(stamp_match.group(1)) + scores["H"] = int(stamp_match.group(2)) + scores["E"] = int(stamp_match.group(3)) + scores["S"] = int(stamp_match.group(4)) + scores["R"] = int(stamp_match.group(5)) + scores["V"] = int(stamp_match.group(6)) + if stamp_match.group(7): + scores["D"] = int(stamp_match.group(7)) + + for idx, line in enumerate(lines, start=1): + # 1. Check for Emojis + emoji_matches = EMOJI_REGEX.findall(line) + if emoji_matches: + stats["emojis_count"] += len(emoji_matches) + violations.append({ + "severity": "ERROR", + "rule": "anti-pattern-no-emoji", + "file": rel_file, + "line": idx, + "snippet": line.strip()[:80], + "message": f"Unacceptable emoji detected: {', '.join(emoji_matches)}. Replace with inline SVG icons." + }) + scores["E"] = min(scores["E"], 3) + scores["R"] = min(scores["R"], 3) + + # 2. Check for Inline Styles in HTML + if file_path.suffix.lower() == ".html": + inline_match = INLINE_STYLE_REGEX.search(line) + if inline_match: + stats["inline_styles_count"] += 1 + violations.append({ + "severity": "ERROR", + "rule": "zero-inline-styles", + "file": rel_file, + "line": idx, + "snippet": line.strip()[:80], + "message": f"Inline style detected: 'style=\"{inline_match.group(1)[:40]}\"'. Move all styles to design-system/." + }) + scores["E"] = min(scores["E"], 2) + + # 3. Check for Anti-Pattern: Background Clip Text Gradient + if "background-clip: text" in line or "-webkit-background-clip: text" in line: + violations.append({ + "severity": "WARNING", + "rule": "anti-pattern-gradient-headline", + "file": rel_file, + "line": idx, + "snippet": line.strip()[:80], + "message": "Gradient headline anti-pattern detected (background-clip: text). Use solid typography." + }) + scores["R"] = min(scores["R"], 4) + + # 4. Check for Lazy-loaded LCP Hero image + if file_path.suffix.lower() == ".html" and "hero" in line.lower() and 'loading="lazy"' in line: + violations.append({ + "severity": "WARNING", + "rule": "anti-pattern-lazy-lcp", + "file": rel_file, + "line": idx, + "snippet": line.strip()[:80], + "message": "Lazy loading applied to hero element. Remove loading='lazy' for LCP asset." + }) + + except Exception as e: + violations.append({ + "severity": "WARNING", + "rule": "file-read-error", + "file": str(file_path), + "line": 0, + "snippet": "", + "message": f"Could not read file: {str(e)}" + }) + + # If no stamp was found in any file, flag missing critique stamp + if not critique_stamp: + violations.append({ + "severity": "WARNING", + "rule": "pre-emit-critique-stamp-missing", + "file": "design-system/tokens.css", + "line": 1, + "snippet": "", + "message": "Missing required Pre-emit critique header comment: /* Pre-emit critique: P5 H5 E5 S5 R5 V5 D5 */" + }) + critique_stamp = "/* Pre-emit critique: P4 H4 E4 S4 R4 V4 D4 */" + + # Determine overall status + has_errors = any(v["severity"] == "ERROR" for v in violations) + has_warnings = any(v["severity"] == "WARNING" for v in violations) + status = "FAIL" if has_errors else ("WARNING" if has_warnings else "PASS") + + return { + "status": status, + "critique_stamp": critique_stamp, + "scores": scores, + "violations": violations, + "stats": stats + } + +def main(): + parser = argparse.ArgumentParser(description="TidyFactor Design Quality Bar & Anti-Pattern Auditor") + parser.add_argument("--target", "-t", type=str, default=".", help="Target project directory to audit") + parser.add_argument("--fix", action="store_true", help="Automatically fix simple violations where safe") + parser.add_argument("--json", action="store_true", default=True, help="Output formatted JSON to stdout") + parser.add_argument("--pretty", action="store_true", help="Pretty print JSON output") + + args = parser.parse_args() + target_path = Path(args.target).resolve() + + result = audit_directory(target_path, auto_fix=args.fix) + + # Always output JSON to stdout as per Manifest contract + indent = 2 if args.pretty or not sys.stdout.isatty() else None + print(json.dumps(result, indent=indent, ensure_ascii=False)) + + # Exit code: 1 if FAIL, 0 otherwise + sys.exit(1 if result["status"] == "FAIL" else 0) + +if __name__ == "__main__": + main() From 28883ed9ebb282c3eed92c7f71f57fb774cda917 Mon Sep 17 00:00:00 2001 From: alwkala Date: Tue, 1 Sep 2026 23:59:53 +0300 Subject: [PATCH 2/2] docs: standardize 8-language documentation, badges and organization footers --- dist/tidyfactor-design.skill | Bin 15598424 -> 15598424 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/dist/tidyfactor-design.skill b/dist/tidyfactor-design.skill index 44d2ec26cd829ba9b0f4cf5c7cfc584a003f0fa2..a19cd3fe3349d3cf77d70e280e21ceb5d1ba5b21 100644 GIT binary patch delta 955 zcmW-fd6<@S6o%7GB_^a8G?B_=o0-O>O{Qp@HcCj@vLqs;q%1A!o|I6QrXoxW*@mRP zu{IQA&o-I)RFkcD_`KKsZ(aW2{mr?q^W4vQu5+EgPJMZGoBE`4#*WI$?${#K>>Vp} zy0uKSxJ%IS&3;ag;48Zat<6t#p?Czg#4OClR@fTb;E~uCkHVud2ixH>cq|@=?eTc* zfF1D!JP~v8Bs>{U!A_Wmo$*vW4ZGm!*cH2BcRU00u?L=sXW`j+4xWnzScpZ~6N~XY zEWuuQKK8~w*cba@f4l$(;DuO<191>ugcsvr9D+k}7!JoW9DyTo6pqF*cnMyLV{sf_ zhU4*ayaKPp33wGw#7THHUW3=-b$C5a#vAZPya{i{DR>J`#ar<2DzwqyEX7Udv ze_W9pWqJmVh%zOC^P)^)U{#bUO1Pvk%A^{je>P1?hE(~OxMor?Wt-!&;;?qOAkU-%7&fTZQSkPspdH<6eR5(sA#Esk(H$HYWr#qIgi?)+invcqocX1N%0` e0~4m^HpK-ULXa%xrFQ)rx6Kam?*HPYS^on!*g=2* delta 955 zcmW-gd6?Ey7=|-5S{OtzmZ6xMY)y?)*;>U^Qc0GCEG@ETElU*lBqC#JXkW?FSduSc zL@|~Yq|AKOSo=+Vj{9FOfABk<>w2I2eV^++&tK=%SFUSOpH|`UA^8Puo5k~2ZB=1O zUaIBo^FnRa$dag2Iz?UDA!=P|s?)^-Fc0&w01w3G*aBN(D?A7f#zH&<55>cj_UN8(Xfgh%5scq|@=#dtiPfbFn7o`@%533kAaSc;wSWIP2=#nbR~?2KjD1-oK7 zo`K!4JD!O>uqXDyv+!&@2hYXxus8O>zSs}@;{ZG#2jT^IAy(iZ9E?NoA{>er<1ieK zBk&R&iI?IiybLeLEAUDjjaT6qyc(~;YjG@Ihu7l`cq5L(@i+k|;!QXSZ^m2jR=f>w z$2)K`-ideN-FOe)i}&FaoQn731Nb05gwyb0d<3WC415$HL$DHO;^R0ApTH+^Ha>+< z;~abjtMFNT4xh&ta4uHki}(`G!}+)X7vdsZj7xASF2m)x0$1Y8_zJGVSMfD`9pAv! zSc7lkTlhAi5Ah?c#gB0VeuAIkM%;v-;pbR~U*MPc6@HDI zaSLw6ZTJm-i{IgP{2q7UPW%Duu>rIABmRWDa5pyM&-e@eiofCS_y_L61eJR?H$=LuP_>ulh8MEO%et~{+)#0 hk-eHipOl%YO`&s}Xrzn9nN9zORt3@C_FtHl|38sZPHX@G