@litfamily/litgrok 1.0.26 → 1.0.28

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.
Files changed (235) hide show
  1. package/.grok/hooks/lit-mark.mjs +42 -0
  2. package/.grok/hooks/lit-status-line.mjs +174 -21
  3. package/.grok/hooks/plan-gate.mjs +13 -3
  4. package/.grok/hooks/record-passive-event.mjs +40 -6
  5. package/.grok/hooks/session-end.json +15 -0
  6. package/.grok/hooks/session-end.mjs +6 -0
  7. package/.grok/hooks/session-liveness.mjs +102 -0
  8. package/.grok/hooks/session-rows.mjs +57 -0
  9. package/.grok/hooks/session-start.mjs +17 -0
  10. package/.grok/hooks/workflow-stage.mjs +5 -2
  11. package/.grok/rules/00-litgrok.md +14 -0
  12. package/.grok/skills/frontend-ui-ux/ATTRIBUTION.md +23 -0
  13. package/.grok/skills/frontend-ui-ux/SKILL.md +4 -1
  14. package/.grok/skills/frontend-ui-ux/examples/phase-3-readme-ab/README.md +9 -0
  15. package/.grok/skills/frontend-ui-ux/kit/components.css +414 -0
  16. package/.grok/skills/frontend-ui-ux/kit/fonts.json +22 -0
  17. package/.grok/skills/frontend-ui-ux/kit/layouts/landing.html +164 -0
  18. package/.grok/skills/frontend-ui-ux/kit/layouts/settings.html +114 -0
  19. package/.grok/skills/frontend-ui-ux/kit/layouts/workspace.html +115 -0
  20. package/.grok/skills/frontend-ui-ux/kit/styles/computational-brutalism.json +227 -0
  21. package/.grok/skills/frontend-ui-ux/kit/styles/field-notes.json +205 -0
  22. package/.grok/skills/frontend-ui-ux/kit/styles/graphite.json +200 -0
  23. package/.grok/skills/frontend-ui-ux/kit/styles/meadow.json +199 -0
  24. package/.grok/skills/frontend-ui-ux/kit/styles/neo-brutalism.json +222 -0
  25. package/.grok/skills/frontend-ui-ux/kit/ui.js +226 -0
  26. package/.grok/skills/frontend-ui-ux/references/adaptive-layout.md +10 -4
  27. package/.grok/skills/frontend-ui-ux/references/brand-and-imagery.md +11 -7
  28. package/.grok/skills/frontend-ui-ux/references/complete-contract.md +21 -0
  29. package/.grok/skills/frontend-ui-ux/references/composition.md +10 -6
  30. package/.grok/skills/frontend-ui-ux/references/craft-floor.md +256 -93
  31. package/.grok/skills/frontend-ui-ux/references/creative-directions.md +9 -6
  32. package/.grok/skills/frontend-ui-ux/references/default-editorial-pixel.json +28 -0
  33. package/.grok/skills/frontend-ui-ux/references/house-styles.md +234 -0
  34. package/.grok/skills/frontend-ui-ux/references/implementation-platforms.md +10 -6
  35. package/.grok/skills/frontend-ui-ux/references/inclusive-interface.md +11 -5
  36. package/.grok/skills/frontend-ui-ux/references/interaction-motion.md +34 -78
  37. package/.grok/skills/frontend-ui-ux/references/motion-guide.md +10 -7
  38. package/.grok/skills/frontend-ui-ux/references/performance-delivery.md +11 -8
  39. package/.grok/skills/frontend-ui-ux/references/probe-loop.md +1 -1
  40. package/.grok/skills/frontend-ui-ux/references/product-direction.md +9 -4
  41. package/.grok/skills/frontend-ui-ux/references/production-interview.md +17 -0
  42. package/.grok/skills/frontend-ui-ux/references/redesign-playbook.md +10 -6
  43. package/.grok/skills/frontend-ui-ux/references/slop-register.md +148 -73
  44. package/.grok/skills/frontend-ui-ux/references/system-foundations.md +10 -4
  45. package/.grok/skills/frontend-ui-ux/references/visual-language.md +10 -4
  46. package/.grok/skills/frontend-ui-ux/references/visual-reconstruction.md +39 -72
  47. package/.grok/skills/frontend-ui-ux/scripts/design-lock.mjs +400 -0
  48. package/.grok/skills/frontend-ui-ux/scripts/interface-probe-driver.mjs +33 -0
  49. package/.grok/skills/frontend-ui-ux/scripts/interface-probe-lock.mjs +196 -0
  50. package/.grok/skills/frontend-ui-ux/scripts/interface-probe-page.mjs +1555 -0
  51. package/.grok/skills/frontend-ui-ux/scripts/interface-probe-rules.mjs +153 -0
  52. package/.grok/skills/frontend-ui-ux/scripts/interface-probe-server.mjs +57 -0
  53. package/.grok/skills/frontend-ui-ux/scripts/interface-probe-static.mjs +139 -0
  54. package/.grok/skills/frontend-ui-ux/scripts/interface-probe.mjs +363 -0
  55. package/.grok/skills/frontend-ui-ux/scripts/pixel-art.mjs +60 -0
  56. package/.grok/skills/lit-adhd/SKILL.md +155 -0
  57. package/.grok/skills/lit-adhd/references/card-examples.md +131 -0
  58. package/.grok/skills/lit-adhd/references/status-taxonomy.md +50 -0
  59. package/.grok/skills/lit-adhd/scripts/lib/brief.mjs +421 -0
  60. package/.grok/skills/lit-adhd/scripts/lib/collect.mjs +395 -0
  61. package/.grok/skills/lit-adhd/scripts/lib/gauge.mjs +87 -0
  62. package/.grok/skills/lit-adhd/scripts/lib/next-step.mjs +22 -0
  63. package/.grok/skills/lit-adhd/scripts/lib/plan-task-rows.mjs +32 -0
  64. package/.grok/skills/lit-adhd/scripts/lib/project-state-root.mjs +55 -0
  65. package/.grok/skills/lit-adhd/scripts/lib/redact.mjs +64 -0
  66. package/.grok/skills/lit-adhd/scripts/lib/suggest.mjs +140 -0
  67. package/.grok/skills/lit-adhd/scripts/lib/transcripts.mjs +232 -0
  68. package/.grok/skills/lit-adhd/scripts/rewind.mjs +6 -0
  69. package/.grok/skills/lit-diagram-drawer/SKILL.md +17 -5
  70. package/.grok/skills/lit-diagram-drawer/references/output-spec.md +2 -2
  71. package/.grok/skills/lit-diagram-drawer/references/style-guide.md +20 -11
  72. package/.grok/skills/lit-diagram-drawer/references/type-architecture.md +3 -3
  73. package/.grok/skills/lit-diagram-drawer/references/type-dependency.md +1 -1
  74. package/.grok/skills/lit-diagram-drawer/references/type-tree.md +3 -3
  75. package/.grok/skills/lit-diagram-drawer/references/type-wardley.md +1 -1
  76. package/.grok/skills/lit-diagram-drawer/references/verifier-guide.md +4 -0
  77. package/.grok/skills/lit-diagram-drawer/scripts/visual-quality.mjs +2 -2
  78. package/.grok/skills/lit-handoff/SKILL.md +2 -0
  79. package/.grok/skills/lit-hijack/SKILL.md +459 -0
  80. package/.grok/skills/lit-hijack/references/capture-and-provenance.md +124 -0
  81. package/.grok/skills/lit-hijack/references/clean-room-build.md +130 -0
  82. package/.grok/skills/lit-hijack/references/distil-and-licence.md +128 -0
  83. package/.grok/skills/lit-hijack/references/gap-and-port-design.md +150 -0
  84. package/.grok/skills/lit-hijack/references/parity-and-report.md +130 -0
  85. package/.grok/skills/lit-hijack/scripts/hijack.mjs +890 -0
  86. package/.grok/skills/lit-hijack/scripts/lib/safe-fetch.mjs +213 -0
  87. package/.grok/skills/lit-plan/SKILL.md +3 -1
  88. package/.grok/skills/lit-plan/references/plan-schema.md +4 -0
  89. package/.grok/skills/lit-plan/scripts/scaffold-plan.mjs +9 -2
  90. package/.grok/skills/lit-plan/scripts/scope-roots.mjs +83 -0
  91. package/.grok/skills/lit-pptx/SKILL.md +10 -5
  92. package/.grok/skills/lit-pptx/examples/13-engineering-review-computational-brutalism-ko.md +173 -0
  93. package/.grok/skills/lit-pptx/examples/14-launch-pitch-neo-brutalism-ko.md +154 -0
  94. package/.grok/skills/lit-pptx/examples/15-design-lecture-bauhaus-ko.md +139 -0
  95. package/.grok/skills/lit-pptx/examples/16-community-programme-riso-ko.md +158 -0
  96. package/.grok/skills/lit-pptx/examples/17-public-data-briefing-newsroom-ko.md +179 -0
  97. package/.grok/skills/lit-pptx/fonts/jetbrains-mono/JetBrainsMono-Bold.ttf +0 -0
  98. package/.grok/skills/lit-pptx/fonts/jetbrains-mono/JetBrainsMono-Regular.ttf +0 -0
  99. package/.grok/skills/lit-pptx/fonts/jetbrains-mono/OFL.txt +93 -0
  100. package/.grok/skills/lit-pptx/fonts/jetbrains-mono/provenance.json +1 -0
  101. package/.grok/skills/lit-pptx/references/direction-step.md +34 -8
  102. package/.grok/skills/lit-pptx/references/tonalities/bauhaus.md +140 -0
  103. package/.grok/skills/lit-pptx/references/tonalities/computational-brutalism.md +150 -0
  104. package/.grok/skills/lit-pptx/references/tonalities/neo-brutalism.md +161 -0
  105. package/.grok/skills/lit-pptx/references/tonalities/newsroom.md +144 -0
  106. package/.grok/skills/lit-pptx/references/tonalities/riso.md +137 -0
  107. package/.grok/skills/lit-pptx/scripts/compile-deck.js +1 -1
  108. package/.grok/skills/lit-pptx/scripts/craft_extras.py +61 -3
  109. package/.grok/skills/lit-pptx/scripts/deck_output.py +76 -62
  110. package/.grok/skills/lit-pptx/scripts/embed_fonts.py +14 -1
  111. package/.grok/skills/lit-pptx/scripts/lib/grid-resolver.js +101 -110
  112. package/.grok/skills/lit-pptx/scripts/lib/layout-resolver.js +9 -15
  113. package/.grok/skills/lit-pptx/scripts/lib/render-pack.js +389 -582
  114. package/.grok/skills/lit-pptx/scripts/lib/slide-grid.js +104 -0
  115. package/.grok/skills/lit-pptx/scripts/lib/template-registry.js +60 -8
  116. package/.grok/skills/lit-pptx/scripts/qa_deck.py +4 -4
  117. package/.grok/skills/lit-pptx/templates/tonalities/atlas/pack.yaml +2 -0
  118. package/.grok/skills/lit-pptx/templates/tonalities/bauhaus/pack.yaml +98 -0
  119. package/.grok/skills/lit-pptx/templates/tonalities/chalk/pack.yaml +2 -0
  120. package/.grok/skills/lit-pptx/templates/tonalities/computational-brutalism/pack.yaml +99 -0
  121. package/.grok/skills/lit-pptx/templates/tonalities/gazette/pack.yaml +2 -0
  122. package/.grok/skills/lit-pptx/templates/tonalities/ledger/pack.yaml +2 -0
  123. package/.grok/skills/lit-pptx/templates/tonalities/neo-brutalism/pack.yaml +107 -0
  124. package/.grok/skills/lit-pptx/templates/tonalities/newsroom/pack.yaml +99 -0
  125. package/.grok/skills/lit-pptx/templates/tonalities/night/pack.yaml +2 -0
  126. package/.grok/skills/lit-pptx/templates/tonalities/paper/pack.yaml +2 -0
  127. package/.grok/skills/lit-pptx/templates/tonalities/riso/pack.yaml +99 -0
  128. package/.grok/skills/lit-pptx/templates/tonalities/signal/pack.yaml +3 -0
  129. package/.grok/skills/lit-pptx/templates/tonalities/studio/pack.yaml +2 -0
  130. package/.grok/skills/lit-recap/SKILL.md +1 -1
  131. package/.grok/skills/lit-schematic/SKILL.md +140 -0
  132. package/.grok/skills/lit-schematic/examples/iso-heat-exchanger/build.mjs +38 -0
  133. package/.grok/skills/lit-schematic/examples/iso-heat-exchanger/scene.mjs +133 -0
  134. package/.grok/skills/lit-schematic/examples/journal-adsorption-rig/build.mjs +87 -0
  135. package/.grok/skills/lit-schematic/examples/pid-dosing-skid/build.mjs +85 -0
  136. package/.grok/skills/lit-schematic/references/cutaway-outputs.md +70 -0
  137. package/.grok/skills/lit-schematic/references/isometric-craft.md +101 -0
  138. package/.grok/skills/lit-schematic/references/journal-figures.md +72 -0
  139. package/.grok/skills/lit-schematic/references/kit-api.md +134 -0
  140. package/.grok/skills/lit-schematic/references/pfd-and-layout.md +53 -0
  141. package/.grok/skills/lit-schematic/references/pid-drafting.md +103 -0
  142. package/.grok/skills/lit-schematic/references/pid-symbols.md +163 -0
  143. package/.grok/skills/lit-schematic/references/verification.md +100 -0
  144. package/.grok/skills/lit-schematic/scripts/doctor.mjs +57 -0
  145. package/.grok/skills/lit-schematic/scripts/lib/figure.mjs +81 -0
  146. package/.grok/skills/lit-schematic/scripts/lib/fonts.mjs +27 -0
  147. package/.grok/skills/lit-schematic/scripts/lib/geom.mjs +113 -0
  148. package/.grok/skills/lit-schematic/scripts/lib/interactive.mjs +292 -0
  149. package/.grok/skills/lit-schematic/scripts/lib/isa.mjs +115 -0
  150. package/.grok/skills/lit-schematic/scripts/lib/iso.mjs +719 -0
  151. package/.grok/skills/lit-schematic/scripts/lib/legend-sheet.mjs +162 -0
  152. package/.grok/skills/lit-schematic/scripts/lib/pid.mjs +937 -0
  153. package/.grok/skills/lit-schematic/scripts/lib/png.mjs +132 -0
  154. package/.grok/skills/lit-schematic/scripts/lib/qa-core.mjs +658 -0
  155. package/.grok/skills/lit-schematic/scripts/lib/route.mjs +218 -0
  156. package/.grok/skills/lit-schematic/scripts/lib/sheet.mjs +890 -0
  157. package/.grok/skills/lit-schematic/scripts/lib/svg.mjs +82 -0
  158. package/.grok/skills/lit-schematic/scripts/lib/theme.mjs +115 -0
  159. package/.grok/skills/lit-schematic/scripts/motion.mjs +129 -0
  160. package/.grok/skills/lit-schematic/scripts/qa.mjs +92 -0
  161. package/.grok/skills/lit-schematic/scripts/render.mjs +233 -0
  162. package/.grok/skills/lit-schematic/scripts/scaffold.mjs +60 -0
  163. package/.grok/skills/lit-scientific-visualization/SKILL.md +36 -12
  164. package/.grok/skills/lit-typographic-motion/SKILL.md +7 -4
  165. package/.grok/skills/lit-typographic-motion/THIRD_PARTY_NOTICES +11 -0
  166. package/.grok/skills/lit-typographic-motion/recipes/hero-3d/expected.json +62 -0
  167. package/.grok/skills/lit-typographic-motion/recipes/hero-3d/index.html +82 -0
  168. package/.grok/skills/lit-typographic-motion/references/choice-first.md +30 -0
  169. package/.grok/skills/lit-typographic-motion/references/cover.md +10 -1
  170. package/.grok/skills/lit-typographic-motion/references/depth.md +119 -0
  171. package/.grok/skills/lit-typographic-motion/references/treatment.md +9 -1
  172. package/.grok/skills/lit-typographic-motion/scripts/blender/runner.py +218 -0
  173. package/.grok/skills/lit-typographic-motion/scripts/lib/assets.mjs +230 -0
  174. package/.grok/skills/lit-typographic-motion/scripts/lib/blender.mjs +136 -0
  175. package/.grok/skills/lit-typographic-motion/scripts/lib/board.mjs +153 -0
  176. package/.grok/skills/lit-typographic-motion/scripts/lib/chrome.mjs +61 -32
  177. package/.grok/skills/lit-typographic-motion/scripts/lib/constants.mjs +4 -2
  178. package/.grok/skills/lit-typographic-motion/scripts/lib/cover-capture.mjs +20 -11
  179. package/.grok/skills/lit-typographic-motion/scripts/lib/cover-treatment.mjs +26 -2
  180. package/.grok/skills/lit-typographic-motion/scripts/lib/cover.mjs +12 -5
  181. package/.grok/skills/lit-typographic-motion/scripts/lib/frame-pool.mjs +78 -1
  182. package/.grok/skills/lit-typographic-motion/scripts/lib/gallery.mjs +160 -0
  183. package/.grok/skills/lit-typographic-motion/scripts/lib/house.mjs +43 -0
  184. package/.grok/skills/lit-typographic-motion/scripts/lib/look.mjs +39 -1
  185. package/.grok/skills/lit-typographic-motion/scripts/lib/scaffold.mjs +174 -0
  186. package/.grok/skills/lit-typographic-motion/scripts/lib/score.mjs +640 -0
  187. package/.grok/skills/lit-typographic-motion/scripts/lib/sound.mjs +143 -0
  188. package/.grok/skills/lit-typographic-motion/scripts/lib/soundtrack.mjs +12 -3
  189. package/.grok/skills/lit-typographic-motion/scripts/lib/stage-gate.mjs +44 -0
  190. package/.grok/skills/lit-typographic-motion/scripts/lib/stage-qa.mjs +132 -3
  191. package/.grok/skills/lit-typographic-motion/scripts/lib/stage-session.mjs +51 -3
  192. package/.grok/skills/lit-typographic-motion/scripts/lib/stage.mjs +74 -9
  193. package/.grok/skills/lit-typographic-motion/scripts/lib/styles.mjs +224 -0
  194. package/.grok/skills/lit-typographic-motion/scripts/lib/treatment.mjs +198 -4
  195. package/.grok/skills/lit-typographic-motion/scripts/lib/vendor/three/LICENSE +21 -0
  196. package/.grok/skills/lit-typographic-motion/scripts/lib/vendor/three/addons/environments/RoomEnvironment.js +144 -0
  197. package/.grok/skills/lit-typographic-motion/scripts/lib/vendor/three/addons/geometries/RoundedBoxGeometry.js +155 -0
  198. package/.grok/skills/lit-typographic-motion/scripts/lib/vendor/three/three.module.js +54571 -0
  199. package/.grok/skills/lit-typographic-motion/scripts/motion.mjs +56 -6
  200. package/.grok/skills/lit-typographic-motion/scripts/stage/cover-init.js +20 -8
  201. package/.grok/skills/lit-typographic-motion/scripts/stage/loop-kit.js +2 -2
  202. package/.grok/skills/lit-typographic-motion/scripts/stage/stage-kit.js +25 -0
  203. package/.grok/skills/lit-typographic-motion/styles/paper.json +1 -0
  204. package/.grok/skills/lit-typographic-motion/styles/swiss-signal.json +1 -0
  205. package/.grok/skills/lit-typographic-motion/styles/terminalcore.json +1 -0
  206. package/.grok/skills/lit-typographic-motion/styles/tidal.json +1 -0
  207. package/.grok/skills/litgrok/SKILL.md +1 -1
  208. package/.grok/skills/litresearch/SKILL.md +2 -0
  209. package/.grok/skills/readme-studio/SKILL.md +14 -12
  210. package/.grok/skills/readme-studio/references/choice-first.md +24 -0
  211. package/.grok/skills/start-work/SKILL.md +8 -1
  212. package/.grok-plugin/plugin.json +4 -1
  213. package/CHANGELOG.md +18 -0
  214. package/README.md +11 -11
  215. package/README_ko-KR.md +11 -11
  216. package/TRADEMARK.md +12 -0
  217. package/bin/litgrok.mjs +2 -0
  218. package/docs/assets/readme/badge-version.svg +1 -1
  219. package/docs/assets/showcase/brief.webp +0 -0
  220. package/docs/assets/showcase/deck.webp +0 -0
  221. package/docs/assets/showcase/page.webp +0 -0
  222. package/docs/assets/showcase/pid.webp +0 -0
  223. package/docs/assets/skills/lit-adhd.webp +0 -0
  224. package/docs/assets/skills/lit-hijack.webp +0 -0
  225. package/docs/assets/skills/lit-schematic.webp +0 -0
  226. package/docs/reference.md +11 -7
  227. package/docs/reference_ko-KR.md +11 -7
  228. package/hooks/hooks.json +11 -0
  229. package/package.json +6 -1
  230. package/plugin.json +1 -1
  231. package/.grok/skills/frontend-ui-ux/scripts/page-probe.mjs +0 -105
  232. package/.grok/skills/frontend-ui-ux/scripts/probe.mjs +0 -91
  233. package/.grok/skills/frontend-ui-ux/scripts/rule-data.mjs +0 -56
  234. package/.grok/skills/frontend-ui-ux/scripts/static-probe.mjs +0 -27
  235. package/.grok/skills/frontend-ui-ux/scripts/static-server.mjs +0 -19
@@ -3,8 +3,6 @@ first; after the first edit nobody can tell a regression from an intended change
3
3
 
4
4
  ## Baseline capture
5
5
 
6
- Capture before touching a file. No baseline means no parity list and no regression guard.
7
-
8
6
  - Pin the pre-change revision; its `source_hash` is the baseline identity.
9
7
  - Capture every affected route at `compact` and `expanded`.
10
8
  - Capture `loading`, `empty`, `error`, `disabled`, and overflow per route.
@@ -21,8 +19,6 @@ Classify debt before proposing a treatment; the category decides how far the fix
21
19
  5. Behavioral: no recovery path, destroyed input, missing progress feedback.
22
20
  6. Aesthetic: dated treatment with no functional cost.
23
21
 
24
- Rank by what a user cannot do. Aesthetic debt alone does not justify opening a surface.
25
-
26
22
  ## Decision per surface
27
23
 
28
24
  Record exactly one of four decisions per inventory surface, with one line of reasoning.
@@ -44,8 +40,6 @@ Order the work so the product ships at the end of every stage.
44
40
  4. Keep behavioral fixes in their own stages, never folded into a visual stage.
45
41
  5. Delete the superseded path only after its last consumer moves.
46
42
 
47
- A stage that cannot ship alone is too large. Split it.
48
-
49
43
  ## Parity list
50
44
 
51
45
  These hold at every stage boundary. Check the captured baseline, not memory.
@@ -85,3 +79,13 @@ Close only when the record is complete.
85
79
  - The parity list holds, or each break has an owner and an expiry.
86
80
  - The final artifact reached the independent review pass bound to the design contract hash.
87
81
  - The receipt states `PASS`, `FAIL`, or `BLOCKED` and names unresolved deviations.
82
+
83
+ ## Failure patterns
84
+
85
+ Reject:
86
+
87
+ - Editing before the baseline is captured.
88
+ - "Modernize it" accepted as a scope statement.
89
+ - One branch that migrates every route at once.
90
+ - A failing test rewritten to match the new implementation.
91
+ - A redesign called done while one route still renders the superseded system.
@@ -1,75 +1,150 @@
1
1
  # Slop register
2
2
 
3
- Use these entries after the craft-floor pass to find repeated defaults, filler, and fake functionality. A deterministic signal may identify a candidate, but a row marked JUDG or DET-assist needs a reviewer to decide whether the context earns an exception. Do not convert taste into an automatic HIGH. The probe can check live DOM and computed styles; the static fallback reports only source-visible signals and keeps all rendered checks `not_verified`.
4
-
5
- When a row fires, remove the unnecessary element first, use a native platform control when possible, reuse an existing component or token, correct a value, and add new code only if none of those resolves the problem. Preserve genuine facts, credited data, and explicit design direction. A claimed fix is supported by a second probe at the affected view and the final responsive matrix.
6
-
7
- | Rule | Pattern and observable signal | Trigger | Severity | First repair |
8
- |---|---|---|---|---|
9
- | SLOP-001 | **Cloned split-hero repetition** (DET): Walk sibling `<section>`s; hash each one's column-count + which side holds the image node; flag a run where the same hash repeats | run length ≥ 3 consecutive sections | MEDIUM | Break the run with a full-width, stacked, or bento section before the 3rd repeat (correct) |
10
- | SLOP-002 | **Identical tile-grid repetition** (DET): For each grid, compare child bounding-box width/height (tolerance ±4px) and child DOM shape across siblings; count grids on the page matching this signature | ≥ 4 identical tiles in one grid, where each tile's child shape is icon/svg/img + heading + text. A grid rendered as `ul`, `ol` or `table` is a data collection and is skipped (Delta 1: the calibrated n ≥ 4 floor; every clean reference has a legitimate 3-item grid) | MEDIUM | Vary tile size/structure per item, or switch one instance to a different layout family (correct) |
11
- | SLOP-003 | **Nested card shells / unfilled bento cells** (DET-assist, JUDG verdict): Count nesting depth of bordered/shadowed containers sharing one content region; separately, diff a bento grid's cell count against its actual content-item count | nesting depth ≥ 3, or cell count ≠ content-item count | MEDIUM | Collapse the redundant wrapper, or reshape the grid to match the content count (delete) |
12
- | SLOP-004 | **Split-header filler paragraph** (DET-assist, JUDG verdict): DET-assist: header block with two columns where one column's text length < 15 words and has no distinct visual role (icon, stat, CTA). JUDG: does the short column merely restate/paraphrase the headline, or does it carry a real second message (e.g. a deliberate one-sentence subhead)? | short column < 15 words, no distinct role, AND JUDG finds no real second message | MEDIUM | Stack headline and body vertically instead of splitting them (correct) |
13
- | SLOP-005 | **Layout family reused verbatim across the page** (DET): Structural-signature hash (column count, media position, card count) per section; flag any hash appearing at least this many times | repeat count ≥ 3 (raised from ≥ 2 — reusing one layout family exactly twice on a longer page is ordinary, deliberate design-system consistency; ≥ 3 aligns with SLOP-001's consecutive-run floor) | MEDIUM | Give the repeat's second occurrence a different layout family (correct) |
14
- | SLOP-006 | **Monotonous spacing rhythm** (DET): Bucket computed gap values (round to 4px) between direct sibling elements within one section at a time, not every element on the page; flag when one bucket dominates a page complex enough to need real grouping | page has ≥ 5 distinct visual regions AND ≥ 10 samples, dominant bucket > 85% of samples, ≤ 3 distinct nonzero buckets (raised from > 60% / whole-page sampling — a restrained, intentional 3-token spacing system on a simple page is good practice, not slop) | MEDIUM | Introduce a real multi-step spacing scale and apply it by relationship, not by habit (correct) |
15
- | SLOP-007 | **Decorative empty space with no hierarchy role** (JUDG): Checklist: for any gap noticeably larger than its neighbors, can a reviewer name what it is protecting or separating? | — | LOW (WARN) | Remove the gap or attach it to a real grouping decision (delete) |
16
- | SLOP-008 | **Default purple/blue "AI" gradient palette** (DET): Convert computed text colour and gradient stops to HSL hue; flag heading text (h1–h3 or ≥ 20px) or any gradient stop whose hue falls in the banned band with a channel spread (max − min RGB) ≥ 50/255, unless that same hue is also the site's own declared/repeated primary brand color across more than one unrelated page region | HSL hue 260°–310° with a channel spread ≥ 50/255, on heading text (h1–h3 or ≥ 20px) or on any gradient stop; brand-consistency exemption applies (Delta 1: the earlier 220°–280° band pulled in ordinary brand blues near 221°–224°) | MEDIUM (calibration: never fired on any of the 19 clean/real pages in this task pack — a narrow single-pattern check, not a validated near-universal tell; downgraded from HIGH) | Swap in a neutral base plus one hue rooted in the actual brand, per the existing lila guardrail (correct) |
17
- | SLOP-009 | **Gradient-filled headline text** (DET): Same element has both a background-clip:text (or equivalent) property and a multi-stop gradient value | co-occurrence present | MEDIUM | Replace with a solid color and a weight or size change (correct) |
18
- | SLOP-010 | **Glow / bloom halo on primary actions or headings** (DET): Box-shadow or filter value passes the glow test shared with CF-404 (offset ≤ 2px, blur ≥ 16px, shadow HSL saturation > 0.4), on a primary button or heading, excluding any `:focus`/`:focus-visible` state (an accessible keyboard-focus ring legitimately uses the same zero-offset colored-glow shape) | shared glow test, not a focus state, and the same glow recurring on ≥ 2 unrelated elements | MEDIUM when the same glow recurs on ≥ 2 unrelated elements (Delta 1: a genericness tell is at most MEDIUM); a single glow is reported once under CF-404 (LOW), never twice | Use the shadow-as-border recipe (offset + soft neutral blur) instead, or drop the shadow (correct) |
19
- | SLOP-011 | **Floating blob / sphere decoration** (DET-assist, JUDG verdict): DET-assist: radial-gradient element, opacity < 0.3, absolutely positioned, not bound to any content element. JUDG: is there a stated atmospheric/focal purpose for it, or is it reflex decoration? | presence AND JUDG finds no stated purpose (a single deliberate atmospheric blob is a common, often well-regarded accent on modern SaaS marketing pages, not by itself a tell) | MEDIUM | Remove, or tie it to an actual focal point in the layout (delete) |
20
- | SLOP-012 | **Decorative dot/grid background with no referent** (DET): Repeating small-scale background pattern (dot or grid) present with no `<canvas>`/`<svg>` chart or data table in the same section, co-occurring with at least one other decorative-visual slop signal from this cluster (e.g. a floating blob or a banned-hue gradient) | presence, no adjacent data element, AND ≥ 1 co-occurring slop signal (a dot-grid or blueprint texture alone is a common, tasteful choice on developer-tool sites, not inherently a tell) | MEDIUM | Remove unless the grid is standing in for a real chart (delete) |
21
- | SLOP-013 | **Over-rendered noise hiding the layout** (JUDG): Checklist: with the texture layer hidden, does the layout read the same or better? | — | LOW (WARN) | Reduce opacity or remove; if kept, confine it to a fixed non-scrolling layer (correct) |
22
- | SLOP-014 | **Glassmorphism used as unexamined default** (JUDG): Checklist: is there a stated reason (premium/luxury/media-overlay context) for the blur, and a solid fallback under `prefers-reduced-transparency`? | — | LOW (WARN) | Drop the blur for a solid surface unless the brief earns it (delete) |
23
- | SLOP-015 | **Fake pseudo-border accent stripe** (DET): Independently count, per scope: (a) a single-side accent on a rounded container: one side's border is ≥ 2px with HSL saturation > 0.3 while the other three sides are 0 or ≤ 1px neutral (a uniform chromatic border on all sides, such as an outline button, is not a stripe), (b) an inset box-shadow with two lengths and one chromatic stop, (c) a positioned pseudo-element bar (geometry in §C.3's SLOP-015 row) — excluding any element carrying `role="alert"`/`role="note"` or a recognizable callout/admonition class, since distinct semantic callout types (info/warning/error) legitimately use distinct colored accents by design | any one of (a)/(b)/(c) reaching ≥ 2 occurrences in one rounded scope; variant (b) alone reaches threshold at ≥ 1 | MEDIUM | Drop the stripe; carry the same emphasis in the card's own fill or an icon (delete) |
24
- | SLOP-016 | **Reflex default sans font** (DET-assist, JUDG verdict): DET-assist: the first family in the resolved `getComputedStyle(el).fontFamily` stack that actually loaded (never any fallback family further down the stack; or an `@font-face`/Google-Fonts URL in `document.styleSheets`) matches a fixed common-default list, **excluding Geist / Geist Sans / Geist Mono** — the current corpus names Geist as its own recommended first alternative to Inter (§4.1), so this row cannot also ban it without reconciling that. JUDG: is there a declared design-token rationale for keeping a matched font (Inter/system-ui in particular are used by many acclaimed, legible real products, not only as a lazy default)? | any match on the fixed list (Geist family excepted) AND JUDG finds no declared rationale | MEDIUM | Pick a less common face tied to the product's own voice, or state why the common one was kept (correct) |
25
- | SLOP-017 | **Serif reached for without a stated reason** (DET-assist, JUDG verdict): DET: heading font-family matches a fixed banned-serif shortlist. JUDG: is there a one-line stated rationale tying this serif to this brand? | any match on the shortlist AND no rationale recorded | MEDIUM | Switch to a sans display face, or keep the serif only with a recorded rationale (correct) |
26
- | SLOP-018 | **Giant headline over a weak tiny subhead** (DET-assist, JUDG verdict): DET-assist: ratio of heading computed font-size to its adjacent subhead font-size. JUDG: does the small text actually read as an afterthought, or as a deliberate eyebrow/caption doing its intended job? | ratio ≥ ~3.5 with subhead below ~14px, AND JUDG confirms it reads as an afterthought | MEDIUM | Raise the subhead's role in the scale or shorten the headline pairing (correct) |
27
- | SLOP-019 | **Too many type moods on one page** (DET): Count of distinct computed `font-family` values across the document (base family only, ignoring fallbacks), excluding any family that resolves only on elements matching a known icon-font signature (single-glyph text content, `aria-hidden="true"`, or a recognized icon-font class/family name) | > 3 distinct families, icon fonts excluded. Chosen over the stricter one-family "distill" ceiling of an earlier reference catalogue because distill is a deliberate reduction workflow, not a general craft floor; krehel's general guidance ("rarely use more than three") is used instead | MEDIUM | Cut back to the stated ceiling for the page (delete) |
28
- | SLOP-020 | **Lazy all-caps overuse** (DET): `text-transform: uppercase` measured per rendered leaf text node (not per ancestor merely carrying the CSS property, which over-counts when e.g. a `nav ul` wrapper applies it to several short labels at once), skipped when the matched text is > 50% non-cased script (CJK/Hangul), since the transform has no visual "shouting" effect there | leaf text length > ~40 chars under `text-transform: uppercase`, majority-cased-script text only | LOW | Reserve uppercase for short labels only; sentence-case the rest (correct) |
29
- | SLOP-021 | **Washed-out gray secondary text on a colored surface** (DET): Text lightness is 40–70% AND saturation < 10% (targets genuine mid-gray only; explicitly excludes near-white text at L > 90% and near-black text at L < 10%, both standard, correct, accessible choices of text color on a colored surface), while its containing scope's background is chromatic (saturation clearly above the text's), same tag/branch | text L 40–70%, S < 10%, background chromatic | MEDIUM (cross-ref **CF-201** — craft floor owns the canonical contrast-floor check this overlaps; kept here for the reflex-default pattern itself) | Tint the secondary text from the surface's own hue instead of plain gray (correct) |
30
- | SLOP-022 | **More than one accent hue competing per screen** (JUDG, DET-assist): DET-assist: histogram of high-saturation hues, sampled only from filled background surfaces ≥ 24×24px (buttons/chips/blocks) — not text or border color, which conflates decorative accents with thin status underlines — and excluding any element carrying a recognized status/semantic role (`role="status"`, `aria-invalid`, a matched success/warning/error/info class, or a small badge/pill shape), since necessary status color-coding is not a competing decorative accent; flag > 1 distinct remaining hue family | > 1 accent hue family, fill-surfaces ≥ 24×24px only, status colors excluded | MEDIUM (cross-ref **CF-205** — craft floor owns the canonical one-accent-per-view threshold and the identical filled-surface/status-role-excluded histogram method; this row restates the same finding as a genericness signal, see Section C's CF-205 catalogue entry for the executable algorithm) | Pick one accent per view and demote the rest to neutral (correct) |
31
- | SLOP-023 | **Pure black or pure white as a base surface** (DET): Computed background-color or text color exactly `#000000` or `#ffffff` on a primary surface/text role, excluding a surface under `[data-theme="dark"]`/`prefers-color-scheme: dark` where true black is used consistently as the dominant background across the whole page (a deliberate OLED/monochrome-system choice, not a reflex default) | exact match, outside the declared-dark-theme exception | LOW | Shift to an off-black/off-white a few percent toward the brand's neutral (correct) |
32
- | SLOP-024 | **Spring/bounce easing on routine feedback** (DET): `getComputedStyle().animationName`/`transitionTimingFunction` resolves to a bounce/elastic keyword, or a raw cubic-bezier with control points outside roughly [-0.1, 1.1], scoped to routine controls (toggle/checkbox/button-press/toast transitions) and excluding a one-shot celebratory/confirmation animation (an element with a `role="status"`/single-fire class not bound to a form control) | keyword match, or bezier outside that range, on a routine control | MEDIUM (cross-ref **CF-505** — craft floor owns the canonical threshold and the executable `scanAnimationTimingIssues` algorithm in Section C; this row is a cross-reference, not a second implementation) | Replace with a settled ease-out curve, or a spring config with bounce fixed at 0 (correct) |
33
- | SLOP-025 | **Entrance animation scaling in from zero** (DET): Keyframe/initial transform for a card/section mount animation includes a scale value at or near 0 | scale start ≤ ~0.1 | MEDIUM (cross-ref **CF-503** — craft floor's floor is 0.95, tighter than this row's ~0.1; craft floor owns the canonical threshold) | Start near 0.95, never 0 (correct). Note: an absolutely-positioned icon swap/cross-fade is a distinct convention with its own recipe (`scale: 0.25 → 1`, never 0.5 or 0.6) — don't fold that case into this general entrance-scale floor |
34
- | SLOP-026 | **Animating layout-triggering properties for motion** (DET): Transition/animation `property` value list includes a layout-affecting property, and the value isn't the deliberate `all`, excluding a `height`/`max-height` transition bound to an expand/collapse disclosure pattern (`aria-expanded` toggle, `<details>`, or a matched accordion class) — there is no reliable cross-browser transform-only technique for transitioning to `auto` height | any layout property present outside the disclosure exception | MEDIUM (cross-ref **CF-508** — craft floor owns the canonical threshold; the slop angle is the reflex choice, not just the cost) | Animate `transform`/`opacity` instead (correct) |
35
- | SLOP-027 | **Decorative infinite pulse/blink with no bound state** (DET): Keyframe loop (`animation-iteration-count: infinite`) on an opacity/shadow property, element has none of: a `data-state`/other `data-*` attribute, `aria-busy="true"`, or a recognized skeleton/shimmer/loading class name (the standard loading-skeleton pattern is real and bound, but typically expressed via one of the latter two rather than `data-state` specifically) | presence, no bound-state signal of any of the above kinds | LOW | Remove, or slow it and bind it to the real status it claims to show (delete) |
36
- | SLOP-028 | **Motion fired on every routine, high-frequency interaction** (JUDG, DET-assist): DET-assist: count animated-transition bindings, restricted to a fixed, inherently-high-frequency selector set (`:hover` transitions, list-item/row transitions, per-item scroll/re-render transitions) as the operational proxy for "fires often" — live session-frequency isn't observable from a single-pass DOM probe | transition duration > ~150ms on a selector in the fixed high-frequency set | LOW (cross-ref **CF-506** — craft floor's ≤150ms high-frequency ceiling is the same threshold, scoped to a repeated-selector/scrollable-container gate) | Make the routine case instant or ≤150ms; save longer motion for rare, meaningful moments (correct) |
37
- | SLOP-029 | **Eyebrow/kicker label templated above most headings** (DET): Count eyebrow labels: the previous visible element sibling of an h1–h3 that has ≤ 4 words, an uppercase transform or all-caps Latin text, letter-spacing ≥ 0.05em, and a font-size ≤ 0.75× the heading's — counting only elements actually rendered at the current breakpoint (`visible()`) — excludes a hidden responsive-duplicate nav mirror or a currently-collapsed accordion panel from double-counting | count > ceil(sectionCount / 3), where sectionCount = the number of visible h2; visible elements only | MEDIUM (Delta 1: a genericness tell is at most MEDIUM) | Drop the eyebrow; the heading and the section's place on the page already carry the context (delete) |
38
- | SLOP-030 | **Section numbering used as decoration** (DET-assist, JUDG verdict): DET: regex match of a zero-padded numeric section/tile label prefix, min. 2 distinct index values (the narrower numeric-index-beside-heading coverage). JUDG: does the sequence carry real, meaningful process information (onboarding steps, checkout stages) rather than decorative counting? | any match, ≥ 2 distinct index values, AND JUDG finds no real ordering behind it — the ubiquitous "01/02/03 — how it works" pattern describing a genuinely sequential process is not itself a defect | MEDIUM | Remove the numbering; if progression matters, name the step itself instead of counting it (delete) |
39
- | SLOP-031 | **Unreleased-looking version/status stamp in marketing copy** (DET-assist, JUDG verdict): DET: regex for a version-like token (`vN.N`, `BETA`, `ALPHA`, build-hash pattern) inside visible copy. JUDG: is this inside a real changelog/release-notes/docs context (a live-DOM probe can't reliably distinguish a real changelog page from a mocked one) | any match AND JUDG finds no real release-notes context | MEDIUM | Remove the stamp unless the brief is genuinely about a launch/preview status (delete) |
40
- | SLOP-032 | **Decorative status dot with no bound state** (DET): Small colored circle/pseudo-element directly preceding label text, with no `data-state`/live-status attribute behind it | presence, no bound attribute | LOW | Remove, or reserve it for an actual live/availability signal (delete) |
41
- | SLOP-033 | **Middle-dot / locale-time separator strip overused** (DET): Count of `·` glyphs on one line ≥ 3 (raised from the corpus's literal "max 1" cap — a 2-dot "Author · Date · Read time"-style byline strip is standard, tasteful editorial practice, not slop; deliberately loosened here, see Calibration & review changes below); separately, a line combining ≥ 2 of {city name, UTC/GMT offset, temperature/weather token} in one string, which is the observable proxy for "locale strip" (a DOM probe can't see whether the brief is travel-themed) | `·` count ≥ 3 on one line, OR ≥ 2 co-occurring locale/weather tokens on one line | LOW | Prefer line breaks or columns to chained middle-dots; drop the locale strip unless the brief is genuinely place/time relevant (delete) |
42
- | SLOP-034 | **Decorative word strip at the hero's foot** (DET): Short list of all-caps tokens joined by separators, non-interactive, positioned within the bottom ~15% of the hero's own bounding box, excluding a token strip matching a known certification/compliance vocabulary (e.g. SOC2, GDPR, ISO27001, HIPAA), which communicates real information rather than decorative mood-words | presence within the bottom 15% of the hero's bbox, no `<a>`/real status content inside, not a compliance-badge strip | MEDIUM | Remove, unless it is a real sticky navigation strip or genuine build/status info (delete) |
43
- | SLOP-035 | **Scroll-cue label or arrow at the first viewport** (DET): Element containing scroll-cue text or an animated chevron icon, with no function beyond restating that the page continues | presence | LOW | Remove; a visitor at the top of the page already knows the page continues (delete) |
44
- | SLOP-036 | **Marketing buzzword filler** (DET): `visible()` text nodes outside `code`/`pre`/`blockquote` and form-control values (authored-copy scope above), matched whole-word and case-insensitive against the cited detector's fixed 29-entry list, which is mostly multi-word or hyphenated stock phrases; never an open list of bare common words | count ≥ 1 | MEDIUM (Delta 1: a genericness tell is at most MEDIUM) | Replace with a specific, product-true claim (correct) |
45
- | SLOP-037 | **Fabricated placeholder brand wordmark** (DET-assist, JUDG verdict): DET-assist: text node matched against a fixed placeholder-brand-name list; whether an unlisted wordmark also has "no semantic tie to the brief" isn't something a DOM probe can judge, so it is not part of the DET condition. JUDG: the reviewer confirms the match is not the product's real name — several listed names are real brands a user may own, and the probe never sees the brief | any match on the fixed list AND JUDG confirms it is not the product's real name | MEDIUM (Delta 1) | Name the product from the brief itself, or invent one name tied to what it actually does (correct) |
46
- | SLOP-038 | **Generic placeholder person name (the "Jane Doe" effect)** (DET): Attributed name text matched against a fixed common-filler-name list | any match | MEDIUM | Replace with a specific, locale-appropriate name (correct) |
47
- | SLOP-039 | **Aphoristic "Not X. Y." cadence repeated** (DET): Count of sentence pairs matching the negate-then-restate pattern | combined count ≥ 3 | LOW | Vary sentence rhythm; keep the device to at most one use per page (correct) |
48
- | SLOP-040 | **Em-dash (or flourish en-dash) anywhere in shipped copy** (DET): Scan visible body text nodes only (authored-copy scope above), excluding `<title>`, attribute values, `code`/`pre`/`kbd` and form-control values, for exactly two code points: U+2014 (em-dash, after entity decoding), and U+2013 (en-dash) only when it has whitespace on both sides and is not flanked by digits, times or dates — a numeric range such as `9:00 – 18:00` or `2018–2026` is correct en-dash use and never counts. Look-alike glyphs are outside the scan by construction and must not be folded in by normalization or a broad dash class: U+30FC and U+FF70 (Japanese long-vowel marks), U+2015 (horizontal bar), U+FF0D (fullwidth hyphen-minus), U+2500 (box-drawing line), U+4E00 (the Han numeral one). Two narrow carve-outs leave the main count: a doubled U+2014 inside a Han-majority text node (over 30% of its characters in U+4E00–U+9FFF), which is the standard Chinese dash; and a dash inside a `<blockquote>` or `<q>` whose `cite` attribute names a URL on another origin, which marks a verbatim third-party quote. The attribution line outside the quote element, and any quote without such a `cite`, stay in the main count, since the corpus bans the dash in authored quotes and attribution alike | count ≥ 1 in the main scope (zero tolerance unchanged, see Open Question 3); each carve-out hit is reported separately at LOW | MEDIUM (Delta 1: a dash neither blocks nor misleads a visitor; carve-out hits: LOW) | Rewrite with a period, comma, or parentheses instead (correct) |
49
- | SLOP-041 | **Fabricated-looking numeric claim** (JUDG, DET-assist): DET-assist: a stat-shaped number in visible copy (authored-copy scope above): a percentage (`92%`), a multiplier (`4.1×`, `10x`), an abbreviated or plus-suffixed count (`48k`, `2.3M`, `10,000+`), or a number tied to a measurement or rate unit (`5.8 mm`, `13.4 lb`, `47.2 tasks/day`). Removed before matching: currency amounts (a currency symbol, ISO code or `원` beside the number), standalone years 1900–2099 and other dates or clock times, phone-number patterns, version strings (owned by SLOP-031 and SLOP-044), and numbers inside form controls, `<code>`/`<pre>`/`<kbd>`, `<time>` or `<table>` cells. A remaining hit is a candidate only when its nearest block-level ancestor carries no source or mock marker: a `<cite>`, a footnote `<sup>` or reference link, visible text such as source, according to, as of, example, sample, mock or illustrative, or an HTML comment node reading `mock`. JUDG: does the figure come from the brief, brand guidelines or public metrics, or is it invented spec texture? | ≥ 1 candidate after the exclusions, with no source/mock marker in its block, AND JUDG finds no real origin for it | MEDIUM | Cite the real figure, label it as an example, or cut the number entirely (correct) |
50
- | SLOP-042 | **Duplicate call-to-action wording for one intent** (JUDG, DET-assist): DET-assist: cluster all CTA button texts by a small synonym-group list per intent; flag > 1 distinct label mapping to the same intent cluster | > 1 distinct label per intent, same page | LOW | Pick one label for that intent and reuse it everywhere on the page (correct) |
51
- | SLOP-043 | **Div-built fake product screenshot** (DET-assist, JUDG verdict): DET-assist: a visible container at least 240×160px with no `<img>`, `<picture>`, `<video>`, `<canvas>`, `<iframe>` or `<object>` anywhere in its subtree, showing (a) window chrome: ≥ 3 circles, each ≤ 14px across with `border-radius` ≥ 50%, in one horizontal row along the container's top edge (within its top 48px); (b) a side rail plus placeholder rows together: a filled child ≤ 30% of the container's width and ≥ 60% of its height, and ≥ 3 filled sibling blocks ≤ 24px tall holding ≤ 2 characters of `innerText` each; or (c) a rotate/perspective/`scale` < 1 transform on the container (a tilted mockup). It never fires on a container that has a focusable descendant, nor on the page's `main` landmark itself — a real div-built app screen is not a fake one. The geometry bounds are house defaults with no published source; recalibrate on labeled fixtures. JUDG: the corpus explicitly allows a real mini-version of the product UI built from live components, and a static but genuine preview renders the same DOM shape as a fake one, so a reviewer decides whether this is a stand-in for a screenshot | any of (a)/(b)/(c) with no real-media or focusable descendant, AND JUDG confirms a stand-in rather than a real component preview | MEDIUM once JUDG confirms (tier Inferred, the same posture MD-011 takes for its JUDG items); a DET-assist hit alone is a review candidate, never a finding by itself | Use a real screenshot, a generated image, or a real component preview instead (correct / platform) |
52
- | SLOP-044 | **Fake build/version footer inside a mock preview** (DET-assist, JUDG verdict): DET: regex for a build/sync-style string inside a decorative preview or a marketing-page footer. JUDG: is this actually a real changelog/docs surface (not reliably distinguishable from the DOM alone) | any match AND JUDG finds no real changelog/docs surface | MEDIUM | Remove; this is CLI-fixture flavor with nothing to say to a visitor (delete) |
53
- | SLOP-045 | **Decorative identical stat/KPI columns** (DET-assist, JUDG verdict): DET-assist: visible sibling blocks sharing one shape — a numeric text run rendered at ≥ 1.5× the computed font-size of the label beside it, block heights within ±4px of each other — counted as ≥ 4 such siblings, or ≥ 3 inside a section that also holds a marketing CTA link or button. Whether a figure is real is not observable from the rendered DOM: every rendered figure is a literal text node, so the DET half never asserts "unbound". JUDG: did the brief ask for these figures, and does each trace to a real source (brief, brand guidelines, public metrics) or carry a visible source or mock note? | ≥ 4 same-shape stat siblings (≥ 3 beside a marketing CTA), AND JUDG finds KPIs were not requested or a figure has no real source | MEDIUM once JUDG confirms (tier Inferred, MD-011's JUDG posture); a DET-assist hit alone is a review candidate, since an accurate stats banner is a legitimate pattern until judged otherwise | Remove unless the brief actually asked for KPI display, and back any kept number with a real source (delete) |
54
- | SLOP-046 | **Decorative gauge/sparkline/progress element with a hard-coded value** (DET-assist, JUDG verdict): DET-assist: a gauge-, ring-, bar- or sparkline-shaped element — `<progress>`, `<meter>`, `role="progressbar"` or `role="meter"`, an inline `<svg>` circle with a non-`none` `stroke-dasharray` (ring), or an inline `<svg>` holding one `polyline`/`path` series ≤ 64px tall with no axis `<text>` (sparkline) — that shows no visible numeric value, no axis or legend, and has no accessible name. After render every such value is a literal (`value`, `aria-valuenow`, a dash offset, a path string) whether or not it came from data, so the DET half only locates candidates. JUDG: does the element encode a real, current data point from the brief or the product, or is it texture? | candidate present, AND JUDG finds no real data point behind it | MEDIUM | Remove unless it encodes a real, current data point (delete) |
55
- | SLOP-047 | **Illegible ticker-scale logo wall** (DET): An element running (per `getAnimations()`) or declaring an `infinite` keyframe loop that translates along X, whose logo children (`<img>`, inline `<svg>` or background-image elements) resolve to ≤ 6 distinct sources once loop clones collapse (distinct `currentSrc`, background-image URL, or serialized inline-SVG markup), and whose logos render below the floor, measured on each logo element's own `getBoundingClientRect().height`, not its wrapper's | distinct-logo count ≤ 6, AND median rendered logo height < 20px at the 1440px RS viewport. The 20px floor is a house default: the corpus names the failure ('unreadable mosquito logos') without a size, and neither reference clone publishes one; recalibrate on labeled logo walls before tightening | MEDIUM | Slow it down, enlarge the logos, or replace the loop with a static row if the count is this small (correct) |
56
- | SLOP-048 | **Autoplay carousel dots with no real function** (DET): Dot-nav candidate: ≥ 2 visible sibling elements, each ≤ 16×16px with `border-radius` ≥ 50% of its shorter side (or a recognized dots/bullets/indicator class), inside a container that also holds ≥ 2 slides. Autoplay: a declared attribute on the carousel root (`data-autoplay`, `data-bs-ride="carousel"`, `autoplay`), or the active slide or active dot changing between two reads ≥ 6 s apart with no input dispatched; the timed read runs once, at one viewport, and only when a candidate exists, to stay inside the §C.7 per-viewport time cap. Accessible binding, any one of which passes: each dot is a focusable (`tabIndex` ≥ 0) native `<button>`, `role="button"` or `role="tab"` element with an accessible name; the dots carry `aria-controls`; or the current dot carries `aria-selected="true"` (tabbed picker), `aria-disabled="true"` (grouped button picker) or `aria-current`. A key handler attached with `addEventListener` cannot be enumerated from page script (the limit SLOP-058 already states), so this check reads only element and attribute facts and never asserts 'no keyboard binding' | candidate present, autoplay declared or observed, and none of the accessible-binding signals present | LOW | Remove the dots or wire them to real keyboard/AT-reachable navigation (correct) |
57
- | SLOP-049 | **Generic silhouette/egg avatar standing in for a person** (DET): Avatar element resolves to a small fixed set of known generic-icon asset ids/classes | match against the fixed list | LOW | Use a believable photo placeholder or a deliberate illustrated style instead (correct) |
58
- | SLOP-050 | **Category label printed under every logo in a trust wall** (DET): Text node directly under a logo image matching a short category-word pattern | any match | LOW | Drop the caption; the logo alone carries the credibility (delete) |
59
- | SLOP-051 | **Illustration assembled from an excessive primitive count** (JUDG, DET-assist): DET-assist, a published detector re-expressed for the live DOM: an inline `<svg>` rendered at ≥ 200×200px that holds ≥ 8 `rect`/`circle`/`ellipse`/`polygon` elements anywhere in its subtree (`path` is not counted; drawn artwork is mostly paths), ≥ 3 distinct resolved fill paints (ignoring `none`/`transparent`), ≤ 2 `text`/`tspan` elements, and no `<pattern>`. JUDG: an assembled stand-in scene, or a data graphic or diagram whose shape count is honest? | all DET-assist conditions met (≥ 8 primitives, ≥ 200×200px, ≥ 3 fills, ≤ 2 text elements, no pattern) AND JUDG confirms a stand-in scene. The constants are the published ones of an earlier reference catalogue (it reads declared width/height or viewBox; this row reads the rendered box), not yet calibrated on this family's pages | MEDIUM | Commission or simplify the illustration; don't primitive-stack a substitute (correct) |
60
- | SLOP-052 | **Busy geometric mask faking a photographic edge** (DET): `getComputedStyle(el).clipPath` is a `polygon()` with ≥ 10 vertices where at least half of all coordinate values sit more than 0.5 away from a multiple of 25 (an off-grid, organic contour), or a `path()` with ≥ 3 curve commands (`C`/`S`/`Q`/`T`/`A`, either case). `circle()`, `ellipse()`, `inset()` and grid-aligned polygons (cut corners, diagonals, hexagons) never match | polygon: ≥ 10 vertices and mostly off-grid; path(): ≥ 3 curve segments (published constants of an earlier reference catalogue) | LOW | Use a real photographic crop, or a simple deliberate shape (correct) |
61
- | SLOP-053 | **Emoji glyphs standing in for a real icon set** (DET-assist, JUDG verdict): DET: text node inside a control/nav/badge element matches the emoji Unicode ranges. JUDG: does the brief carry an explicit emoji-policy exception (not observable from the DOM) | any match AND JUDG finds no stated emoji-policy exception | LOW | Replace with the project's chosen icon set (correct) |
62
- | SLOP-054 | **Hover transform applied to the image element itself** (DET): CSS rule with a `:hover` transform selector whose target is an `<img>` element (or an element whose only content is a background-image) rather than a parent wrapper | rule targets the image node itself | LOW | Move the transform to the container; animate the frame, not the picture (correct) |
63
- | SLOP-055 | **Recurring cluster of generic tells appearing together** (JUDG): Checklist: after running the deterministic rows above, does any single component trip 2 or more of them at once? | ≥ 2 co-occurring DET hits on one component escalates the row from WARN to a real finding | MEDIUM (escalated); LOW (WARN) below that | Break up the combination; vary the visual language for that component specifically (correct) |
64
- | SLOP-056 | **Overall "could be any competitor's product" genericness** (JUDG): Checklist, run only after every deterministic row above has already been checked — never as the first or only pass | — | LOW (WARN), holistic-only | No single fix; return to the specific rows above that are contributing to the impression and act on those (correct) |
65
- | SLOP-057 | **Broken image source** (DET): Flag only when `src`/`srcset` is empty, `#` or the literal `undefined` with no lazy-loader data attribute (`data-src`, `data-srcset`, `data-lazy*`), or when `img.complete && img.naturalWidth === 0` after settle (the fetch finished and failed). An image with `complete === false` at capture (for example a `loading="lazy"` image outside that viewport's load margin, which the probe never scrolls to), or an empty `src` beside a lazy-loader attribute, is `not_verified`, never HIGH | any match | HIGH | Fix or replace the source, or remove the element (correct / delete) |
66
- | SLOP-058 | **Dead link** (DET (derived — an attribute scan cannot see an attached handler)): `href="#"` or `href` starting `javascript:` | any match | HIGH (nav/primary) / MEDIUM (decorative) | Point it at a real destination, or make it a real button if it has no destination (correct) |
67
- | SLOP-059 | **Button with no type/handler inside a form** (DET inside a form; JUDG outside one): Attribute + form-owner scan (`button.form`, which also covers a `form="id"` association); the outside-form case has no reliable attribute-only signal (a working `addEventListener` handler is invisible to a DOM scan) and stays a JUDG prompt: "does this control visibly do something on click?" | missing `type` on a button whose form owner has ≥2 submit-capable buttons (a lone typeless button is the intended implicit submit) | HIGH (inside a form only) | Add an explicit `type="button"` (or `"submit"` when that is genuinely intended) (correct) |
68
- | SLOP-060 | **Placeholder / lorem text** (DET): Regex match over visible text nodes | any match | LOW | Replace with real, brief-specific copy (correct) |
69
- | SLOP-061 | **Marquee / scrolling ticker on text** (DET): Tag check, or keyframe direction scan for an unbounded loop with no pause/stop affordance in the DOM | any match | LOW | Replace with a static row, or add a real pause/stop control (correct) |
70
- | SLOP-062 | **Modal opened by reflex with no real interruption need** (JUDG): Checklist: does the content genuinely require blocking the rest of the page, or would an inline panel/toast serve the same purpose? | — | LOW (WARN) | Replace with an inline panel, toast, or disclosure (correct) |
71
- | SLOP-063 | **Monospace used as a "technical" costume** (JUDG): Checklist: does the monospace content contain actual code, a command, or aligned data — or is it plain prose wearing a technical costume? | — | LOW (WARN) | Switch to the page's normal text face unless the content is genuinely code/data (correct) |
72
-
73
- ## Reading a result
74
-
75
- The rule's condition must be observed in the same surface being judged. A stylesheet declaration that never runs can be Derived or advisory; do not report it as a user-observed animation. An attribute such as a dead link is Derived because an attached listener cannot be enumerated from in-page JavaScript. A page-wide cluster or brand rationale is Inferred. Record a selector, viewport, value, threshold, and cheapest practical repair for each machine finding. The register is an index for review, not a substitute for the screenshots or the mode's Block/Approve decision.
3
+ This register loads with `references/craft-floor.md` whenever `frontend-ui-ux` activates. A row
4
+ earns a `SLOP-*` id when a designer would read it as a reflex default, the "made by a generator"
5
+ tell, rather than a plain bug below a number. A genericness tell is at most `MEDIUM`: it never
6
+ blocks "done" by itself. The only `HIGH` rows are the three functional ones (SLOP-057 broken
7
+ image, SLOP-058 dead text, nav or call-to-action link, SLOP-059 typeless button beside another
8
+ submit), which block "done" like a craft-floor HIGH until fixed or stated as a limitation.
9
+
10
+ How to use it:
11
+
12
+ - **Run the deterministic rows first.** The interface probe measures every row marked
13
+ *probe*; the static fallback reads the rows marked *static* from source when no browser can
14
+ render. Only then form a holistic view (SLOP-055, SLOP-056), and ground it in the rows that
15
+ fired. "Looks generic" with no cited row is not a finding.
16
+ - **Coverage "judgment"** means DET-assist: the probe prints the hit under "Judgment calls", never
17
+ as a finding, and a person decides (a recorded reason for a common font, a real sequence behind
18
+ section numbers, an emoji policy the brief asked for, a real source behind a figure). The
19
+ severity applies only once you confirm it; state the call as Inferred.
20
+ - **Copy rows read authored copy only**: visible text of the top document, outside code, form
21
+ values, `<title>` and attributes. Text inside a frame is never charged to the page.
22
+ - **Fix with the cheapest tool**: delete, then use the platform, then reuse, then correct a
23
+ value, then add.
24
+ - **Page type decides nothing.** Every surface, from a form to a marketing page, gets the same
25
+ register.
26
+
27
+ Coverage column: *probe* (rendered check), *static* (source check without a browser), *both*,
28
+ or *checklist* (review by eye).
29
+
30
+ ## Layout and composition
31
+
32
+ | Id | Tell | Signal and threshold | Severity | Fix | Coverage |
33
+ |---|---|---|---|---|---|
34
+ | SLOP-001 | The same text-and-image split stamped section after section | ≥ 3 consecutive sections with the same column shape and image side | MEDIUM | Break the run with a stacked or full-width section | checklist |
35
+ | SLOP-002 | Identical icon-heading-text tiles as the default way to show anything | ≥ 4 tiles of equal size (±4 px) and structure in one grid, each an icon or image, a heading and text; `ul`, `ol` and `table` grids skipped | MEDIUM | Vary tile size or content shape, or present the items as a list | probe |
36
+ | SLOP-003 | Cards inside cards, or bento cells with nothing in them | nesting depth ≥ 3, or cell count ≠ content count | MEDIUM | Remove the extra shell or reshape the grid | checklist |
37
+ | SLOP-004 | A split header whose side column only restates the headline | short side column (< 15 words) with no role of its own | MEDIUM | Stack headline and body | checklist |
38
+ | SLOP-005 | One section shape reused for unrelated topics | the same structure ≥ 3 times | MEDIUM | Give later repeats a different layout | checklist |
39
+ | SLOP-006 | Every gap the same size on a page that needs grouping | ≥ 5 regions and ≥ 10 samples, one 4 px bucket > 85 %, ≤ 3 buckets | MEDIUM | Space by relationship on a real scale | checklist |
40
+ | SLOP-007 | Big empty gaps that separate nothing | a gap much larger than its neighbours with no job | LOW | Remove it or give it a grouping role | checklist |
41
+
42
+ ## Decoration
43
+
44
+ | Id | Tell | Signal and threshold | Severity | Fix | Coverage |
45
+ |---|---|---|---|---|---|
46
+ | SLOP-008 | The reflex violet accent | a gradient stop, or heading text (h1 to h3 or ≥ 20 px), with hue 260° to 310° and an RGB channel spread ≥ 50, unless that hue is the brand's own action colour in ≥ 2 regions | MEDIUM | Neutral surface plus one real brand hue | both |
47
+ | SLOP-009 | Reflex gradient-filled text | `background-clip: text` with a gradient that has a violet stop (SLOP-008's band), or on more than one element, or with a stop under 4.5:1 (3:1 at ≥ 24 px) on its surface; one gradient headline in the palette's own hues is craft | MEDIUM | Keep one, in palette hues with every stop readable, or use a solid colour | both (static: the violet or repeated form) |
48
+ | SLOP-010 | The same coloured glow repeated | CF-404's glow test (≤ 2 px offset, ≥ 16 px blur, saturation > 0.4) on ≥ 3 unrelated controls or headings, not a focus state; one or two glows are CF-404, and a glow on a surface (`ui-glow`) is craft | MEDIUM | Keep the glow for the surface it lights | probe |
49
+ | SLOP-011 | Faint floating blobs with no focal job | ≥ 2 absolutely placed radial gradients under 0.3 opacity that paint only themselves (no text, media, control or link inside); one atmosphere layer behind the focal point is craft | MEDIUM | Keep one layer tied to the focal point | probe (judgment) |
50
+ | SLOP-012 | Dot or line grid texture next to other decoration | ≥ 2 gradient layers or a radial dot on a fixed px cell ≤ 48 px, no canvas, table, grid, `role=img` or SVG over 48 px in its section or landmark, beside a SLOP-008 or SLOP-011 signal (so notebook dots under one atmosphere layer pass) | MEDIUM | Remove unless it stands in for real data | probe |
51
+ | SLOP-013 | Grain or noise dense enough to hide the layout | layout reads better with the layer hidden | LOW | Lighten it or remove it | checklist |
52
+ | SLOP-014 | Glass blur as a default surface | no stated reason and no solid fallback for reduced transparency | LOW | Solid surface unless the brief earns it | checklist |
53
+ | SLOP-015 | Coloured side stripes faking emphasis on cards | on rounded elements: a single-side accent (one side ≥ 2 px saturated, the other three 0 or ≤ 1 px neutral; an all-round outline is not a stripe), an absolutely placed 3 to 12 px `::before`/`::after` bar pinned to one edge (tab and nav indicators skipped), ≥ 3 per scope; an inset 3 to 12 px chromatic shadow counts at 2; status regions and callouts excepted | MEDIUM | Carry emphasis with the fill or an icon | probe |
54
+
55
+ ## Typography
56
+
57
+ | Id | Tell | Signal and threshold | Severity | Fix | Coverage |
58
+ |---|---|---|---|---|---|
59
+ | SLOP-016 | A reflex default face (Inter, Roboto, Open Sans, Lato, Montserrat, Arial, Helvetica, Space Grotesk and similar; the Geist family is exempt) | the first family in the stack that actually loaded matches the list (a fallback further down never counts; form controls' browser default is skipped) | MEDIUM | Choose a face for the product or record why the common one stays | both (judgment) |
60
+ | SLOP-017 | A display serif with no reason | a shortlisted serif on headings and no recorded rationale | MEDIUM | Sans display, or record the reason | checklist |
61
+ | SLOP-018 | A giant headline over a tiny afterthought subhead | size ratio ≥ 3.5 and subhead < 14 px | MEDIUM | Raise the subhead or shorten the pairing | checklist |
62
+ | SLOP-019 | Too many type moods | > 3 base families (icon fonts excepted) | MEDIUM | Cut to three or fewer | probe |
63
+ | SLOP-020 | Long all-caps text | uppercase leaf text > 40 characters in a cased script | LOW | Uppercase only for short labels | probe |
64
+
65
+ ## Colour
66
+
67
+ | Id | Tell | Signal and threshold | Severity | Fix | Coverage |
68
+ |---|---|---|---|---|---|
69
+ | SLOP-021 | Neutral mid-gray text on a coloured surface | text lightness 40 % to 70 % and saturation < 10 % on a surface with saturation ≥ 25 % (see CF-201 for the contrast floor) | MEDIUM | Tint the text from the surface hue | probe |
70
+ | SLOP-022 | Too many accent hues competing | more than four saturated clusters among filled surfaces (more than one in a calm lock); measured as CF-205 | MEDIUM | Fold the extras into a family the page already uses | via CF-205 |
71
+ | SLOP-023 | Pure #000 or #fff as the base | exact black or white body background or ink (a deliberate all-black dark theme excepted) | LOW | Move a few percent toward the brand neutral | probe |
72
+
73
+ ## Motion
74
+
75
+ | Id | Tell | Signal and threshold | Severity | Fix | Coverage |
76
+ |---|---|---|---|---|---|
77
+ | SLOP-024 | Bouncy easing on routine feedback | measured as CF-505 | MEDIUM | Ease-out, no overshoot | via CF-505 |
78
+ | SLOP-025 | Entrances growing out of nothing | measured as CF-503 (start ≥ 0.95) | MEDIUM | Start near 0.95 with opacity 0 | via CF-503 |
79
+ | SLOP-026 | Animating layout properties | measured as CF-508 | MEDIUM | Transform and opacity instead | via CF-508 |
80
+ | SLOP-027 | An endless pulse or blink bound to nothing | infinite opacity or shadow animation with no `data-*`, `aria-busy` or loading class | LOW | Remove, or bind it to real live status | probe |
81
+ | SLOP-028 | Full transitions on every hover and re-render | > 150 ms on repeated interactions (CF-506) | LOW | Instant or ≤ 150 ms for routine changes | checklist |
82
+
83
+ ## Structural micro-labels
84
+
85
+ | Id | Tell | Signal and threshold | Severity | Fix | Coverage |
86
+ |---|---|---|---|---|---|
87
+ | SLOP-029 | A tracked uppercase eyebrow over most headings | the visible element right before an h1 to h3 with ≤ 4 words, uppercase, letter-spacing ≥ 0.05 em and ≤ 0.75 × the heading's size; more of them than ceil(visible h2 count / 3) | MEDIUM | Drop the eyebrows | probe |
88
+ | SLOP-030 | 01 / 02 / 03 numbering with no real order | ≥ 2 distinct zero-padded labels before headings | MEDIUM | Remove, or name the real steps | probe (judgment) |
89
+ | SLOP-031 | A fake version or beta stamp in marketing copy | a `vN.N`, beta or build-hash token outside real release notes | MEDIUM | Remove unless the brief is about a release | checklist |
90
+ | SLOP-032 | Decorative status dots | a small coloured dot before labels with no bound state | LOW | Remove or bind to real status | checklist |
91
+ | SLOP-033 | Chained middle-dot strips | ≥ 3 `·` on one line, or a city, offset and weather strip | LOW | Lines or columns instead | probe |
92
+ | SLOP-034 | A strip of mood words along the hero's foot | uppercase non-link tokens in the bottom 15 % of the hero (compliance badges excepted) | MEDIUM | Remove | checklist |
93
+ | SLOP-035 | A "scroll" cue in the first viewport | scroll text or a bouncing chevron | LOW | Remove | checklist |
94
+
95
+ ## Copy
96
+
97
+ | Id | Tell | Signal and threshold | Severity | Fix | Coverage |
98
+ |---|---|---|---|---|---|
99
+ | SLOP-036 | Stock marketing phrases | ≥ 1 whole-phrase match against the fixed phrase list in the rule table ("seamless experience", "harness the power", "best-in-class", "차세대 플랫폼" and similar), outside quotes; a bare common word such as "seamless" alone never counts | MEDIUM | A specific, product-true claim | both |
100
+ | SLOP-037 | A placeholder brand name | a stock fictional company name in visible copy | MEDIUM | Name the product from the brief | probe (judgment: it may be the real name) |
101
+ | SLOP-038 | A filler person name | "John Doe", "Jane Smith", "홍길동" and the like | MEDIUM | A specific, local name | probe |
102
+ | SLOP-039 | The "Not X. Y." cadence | ≥ 3 sentence pairs of two shapes: "Not a/an" + a short clause then a capitalised sentence, or a sentence then one opening "No" or "Just" (Latin copy only; no Hangul shape is defined) | LOW | Vary the rhythm | probe |
103
+ | SLOP-040 | Em dashes in shipped copy | any U+2014, or a U+2013 with spaces on both sides that is not a number, time or date range; a doubled dash in Han-majority text and a quote with a cross-origin `cite` are LOW | MEDIUM | Period, comma or parentheses | both |
104
+ | SLOP-041 | Suspiciously round or precise numbers with no source | a stat-shaped number (percent, multiplier, 48k, 10,000+, a unit rate) outside money, dates, times, versions, tables and forms, with no source, footnote, example or mock marker in its block | MEDIUM | Cite it, label it as an example, or cut it | probe (judgment) |
105
+ | SLOP-042 | Several labels for one action | > 1 wording for the same intent | LOW | One label per intent | checklist |
106
+
107
+ ## Fake assets and data
108
+
109
+ | Id | Tell | Signal and threshold | Severity | Fix | Coverage |
110
+ |---|---|---|---|---|---|
111
+ | SLOP-043 | A product screenshot built from divs | a ≥ 240 × 160 px box with no media and no focusable control inside showing a row of ≥ 3 window-chrome dots in its top 48 px, or tilted by a transform | MEDIUM | Real screenshot or real component | probe (judgment: a real component preview looks the same) |
112
+ | SLOP-044 | A fake build or sync footer | a version or "synced 4s ago" string outside real docs | MEDIUM | Remove | checklist |
113
+ | SLOP-045 | Matching stat blocks with nothing behind them | ≥ 4 same-height siblings whose figure is ≥ 1.5 × its label (≥ 3 beside a call to action) | MEDIUM | Remove, or back each number with a source | probe (judgment: needs the brief) |
114
+ | SLOP-046 | A gauge or sparkline with a hard-coded value | a progress, meter, dash-array ring or single-series sparkline ≤ 64 px tall with no visible value, axis or accessible name | MEDIUM | Remove unless it shows real data | probe (judgment) |
115
+ | SLOP-047 | A looping logo wall too small to read | an infinite sideways loop of ≤ 6 distinct logos with a median height < 20 px at 1440 px | MEDIUM | Static row, larger logos | probe |
116
+ | SLOP-048 | Carousel dots that do nothing | ≥ 2 dot controls beside ≥ 2 slides, declared autoplay, and no focusable named dot, `aria-controls`, `aria-selected`, `aria-disabled` or `aria-current` (without a declared autoplay attribute the timed read is not run: not verified) | LOW | Remove or wire them up | probe |
117
+ | SLOP-049 | Egg or silhouette avatars | a generic avatar asset | LOW | A believable photo or a deliberate style | checklist |
118
+ | SLOP-050 | Category captions under trust logos | a category word under each logo | LOW | Logo only | checklist |
119
+
120
+ ## Icons and illustration
121
+
122
+ | Id | Tell | Signal and threshold | Severity | Fix | Coverage |
123
+ |---|---|---|---|---|---|
124
+ | SLOP-051 | An unlabelled illustration stacked from primitives | an inline SVG ≥ 200 × 200 px with ≥ 8 rect, circle, ellipse or polygon shapes, ≥ 3 fills, ≤ 2 text elements, no pattern and no name (`role="img"` with `aria-label`/`aria-labelledby`, or a `<title>`); a named many-shape drawing of the subject is an authored illustration | MEDIUM | Name what it shows, or draw the subject instead of a generic stack | probe (judgment: an honest diagram clears it) |
125
+ | SLOP-052 | A many-vertex mask faking a photo edge | `clip-path: polygon()` with ≥ 10 vertices, at least half its coordinates off the 25 % grid, or `path()` with ≥ 3 curves | LOW | A real crop or a simple shape | probe |
126
+ | SLOP-053 | Emoji in place of an icon set | emoji as the whole content of a small control, or leading a nav item, badge, list item or heading | LOW | The project's icon set | probe (judgment) |
127
+ | SLOP-054 | Hover zoom on the image itself | a `:hover` transform on `img` | LOW | Transform the container | checklist |
128
+
129
+ ## Whole-page reads (last)
130
+
131
+ | Id | Tell | Signal and threshold | Severity | Fix | Coverage |
132
+ |---|---|---|---|---|---|
133
+ | SLOP-055 | Several small tells stacked on one component | ≥ 2 deterministic rows on the same component | MEDIUM (else LOW) | Change that component's visual language | checklist |
134
+ | SLOP-056 | "Could be any competitor's product" | only after every row above ran | LOW | Act on the rows that contribute | checklist |
135
+
136
+ ## Functional tells
137
+
138
+ | Id | Tell | Signal and threshold | Severity | Fix | Coverage |
139
+ |---|---|---|---|---|---|
140
+ | SLOP-057 | Broken image | empty, `#` or `undefined` `src` or `srcset` with no lazy-loader attribute, or a fetch that finished and failed; an image not yet fetched at capture is not verified | HIGH | Fix the source or remove the element | both |
141
+ | SLOP-058 | Link to nowhere | `href="#"` or `javascript:` (tier derived: a script handler is invisible to the scan) | HIGH for text, nav or call-to-action links; MEDIUM for logo or icon-only links | A real destination, or a real button | both |
142
+ | SLOP-059 | A typeless button beside another submit | `<button>` without `type` whose form owner (`button.form`, so `form="id"` counts) has ≥ 2 submit-capable buttons; a lone typeless button is the form's intended submit | HIGH | `type="button"` unless it really submits | probe |
143
+ | SLOP-060 | Lorem or placeholder copy | lorem ipsum, `[placeholder]`, TODO, TBD in visible text | LOW | Real copy | both |
144
+ | SLOP-061 | Text in an endless marquee | `<marquee>` or a looping sideways keyframe with no pause | LOW | Static row or a pause control | both |
145
+ | SLOP-062 | A modal opened by reflex | the content did not need to block the page | LOW | Inline panel, toast or disclosure | checklist |
146
+ | SLOP-063 | Monospace as a "technical" costume | monospace on prose with no code or aligned data | LOW | The normal text face | checklist |
147
+
148
+ Slides, documents and diagrams share the layout, decoration, typography, colour, copy and
149
+ fake-data rows; motion, scroll, hover and carousel rows do not transfer. The office and diagram
150
+ skills enforce their own subset in their QA scripts.
@@ -2,8 +2,6 @@ A design system is three token layers, a finite primitive set, and a gate that p
2
2
 
3
3
  ## Audit before authoring anything
4
4
 
5
- Write nothing until the audit shows no existing token or primitive fits.
6
-
7
5
  - List tokens, primitives with their variants, and duplicate components.
8
6
  - Count raw one-off values per file; that is the migration size.
9
7
  - Mark each primitive keep, extend, or replace, with its replacement cost.
@@ -11,8 +9,6 @@ Write nothing until the audit shows no existing token or primitive fits.
11
9
 
12
10
  ## Split the three token layers
13
11
 
14
- Layers exist so a value change and a meaning change land in different diffs.
15
-
16
12
  1. Foundation: raw values with no meaning — `color.slate.700`, `space.16`, `duration.150`.
17
13
  2. Semantic roles: meaning per theme — `color.text.muted`, `color.border.strong`, `radius.control`.
18
14
  3. Component decisions: `button.primary.bg`, resolving to a semantic role and nothing else.
@@ -72,3 +68,13 @@ The system lives in the contract, not in tribal knowledge.
72
68
  - Validate from the installed skill root: `node .grok/skills/frontend-ui-ux/scripts/validate-design-contract.mjs <path>`.
73
69
  - Record the contract hash so the independent review pass binds its receipt to those bytes.
74
70
  - Shipping this package also requires `npm test` and the canonical-corpus verifier.
71
+
72
+ ## Governance reject-list
73
+
74
+ Reject:
75
+
76
+ - A component reaching past the semantic layer to a foundation value.
77
+ - A primitive or variant introduced for exactly one screen.
78
+ - A state surfaced by review rather than declared in the anatomy.
79
+ - A dark theme assembled from per-component overrides.
80
+ - A value change bundled into the same diff as a reference migration.
@@ -2,8 +2,6 @@ Visual language is a closed set of named roles with fixed values. What a compone
2
2
 
3
3
  ## Name type by role, not by family
4
4
 
5
- Decide the roles the product needs, bind values to each, and choose a family last.
6
-
7
5
  - Cap at 7 roles: display, page title, section title, body, body-strong, meta, label. Add mono only for code.
8
6
  - Every role fixes size, weight, line height, tracking, and wrapping behavior.
9
7
  - Line height 1.5 for body, 1.2-1.3 for headings, 1.6 for CJK body copy.
@@ -39,8 +37,6 @@ One geometry, one weight, one metaphor vocabulary. An icon sharpens a label; it
39
37
 
40
38
  ## Treat imagery as tokens
41
39
 
42
- Imagery inherits system values. Undecided imagery becomes layout instability at load.
43
-
44
40
  - Aspect-ratio tokens, a declared focal point, and a reserved box before the asset lands.
45
41
  - Never bake text into an image; it cannot translate, zoom, or be announced.
46
42
  - Text over imagery needs a scrim that restores the measured contrast minimum.
@@ -72,3 +68,13 @@ Drift is mechanically detectable. Run these before the independent review pass.
72
68
  2. Count type roles, elevation levels, and radius values against the direction card.
73
69
  3. Re-measure contrast in light theme, dark theme, and forced colors.
74
70
  4. Record every accepted deviation in `accepted_exceptions` with an owner and expiry.
71
+
72
+ ## Failure patterns
73
+
74
+ Reject:
75
+
76
+ - A component importing a palette scale directly.
77
+ - Status carried by hue alone.
78
+ - Contrast reported as "looks fine" with no ratio.
79
+ - Two icon families on one surface.
80
+ - A pie chart with seven slices, or a chart where a table answers the question.
@@ -1,84 +1,51 @@
1
- A reference shows one state at one width, produced by a stack you do not control. Rebuild it as
2
- real markup with real semantics; never close the gap with a screenshot.
1
+ # Visual reconstruction from references
3
2
 
4
- ## Claim classes
3
+ A reference image shows one state at one viewport, rendered by a stack you may not know.
4
+ Rebuild semantic, responsive markup and tune it toward the reference. Never use a screenshot
5
+ as the page background or as a substitute for real content.
5
6
 
6
- Use observed, inferred, and unknown as internal working categories while measuring.
7
- Keep those labels in the design notes; reader-facing copy should state supported
8
- measurements normally and ask for missing input directly. State a material
9
- reconstruction gap once in the reply.
7
+ ## Measure the frame
10
8
 
11
- - Observed: measurable in the image — a pixel distance, a sampled hex value, a glyph.
12
- - Inferred: a reading the image does not prove, such as a scale behind three gaps.
13
- - Unknown: not depicted — hover, focus, error, empty, loading, any other width.
9
+ Record the image dimensions and device scale. Measure the main content width, outer margins,
10
+ columns, type sizes, baseline spacing, and large color regions before coding. Sample flat
11
+ interior pixels, not edges or gradients. Use the smallest spacing scale that explains the
12
+ measured gaps; do not choose values only because they look close.
14
13
 
15
- Only observed claims are criteria; inferred claims need an owner, unknowns are user questions.
14
+ Keep an internal note that separates direct observations from responsive or behavior
15
+ assumptions and states that other states are not shown. A reference does not establish
16
+ hover, focus, error, loading, or narrower layouts. Add those states from the product's
17
+ interaction contract or ask about a material unknown. Do not place observation labels on
18
+ the interface itself.
16
19
 
17
- ## Measurement pass
20
+ ## Rebuild meaning and assets
18
21
 
19
- Measure before writing code. Guessed numbers cost the most to unwind.
22
+ - Use heading elements in outline order, real navigation lists, and selectable text.
23
+ - Do not reproduce contrast failures or suppress visible keyboard focus.
24
+ - Recreate permitted geometry, rules, simple icons, and gradients.
25
+ - Extract only assets the project is allowed to use; preserve their source resolution.
26
+ - Substitute an unavailable permitted asset at the same dimensions, or omit decoration
27
+ that carries no information. Never recreate a logo, wordmark, or licensed photograph.
20
28
 
21
- 1. Record pixel dimensions and device scale; divide the scale out before quoting.
22
- 2. Sample color at flat interior pixels, never on an edge or in a gradient.
23
- 3. Measure cap height and baseline-to-baseline distance per size; derive line height.
24
- 4. Fit every gap, gutter, and outer margin to the smallest plausible scale.
29
+ When the reference font is unavailable or unlicensed, choose a metric-compatible fallback.
30
+ Compare cap height, x-height, and advance width; adjust line-box metrics only when needed;
31
+ then verify that the longest real label still fits.
25
32
 
26
- ## Semantic reconstruction
33
+ ## Infer responsive behavior
27
34
 
28
- Build the structure the content deserves, then style it toward the reference.
35
+ One frame proves one width. Classify regions as fixed rail, fluid column, or centered max
36
+ width. Set breakpoints where measured content stops fitting. Decide what wraps, stacks,
37
+ collapses, or scrolls, and inspect the narrowest supported width plus one width around each
38
+ breakpoint. Keep these assumptions in the Design Contract until the user or another source
39
+ confirms them.
29
40
 
30
- - Headings become heading elements in outline order; large and bold is not an `h1`.
31
- - A row of links becomes a navigation list, not a flex row of `div`s.
32
- - Text baked into the image becomes real, selectable, translatable text.
33
- - Contrast failures and suppressed focus in the reference are not reproduced.
41
+ ## Iterate against the capture
34
42
 
35
- ## Asset decisions
43
+ Capture the build at the reference dimensions and device scale. Compare structure, spacing,
44
+ type, then color. Fix the largest measured mismatch and recapture. Stop after three passes
45
+ that do not reduce the overall difference. A fidelity review record can retain per-region
46
+ measurements, source and output paths, unconfirmed states, and asset decisions; the normal
47
+ reader reply needs only the result and a material limitation once.
36
48
 
37
- Decide per asset and record the decision.
38
-
39
- - Recreate: geometric shapes, rules, dividers, simple icons, gradients.
40
- - Extract: only assets you are permitted to use, at source resolution.
41
- - Substitute: a placeholder at identical dimensions, marked as a placeholder.
42
- - Omit: decoration carrying no information; record it in `omissions`.
43
-
44
- Never recreate a logo, wordmark, or licensed photograph. Substitute and raise a hard stop.
45
-
46
- ## Metric-compatible font fallback
47
-
48
- When the reference face is unavailable or unlicensed, choose the fallback by metrics.
49
-
50
- 1. Match units-per-em, cap height, x-height, and default advance width.
51
- 2. Hold line boxes with `size-adjust`, `ascent-override`, `descent-override`.
52
- 3. Verify the longest real label still fits at the fallback's advance.
53
- 4. Record the substitution and its metric delta as an owned inferred claim.
54
-
55
- ## Responsive inference from one frame
56
-
57
- One frame proves one width. State every adaptation as an assumption until confirmed.
58
-
59
- - Classify each region: fixed rail, fluid column, or centered maximum width.
60
- - Break where your measured content breaks, not at the reference's width.
61
- - Name what wraps, stacks, collapses, or scrolls below that width.
62
- - Check the narrowest supported width and one width above each break.
63
-
64
- ## Iteration loop
65
-
66
- Iterate on measured deltas, never on impressions.
67
-
68
- 1. Capture your build at the reference's exact dimensions and device scale.
69
- 2. Compare region by region in order: structure, spacing, type, then color.
70
- 3. Fix the single largest measured delta and recapture.
71
- 4. Stop after three passes that do not reduce total delta; report the remainder.
72
-
73
- ## Internal comparison record
74
-
75
- Keep region deltas, capture paths, assumptions, unknown states, asset decisions, and verdict in
76
- internal task notes or the verification receipt. Bind independent review to the design-contract
77
- hash. In the reply, state the result plainly and name a material fidelity gap once.
78
-
79
- ## “Pixel perfect” gate
80
-
81
- Use this phrase only when both captures share dimensions and device scale; measured differences
82
- are resolved; assumptions and unknown states are closed; fonts and assets are authorized; and
83
- every declared state was compared. Otherwise keep numeric comparisons internal and describe
84
- fidelity in ordinary language.
49
+ Use “pixel perfect” only when dimensions and scale match, every visible state is compared,
50
+ no unexplained measured gap remains, and the typeface and assets are approved. Otherwise
51
+ describe the measured result and the remaining mismatch plainly.