fable-engine 1.3.1__py3-none-any.whl
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.
- fable_compressor.py +356 -0
- fable_engine/__init__.py +1 -0
- fable_engine/actions/__init__.py +291 -0
- fable_engine/actions/cas.py +182 -0
- fable_engine/actions/deliberation.py +523 -0
- fable_engine/actions/fleet.py +807 -0
- fable_engine/actions/lifecycle.py +298 -0
- fable_engine/actions/scrapers.py +116 -0
- fable_engine/actions/system3.py +815 -0
- fable_engine/browser.py +824 -0
- fable_engine/cas.py +974 -0
- fable_engine/fable_session.json +510 -0
- fable_engine/guards.py +283 -0
- fable_engine/schema.py +714 -0
- fable_engine/scrapers/__init__.py +32 -0
- fable_engine/scrapers/arxiv.py +115 -0
- fable_engine/scrapers/base.py +386 -0
- fable_engine/scrapers/github.py +129 -0
- fable_engine/scrapers/reddit.py +154 -0
- fable_engine/scrapers/web.py +120 -0
- fable_engine/scrapers/x.py +125 -0
- fable_engine/scrapers/youtube.py +132 -0
- fable_engine/server.py +414 -0
- fable_engine/session.py +1819 -0
- fable_engine/test_server.py +1362 -0
- fable_engine/updater.py +541 -0
- fable_engine-1.3.1.dist-info/LICENSE +22 -0
- fable_engine-1.3.1.dist-info/METADATA +173 -0
- fable_engine-1.3.1.dist-info/RECORD +104 -0
- fable_engine-1.3.1.dist-info/WHEEL +5 -0
- fable_engine-1.3.1.dist-info/entry_points.txt +5 -0
- fable_engine-1.3.1.dist-info/top_level.txt +6 -0
- fable_mode/__init__.py +3 -0
- fable_mode/__main__.py +4 -0
- fable_mode/adapters.py +1014 -0
- fable_mode/installer.py +553 -0
- fable_mode/launcher.py +437 -0
- fable_mode/manifest.py +142 -0
- fable_mode/resources.json +114 -0
- fable_mode/safety.py +103 -0
- fable_mode_entry.py +10 -0
- fable_v2/__init__.py +146 -0
- fable_v2/adapters.py +151 -0
- fable_v2/coder_fleet/__init__.py +100 -0
- fable_v2/coder_fleet/ast_tools.py +158 -0
- fable_v2/coder_fleet/compute.py +199 -0
- fable_v2/coder_fleet/design_engine.py +1316 -0
- fable_v2/coder_fleet/diagnostics.py +293 -0
- fable_v2/coder_fleet/fleet_dispatcher.py +214 -0
- fable_v2/coder_fleet/mock_auditor.py +306 -0
- fable_v2/coder_fleet/mutation.py +216 -0
- fable_v2/coder_fleet/property_oracle.py +260 -0
- fable_v2/coder_fleet/receipt_attestor.py +122 -0
- fable_v2/coder_fleet/red_team_swarm.py +908 -0
- fable_v2/coder_fleet/test_harness.py +198 -0
- fable_v2/coder_fleet/vector_engine.py +1287 -0
- fable_v2/coder_fleet/visual.py +357 -0
- fable_v2/coder_fleet/workspace.py +153 -0
- fable_v2/cortical/__init__.py +20 -0
- fable_v2/cortical/plasticity_engine.py +992 -0
- fable_v2/execution_broker.py +811 -0
- fable_v2/proof_engine.py +1141 -0
- fable_v2/protocol.py +485 -0
- fable_v2/runtime.py +1010 -0
- fable_v2/system3/__init__.py +204 -0
- fable_v2/system3/causal.py +558 -0
- fable_v2/system3/dialectical.py +577 -0
- fable_v2/system3/evolution.py +503 -0
- fable_v2/system3/executive.py +338 -0
- fable_v2/system3/free_energy.py +479 -0
- fable_v2/system3/hyperbolic.py +555 -0
- fable_v2/system3/induction.py +336 -0
- fable_v2/system3/kripke.py +548 -0
- fable_v2/system3/oracle.py +745 -0
- fable_v2/verifiers.py +72 -0
- tests/__init__.py +1 -0
- tests/test_anti_loop_circuit_breaker.py +64 -0
- tests/test_auto_updater.py +407 -0
- tests/test_coder_fleet.py +535 -0
- tests/test_delegation_compiler.py +54 -0
- tests/test_descriptor_boundaries.py +126 -0
- tests/test_design_engine.py +603 -0
- tests/test_epistemic_evidence_validator.py +66 -0
- tests/test_execution_broker.py +233 -0
- tests/test_fable_v2.py +406 -0
- tests/test_fleet_transitions.py +116 -0
- tests/test_fsm_redteam_evolution.py +406 -0
- tests/test_goal_rubric_and_pipeline.py +367 -0
- tests/test_hebbian_plasticity.py +585 -0
- tests/test_packaging_runtime.py +194 -0
- tests/test_proof_engine.py +259 -0
- tests/test_red_team_swarm.py +645 -0
- tests/test_redteam_remediation.py +169 -0
- tests/test_registration_transaction.py +375 -0
- tests/test_requested_regressions.py +467 -0
- tests/test_scrapers.py +370 -0
- tests/test_server_actions.py +93 -0
- tests/test_server_frontier_actions.py +269 -0
- tests/test_server_protocol.py +88 -0
- tests/test_stealth_browser.py +970 -0
- tests/test_system3.py +381 -0
- tests/test_system3_deep_integration.py +385 -0
- tests/test_system3_frontier.py +436 -0
- tests/test_vector_engine.py +608 -0
|
@@ -0,0 +1,1316 @@
|
|
|
1
|
+
"""Fable-Mode Frontier Frontend Design & Anti-Slop Taste Engine.
|
|
2
|
+
|
|
3
|
+
Pure-Python, zero-external-dependency engine ensuring AI slop never enters
|
|
4
|
+
Fable-Mode deliverables and that even simple prompts yield Awwwards-caliber
|
|
5
|
+
digital experiences.
|
|
6
|
+
|
|
7
|
+
Core Subsystems:
|
|
8
|
+
1. DesignDials: Calibrated Variance (1-10), Motion (1-10), and Density (1-10).
|
|
9
|
+
2. AestheticArchetype: 6 Haute Aesthetic Universes (Cyber Obsidian Monolith,
|
|
10
|
+
Haute Editorial Modernism, Swiss Precision Vignelli, Kinetic Spatial HUD,
|
|
11
|
+
Neo-Nordic Warmth, Cold Chromatic Luxury).
|
|
12
|
+
3. DesignTokens: Curated OKLCH colorway math, fluid typography clamp scales,
|
|
13
|
+
variable font pairings, and Newtonian damped harmonic spring presets.
|
|
14
|
+
4. AntiSlopAuditor: Deep AST/regex inspection eradicating purple gradient blobs,
|
|
15
|
+
3-card centered boilerplates, LLM marketing fluff, fake div screenshot windows,
|
|
16
|
+
and viewport instability.
|
|
17
|
+
5. BriefInferenceEngine: Infers page kind, target audience, calibrated dials,
|
|
18
|
+
optimal Haute archetype, and emits the mandatory Design Read Declaration.
|
|
19
|
+
6. AwwwardsScaffoldGenerator: Emits production-ready, zero-slop Tailwind v4
|
|
20
|
+
and semantic HTML/JSX layouts with 7-layer optical depth and asymmetric bento grids.
|
|
21
|
+
7. PreFlightDesignGate: Mechanical 5-point verification gate validating viewport fit,
|
|
22
|
+
typographic descender clearance, invariant locks, WCAG AA contrast, and copy restraint.
|
|
23
|
+
"""
|
|
24
|
+
from __future__ import annotations
|
|
25
|
+
|
|
26
|
+
import math
|
|
27
|
+
import re
|
|
28
|
+
from dataclasses import dataclass, field
|
|
29
|
+
from enum import Enum
|
|
30
|
+
from typing import Any, Dict, List, Optional, Tuple, Union
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
# ==============================================================================
|
|
34
|
+
# 1. THE THREE CALIBRATED DIALS
|
|
35
|
+
# ==============================================================================
|
|
36
|
+
|
|
37
|
+
@dataclass
|
|
38
|
+
class DesignDials:
|
|
39
|
+
"""The 3 Discrete Dials governing layout variance, motion, and visual density (1 - 10 scale).
|
|
40
|
+
|
|
41
|
+
Aesthetic Vector = <DESIGN_VARIANCE, MOTION_INTENSITY, VISUAL_DENSITY>
|
|
42
|
+
- variance: 1 = Predictable Symmetric Grid, 10 = Kinetic Overlaps & Dynamic Asymmetry
|
|
43
|
+
- motion: 1 = Static Subtle Color Transitions, 10 = Cinematic Scroll & Physics
|
|
44
|
+
- density: 1 = Airy Gallery & Expansive Whitespace, 10 = High-Density Telemetry Cockpit
|
|
45
|
+
"""
|
|
46
|
+
|
|
47
|
+
variance: int = 7
|
|
48
|
+
motion: int = 6
|
|
49
|
+
density: int = 4
|
|
50
|
+
|
|
51
|
+
def __post_init__(self) -> None:
|
|
52
|
+
self.variance = max(1, min(10, int(self.variance)))
|
|
53
|
+
self.motion = max(1, min(10, int(self.motion)))
|
|
54
|
+
self.density = max(1, min(10, int(self.density)))
|
|
55
|
+
|
|
56
|
+
def to_dict(self) -> dict[str, int]:
|
|
57
|
+
return {
|
|
58
|
+
"variance": self.variance,
|
|
59
|
+
"motion": self.motion,
|
|
60
|
+
"density": self.density,
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
def vector_str(self) -> str:
|
|
64
|
+
return f"Variance: {self.variance} / Motion: {self.motion} / Density: {self.density}"
|
|
65
|
+
|
|
66
|
+
@classmethod
|
|
67
|
+
def from_dict(cls, d: dict[str, Any]) -> DesignDials:
|
|
68
|
+
return cls(
|
|
69
|
+
variance=int(d.get("variance", 7)),
|
|
70
|
+
motion=int(d.get("motion", 6)),
|
|
71
|
+
density=int(d.get("density", 4)),
|
|
72
|
+
)
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
# ==============================================================================
|
|
76
|
+
# 2. THE 6 HAUTE AESTHETIC ARCHETYPES
|
|
77
|
+
# ==============================================================================
|
|
78
|
+
|
|
79
|
+
class AestheticArchetype(str, Enum):
|
|
80
|
+
"""The 6 Curated Haute Aesthetic Universes eliminating generic AI templates."""
|
|
81
|
+
|
|
82
|
+
CYBER_OBSIDIAN_MONOLITH = "cyber_obsidian_monolith"
|
|
83
|
+
HAUTE_EDITORIAL_MODERNISM = "haute_editorial_modernism"
|
|
84
|
+
SWISS_PRECISION_VIGNELLI = "swiss_precision_vignelli"
|
|
85
|
+
KINETIC_SPATIAL_HUD = "kinetic_spatial_hud"
|
|
86
|
+
NEO_NORDIC_WARMTH = "neo_nordic_warmth"
|
|
87
|
+
COLD_CHROMATIC_LUXURY = "cold_chromatic_luxury"
|
|
88
|
+
|
|
89
|
+
@classmethod
|
|
90
|
+
def from_str(cls, val: Optional[str]) -> Optional[AestheticArchetype]:
|
|
91
|
+
"""Normalize string to matching AestheticArchetype, handling hyphens, spaces, and case."""
|
|
92
|
+
if not val or not isinstance(val, str):
|
|
93
|
+
return None
|
|
94
|
+
normalized = val.strip().lower().replace("-", "_").replace(" ", "_")
|
|
95
|
+
for member in cls:
|
|
96
|
+
if member.value == normalized or member.name.lower() == normalized:
|
|
97
|
+
return member
|
|
98
|
+
return None
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
# ==============================================================================
|
|
102
|
+
# 3. DESIGN TOKENS, FLUID TYPOGRAPHY & SPRING PHYSICS
|
|
103
|
+
# ==============================================================================
|
|
104
|
+
|
|
105
|
+
@dataclass
|
|
106
|
+
class OKLCHColorToken:
|
|
107
|
+
"""Perceptually uniform OKLCH color token with luminance and CSS declaration."""
|
|
108
|
+
|
|
109
|
+
l: float
|
|
110
|
+
c: float
|
|
111
|
+
h: float
|
|
112
|
+
alpha: float = 1.0
|
|
113
|
+
|
|
114
|
+
def to_css(self) -> str:
|
|
115
|
+
if self.alpha < 0.999:
|
|
116
|
+
return f"oklch({self.l:.3f} {self.c:.3f} {self.h:.1f} / {self.alpha:.2f})"
|
|
117
|
+
return f"oklch({self.l:.3f} {self.c:.3f} {self.h:.1f})"
|
|
118
|
+
|
|
119
|
+
@property
|
|
120
|
+
def relative_luminance(self) -> float:
|
|
121
|
+
"""Approximate relative luminance for contrast math."""
|
|
122
|
+
return max(0.0, min(1.0, self.l ** 2.2))
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
def calculate_contrast_ratio(fg: OKLCHColorToken, bg: OKLCHColorToken) -> float:
|
|
126
|
+
"""Calculate standard WCAG relative luminance contrast ratio (1.0 to 21.0)."""
|
|
127
|
+
l1 = max(fg.relative_luminance, bg.relative_luminance)
|
|
128
|
+
l2 = min(fg.relative_luminance, bg.relative_luminance)
|
|
129
|
+
return round((l1 + 0.05) / (l2 + 0.05), 2)
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
def generate_fluid_clamp(min_rem: float, max_rem: float, min_vw: float = 375.0, max_vw: float = 1440.0) -> str:
|
|
133
|
+
"""Compute mathematical fluid CSS clamp(min, preferred, max) without layout thrashing.
|
|
134
|
+
|
|
135
|
+
Formula: clamp(min, slope * 100vw + y_intercept, max)
|
|
136
|
+
"""
|
|
137
|
+
slope = (max_rem - min_rem) / ((max_vw - min_vw) / 16.0)
|
|
138
|
+
y_intercept = min_rem - slope * (min_vw / 16.0)
|
|
139
|
+
return f"clamp({min_rem:.3f}rem, {y_intercept:.3f}rem + {slope * 100:.2f}vw, {max_rem:.3f}rem)"
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
@dataclass
|
|
143
|
+
class SpringPreset:
|
|
144
|
+
"""Newtonian 2nd-order damped harmonic oscillator physics parameters."""
|
|
145
|
+
|
|
146
|
+
name: str
|
|
147
|
+
stiffness: float
|
|
148
|
+
damping: float
|
|
149
|
+
mass: float = 1.0
|
|
150
|
+
zeta: float = 0.85
|
|
151
|
+
description: str = ""
|
|
152
|
+
|
|
153
|
+
def to_dict(self) -> dict[str, Any]:
|
|
154
|
+
return {
|
|
155
|
+
"name": self.name,
|
|
156
|
+
"stiffness": self.stiffness,
|
|
157
|
+
"damping": self.damping,
|
|
158
|
+
"mass": self.mass,
|
|
159
|
+
"zeta": self.zeta,
|
|
160
|
+
"description": self.description,
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
|
|
164
|
+
SPRING_PRESETS: dict[str, SpringPreset] = {
|
|
165
|
+
"snappy": SpringPreset(
|
|
166
|
+
name="snappy",
|
|
167
|
+
stiffness=380.0,
|
|
168
|
+
damping=28.0,
|
|
169
|
+
mass=1.0,
|
|
170
|
+
zeta=0.72,
|
|
171
|
+
description="Snappy micro-interactions: micro-buttons, badges, toggle switches",
|
|
172
|
+
),
|
|
173
|
+
"modal": SpringPreset(
|
|
174
|
+
name="modal",
|
|
175
|
+
stiffness=280.0,
|
|
176
|
+
damping=33.5,
|
|
177
|
+
mass=1.0,
|
|
178
|
+
zeta=1.00,
|
|
179
|
+
description="Critically damped: modal dialogues, drawers, navigation switches (zero overshoot)",
|
|
180
|
+
),
|
|
181
|
+
"velvet": SpringPreset(
|
|
182
|
+
name="velvet",
|
|
183
|
+
stiffness=140.0,
|
|
184
|
+
damping=18.0,
|
|
185
|
+
mass=1.0,
|
|
186
|
+
zeta=0.88,
|
|
187
|
+
description="Liquid velvet float: scroll parallax, cursor follow, layout morphs",
|
|
188
|
+
),
|
|
189
|
+
"magnetic": SpringPreset(
|
|
190
|
+
name="magnetic",
|
|
191
|
+
stiffness=450.0,
|
|
192
|
+
damping=36.0,
|
|
193
|
+
mass=1.2,
|
|
194
|
+
zeta=0.77,
|
|
195
|
+
description="Heavy magnetic snap: drag-and-drop docking, card snapping",
|
|
196
|
+
),
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
|
|
200
|
+
@dataclass
|
|
201
|
+
class HauteDesignTheme:
|
|
202
|
+
"""Comprehensive design system tokens for a Haute Aesthetic Archetype."""
|
|
203
|
+
|
|
204
|
+
archetype: AestheticArchetype
|
|
205
|
+
title: str
|
|
206
|
+
description: str
|
|
207
|
+
dials: DesignDials
|
|
208
|
+
bg_void: OKLCHColorToken
|
|
209
|
+
surface_card: OKLCHColorToken
|
|
210
|
+
surface_elevated: OKLCHColorToken
|
|
211
|
+
border_hairline: OKLCHColorToken
|
|
212
|
+
border_specular: OKLCHColorToken
|
|
213
|
+
text_primary: OKLCHColorToken
|
|
214
|
+
text_muted: OKLCHColorToken
|
|
215
|
+
accent_primary: OKLCHColorToken
|
|
216
|
+
accent_glow: OKLCHColorToken
|
|
217
|
+
font_display: str
|
|
218
|
+
font_body: str
|
|
219
|
+
font_mono: str
|
|
220
|
+
border_radius_scale: str
|
|
221
|
+
spring_preset_name: str = "snappy"
|
|
222
|
+
|
|
223
|
+
def get_fluid_typography_tokens(self) -> dict[str, str]:
|
|
224
|
+
"""Compute fluid typography tokens for this theme."""
|
|
225
|
+
return {
|
|
226
|
+
"--font-display-hero": generate_fluid_clamp(2.75, 6.50),
|
|
227
|
+
"--font-display-h1": generate_fluid_clamp(2.00, 4.25),
|
|
228
|
+
"--font-display-h2": generate_fluid_clamp(1.50, 2.75),
|
|
229
|
+
"--font-heading-h3": generate_fluid_clamp(1.25, 1.875),
|
|
230
|
+
"--font-body-lead": generate_fluid_clamp(1.0625, 1.25),
|
|
231
|
+
"--font-body-base": generate_fluid_clamp(0.9375, 1.0625),
|
|
232
|
+
"--font-caption-sm": generate_fluid_clamp(0.8125, 0.875),
|
|
233
|
+
"--font-mono-telemetry": generate_fluid_clamp(0.6875, 0.8125),
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
def to_tailwind_v4_theme(self) -> str:
|
|
237
|
+
"""Render production-ready Tailwind CSS v4 @theme block with CSS variables."""
|
|
238
|
+
typo = self.get_fluid_typography_tokens()
|
|
239
|
+
spring = SPRING_PRESETS.get(self.spring_preset_name, SPRING_PRESETS["snappy"])
|
|
240
|
+
lines = [
|
|
241
|
+
f"/* Fable Haute Aesthetic: {self.title} */",
|
|
242
|
+
"@theme {",
|
|
243
|
+
f" --color-bg-void: {self.bg_void.to_css()};",
|
|
244
|
+
f" --color-surface-card: {self.surface_card.to_css()};",
|
|
245
|
+
f" --color-surface-elevated: {self.surface_elevated.to_css()};",
|
|
246
|
+
f" --color-border-hairline: {self.border_hairline.to_css()};",
|
|
247
|
+
f" --color-border-specular: {self.border_specular.to_css()};",
|
|
248
|
+
f" --color-text-primary: {self.text_primary.to_css()};",
|
|
249
|
+
f" --color-text-muted: {self.text_muted.to_css()};",
|
|
250
|
+
f" --color-accent-primary: {self.accent_primary.to_css()};",
|
|
251
|
+
f" --color-accent-glow: {self.accent_glow.to_css()};",
|
|
252
|
+
f" --font-family-display: {self.font_display};",
|
|
253
|
+
f" --font-family-body: {self.font_body};",
|
|
254
|
+
f" --font-family-mono: {self.font_mono};",
|
|
255
|
+
f" --radius-scale: {self.border_radius_scale};",
|
|
256
|
+
f" --spring-stiffness: {spring.stiffness};",
|
|
257
|
+
f" --spring-damping: {spring.damping};",
|
|
258
|
+
f" --spring-mass: {spring.mass};",
|
|
259
|
+
]
|
|
260
|
+
for var_name, clamp_val in typo.items():
|
|
261
|
+
lines.append(f" {var_name}: {clamp_val};")
|
|
262
|
+
lines.append("}")
|
|
263
|
+
return "\n".join(lines)
|
|
264
|
+
|
|
265
|
+
def to_dict(self) -> dict[str, Any]:
|
|
266
|
+
contrast = calculate_contrast_ratio(self.text_primary, self.bg_void)
|
|
267
|
+
return {
|
|
268
|
+
"archetype": self.archetype.value,
|
|
269
|
+
"title": self.title,
|
|
270
|
+
"description": self.description,
|
|
271
|
+
"dials": self.dials.to_dict(),
|
|
272
|
+
"palette": {
|
|
273
|
+
"bg_void": self.bg_void.to_css(),
|
|
274
|
+
"surface_card": self.surface_card.to_css(),
|
|
275
|
+
"surface_elevated": self.surface_elevated.to_css(),
|
|
276
|
+
"border_hairline": self.border_hairline.to_css(),
|
|
277
|
+
"border_specular": self.border_specular.to_css(),
|
|
278
|
+
"text_primary": self.text_primary.to_css(),
|
|
279
|
+
"text_muted": self.text_muted.to_css(),
|
|
280
|
+
"accent_primary": self.accent_primary.to_css(),
|
|
281
|
+
"accent_glow": self.accent_glow.to_css(),
|
|
282
|
+
},
|
|
283
|
+
"typography": {
|
|
284
|
+
"font_display": self.font_display,
|
|
285
|
+
"font_body": self.font_body,
|
|
286
|
+
"font_mono": self.font_mono,
|
|
287
|
+
"fluid_scales": self.get_fluid_typography_tokens(),
|
|
288
|
+
},
|
|
289
|
+
"border_radius_scale": self.border_radius_scale,
|
|
290
|
+
"spring_physics": SPRING_PRESETS.get(self.spring_preset_name, SPRING_PRESETS["snappy"]).to_dict(),
|
|
291
|
+
"wcag_aa_contrast": {
|
|
292
|
+
"primary_to_bg_ratio": contrast,
|
|
293
|
+
"meets_wcag_aa": contrast >= 4.5,
|
|
294
|
+
"meets_wcag_aaa": contrast >= 7.0,
|
|
295
|
+
},
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
|
|
299
|
+
# Registry of the 6 Curated Haute Aesthetic Archetypes
|
|
300
|
+
HAUTE_THEMES: dict[AestheticArchetype, HauteDesignTheme] = {
|
|
301
|
+
AestheticArchetype.CYBER_OBSIDIAN_MONOLITH: HauteDesignTheme(
|
|
302
|
+
archetype=AestheticArchetype.CYBER_OBSIDIAN_MONOLITH,
|
|
303
|
+
title="Cyber-Obsidian Monolith",
|
|
304
|
+
description="Dark industrial aerospace, hairline vectors, and high-voltage spectral accents (Teenage Engineering / Avionics).",
|
|
305
|
+
dials=DesignDials(variance=8, motion=7, density=6),
|
|
306
|
+
bg_void=OKLCHColorToken(0.08, 0.02, 270.0),
|
|
307
|
+
surface_card=OKLCHColorToken(0.12, 0.015, 270.0, 0.70),
|
|
308
|
+
surface_elevated=OKLCHColorToken(0.16, 0.02, 270.0, 0.85),
|
|
309
|
+
border_hairline=OKLCHColorToken(1.0, 0.0, 0.0, 0.12),
|
|
310
|
+
border_specular=OKLCHColorToken(1.0, 0.0, 0.0, 0.25),
|
|
311
|
+
text_primary=OKLCHColorToken(0.985, 0.005, 270.0),
|
|
312
|
+
text_muted=OKLCHColorToken(0.68, 0.02, 270.0),
|
|
313
|
+
accent_primary=OKLCHColorToken(0.78, 0.18, 165.0), # Luminescent Cyber Mint / Cyan
|
|
314
|
+
accent_glow=OKLCHColorToken(0.78, 0.18, 165.0, 0.20),
|
|
315
|
+
font_display='"Geist Display", "Cabinet Grotesk", sans-serif',
|
|
316
|
+
font_body='"Geist", sans-serif',
|
|
317
|
+
font_mono='"Geist Mono", "JetBrains Mono", monospace',
|
|
318
|
+
border_radius_scale="rounded-sm",
|
|
319
|
+
spring_preset_name="snappy",
|
|
320
|
+
),
|
|
321
|
+
AestheticArchetype.HAUTE_EDITORIAL_MODERNISM: HauteDesignTheme(
|
|
322
|
+
archetype=AestheticArchetype.HAUTE_EDITORIAL_MODERNISM,
|
|
323
|
+
title="Haute Editorial Modernism",
|
|
324
|
+
description="Asymmetric 1.618 golden-ratio negative space, 0.5px hair rules, and dramatic serif scale (Stripe Press / Literary Journal).",
|
|
325
|
+
dials=DesignDials(variance=9, motion=5, density=3),
|
|
326
|
+
bg_void=OKLCHColorToken(0.975, 0.008, 85.0), # Crisp Bone Paper
|
|
327
|
+
surface_card=OKLCHColorToken(0.995, 0.003, 85.0, 0.95),
|
|
328
|
+
surface_elevated=OKLCHColorToken(1.0, 0.0, 0.0),
|
|
329
|
+
border_hairline=OKLCHColorToken(0.20, 0.01, 60.0, 0.12),
|
|
330
|
+
border_specular=OKLCHColorToken(0.20, 0.01, 60.0, 0.22),
|
|
331
|
+
text_primary=OKLCHColorToken(0.12, 0.015, 60.0), # True Carbon Espresso
|
|
332
|
+
text_muted=OKLCHColorToken(0.48, 0.02, 60.0),
|
|
333
|
+
accent_primary=OKLCHColorToken(0.48, 0.17, 38.0), # Burnt Terracotta / Rust
|
|
334
|
+
accent_glow=OKLCHColorToken(0.48, 0.17, 38.0, 0.15),
|
|
335
|
+
font_display='"PP Editorial New", "Reckless Neue", "Tiempos Headline", serif',
|
|
336
|
+
font_body='"Söhne", "PP Neue Montreal", sans-serif',
|
|
337
|
+
font_mono='"Commit Mono", monospace',
|
|
338
|
+
border_radius_scale="rounded-none",
|
|
339
|
+
spring_preset_name="velvet",
|
|
340
|
+
),
|
|
341
|
+
AestheticArchetype.SWISS_PRECISION_VIGNELLI: HauteDesignTheme(
|
|
342
|
+
archetype=AestheticArchetype.SWISS_PRECISION_VIGNELLI,
|
|
343
|
+
title="Swiss Precision & Vignelli",
|
|
344
|
+
description="Pure mathematical grid, extreme scale contrast, monochrome base + single International Accent (Massimo Vignelli / Braun / Leica).",
|
|
345
|
+
dials=DesignDials(variance=6, motion=3, density=5),
|
|
346
|
+
bg_void=OKLCHColorToken(0.995, 0.0, 0.0), # Pure Architectural White
|
|
347
|
+
surface_card=OKLCHColorToken(0.965, 0.0, 0.0),
|
|
348
|
+
surface_elevated=OKLCHColorToken(1.0, 0.0, 0.0),
|
|
349
|
+
border_hairline=OKLCHColorToken(0.0, 0.0, 0.0, 0.14),
|
|
350
|
+
border_specular=OKLCHColorToken(0.0, 0.0, 0.0, 0.28),
|
|
351
|
+
text_primary=OKLCHColorToken(0.08, 0.0, 0.0), # Deep Pitch Black
|
|
352
|
+
text_muted=OKLCHColorToken(0.44, 0.0, 0.0),
|
|
353
|
+
accent_primary=OKLCHColorToken(0.55, 0.24, 25.0), # International Signal Red
|
|
354
|
+
accent_glow=OKLCHColorToken(0.55, 0.24, 25.0, 0.12),
|
|
355
|
+
font_display='"Neue Haas Grotesk", "Helvetica Neue", sans-serif',
|
|
356
|
+
font_body='"Neue Haas Grotesk", "Helvetica Neue", sans-serif',
|
|
357
|
+
font_mono='"Diatype Mono", monospace',
|
|
358
|
+
border_radius_scale="rounded-none",
|
|
359
|
+
spring_preset_name="modal",
|
|
360
|
+
),
|
|
361
|
+
AestheticArchetype.KINETIC_SPATIAL_HUD: HauteDesignTheme(
|
|
362
|
+
archetype=AestheticArchetype.KINETIC_SPATIAL_HUD,
|
|
363
|
+
title="Kinetic Spatial HUD",
|
|
364
|
+
description="Containerless telemetry ribbons, sub-pixel badge pills, scanlines, and live telemetry feeds (Raycast / Developer Console).",
|
|
365
|
+
dials=DesignDials(variance=7, motion=8, density=8),
|
|
366
|
+
bg_void=OKLCHColorToken(0.06, 0.015, 250.0), # Deep Space Void
|
|
367
|
+
surface_card=OKLCHColorToken(0.10, 0.02, 250.0, 0.65),
|
|
368
|
+
surface_elevated=OKLCHColorToken(0.14, 0.025, 250.0, 0.80),
|
|
369
|
+
border_hairline=OKLCHColorToken(1.0, 0.0, 0.0, 0.10),
|
|
370
|
+
border_specular=OKLCHColorToken(1.0, 0.0, 0.0, 0.20),
|
|
371
|
+
text_primary=OKLCHColorToken(0.97, 0.005, 250.0),
|
|
372
|
+
text_muted=OKLCHColorToken(0.60, 0.02, 250.0),
|
|
373
|
+
accent_primary=OKLCHColorToken(0.72, 0.22, 145.0), # High-Voltage Phosphor Emerald
|
|
374
|
+
accent_glow=OKLCHColorToken(0.72, 0.22, 145.0, 0.25),
|
|
375
|
+
font_display='"Geist Mono", "JetBrains Mono", monospace',
|
|
376
|
+
font_body='"Geist", sans-serif',
|
|
377
|
+
font_mono='"Geist Mono", monospace',
|
|
378
|
+
border_radius_scale="rounded-md",
|
|
379
|
+
spring_preset_name="magnetic",
|
|
380
|
+
),
|
|
381
|
+
AestheticArchetype.NEO_NORDIC_WARMTH: HauteDesignTheme(
|
|
382
|
+
archetype=AestheticArchetype.NEO_NORDIC_WARMTH,
|
|
383
|
+
title="Neo-Nordic Tactile Warmth",
|
|
384
|
+
description="Alpine spruce, sand bone, smooth pebble contours, and organic tactile warmth (Bang & Olufsen / Alvar Aalto).",
|
|
385
|
+
dials=DesignDials(variance=7, motion=4, density=4),
|
|
386
|
+
bg_void=OKLCHColorToken(0.975, 0.008, 140.0), # Bone Sand
|
|
387
|
+
surface_card=OKLCHColorToken(0.94, 0.012, 140.0),
|
|
388
|
+
surface_elevated=OKLCHColorToken(0.99, 0.005, 140.0),
|
|
389
|
+
border_hairline=OKLCHColorToken(0.35, 0.05, 150.0, 0.12),
|
|
390
|
+
border_specular=OKLCHColorToken(0.35, 0.05, 150.0, 0.22),
|
|
391
|
+
text_primary=OKLCHColorToken(0.16, 0.03, 150.0), # Deep Forest Umber
|
|
392
|
+
text_muted=OKLCHColorToken(0.48, 0.04, 150.0),
|
|
393
|
+
accent_primary=OKLCHColorToken(0.38, 0.09, 150.0), # Alpine Spruce
|
|
394
|
+
accent_glow=OKLCHColorToken(0.38, 0.09, 150.0, 0.15),
|
|
395
|
+
font_display='"Satoshi", "Cabinet Grotesk", sans-serif',
|
|
396
|
+
font_body='"Satoshi", sans-serif',
|
|
397
|
+
font_mono='"Commit Mono", monospace',
|
|
398
|
+
border_radius_scale="rounded-3xl",
|
|
399
|
+
spring_preset_name="velvet",
|
|
400
|
+
),
|
|
401
|
+
AestheticArchetype.COLD_CHROMATIC_LUXURY: HauteDesignTheme(
|
|
402
|
+
archetype=AestheticArchetype.COLD_CHROMATIC_LUXURY,
|
|
403
|
+
title="Cold Chromatic Luxury",
|
|
404
|
+
description="Silver-grey chrome, true off-black, hairline borders, and ultra-crisp sans display (Balenciaga / High-End Hardware).",
|
|
405
|
+
dials=DesignDials(variance=8, motion=5, density=3),
|
|
406
|
+
bg_void=OKLCHColorToken(0.985, 0.002, 240.0), # Silver White
|
|
407
|
+
surface_card=OKLCHColorToken(0.93, 0.004, 240.0),
|
|
408
|
+
surface_elevated=OKLCHColorToken(1.0, 0.0, 0.0),
|
|
409
|
+
border_hairline=OKLCHColorToken(0.14, 0.01, 240.0, 0.14),
|
|
410
|
+
border_specular=OKLCHColorToken(0.14, 0.01, 240.0, 0.28),
|
|
411
|
+
text_primary=OKLCHColorToken(0.12, 0.01, 240.0), # Smoked Charcoal
|
|
412
|
+
text_muted=OKLCHColorToken(0.46, 0.01, 240.0),
|
|
413
|
+
accent_primary=OKLCHColorToken(0.52, 0.22, 255.0), # High-Voltage Pure Cobalt
|
|
414
|
+
accent_glow=OKLCHColorToken(0.52, 0.22, 255.0, 0.20),
|
|
415
|
+
font_display='"ABC Diatype", "Söhne Breit", sans-serif',
|
|
416
|
+
font_body='"ABC Diatype", sans-serif',
|
|
417
|
+
font_mono='"Commit Mono", monospace',
|
|
418
|
+
border_radius_scale="rounded-sm",
|
|
419
|
+
spring_preset_name="snappy",
|
|
420
|
+
),
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
|
|
424
|
+
# ==============================================================================
|
|
425
|
+
# 4. THE ANTI-SLOP AUDITOR
|
|
426
|
+
# ==============================================================================
|
|
427
|
+
|
|
428
|
+
@dataclass
|
|
429
|
+
class SlopViolation:
|
|
430
|
+
"""An identified AI slop violation with exact rule, severity, and prescribed remedy."""
|
|
431
|
+
|
|
432
|
+
rule_id: str
|
|
433
|
+
category: str
|
|
434
|
+
message: str
|
|
435
|
+
severity: str # "FATAL", "HIGH", "MEDIUM"
|
|
436
|
+
snippet: str
|
|
437
|
+
line_number: Optional[int]
|
|
438
|
+
remedy: str
|
|
439
|
+
|
|
440
|
+
def to_dict(self) -> dict[str, Any]:
|
|
441
|
+
return {
|
|
442
|
+
"rule_id": self.rule_id,
|
|
443
|
+
"category": self.category,
|
|
444
|
+
"message": self.message,
|
|
445
|
+
"severity": self.severity,
|
|
446
|
+
"snippet": self.snippet,
|
|
447
|
+
"line_number": self.line_number,
|
|
448
|
+
"remedy": self.remedy,
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
|
|
452
|
+
class AntiSlopAuditor:
|
|
453
|
+
"""Rigorous mechanical auditor hunting and eradicating all forms of AI slop in code."""
|
|
454
|
+
|
|
455
|
+
# Banned LLM marker phrases
|
|
456
|
+
_BANNED_LLM_WORDS = [
|
|
457
|
+
(r"\bsupercharge\b", "Banned buzzword: 'supercharge'"),
|
|
458
|
+
(r"\bunleash\b", "Banned buzzword: 'unleash'"),
|
|
459
|
+
(r"\bnext-gen(?:\s+ai)?\b", "Banned buzzword: 'next-gen [ai]'"),
|
|
460
|
+
(r"\bdelve\s+into\b", "Banned phrase: 'delve into'"),
|
|
461
|
+
(r"\bseamlessly\s+(?:elevate|integrate|transform)\b", "Banned phrase: 'seamlessly [verb]'"),
|
|
462
|
+
(r"\bvisionary\s+craftsmanship\b", "Banned phrase: 'visionary craftsmanship'"),
|
|
463
|
+
(r"\bgame-changing\b", "Banned buzzword: 'game-changing'"),
|
|
464
|
+
(r"\brevolutionize\b", "Banned buzzword: 'revolutionize'"),
|
|
465
|
+
(r"\bstreamline\s+your\s+workflow\b", "Banned phrase: 'streamline your workflow'"),
|
|
466
|
+
(r"\belevate\s+your\s+experience\b", "Banned phrase: 'elevate your experience'"),
|
|
467
|
+
(r"\bin\s+today's\s+(?:fast-paced|rapidly\s+evolving|modern)\s+world\b", "Banned cliché: 'in today\\'s fast-paced world'"),
|
|
468
|
+
(r"\bdive\s+deep(?:\s+into)?\b", "Banned cliché: 'dive deep'"),
|
|
469
|
+
(r"\bunlock\s+(?:the\s+)?potential\b", "Banned cliché: 'unlock [the] potential'"),
|
|
470
|
+
(r"\bempower(?:ing)?\s+(?:your|teams?|users?)\b", "Banned buzzword: 'empower [teams/users]'"),
|
|
471
|
+
(r"\bseamless\s+integration\b", "Banned cliché: 'seamless integration'"),
|
|
472
|
+
(r"\bparadigm\s+shift\b", "Banned buzzword: 'paradigm shift'"),
|
|
473
|
+
(r"\btestament\s+to\b", "Banned cliché: 'testament to'"),
|
|
474
|
+
(r"\bharness\s+(?:the\s+)?power\b", "Banned cliché: 'harness the power'"),
|
|
475
|
+
(r"\bat\s+your\s+fingertips\b", "Banned cliché: 'at your fingertips'"),
|
|
476
|
+
(r"\btake\s+your\s+.*?\s+to\s+the\s+next\s+level\b", "Banned cliché: 'take ... to the next level'"),
|
|
477
|
+
(r"\bstate-of-the-art\b", "Banned buzzword: 'state-of-the-art'"),
|
|
478
|
+
(r"\bcutting-edge\b", "Banned buzzword: 'cutting-edge'"),
|
|
479
|
+
(r"\bcrafted\s+with\s+(?:passion|care)\b", "Banned cliché: 'crafted with passion/care'"),
|
|
480
|
+
]
|
|
481
|
+
|
|
482
|
+
# Banned purple/violet glowing gradients (including text gradients, reverse orders, and linear/radial hexes)
|
|
483
|
+
_PURPLE_GRADIENT_PATTERNS = [
|
|
484
|
+
re.compile(
|
|
485
|
+
r"from-(?:purple|violet|fuchsia|indigo)-[4-7]00\s+(?:(?:via-[a-z]+-[4-7]00\s+)?to-(?:indigo|pink|blue|violet|purple|fuchsia)-[4-7]00|"
|
|
486
|
+
r"to-(?:indigo|pink|blue|violet|purple|fuchsia)-[4-7]00)",
|
|
487
|
+
re.IGNORECASE,
|
|
488
|
+
),
|
|
489
|
+
re.compile(
|
|
490
|
+
r"from-(?:pink|blue|indigo)-[4-7]00\s+(?:via-[a-z]+-[4-7]00\s+)?to-(?:purple|violet|fuchsia)-[4-7]00",
|
|
491
|
+
re.IGNORECASE,
|
|
492
|
+
),
|
|
493
|
+
re.compile(
|
|
494
|
+
r"bg-gradient-to-(?:tr|r|br|t|b|l|tl|bl)\s+from-(?:purple|violet|fuchsia)-\d+.*?(?:blur-[23]xl|bg-clip-text)",
|
|
495
|
+
re.IGNORECASE,
|
|
496
|
+
),
|
|
497
|
+
re.compile(
|
|
498
|
+
r"(?:radial|linear)-gradient\([^)]*#(?:8b5cf6|a855f7|7c3aed|6366f1|9333ea|c084fc|d946ef)",
|
|
499
|
+
re.IGNORECASE,
|
|
500
|
+
),
|
|
501
|
+
re.compile(
|
|
502
|
+
r"(?:radial|linear)-gradient\([^)]*(?:rgb\(\s*139\s*,\s*92\s*,\s*246|rgb\(\s*168\s*,\s*85\s*,\s*247|rgb\(\s*124\s*,\s*58\s*,\s*237|rgb\(\s*99\s*,\s*102\s*,\s*241)",
|
|
503
|
+
re.IGNORECASE,
|
|
504
|
+
),
|
|
505
|
+
]
|
|
506
|
+
|
|
507
|
+
# Banned fake div screenshot windows (macOS 3-dot window bars in any class order)
|
|
508
|
+
_DIV_DOTS_PATTERN = re.compile(
|
|
509
|
+
r"(?:<(?:span|div)[^>]*\b(?:bg-red-[456]00|bg-\[#ff5f56\]|bg-red-500)\b[^>]*>.*?<(?:span|div)[^>]*\b(?:bg-(?:yellow|amber)-[456]00|bg-\[#ffbd2e\]|bg-yellow-500)\b[^>]*>.*?<(?:span|div)[^>]*\b(?:bg-(?:green|emerald)-[456]00|bg-\[#27c93f\]|bg-green-500)\b[^>]*>|"
|
|
510
|
+
r"w-[23](?:\.5)?\s+h-[23](?:\.5)?\s+rounded-full\s+bg-red-500.*?w-[23](?:\.5)?\s+h-[23](?:\.5)?\s+rounded-full\s+bg-yellow-500|"
|
|
511
|
+
r"bg-red-[45]00.*?bg-yellow-[45]00.*?bg-green-[45]00)",
|
|
512
|
+
re.IGNORECASE | re.DOTALL,
|
|
513
|
+
)
|
|
514
|
+
|
|
515
|
+
# Centered 3-card boilerplate detector (on grid container or across 3 cards)
|
|
516
|
+
_THREE_CARD_CENTERED_PATTERN = re.compile(
|
|
517
|
+
r"(?:grid-cols-1\s+(?:[a-z0-9:-]+\s+)*(?:md|lg|sm|xl):grid-cols-3|grid-cols-3)[^>]*\btext-center\b|"
|
|
518
|
+
r"(?:grid-cols-1\s+(?:[a-z0-9:-]+\s+)*(?:md|lg|sm|xl):grid-cols-3|grid-cols-3).*?text-center.*?text-center.*?text-center",
|
|
519
|
+
re.IGNORECASE | re.DOTALL,
|
|
520
|
+
)
|
|
521
|
+
|
|
522
|
+
# Viewport instability: h-screen instead of min-h-[100dvh]
|
|
523
|
+
_H_SCREEN_PATTERN = re.compile(r"\bh-screen\b|height:\s*100vh\b", re.IGNORECASE)
|
|
524
|
+
|
|
525
|
+
# Default Inter / Arial crutch
|
|
526
|
+
_DEFAULT_FONT_PATTERN = re.compile(r'font-family:\s*(?:Inter|Arial|sans-serif)\s*[,;]', re.IGNORECASE)
|
|
527
|
+
|
|
528
|
+
# Generic rounded icon circle containers
|
|
529
|
+
_ICON_CIRCLE_PATTERNS = [
|
|
530
|
+
re.compile(
|
|
531
|
+
r"(?:w-[12]\d\s+h-[12]\d|h-[12]\d\s+w-[12]\d)\s+rounded-full\s+bg-(?:blue|indigo|purple|emerald|teal|cyan|amber|rose)-100.*?flex\s+items-center\s+justify-center",
|
|
532
|
+
re.IGNORECASE | re.DOTALL,
|
|
533
|
+
),
|
|
534
|
+
re.compile(
|
|
535
|
+
r"rounded-full\s+bg-(?:blue|indigo|purple|emerald|cyan|amber|rose)-100.*?text-(?:blue|indigo|purple|emerald|cyan|amber|rose)-600",
|
|
536
|
+
re.IGNORECASE | re.DOTALL,
|
|
537
|
+
),
|
|
538
|
+
]
|
|
539
|
+
|
|
540
|
+
# Interactive elements pattern for focus accessibility verification
|
|
541
|
+
_INTERACTIVE_ELEMENT_PATTERN = re.compile(
|
|
542
|
+
r"<(?:button|a|input|select|textarea)\b[^>]*class=[\"']([^\"']*)[\"'][^>]*>",
|
|
543
|
+
re.IGNORECASE,
|
|
544
|
+
)
|
|
545
|
+
|
|
546
|
+
# Layout thrashing transitions on layout geometry
|
|
547
|
+
_LAYOUT_THRASHING_PATTERN = re.compile(
|
|
548
|
+
r"transition:\s*[^;]*(?:width|height|margin|padding|top|left)\b",
|
|
549
|
+
re.IGNORECASE,
|
|
550
|
+
)
|
|
551
|
+
|
|
552
|
+
def audit_code(self, code: str, file_path: str = "") -> dict[str, Any]:
|
|
553
|
+
"""Perform exhaustive static scan of frontend code for AI slop anti-patterns."""
|
|
554
|
+
if not code or not code.strip():
|
|
555
|
+
return {
|
|
556
|
+
"clean": True,
|
|
557
|
+
"score": 1.0,
|
|
558
|
+
"violations": [],
|
|
559
|
+
"recommendations": ["No code provided to audit."],
|
|
560
|
+
}
|
|
561
|
+
|
|
562
|
+
violations: list[SlopViolation] = []
|
|
563
|
+
lines = code.splitlines()
|
|
564
|
+
|
|
565
|
+
# 1. Check Purple Gradient Slop
|
|
566
|
+
for pat in self._PURPLE_GRADIENT_PATTERNS:
|
|
567
|
+
for match in pat.finditer(code):
|
|
568
|
+
snippet = match.group(0)[:60]
|
|
569
|
+
line_no = code[:match.start()].count("\n") + 1
|
|
570
|
+
violations.append(
|
|
571
|
+
SlopViolation(
|
|
572
|
+
rule_id="ANTI_SLOP_01_PURPLE_GRADIENT",
|
|
573
|
+
category="Color Calibration",
|
|
574
|
+
message="Generic AI purple/violet glowing gradient blob detected.",
|
|
575
|
+
severity="FATAL",
|
|
576
|
+
snippet=snippet,
|
|
577
|
+
line_number=line_no,
|
|
578
|
+
remedy="Replace purple blobs with single curated OKLCH accent on neutral void base.",
|
|
579
|
+
)
|
|
580
|
+
)
|
|
581
|
+
|
|
582
|
+
# 2. Check Banned LLM Marketing Buzzwords
|
|
583
|
+
for pat_str, desc in self._BANNED_LLM_WORDS:
|
|
584
|
+
p = re.compile(pat_str, re.IGNORECASE)
|
|
585
|
+
for idx, line in enumerate(lines, 1):
|
|
586
|
+
match = p.search(line)
|
|
587
|
+
if match:
|
|
588
|
+
violations.append(
|
|
589
|
+
SlopViolation(
|
|
590
|
+
rule_id="ANTI_SLOP_02_LLM_BUZZWORD",
|
|
591
|
+
category="Copywriting Polish",
|
|
592
|
+
message=f"{desc} detected in rendered text.",
|
|
593
|
+
severity="HIGH",
|
|
594
|
+
snippet=line.strip()[:80],
|
|
595
|
+
line_number=idx,
|
|
596
|
+
remedy="Replace generic buzzwords with concrete functional telemetry and measurable engineering claims.",
|
|
597
|
+
)
|
|
598
|
+
)
|
|
599
|
+
|
|
600
|
+
# 3. Check Fake Div Screenshot Mockups (macOS 3-dot window bars)
|
|
601
|
+
match_dots = self._DIV_DOTS_PATTERN.search(code)
|
|
602
|
+
if match_dots:
|
|
603
|
+
line_no = code[:match_dots.start()].count("\n") + 1
|
|
604
|
+
violations.append(
|
|
605
|
+
SlopViolation(
|
|
606
|
+
rule_id="ANTI_SLOP_03_DIV_SCREENSHOT_MOCKUP",
|
|
607
|
+
category="Visual Assets & Materiality",
|
|
608
|
+
message="Banned fake software preview window rendered with div bars and 3 colored circle dots.",
|
|
609
|
+
severity="FATAL",
|
|
610
|
+
snippet=match_dots.group(0)[:80].replace("\n", " "),
|
|
611
|
+
line_number=line_no,
|
|
612
|
+
remedy="Use authentic component sandboxes or photorealistic product imagery; never render fake macOS dots.",
|
|
613
|
+
)
|
|
614
|
+
)
|
|
615
|
+
|
|
616
|
+
# 4. Check Centered 3-Card Boilerplate
|
|
617
|
+
match_3card = self._THREE_CARD_CENTERED_PATTERN.search(code)
|
|
618
|
+
if match_3card:
|
|
619
|
+
line_no = code[:match_3card.start()].count("\n") + 1
|
|
620
|
+
violations.append(
|
|
621
|
+
SlopViolation(
|
|
622
|
+
rule_id="ANTI_SLOP_04_CENTERED_THREE_CARD",
|
|
623
|
+
category="Layout Diversity",
|
|
624
|
+
message="Banned centered 3-card equal boilerplate detected.",
|
|
625
|
+
severity="HIGH",
|
|
626
|
+
snippet=match_3card.group(0)[:80].replace("\n", " "),
|
|
627
|
+
line_number=line_no,
|
|
628
|
+
remedy="Replace with dynamic asymmetric Bento Grid (mixed spans 2x2, 2x1, 1x1, contrasting surface treatments).",
|
|
629
|
+
)
|
|
630
|
+
)
|
|
631
|
+
|
|
632
|
+
# 5. Check Viewport Instability (h-screen)
|
|
633
|
+
for idx, line in enumerate(lines, 1):
|
|
634
|
+
if self._H_SCREEN_PATTERN.search(line):
|
|
635
|
+
violations.append(
|
|
636
|
+
SlopViolation(
|
|
637
|
+
rule_id="ANTI_SLOP_05_VIEWPORT_INSTABILITY",
|
|
638
|
+
category="Viewport Mechanics",
|
|
639
|
+
message="Banned 'h-screen' causes mobile address-bar resize jumping.",
|
|
640
|
+
severity="MEDIUM",
|
|
641
|
+
snippet=line.strip()[:80],
|
|
642
|
+
line_number=idx,
|
|
643
|
+
remedy="Replace 'h-screen' with 'min-h-[100dvh]' for stable viewport sizing across mobile and desktop.",
|
|
644
|
+
)
|
|
645
|
+
)
|
|
646
|
+
|
|
647
|
+
# 6. Check Eyebrow Overuse (> 1 per 3 sections)
|
|
648
|
+
eyebrow_matches = re.findall(
|
|
649
|
+
r"(?:tracking-wid(?:er|est)\s+(?:[^\s>]+\s+)*uppercase|uppercase\s+(?:[^\s>]+\s+)*tracking-wid(?:er|est)|data-eyebrow)",
|
|
650
|
+
code,
|
|
651
|
+
re.IGNORECASE,
|
|
652
|
+
)
|
|
653
|
+
section_count = max(1, len(re.findall(r"<(?:section|header|footer|main|div\s+(?:id|class)=[\"'][^\"']*(?:section|container|hero|bento|feature))", code, re.IGNORECASE)))
|
|
654
|
+
max_allowed_eyebrows = max(1, math.ceil(section_count / 3))
|
|
655
|
+
if len(eyebrow_matches) > max_allowed_eyebrows and len(eyebrow_matches) > 2:
|
|
656
|
+
violations.append(
|
|
657
|
+
SlopViolation(
|
|
658
|
+
rule_id="ANTI_SLOP_06_EYEBROW_OVERLOAD",
|
|
659
|
+
category="Typographic Discipline",
|
|
660
|
+
message=f"Eyebrow overload: found {len(eyebrow_matches)} uppercase tracking eyebrows across {section_count} sections (max allowed: {max_allowed_eyebrows}).",
|
|
661
|
+
severity="MEDIUM",
|
|
662
|
+
snippet=eyebrow_matches[0][:60],
|
|
663
|
+
line_number=None,
|
|
664
|
+
remedy="Limit uppercase tracking eyebrows to at most 1 per 3 sections to prevent template fatigue.",
|
|
665
|
+
)
|
|
666
|
+
)
|
|
667
|
+
|
|
668
|
+
# 7. Check Generic Icon Circle Blobs
|
|
669
|
+
for pat in self._ICON_CIRCLE_PATTERNS:
|
|
670
|
+
match_icon = pat.search(code)
|
|
671
|
+
if match_icon:
|
|
672
|
+
line_no = code[:match_icon.start()].count("\n") + 1
|
|
673
|
+
violations.append(
|
|
674
|
+
SlopViolation(
|
|
675
|
+
rule_id="ANTI_SLOP_07_ICON_CIRCLE_BLOB",
|
|
676
|
+
category="Visual Diversity & Iconography",
|
|
677
|
+
message="Generic AI colored circle icon blob detected.",
|
|
678
|
+
severity="HIGH",
|
|
679
|
+
snippet=match_icon.group(0)[:80].replace("\n", " "),
|
|
680
|
+
line_number=line_no,
|
|
681
|
+
remedy="Replace generic colored circle icon blobs with bespoke SVG wire glyphs, monochrome telemetry pills, or containerless optical icons.",
|
|
682
|
+
)
|
|
683
|
+
)
|
|
684
|
+
break
|
|
685
|
+
|
|
686
|
+
# 8. Check Naked outline-none removing accessibility (order-independent)
|
|
687
|
+
for match_elem in self._INTERACTIVE_ELEMENT_PATTERN.finditer(code):
|
|
688
|
+
class_str = match_elem.group(1)
|
|
689
|
+
if re.search(r"\b(?:focus:)?outline-none\b", class_str, re.IGNORECASE):
|
|
690
|
+
if not re.search(r"\bfocus-visible:", class_str, re.IGNORECASE):
|
|
691
|
+
line_no = code[:match_elem.start()].count("\n") + 1
|
|
692
|
+
violations.append(
|
|
693
|
+
SlopViolation(
|
|
694
|
+
rule_id="ANTI_SLOP_08_FOCUS_OUTLINE_REMOVAL",
|
|
695
|
+
category="Accessibility (WCAG 2.2 AAA)",
|
|
696
|
+
message="Interactive element removes outline with 'outline-none' without accessible 'focus-visible:' state.",
|
|
697
|
+
severity="HIGH",
|
|
698
|
+
snippet=match_elem.group(0)[:80].replace("\n", " "),
|
|
699
|
+
line_number=line_no,
|
|
700
|
+
remedy="Never remove focus outlines with 'outline-none' without providing accessible 'focus-visible:ring-2' keyboard navigation focus states.",
|
|
701
|
+
)
|
|
702
|
+
)
|
|
703
|
+
break
|
|
704
|
+
|
|
705
|
+
# 9. Check Layout Thrashing Transitions
|
|
706
|
+
match_thrash = self._LAYOUT_THRASHING_PATTERN.search(code)
|
|
707
|
+
if match_thrash:
|
|
708
|
+
line_no = code[:match_thrash.start()].count("\n") + 1
|
|
709
|
+
violations.append(
|
|
710
|
+
SlopViolation(
|
|
711
|
+
rule_id="ANTI_SLOP_09_LAYOUT_THRASHING",
|
|
712
|
+
category="Motion Performance",
|
|
713
|
+
message="CSS transition animates layout geometry properties (width, height, margin, padding, top, left) causing GPU stall.",
|
|
714
|
+
severity="MEDIUM",
|
|
715
|
+
snippet=match_thrash.group(0)[:80].replace("\n", " "),
|
|
716
|
+
line_number=line_no,
|
|
717
|
+
remedy="Animate only composite properties (transform and opacity) using GPU acceleration; avoid animating layout dimensions.",
|
|
718
|
+
)
|
|
719
|
+
)
|
|
720
|
+
|
|
721
|
+
# 10. Check Unstyled Generic Font Crutches (Antibody 3: ab_design_inter_font_crutch)
|
|
722
|
+
has_font_sans_crutch = bool(re.search(r"<(?:body|html|div\s+id=[\"'](?:root|app)[\"'])[^>]*class=[\"'][^\"']*\bfont-sans\b(?![^\"']*\b(?:font-\[var|font-display|font-mono))", code, re.IGNORECASE))
|
|
723
|
+
has_raw_font_family = bool(re.search(r'font-family:\s*(?:Inter|Arial|sans-serif)\s*[,;](?![^;]*var\()', code, re.IGNORECASE))
|
|
724
|
+
has_display_tokens = any(kw in code for kw in ["--font-family-display", "font-[var(", "PP Editorial", "Geist", "Satoshi", "Neue Haas", "ABC Diatype", "Cabinet Grotesk", "Reckless"])
|
|
725
|
+
if (has_font_sans_crutch or has_raw_font_family) and not has_display_tokens:
|
|
726
|
+
violations.append(
|
|
727
|
+
SlopViolation(
|
|
728
|
+
rule_id="ANTI_SLOP_10_DEFAULT_FONT_CRUTCH",
|
|
729
|
+
category="Typographic Discipline",
|
|
730
|
+
message="Default unstyled 'font-sans' or generic Arial/Inter crutch used without curated display pairing.",
|
|
731
|
+
severity="MEDIUM",
|
|
732
|
+
snippet=(code[:80] if has_font_sans_crutch else "font-family: Arial/Inter"),
|
|
733
|
+
line_number=None,
|
|
734
|
+
remedy="Pair curated display typefaces (Geist Display, PP Editorial New, Neue Haas Grotesk, Satoshi) with body sans and monospace telemetry.",
|
|
735
|
+
)
|
|
736
|
+
)
|
|
737
|
+
|
|
738
|
+
# 11. Check React Server Component Motion Leak (Antibody 7: ab_design_rsc_motion_leak)
|
|
739
|
+
if ("motion/react" in code or "framer-motion" in code or "useScroll" in code or "useMotionValue" in code) and ("use client" not in code):
|
|
740
|
+
if file_path.endswith((".tsx", ".jsx")) or "export default" in code or "return (" in code:
|
|
741
|
+
violations.append(
|
|
742
|
+
SlopViolation(
|
|
743
|
+
rule_id="ANTI_SLOP_11_RSC_MOTION_LEAK",
|
|
744
|
+
category="React Server Component Boundary",
|
|
745
|
+
message="Spring motion hooks imported without 'use client' directive, causing Next.js SSR hydration crash.",
|
|
746
|
+
severity="HIGH",
|
|
747
|
+
snippet="import ... from 'motion/react' without 'use client'",
|
|
748
|
+
line_number=1,
|
|
749
|
+
remedy="Add 'use client' at top of file or isolate interactive motion into dedicated client leaf components.",
|
|
750
|
+
)
|
|
751
|
+
)
|
|
752
|
+
|
|
753
|
+
# 12. Check Low-Contrast Gray Text (Antibody 8: ab_design_contrast_sub_ratio_gray)
|
|
754
|
+
low_contrast_match = re.search(
|
|
755
|
+
r"class=[\"'][^\"']*\b(?:bg-white|bg-zinc-100|bg-gray-100|bg-neutral-100)\b[^\"']*\btext-(?:zinc|gray|neutral|slate)-[34]00\b|"
|
|
756
|
+
r"class=[\"'][^\"']*\btext-(?:zinc|gray|neutral|slate)-[34]00\b[^\"']*\b(?:bg-white|bg-zinc-100|bg-gray-100|bg-neutral-100)\b",
|
|
757
|
+
code,
|
|
758
|
+
re.IGNORECASE,
|
|
759
|
+
)
|
|
760
|
+
if low_contrast_match:
|
|
761
|
+
line_no = code[:low_contrast_match.start()].count("\n") + 1
|
|
762
|
+
violations.append(
|
|
763
|
+
SlopViolation(
|
|
764
|
+
rule_id="ANTI_SLOP_12_LOW_CONTRAST_TEXT",
|
|
765
|
+
category="Accessibility (WCAG 2.2 AA)",
|
|
766
|
+
message="Low-contrast text (contrast < 4.5:1) detected on light background (e.g. text-zinc-400 on bg-white/zinc-100).",
|
|
767
|
+
severity="HIGH",
|
|
768
|
+
snippet=low_contrast_match.group(0)[:80].replace("\n", " "),
|
|
769
|
+
line_number=line_no,
|
|
770
|
+
remedy="Validate all text against WCAG AA >= 4.5:1 contrast. Use text-zinc-600/700 or darker for body text on light backgrounds.",
|
|
771
|
+
)
|
|
772
|
+
)
|
|
773
|
+
|
|
774
|
+
# 9. Check Layout Thrashing Transitions
|
|
775
|
+
match_thrash = self._LAYOUT_THRASHING_PATTERN.search(code)
|
|
776
|
+
if match_thrash:
|
|
777
|
+
line_no = code[:match_thrash.start()].count("\n") + 1
|
|
778
|
+
violations.append(
|
|
779
|
+
SlopViolation(
|
|
780
|
+
rule_id="ANTI_SLOP_09_LAYOUT_THRASHING",
|
|
781
|
+
category="Motion Performance",
|
|
782
|
+
message="CSS transition animates layout geometry properties (width, height, margin, padding, top, left) causing GPU stall.",
|
|
783
|
+
severity="MEDIUM",
|
|
784
|
+
snippet=match_thrash.group(0)[:80].replace("\n", " "),
|
|
785
|
+
line_number=line_no,
|
|
786
|
+
remedy="Animate only composite properties (transform and opacity) using GPU acceleration; avoid animating layout dimensions.",
|
|
787
|
+
)
|
|
788
|
+
)
|
|
789
|
+
|
|
790
|
+
# Compute Score (1.0 = flawless, deductions per violation)
|
|
791
|
+
fatal_count = sum(1 for v in violations if v.severity == "FATAL")
|
|
792
|
+
high_count = sum(1 for v in violations if v.severity == "HIGH")
|
|
793
|
+
medium_count = sum(1 for v in violations if v.severity == "MEDIUM")
|
|
794
|
+
|
|
795
|
+
score = max(0.0, 1.0 - (fatal_count * 0.40 + high_count * 0.20 + medium_count * 0.08))
|
|
796
|
+
clean = (fatal_count == 0 and high_count == 0 and medium_count == 0)
|
|
797
|
+
|
|
798
|
+
recommendations: list[str] = []
|
|
799
|
+
if not clean:
|
|
800
|
+
recommendations.append(f"Audit detected {len(violations)} anti-slop violations ({fatal_count} Fatal, {high_count} High, {medium_count} Medium).")
|
|
801
|
+
for v in violations:
|
|
802
|
+
recommendations.append(f"[{v.severity}] {v.rule_id}: {v.remedy}")
|
|
803
|
+
else:
|
|
804
|
+
recommendations.append("Flawless Anti-Slop Audit: Zero AI clichés, pristine typographic discipline, and clean layout hierarchy.")
|
|
805
|
+
|
|
806
|
+
return {
|
|
807
|
+
"clean": clean,
|
|
808
|
+
"score": round(score, 3),
|
|
809
|
+
"total_violations": len(violations),
|
|
810
|
+
"fatal_count": fatal_count,
|
|
811
|
+
"high_count": high_count,
|
|
812
|
+
"medium_count": medium_count,
|
|
813
|
+
"violations": [v.to_dict() for v in violations],
|
|
814
|
+
"recommendations": recommendations,
|
|
815
|
+
}
|
|
816
|
+
|
|
817
|
+
|
|
818
|
+
|
|
819
|
+
# ==============================================================================
|
|
820
|
+
# 5. BRIEF INFERENCE ENGINE ("READ THE ROOM")
|
|
821
|
+
# ==============================================================================
|
|
822
|
+
|
|
823
|
+
class BriefInferenceEngine:
|
|
824
|
+
"""Infers target audience, dials, and optimal Haute archetype from simple user prompts."""
|
|
825
|
+
|
|
826
|
+
_KEYWORD_ARCHETYPE_MAP: list[tuple[list[str], AestheticArchetype, str, str]] = [
|
|
827
|
+
# (Keywords, Archetype, Page Kind, Audience)
|
|
828
|
+
(
|
|
829
|
+
["dev", "terminal", "cli", "telemetry", "metric", "infrastructure", "kubernetes", "api", "monitoring", "docker", "cloud"],
|
|
830
|
+
AestheticArchetype.KINETIC_SPATIAL_HUD,
|
|
831
|
+
"Developer Tools & Infrastructure Cockpit",
|
|
832
|
+
"Platform engineers, SREs, and systems programmers",
|
|
833
|
+
),
|
|
834
|
+
(
|
|
835
|
+
["book", "publish", "press", "journal", "essay", "literature", "editorial", "reading", "author", "article", "newsletter"],
|
|
836
|
+
AestheticArchetype.HAUTE_EDITORIAL_MODERNISM,
|
|
837
|
+
"Haute Editorial Journal & Publication",
|
|
838
|
+
"Discerning readers, authors, and intellectual curators",
|
|
839
|
+
),
|
|
840
|
+
(
|
|
841
|
+
["luxury", "watch", "jewelry", "fashion", "hardware", "leica", "audio", "hifi", "chair", "furniture", "perfume", "titanium"],
|
|
842
|
+
AestheticArchetype.COLD_CHROMATIC_LUXURY,
|
|
843
|
+
"High-End Cold Luxury & Hardware Showcase",
|
|
844
|
+
"Aesthetic connoisseurs, design leaders, and luxury collectors",
|
|
845
|
+
),
|
|
846
|
+
(
|
|
847
|
+
["minimal", "swiss", "bauhaus", "clean", "grid", "portfolio", "architect", "museum", "studio", "poster", "exhibition"],
|
|
848
|
+
AestheticArchetype.SWISS_PRECISION_VIGNELLI,
|
|
849
|
+
"Swiss Precision Architectural Showcase",
|
|
850
|
+
"Art directors, architects, and design purists",
|
|
851
|
+
),
|
|
852
|
+
(
|
|
853
|
+
["nature", "wood", "warm", "coffee", "roast", "organic", "botanical", "tea", "nordic", "scandinavian", "artisan", "ceramics", "acoustic"],
|
|
854
|
+
AestheticArchetype.NEO_NORDIC_WARMTH,
|
|
855
|
+
"Neo-Nordic Tactile Lifestyle & Artisan Storefront",
|
|
856
|
+
"Conscious consumers, culinary enthusiasts, and artisan patrons",
|
|
857
|
+
),
|
|
858
|
+
(
|
|
859
|
+
["ai", "saas", "crypto", "robot", "avionics", "space", "cyber", "hardware", "sound", "synth", "synthesizer", "speed"],
|
|
860
|
+
AestheticArchetype.CYBER_OBSIDIAN_MONOLITH,
|
|
861
|
+
"Cyber-Obsidian Monolith High-Tech Platform",
|
|
862
|
+
"Technical founders, frontier researchers, and creative engineers",
|
|
863
|
+
),
|
|
864
|
+
]
|
|
865
|
+
|
|
866
|
+
def infer_brief(
|
|
867
|
+
self,
|
|
868
|
+
prompt: str = "",
|
|
869
|
+
dials_override: Optional[Dict[str, int]] = None,
|
|
870
|
+
archetype_override: Optional[str] = None,
|
|
871
|
+
**kwargs: Any,
|
|
872
|
+
) -> dict[str, Any]:
|
|
873
|
+
"""Perform brief inference ("Read the Room") and generate calibrated design blueprint."""
|
|
874
|
+
prompt = prompt or kwargs.get("user_prompt") or kwargs.get("brief") or ""
|
|
875
|
+
dials_override = dials_override or kwargs.get("dials")
|
|
876
|
+
archetype_override = archetype_override or kwargs.get("archetype") or kwargs.get("name")
|
|
877
|
+
prompt_lower = (prompt or "").lower()
|
|
878
|
+
|
|
879
|
+
# Check if archetype override is provided
|
|
880
|
+
arch_from_override = AestheticArchetype.from_str(archetype_override)
|
|
881
|
+
|
|
882
|
+
selected_archetype = AestheticArchetype.CYBER_OBSIDIAN_MONOLITH
|
|
883
|
+
page_kind = "Modern Interactive Web Experience"
|
|
884
|
+
target_audience = "Technical decision makers & design-conscious users"
|
|
885
|
+
|
|
886
|
+
if arch_from_override:
|
|
887
|
+
selected_archetype = arch_from_override
|
|
888
|
+
for _, arch, p_kind, aud in self._KEYWORD_ARCHETYPE_MAP:
|
|
889
|
+
if arch == selected_archetype:
|
|
890
|
+
page_kind = p_kind
|
|
891
|
+
target_audience = aud
|
|
892
|
+
break
|
|
893
|
+
else:
|
|
894
|
+
for keywords, arch, p_kind, aud in self._KEYWORD_ARCHETYPE_MAP:
|
|
895
|
+
if any(kw in prompt_lower for kw in keywords):
|
|
896
|
+
selected_archetype = arch
|
|
897
|
+
page_kind = p_kind
|
|
898
|
+
target_audience = aud
|
|
899
|
+
break
|
|
900
|
+
|
|
901
|
+
theme = HAUTE_THEMES[selected_archetype]
|
|
902
|
+
base_dials = theme.dials
|
|
903
|
+
if dials_override:
|
|
904
|
+
dials = DesignDials(
|
|
905
|
+
variance=dials_override.get("variance", base_dials.variance),
|
|
906
|
+
motion=dials_override.get("motion", base_dials.motion),
|
|
907
|
+
density=dials_override.get("density", base_dials.density),
|
|
908
|
+
)
|
|
909
|
+
else:
|
|
910
|
+
dials = base_dials
|
|
911
|
+
|
|
912
|
+
# Build Mandatory Design Read Declaration
|
|
913
|
+
design_read = (
|
|
914
|
+
f"Design Read: {page_kind} for {target_audience}, with a {theme.title} aesthetic language, "
|
|
915
|
+
f"leaning toward Tailwind CSS v4 with Dials at {dials.vector_str()}."
|
|
916
|
+
)
|
|
917
|
+
|
|
918
|
+
return {
|
|
919
|
+
"design_read": design_read,
|
|
920
|
+
"page_kind": page_kind,
|
|
921
|
+
"target_audience": target_audience,
|
|
922
|
+
"archetype": selected_archetype.value,
|
|
923
|
+
"archetype_title": theme.title,
|
|
924
|
+
"dials": dials.to_dict(),
|
|
925
|
+
"palette": {
|
|
926
|
+
"bg_void": theme.bg_void.to_css(),
|
|
927
|
+
"surface_card": theme.surface_card.to_css(),
|
|
928
|
+
"surface_elevated": theme.surface_elevated.to_css(),
|
|
929
|
+
"border_hairline": theme.border_hairline.to_css(),
|
|
930
|
+
"text_primary": theme.text_primary.to_css(),
|
|
931
|
+
"text_muted": theme.text_muted.to_css(),
|
|
932
|
+
"accent_primary": theme.accent_primary.to_css(),
|
|
933
|
+
},
|
|
934
|
+
"typography": {
|
|
935
|
+
"display": theme.font_display,
|
|
936
|
+
"body": theme.font_body,
|
|
937
|
+
"mono": theme.font_mono,
|
|
938
|
+
},
|
|
939
|
+
"layout_blueprint": {
|
|
940
|
+
"hero_stack_max_elements": 4,
|
|
941
|
+
"hero_top_padding_cap": "pt-20 md:pt-24",
|
|
942
|
+
"navigation_height_cap": "h-16 md:h-20 (<= 80px)",
|
|
943
|
+
"bento_grid_structure": "Asymmetric Bento (Hero cell 2x2, Telemetry 2x1, Micro-sandboxes 1x1)",
|
|
944
|
+
"desktop_cta_rule": "Strictly single-line (whitespace-nowrap)",
|
|
945
|
+
},
|
|
946
|
+
"copywriting_guidelines": {
|
|
947
|
+
"anti_buzzword_ban": "Strictly no 'supercharge', 'next-gen AI', 'unleash', or 'delve into'",
|
|
948
|
+
"voice_profile": "Crisp, concrete, functional telemetry and quantifiable specifications",
|
|
949
|
+
"canonical_cta": "Pick exactly 1 action verb ('Start Building' or 'Explore Specs') and lock it globally",
|
|
950
|
+
},
|
|
951
|
+
}
|
|
952
|
+
|
|
953
|
+
|
|
954
|
+
# ==============================================================================
|
|
955
|
+
# 6. AWWWARDS SCAFFOLD GENERATOR
|
|
956
|
+
# ==============================================================================
|
|
957
|
+
|
|
958
|
+
class AwwwardsScaffoldGenerator:
|
|
959
|
+
"""Generates zero-slop, Awwwards-caliber HTML/JSX and CSS layouts from simple prompts."""
|
|
960
|
+
|
|
961
|
+
def __init__(self, inference_engine: Optional[BriefInferenceEngine] = None) -> None:
|
|
962
|
+
self.inference = inference_engine or BriefInferenceEngine()
|
|
963
|
+
self.auditor = AntiSlopAuditor()
|
|
964
|
+
|
|
965
|
+
def generate_scaffold(
|
|
966
|
+
self,
|
|
967
|
+
prompt: str = "",
|
|
968
|
+
archetype_override: Optional[str] = None,
|
|
969
|
+
**kwargs: Any,
|
|
970
|
+
) -> dict[str, Any]:
|
|
971
|
+
"""Synthesize complete, production-grade, zero-slop web application scaffold."""
|
|
972
|
+
p = prompt or kwargs.get("user_prompt") or kwargs.get("brief") or "Modern software platform"
|
|
973
|
+
arch_target = archetype_override or kwargs.get("archetype") or kwargs.get("name")
|
|
974
|
+
arch_enum = AestheticArchetype.from_str(arch_target)
|
|
975
|
+
brief = self.inference.infer_brief(p, archetype_override=arch_enum.value if arch_enum else None)
|
|
976
|
+
selected_arch = AestheticArchetype.from_str(brief["archetype"]) or AestheticArchetype.CYBER_OBSIDIAN_MONOLITH
|
|
977
|
+
theme = HAUTE_THEMES[selected_arch]
|
|
978
|
+
|
|
979
|
+
css_theme = theme.to_tailwind_v4_theme()
|
|
980
|
+
fluid_tokens = theme.get_fluid_typography_tokens()
|
|
981
|
+
|
|
982
|
+
# Build clean semantic HTML/JSX scaffold incorporating 7-layer optical depth
|
|
983
|
+
is_dark = theme.bg_void.l < 0.5
|
|
984
|
+
noise_opacity = "0.035" if is_dark else "0.020"
|
|
985
|
+
grain_blend = "overlay" if is_dark else "multiply"
|
|
986
|
+
|
|
987
|
+
html_layout = f"""<!--
|
|
988
|
+
FABLE-MODE AWWWARDS-WINNING PRODUCTION LAYOUT
|
|
989
|
+
{brief['design_read']}
|
|
990
|
+
-->
|
|
991
|
+
<div class="relative min-h-[100dvh] w-full bg-[var(--color-bg-void)] text-[var(--color-text-primary)] font-[var(--font-family-body)] selection:bg-[var(--color-accent-primary)] selection:text-[var(--color-bg-void)] overflow-x-hidden antialiased">
|
|
992
|
+
|
|
993
|
+
<!-- Layer 1: Procedural Micro-Texture / Film Grain (Anti-Banding Matrix) -->
|
|
994
|
+
<div class="pointer-events-none fixed inset-0 z-50 mix-blend-{grain_blend} opacity-[{noise_opacity}]" aria-hidden="true">
|
|
995
|
+
<svg class="h-full w-full" xmlns="http://www.w3.org/2000/svg">
|
|
996
|
+
<filter id="fable-noise">
|
|
997
|
+
<feTurbulence type="fractalNoise" baseFrequency="0.85" numOctaves="3" stitchTiles="stitch" />
|
|
998
|
+
<feColorMatrix type="matrix" values="1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 1 0" />
|
|
999
|
+
</filter>
|
|
1000
|
+
<rect width="100%" height="100%" filter="url(#fable-noise)" />
|
|
1001
|
+
</svg>
|
|
1002
|
+
</div>
|
|
1003
|
+
|
|
1004
|
+
<!-- Layer 2: Volumetric Directional Lighting (Inverse-Square Spatial Caustics) -->
|
|
1005
|
+
<div class="pointer-events-none fixed inset-0 z-0 overflow-hidden" aria-hidden="true">
|
|
1006
|
+
<div class="absolute -top-40 left-1/2 -translate-x-1/2 w-[850px] h-[450px] rounded-full opacity-25 blur-[120px] bg-[radial-gradient(ellipse_at_center,var(--color-accent-glow),transparent_70%)]"></div>
|
|
1007
|
+
</div>
|
|
1008
|
+
|
|
1009
|
+
<!-- Layer 3 & 4: Top Navigation (Single Line <= 80px, Refractive Substrate, Specular Rim) -->
|
|
1010
|
+
<header class="sticky top-0 z-40 w-full border-b border-[var(--color-border-hairline)] bg-[var(--color-surface-card)] backdrop-blur-xl transition-all">
|
|
1011
|
+
<div class="mx-auto flex h-16 max-w-7xl items-center justify-between px-6 lg:px-8">
|
|
1012
|
+
<a href="/" class="flex items-center gap-3 group">
|
|
1013
|
+
<div class="h-4 w-4 {theme.border_radius_scale} bg-[var(--color-accent-primary)] transition-transform duration-300 group-hover:scale-110"></div>
|
|
1014
|
+
<span class="font-[var(--font-family-display)] font-semibold tracking-tight text-lg text-[var(--color-text-primary)]">{brief['page_kind'].split()[0]}</span>
|
|
1015
|
+
</a>
|
|
1016
|
+
<nav class="hidden md:flex items-center gap-8 text-sm font-medium text-[var(--color-text-muted)]">
|
|
1017
|
+
<a href="#architecture" class="hover:text-[var(--color-text-primary)] transition-colors">Architecture</a>
|
|
1018
|
+
<a href="#specs" class="hover:text-[var(--color-text-primary)] transition-colors">Specifications</a>
|
|
1019
|
+
<a href="#telemetry" class="hover:text-[var(--color-text-primary)] transition-colors">Telemetry</a>
|
|
1020
|
+
</nav>
|
|
1021
|
+
<div class="flex items-center gap-4">
|
|
1022
|
+
<button class="whitespace-nowrap px-4 py-2 text-xs font-semibold tracking-wide {theme.border_radius_scale} bg-[var(--color-accent-primary)] text-[var(--color-bg-void)] shadow-[inset_0_1px_0_0_rgba(255,255,255,0.25)] hover:opacity-95 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--color-accent-primary)] active:scale-[0.98] transition-opacity">
|
|
1023
|
+
Initialize System
|
|
1024
|
+
</button>
|
|
1025
|
+
</div>
|
|
1026
|
+
</div>
|
|
1027
|
+
</header>
|
|
1028
|
+
|
|
1029
|
+
<!-- Layer 5: Asymmetric Hero Section (Hero Stack <= 4 Elements, Desktop Top Padding <= pt-24) -->
|
|
1030
|
+
<main class="relative z-10">
|
|
1031
|
+
|
|
1032
|
+
<section id="hero" class="mx-auto max-w-7xl px-6 pt-16 pb-24 md:pt-24 lg:px-8">
|
|
1033
|
+
<div class="grid grid-cols-1 lg:grid-cols-12 gap-12 items-center">
|
|
1034
|
+
<div class="lg:col-span-7 flex flex-col items-start gap-6">
|
|
1035
|
+
|
|
1036
|
+
<!-- Element 1: Eyebrow (Restrained, max 1 per 3 sections) -->
|
|
1037
|
+
<div class="inline-flex items-center gap-2 px-3 py-1 text-xs font-mono tracking-wider uppercase {theme.border_radius_scale} border border-[var(--color-border-hairline)] bg-[var(--color-surface-card)] text-[var(--color-text-muted)]">
|
|
1038
|
+
<span class="h-1.5 w-1.5 rounded-full bg-[var(--color-accent-primary)]"></span>
|
|
1039
|
+
<span>SYSTEM DISPATCH // V2.5</span>
|
|
1040
|
+
</div>
|
|
1041
|
+
|
|
1042
|
+
<!-- Element 2: Headline (Max 2 lines on desktop, fluid clamp) -->
|
|
1043
|
+
<h1 class="font-[var(--font-family-display)] font-bold tracking-tight text-[clamp(2.25rem,1.5rem+3.5vw,4.5rem)] leading-[0.95] text-[var(--color-text-primary)]">
|
|
1044
|
+
Precision engineering for autonomous scale.
|
|
1045
|
+
</h1>
|
|
1046
|
+
|
|
1047
|
+
<!-- Element 3: Subtext (Max 20 words, zero buzzwords) -->
|
|
1048
|
+
<p class="max-w-xl text-base md:text-lg text-[var(--color-text-muted)] leading-relaxed">
|
|
1049
|
+
Deterministic execution brokers delivering sub-60ms state transitions with mathematical verification guarantees.
|
|
1050
|
+
</p>
|
|
1051
|
+
|
|
1052
|
+
<!-- Element 4: Single-Line Primary CTA + Max 1 Secondary -->
|
|
1053
|
+
<div class="flex flex-wrap items-center gap-4 pt-2">
|
|
1054
|
+
<button class="whitespace-nowrap px-6 py-3.5 text-sm font-semibold {theme.border_radius_scale} bg-[var(--color-accent-primary)] text-[var(--color-bg-void)] shadow-[0_12px_24px_-8px_var(--color-accent-glow)] hover:opacity-95 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--color-accent-primary)] active:scale-[0.98] transition-opacity">
|
|
1055
|
+
Deploy Node
|
|
1056
|
+
</button>
|
|
1057
|
+
<button class="whitespace-nowrap px-6 py-3.5 text-sm font-semibold {theme.border_radius_scale} border border-[var(--color-border-hairline)] bg-[var(--color-surface-card)] text-[var(--color-text-primary)] hover:border-[var(--color-border-specular)] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--color-accent-primary)] active:scale-[0.98] transition-colors">
|
|
1058
|
+
Inspect Architecture
|
|
1059
|
+
</button>
|
|
1060
|
+
</div>
|
|
1061
|
+
|
|
1062
|
+
</div>
|
|
1063
|
+
|
|
1064
|
+
<!-- Hero Visual / Real Interactive Component Sandbox (No Div Dots) -->
|
|
1065
|
+
<div class="lg:col-span-5 relative w-full aspect-square {theme.border_radius_scale} border border-[var(--color-border-hairline)] bg-[var(--color-surface-card)] p-8 flex flex-col justify-between overflow-hidden shadow-2xl">
|
|
1066
|
+
<div class="flex items-center justify-between border-b border-[var(--color-border-hairline)] pb-4">
|
|
1067
|
+
<span class="text-xs font-mono text-[var(--color-text-muted)]">Live Telemetry</span>
|
|
1068
|
+
<span class="inline-flex items-center gap-1.5 text-xs font-mono text-[var(--color-accent-primary)]">
|
|
1069
|
+
<span class="h-2 w-2 rounded-full bg-[var(--color-accent-primary)] animate-pulse"></span>
|
|
1070
|
+
60.0 FPS LOCKED
|
|
1071
|
+
</span>
|
|
1072
|
+
</div>
|
|
1073
|
+
<div class="my-auto font-mono text-xs text-[var(--color-text-muted)] space-y-2">
|
|
1074
|
+
<div class="flex justify-between"><span>Proof Engine:</span><span class="text-[var(--color-text-primary)]">Curry-Howard Verified</span></div>
|
|
1075
|
+
<div class="flex justify-between"><span>VRAM Allocation:</span><span class="text-[var(--color-text-primary)]">18.4 MB / Tier-1</span></div>
|
|
1076
|
+
<div class="flex justify-between"><span>Syntactic Drift:</span><span class="text-[var(--color-text-primary)]">0.0000 %</span></div>
|
|
1077
|
+
</div>
|
|
1078
|
+
<div class="pt-4 border-t border-[var(--color-border-hairline)] flex items-center justify-between text-xs text-[var(--color-text-muted)]">
|
|
1079
|
+
<span>APCA Contrast: Lc >= 78.4</span>
|
|
1080
|
+
<span class="text-[var(--color-accent-primary)]">STATUS: GREEN</span>
|
|
1081
|
+
</div>
|
|
1082
|
+
</div>
|
|
1083
|
+
|
|
1084
|
+
</div>
|
|
1085
|
+
</section>
|
|
1086
|
+
|
|
1087
|
+
<!-- Asymmetric Bento Grid (Purposeful cell spans & rich contrasting treatments) -->
|
|
1088
|
+
<section id="architecture" class="mx-auto max-w-7xl px-6 pb-24 lg:px-8">
|
|
1089
|
+
<div class="mb-12">
|
|
1090
|
+
<h2 class="font-[var(--font-family-display)] text-2xl md:text-3xl font-bold tracking-tight text-[var(--color-text-primary)]">
|
|
1091
|
+
Architectural Invariants
|
|
1092
|
+
</h2>
|
|
1093
|
+
<p class="mt-2 text-sm text-[var(--color-text-muted)]">Sub-second deterministic proofs eliminating runtime failures.</p>
|
|
1094
|
+
</div>
|
|
1095
|
+
|
|
1096
|
+
<div class="grid grid-cols-1 md:grid-cols-3 lg:grid-cols-12 gap-6">
|
|
1097
|
+
|
|
1098
|
+
<!-- Cell 1: 2-column span Hero Cell -->
|
|
1099
|
+
<div class="lg:col-span-8 {theme.border_radius_scale} border border-[var(--color-border-hairline)] bg-[var(--color-surface-card)] p-8 flex flex-col justify-between hover:border-[var(--color-border-specular)] transition-colors">
|
|
1100
|
+
<div>
|
|
1101
|
+
<span class="text-xs font-mono text-[var(--color-accent-primary)] font-medium">[01] // FORMAL PROOF</span>
|
|
1102
|
+
<h3 class="mt-3 font-[var(--font-family-display)] text-xl font-semibold text-[var(--color-text-primary)]">Ungameable AST Grounding</h3>
|
|
1103
|
+
<p class="mt-2 text-sm text-[var(--color-text-muted)] leading-relaxed">
|
|
1104
|
+
Every state transition binds directly to abstract syntax tree symbol nodes and SHA-256 source chains, eliminating circular reasoning.
|
|
1105
|
+
</p>
|
|
1106
|
+
</div>
|
|
1107
|
+
<div class="mt-8 pt-6 border-t border-[var(--color-border-hairline)] flex items-center justify-between text-xs font-mono text-[var(--color-text-muted)]">
|
|
1108
|
+
<span>RECEIPT: HMAC-SHA256</span>
|
|
1109
|
+
<span>AG(safe) SEALED</span>
|
|
1110
|
+
</div>
|
|
1111
|
+
</div>
|
|
1112
|
+
|
|
1113
|
+
<!-- Cell 2: 1-column span Compact Metric -->
|
|
1114
|
+
<div class="lg:col-span-4 {theme.border_radius_scale} border border-[var(--color-border-hairline)] bg-[var(--color-surface-elevated)] p-8 flex flex-col justify-between hover:border-[var(--color-border-specular)] transition-colors">
|
|
1115
|
+
<div>
|
|
1116
|
+
<span class="text-xs font-mono text-[var(--color-accent-primary)] font-medium">[02] // LATENCY</span>
|
|
1117
|
+
<div class="mt-4 font-[var(--font-family-display)] text-4xl font-bold text-[var(--color-text-primary)]">< 60ms</div>
|
|
1118
|
+
<p class="mt-2 text-xs text-[var(--color-text-muted)]">Damped harmonic oscillator response with critical damping.</p>
|
|
1119
|
+
</div>
|
|
1120
|
+
<div class="mt-6 text-xs font-mono text-[var(--color-accent-primary)]">ζ = 1.00 ZERO OVERSHOOT</div>
|
|
1121
|
+
</div>
|
|
1122
|
+
|
|
1123
|
+
</div>
|
|
1124
|
+
</section>
|
|
1125
|
+
|
|
1126
|
+
</main>
|
|
1127
|
+
|
|
1128
|
+
<!-- Clean Footer -->
|
|
1129
|
+
<footer class="border-t border-[var(--color-border-hairline)] py-12 px-6 lg:px-8 text-xs text-[var(--color-text-muted)]">
|
|
1130
|
+
<div class="mx-auto max-w-7xl flex flex-col sm:flex-row items-center justify-between gap-4">
|
|
1131
|
+
<div>© 2026 Fable-Mode Cognitive Architecture. Engineered with zero AI slop.</div>
|
|
1132
|
+
<div class="flex items-center gap-6 font-mono text-xs">
|
|
1133
|
+
<span>WCAG AA COMPLIANT</span>
|
|
1134
|
+
<span>OKLCH COLOR MATRIX</span>
|
|
1135
|
+
</div>
|
|
1136
|
+
</div>
|
|
1137
|
+
</footer>
|
|
1138
|
+
|
|
1139
|
+
</div>
|
|
1140
|
+
"""
|
|
1141
|
+
# Run pre-flight audit on generated layout to guarantee 100% clean Anti-Slop score
|
|
1142
|
+
audit_res = self.auditor.audit_code(html_layout)
|
|
1143
|
+
|
|
1144
|
+
return {
|
|
1145
|
+
"prompt": prompt,
|
|
1146
|
+
"design_read": brief["design_read"],
|
|
1147
|
+
"archetype": selected_arch.value,
|
|
1148
|
+
"theme_title": theme.title,
|
|
1149
|
+
"tailwind_v4_theme": css_theme,
|
|
1150
|
+
"html_layout": html_layout,
|
|
1151
|
+
"audit_result": audit_res,
|
|
1152
|
+
"anti_slop_verified": audit_res["clean"],
|
|
1153
|
+
}
|
|
1154
|
+
|
|
1155
|
+
|
|
1156
|
+
# ==============================================================================
|
|
1157
|
+
# 7. PRE-FLIGHT DESIGN QUALITY GATE
|
|
1158
|
+
# ==============================================================================
|
|
1159
|
+
|
|
1160
|
+
class PreFlightDesignGate:
|
|
1161
|
+
"""Mechanical 5-point quality gate validating frontend code before release."""
|
|
1162
|
+
|
|
1163
|
+
def __init__(self, auditor: Optional[AntiSlopAuditor] = None) -> None:
|
|
1164
|
+
self.auditor = auditor or AntiSlopAuditor()
|
|
1165
|
+
|
|
1166
|
+
def validate_design(self, code: str, theme: Optional[HauteDesignTheme] = None) -> dict[str, Any]:
|
|
1167
|
+
"""Verify the 5 mandatory design invariants:
|
|
1168
|
+
|
|
1169
|
+
1. Viewport Fit & Stability (100dvh, pt-24 max desktop hero)
|
|
1170
|
+
2. Typographic Polish & Descender Clearance
|
|
1171
|
+
3. Color & Shape Invariant Locks (1 primary accent, 1 radius scale)
|
|
1172
|
+
4. Interactive Contrast (WCAG AA >= 4.5:1) & Single-Line CTAs
|
|
1173
|
+
5. Eyebrow Restraint & Copy Audit (zero LLM buzzwords)
|
|
1174
|
+
"""
|
|
1175
|
+
audit = self.auditor.audit_code(code)
|
|
1176
|
+
checklist: list[dict[str, Any]] = []
|
|
1177
|
+
|
|
1178
|
+
# 1. Viewport Stability Check
|
|
1179
|
+
has_100dvh = bool(re.search(r"100dvh", code, re.IGNORECASE))
|
|
1180
|
+
has_h_screen = bool(re.search(r"\bh-screen\b|height:\s*100vh\b", code, re.IGNORECASE))
|
|
1181
|
+
viewport_ok = has_100dvh or not has_h_screen
|
|
1182
|
+
checklist.append({
|
|
1183
|
+
"point": 1,
|
|
1184
|
+
"name": "Viewport Fit & Stability",
|
|
1185
|
+
"passed": viewport_ok,
|
|
1186
|
+
"details": "Uses min-h-[100dvh]; strictly zero mobile-jumping h-screen usages." if viewport_ok else "Fails: contains banned h-screen without 100dvh fallback.",
|
|
1187
|
+
})
|
|
1188
|
+
|
|
1189
|
+
# 2. Typographic Polish Check
|
|
1190
|
+
has_italic_without_clearance = bool(re.search(r"italic\s+[^>]*leading-\[1\.0\]", code, re.IGNORECASE))
|
|
1191
|
+
typo_ok = not has_italic_without_clearance
|
|
1192
|
+
checklist.append({
|
|
1193
|
+
"point": 2,
|
|
1194
|
+
"name": "Typographic Polish & Descender Clearance",
|
|
1195
|
+
"passed": typo_ok,
|
|
1196
|
+
"details": "Italic descenders cleared with leading >= 1.1; font pairings respected." if typo_ok else "Fails: italic descenders clipped by tight leading.",
|
|
1197
|
+
})
|
|
1198
|
+
|
|
1199
|
+
# 3. Color & Shape Invariant Locks
|
|
1200
|
+
multi_accents = len(set(re.findall(r"(?:text|bg)-(?:emerald|cyan|rose|amber|violet|indigo)-[5-7]00", code, re.IGNORECASE))) > 2
|
|
1201
|
+
color_ok = not multi_accents
|
|
1202
|
+
checklist.append({
|
|
1203
|
+
"point": 3,
|
|
1204
|
+
"name": "Color & Shape Invariant Locks",
|
|
1205
|
+
"passed": color_ok,
|
|
1206
|
+
"details": "Locked exactly 1 primary accent color and 1 unified border-radius scale." if color_ok else "Fails: multiple conflicting accent colors found without unified token locking.",
|
|
1207
|
+
})
|
|
1208
|
+
|
|
1209
|
+
# 4. Interactive Contrast & Single-Line CTAs
|
|
1210
|
+
button_has_wrap = bool(re.search(r"<button(?![^>]*whitespace-nowrap)[^>]*>[^<]*\n[^<]*</button>", code, re.IGNORECASE))
|
|
1211
|
+
has_naked_outline = False
|
|
1212
|
+
for btn_match in re.finditer(r"<(?:button|a|input|select|textarea)\b[^>]*class=[\"']([^\"']*)[\"'][^>]*>", code, re.IGNORECASE):
|
|
1213
|
+
c_str = btn_match.group(1)
|
|
1214
|
+
if re.search(r"\b(?:focus:)?outline-none\b", c_str, re.IGNORECASE) and not re.search(r"\bfocus-visible:", c_str, re.IGNORECASE):
|
|
1215
|
+
has_naked_outline = True
|
|
1216
|
+
break
|
|
1217
|
+
cta_ok = (not button_has_wrap) and (not has_naked_outline)
|
|
1218
|
+
checklist.append({
|
|
1219
|
+
"point": 4,
|
|
1220
|
+
"name": "Interactive Contrast & Single-Line CTAs",
|
|
1221
|
+
"passed": cta_ok,
|
|
1222
|
+
"details": "All button CTAs fit on a single line with whitespace-nowrap; focus accessibility preserved." if cta_ok else "Fails: button CTA text wraps across multiple lines or removes focus outlines without focus-visible rings.",
|
|
1223
|
+
})
|
|
1224
|
+
|
|
1225
|
+
# 5. Eyebrow Restraint & Copy Audit
|
|
1226
|
+
copy_ok = (audit["fatal_count"] == 0 and audit["high_count"] == 0)
|
|
1227
|
+
checklist.append({
|
|
1228
|
+
"point": 5,
|
|
1229
|
+
"name": "Eyebrow Restraint & Copy Audit",
|
|
1230
|
+
"passed": copy_ok,
|
|
1231
|
+
"details": "Restrained uppercase eyebrows (<= 1 per 3 sections) and zero LLM marker buzzwords." if copy_ok else f"Fails: {audit['fatal_count'] + audit['high_count']} anti-slop copy/eyebrow violations detected.",
|
|
1232
|
+
})
|
|
1233
|
+
|
|
1234
|
+
passed_count = sum(1 for c in checklist if c["passed"])
|
|
1235
|
+
approved = (passed_count == 5 and audit["clean"])
|
|
1236
|
+
composite_score = round(passed_count / 5.0 * audit["score"], 3)
|
|
1237
|
+
|
|
1238
|
+
return {
|
|
1239
|
+
"approved": approved,
|
|
1240
|
+
"composite_score": composite_score,
|
|
1241
|
+
"passed_checks": passed_count,
|
|
1242
|
+
"total_checks": 5,
|
|
1243
|
+
"checklist": checklist,
|
|
1244
|
+
"anti_slop_audit": audit,
|
|
1245
|
+
}
|
|
1246
|
+
|
|
1247
|
+
|
|
1248
|
+
# ==============================================================================
|
|
1249
|
+
# 8. MASTER FRONTEND DESIGN ENGINE (UNIFIED INTERFACE)
|
|
1250
|
+
# ==============================================================================
|
|
1251
|
+
|
|
1252
|
+
class DesignEngine:
|
|
1253
|
+
"""Master Frontend Design & Anti-Slop Taste Engine for Fable-Mode."""
|
|
1254
|
+
|
|
1255
|
+
def __init__(self) -> None:
|
|
1256
|
+
self.auditor = AntiSlopAuditor()
|
|
1257
|
+
self.brief_inference = BriefInferenceEngine()
|
|
1258
|
+
self.scaffold_generator = AwwwardsScaffoldGenerator(self.brief_inference)
|
|
1259
|
+
self.preflight_gate = PreFlightDesignGate(self.auditor)
|
|
1260
|
+
|
|
1261
|
+
def audit_anti_slop(self, code: str = "", file_path: str = "", **kwargs: Any) -> dict[str, Any]:
|
|
1262
|
+
"""Audit HTML/JSX/CSS code for AI slop anti-patterns."""
|
|
1263
|
+
c = code or kwargs.get("content") or kwargs.get("html") or kwargs.get("source") or ""
|
|
1264
|
+
fp = file_path or kwargs.get("file_path") or ""
|
|
1265
|
+
return self.auditor.audit_code(c, fp)
|
|
1266
|
+
|
|
1267
|
+
def infer_design_brief(
|
|
1268
|
+
self,
|
|
1269
|
+
prompt: str = "",
|
|
1270
|
+
dials_override: Optional[Dict[str, int]] = None,
|
|
1271
|
+
archetype_override: Optional[str] = None,
|
|
1272
|
+
**kwargs: Any,
|
|
1273
|
+
) -> dict[str, Any]:
|
|
1274
|
+
"""Infer design brief, dials, and archetype from prompt."""
|
|
1275
|
+
p = prompt or kwargs.get("user_prompt") or kwargs.get("brief") or ""
|
|
1276
|
+
d_ovr = dials_override or kwargs.get("dials") or kwargs.get("dials_override")
|
|
1277
|
+
a_ovr = archetype_override or kwargs.get("archetype") or kwargs.get("name") or kwargs.get("archetype_override")
|
|
1278
|
+
return self.brief_inference.infer_brief(p, dials_override=d_ovr, archetype_override=a_ovr)
|
|
1279
|
+
|
|
1280
|
+
def generate_design_tokens(self, archetype: Optional[str] = None, **kwargs: Any) -> dict[str, Any]:
|
|
1281
|
+
"""Generate complete design tokens and Tailwind v4 @theme for a Haute archetype."""
|
|
1282
|
+
arch_str = archetype or kwargs.get("name") or kwargs.get("archetype_name") or "cyber_obsidian_monolith"
|
|
1283
|
+
arch_enum = AestheticArchetype.from_str(arch_str) or AestheticArchetype.CYBER_OBSIDIAN_MONOLITH
|
|
1284
|
+
theme = HAUTE_THEMES[arch_enum]
|
|
1285
|
+
data = theme.to_dict()
|
|
1286
|
+
data["tailwind_v4_theme"] = theme.to_tailwind_v4_theme()
|
|
1287
|
+
return data
|
|
1288
|
+
|
|
1289
|
+
def generate_awwwards_scaffold(
|
|
1290
|
+
self,
|
|
1291
|
+
prompt: str = "",
|
|
1292
|
+
archetype: Optional[str] = None,
|
|
1293
|
+
archetype_override: Optional[str] = None,
|
|
1294
|
+
**kwargs: Any,
|
|
1295
|
+
) -> dict[str, Any]:
|
|
1296
|
+
"""Synthesize Awwwards-caliber, zero-slop layout scaffold."""
|
|
1297
|
+
p = prompt or kwargs.get("user_prompt") or kwargs.get("brief") or "Modern software platform"
|
|
1298
|
+
target = archetype_override or archetype or kwargs.get("name") or kwargs.get("archetype_override")
|
|
1299
|
+
return self.scaffold_generator.generate_scaffold(p, target)
|
|
1300
|
+
|
|
1301
|
+
def validate_preflight_design(self, code: str = "", **kwargs: Any) -> dict[str, Any]:
|
|
1302
|
+
"""Validate code against the 5-point Pre-Flight Design Quality Gate."""
|
|
1303
|
+
c = code or kwargs.get("content") or kwargs.get("html") or kwargs.get("source") or ""
|
|
1304
|
+
return self.preflight_gate.validate_design(c)
|
|
1305
|
+
|
|
1306
|
+
def list_design_archetypes(self, **kwargs: Any) -> list[dict[str, Any]]:
|
|
1307
|
+
"""List all 6 available Haute Aesthetic Archetypes with metadata."""
|
|
1308
|
+
return [
|
|
1309
|
+
{
|
|
1310
|
+
"archetype": theme.archetype.value,
|
|
1311
|
+
"title": theme.title,
|
|
1312
|
+
"description": theme.description,
|
|
1313
|
+
"dials": theme.dials.to_dict(),
|
|
1314
|
+
}
|
|
1315
|
+
for theme in HAUTE_THEMES.values()
|
|
1316
|
+
]
|