@litfamily/lithermes 1.0.29 → 1.0.30

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 (165) hide show
  1. package/README.md +12 -9
  2. package/README_Ko-KR.md +12 -9
  3. package/assets/lithermes-plugin/README.md +15 -2
  4. package/assets/lithermes-plugin/__init__.py +49 -10
  5. package/assets/lithermes-plugin/adhd_stack.py +228 -0
  6. package/assets/lithermes-plugin/core.py +30 -4
  7. package/assets/lithermes-plugin/core_commands.py +99 -0
  8. package/assets/lithermes-plugin/core_contexts.py +54 -4
  9. package/assets/lithermes-plugin/core_contract.py +2 -2
  10. package/assets/lithermes-plugin/core_routing.py +126 -0
  11. package/assets/lithermes-plugin/diagnostics.py +3 -2
  12. package/assets/lithermes-plugin/lit_mark.py +75 -0
  13. package/assets/lithermes-plugin/payload-version.json +470 -58
  14. package/assets/lithermes-plugin/plugin.yaml +1 -1
  15. package/assets/lithermes-plugin/scientific_visualization.py +23 -0
  16. package/assets/lithermes-plugin/skills/frontend-ui-ux/SKILL.md +7 -7
  17. package/assets/lithermes-plugin/skills/frontend-ui-ux/kit/components.css +414 -0
  18. package/assets/lithermes-plugin/skills/frontend-ui-ux/kit/fonts.json +42 -0
  19. package/assets/lithermes-plugin/skills/frontend-ui-ux/kit/layouts/landing.html +164 -0
  20. package/assets/lithermes-plugin/skills/frontend-ui-ux/kit/layouts/settings.html +114 -0
  21. package/assets/lithermes-plugin/skills/frontend-ui-ux/kit/layouts/workspace.html +115 -0
  22. package/assets/lithermes-plugin/skills/frontend-ui-ux/kit/styles/computational-brutalism.json +227 -0
  23. package/assets/lithermes-plugin/skills/frontend-ui-ux/kit/styles/field-notes.json +205 -0
  24. package/assets/lithermes-plugin/skills/frontend-ui-ux/kit/styles/graphite.json +200 -0
  25. package/assets/lithermes-plugin/skills/frontend-ui-ux/kit/styles/meadow.json +199 -0
  26. package/assets/lithermes-plugin/skills/frontend-ui-ux/kit/styles/neo-brutalism.json +222 -0
  27. package/assets/lithermes-plugin/skills/frontend-ui-ux/kit/ui.js +226 -0
  28. package/assets/lithermes-plugin/skills/frontend-ui-ux/references/README.md +2 -4
  29. package/assets/lithermes-plugin/skills/frontend-ui-ux/references/complete-contract.md +4 -4
  30. package/assets/lithermes-plugin/skills/frontend-ui-ux/references/craft-floor.md +10 -0
  31. package/assets/lithermes-plugin/skills/frontend-ui-ux/scripts/design-lock.mjs +400 -0
  32. package/assets/lithermes-plugin/skills/frontend-ui-ux/scripts/probe-rules.json +6 -1
  33. package/assets/lithermes-plugin/skills/frontend-ui-ux/scripts/probe.mjs +76 -4
  34. package/assets/lithermes-plugin/skills/lit-adhd/SKILL.md +194 -0
  35. package/assets/lithermes-plugin/skills/lit-adhd/references/brief-contract.md +55 -0
  36. package/assets/lithermes-plugin/skills/lit-adhd/references/card-examples.md +86 -0
  37. package/assets/lithermes-plugin/skills/lit-adhd/references/status-taxonomy.md +40 -0
  38. package/assets/lithermes-plugin/skills/lit-adhd/scripts/adhd.mjs +11 -0
  39. package/assets/lithermes-plugin/skills/lit-adhd/scripts/lib/collect.mjs +554 -0
  40. package/assets/lithermes-plugin/skills/lit-adhd/scripts/lib/gauge.mjs +89 -0
  41. package/assets/lithermes-plugin/skills/lit-adhd/scripts/lib/hermes-sessions.mjs +219 -0
  42. package/assets/lithermes-plugin/skills/lit-adhd/scripts/lib/next-step.mjs +101 -0
  43. package/assets/lithermes-plugin/skills/lit-adhd/scripts/lib/plan-task-rows.mjs +32 -0
  44. package/assets/lithermes-plugin/skills/lit-adhd/scripts/lib/redact.mjs +42 -0
  45. package/assets/lithermes-plugin/skills/lit-adhd/scripts/lib/secret-shapes.mjs +59 -0
  46. package/assets/lithermes-plugin/skills/lit-diagram-drawer/SKILL.md +7 -4
  47. package/assets/lithermes-plugin/skills/lit-diagram-drawer/references/style-guide.md +20 -11
  48. package/assets/lithermes-plugin/skills/lit-diagram-drawer/references/type-architecture.md +3 -3
  49. package/assets/lithermes-plugin/skills/lit-diagram-drawer/references/type-dependency.md +1 -1
  50. package/assets/lithermes-plugin/skills/lit-diagram-drawer/references/type-tree.md +3 -3
  51. package/assets/lithermes-plugin/skills/lit-diagram-drawer/references/type-wardley.md +1 -1
  52. package/assets/lithermes-plugin/skills/lit-diagram-drawer/references/verifier-guide.md +5 -0
  53. package/assets/lithermes-plugin/skills/lit-diagram-drawer/scripts/diagram_quality.py +4 -4
  54. package/assets/lithermes-plugin/skills/lit-docx/SKILL.md +1 -1
  55. package/assets/lithermes-plugin/skills/lit-hijack/SKILL.md +239 -0
  56. package/assets/lithermes-plugin/skills/lit-hijack/references/capture-and-provenance.md +123 -0
  57. package/assets/lithermes-plugin/skills/lit-hijack/references/clean-room-build.md +128 -0
  58. package/assets/lithermes-plugin/skills/lit-hijack/references/distil-and-licence.md +128 -0
  59. package/assets/lithermes-plugin/skills/lit-hijack/references/gap-and-port-design.md +152 -0
  60. package/assets/lithermes-plugin/skills/lit-hijack/references/parity-and-report.md +131 -0
  61. package/assets/lithermes-plugin/skills/lit-hijack/scripts/hijack.mjs +995 -0
  62. package/assets/lithermes-plugin/skills/lit-plan/SKILL.md +1 -0
  63. package/assets/lithermes-plugin/skills/lit-pptx/SKILL.md +11 -6
  64. package/assets/lithermes-plugin/skills/lit-pptx/fonts/jetbrains-mono/JetBrainsMono-Bold.ttf +0 -0
  65. package/assets/lithermes-plugin/skills/lit-pptx/fonts/jetbrains-mono/JetBrainsMono-Regular.ttf +0 -0
  66. package/assets/lithermes-plugin/skills/lit-pptx/fonts/jetbrains-mono/OFL.txt +93 -0
  67. package/assets/lithermes-plugin/skills/lit-pptx/fonts/provenance.json +1 -0
  68. package/assets/lithermes-plugin/skills/lit-pptx/references/anti-slop-checklist.md +3 -0
  69. package/assets/lithermes-plugin/skills/lit-pptx/references/authoring-guide.md +1 -1
  70. package/assets/lithermes-plugin/skills/lit-pptx/references/consensus-protocol.md +1 -1
  71. package/assets/lithermes-plugin/skills/lit-pptx/references/direction-step.md +8 -2
  72. package/assets/lithermes-plugin/skills/lit-pptx/references/examples/13-engineering-review-computational-brutalism-ko.md +175 -0
  73. package/assets/lithermes-plugin/skills/lit-pptx/references/examples/14-launch-pitch-neo-brutalism-ko.md +156 -0
  74. package/assets/lithermes-plugin/skills/lit-pptx/references/examples/15-design-lecture-bauhaus-ko.md +141 -0
  75. package/assets/lithermes-plugin/skills/lit-pptx/references/examples/16-community-programme-riso-ko.md +160 -0
  76. package/assets/lithermes-plugin/skills/lit-pptx/references/examples/17-public-data-briefing-newsroom-ko.md +183 -0
  77. package/assets/lithermes-plugin/skills/lit-pptx/references/layout-families.md +1 -1
  78. package/assets/lithermes-plugin/skills/lit-pptx/references/tonalities/bauhaus.md +105 -0
  79. package/assets/lithermes-plugin/skills/lit-pptx/references/tonalities/computational-brutalism.md +111 -0
  80. package/assets/lithermes-plugin/skills/lit-pptx/references/tonalities/neo-brutalism.md +114 -0
  81. package/assets/lithermes-plugin/skills/lit-pptx/references/tonalities/newsroom.md +106 -0
  82. package/assets/lithermes-plugin/skills/lit-pptx/references/tonalities/riso.md +101 -0
  83. package/assets/lithermes-plugin/skills/lit-pptx/scripts/craft_extras.py +49 -0
  84. package/assets/lithermes-plugin/skills/lit-pptx/scripts/deck_output.py +4 -2
  85. package/assets/lithermes-plugin/skills/lit-pptx/scripts/lib/render-pack.js +96 -10
  86. package/assets/lithermes-plugin/skills/lit-pptx/scripts/lib/template-registry.js +50 -6
  87. package/assets/lithermes-plugin/skills/lit-pptx/templates/tonalities/bauhaus/pack.yaml +103 -0
  88. package/assets/lithermes-plugin/skills/lit-pptx/templates/tonalities/computational-brutalism/pack.yaml +99 -0
  89. package/assets/lithermes-plugin/skills/lit-pptx/templates/tonalities/neo-brutalism/pack.yaml +107 -0
  90. package/assets/lithermes-plugin/skills/lit-pptx/templates/tonalities/newsroom/pack.yaml +99 -0
  91. package/assets/lithermes-plugin/skills/lit-pptx/templates/tonalities/riso/pack.yaml +99 -0
  92. package/assets/lithermes-plugin/skills/lit-recap/SKILL.md +1 -1
  93. package/assets/lithermes-plugin/skills/lit-schematic/SKILL.md +144 -0
  94. package/assets/lithermes-plugin/skills/lit-schematic/examples/iso-heat-exchanger/build.mjs +38 -0
  95. package/assets/lithermes-plugin/skills/lit-schematic/examples/iso-heat-exchanger/scene.mjs +133 -0
  96. package/assets/lithermes-plugin/skills/lit-schematic/examples/journal-adsorption-rig/build.mjs +87 -0
  97. package/assets/lithermes-plugin/skills/lit-schematic/examples/pid-dosing-skid/build.mjs +85 -0
  98. package/assets/lithermes-plugin/skills/lit-schematic/references/cutaway-outputs.md +70 -0
  99. package/assets/lithermes-plugin/skills/lit-schematic/references/isometric-craft.md +101 -0
  100. package/assets/lithermes-plugin/skills/lit-schematic/references/journal-figures.md +72 -0
  101. package/assets/lithermes-plugin/skills/lit-schematic/references/kit-api.md +134 -0
  102. package/assets/lithermes-plugin/skills/lit-schematic/references/pfd-and-layout.md +53 -0
  103. package/assets/lithermes-plugin/skills/lit-schematic/references/pid-drafting.md +103 -0
  104. package/assets/lithermes-plugin/skills/lit-schematic/references/pid-symbols.md +163 -0
  105. package/assets/lithermes-plugin/skills/lit-schematic/references/verification.md +100 -0
  106. package/assets/lithermes-plugin/skills/lit-schematic/scripts/doctor.mjs +57 -0
  107. package/assets/lithermes-plugin/skills/lit-schematic/scripts/lib/figure.mjs +81 -0
  108. package/assets/lithermes-plugin/skills/lit-schematic/scripts/lib/fonts.mjs +27 -0
  109. package/assets/lithermes-plugin/skills/lit-schematic/scripts/lib/geom.mjs +113 -0
  110. package/assets/lithermes-plugin/skills/lit-schematic/scripts/lib/interactive.mjs +292 -0
  111. package/assets/lithermes-plugin/skills/lit-schematic/scripts/lib/isa.mjs +115 -0
  112. package/assets/lithermes-plugin/skills/lit-schematic/scripts/lib/iso.mjs +719 -0
  113. package/assets/lithermes-plugin/skills/lit-schematic/scripts/lib/legend-sheet.mjs +162 -0
  114. package/assets/lithermes-plugin/skills/lit-schematic/scripts/lib/pid.mjs +937 -0
  115. package/assets/lithermes-plugin/skills/lit-schematic/scripts/lib/png.mjs +132 -0
  116. package/assets/lithermes-plugin/skills/lit-schematic/scripts/lib/qa-core.mjs +658 -0
  117. package/assets/lithermes-plugin/skills/lit-schematic/scripts/lib/route.mjs +218 -0
  118. package/assets/lithermes-plugin/skills/lit-schematic/scripts/lib/sheet.mjs +890 -0
  119. package/assets/lithermes-plugin/skills/lit-schematic/scripts/lib/svg.mjs +82 -0
  120. package/assets/lithermes-plugin/skills/lit-schematic/scripts/lib/theme.mjs +115 -0
  121. package/assets/lithermes-plugin/skills/lit-schematic/scripts/motion.mjs +129 -0
  122. package/assets/lithermes-plugin/skills/lit-schematic/scripts/qa.mjs +92 -0
  123. package/assets/lithermes-plugin/skills/lit-schematic/scripts/render.mjs +233 -0
  124. package/assets/lithermes-plugin/skills/lit-schematic/scripts/scaffold.mjs +60 -0
  125. package/assets/lithermes-plugin/skills/lit-scientific-visualization/SKILL.md +19 -1
  126. package/assets/lithermes-plugin/skills/lit-typographic-motion/SKILL.md +12 -11
  127. package/assets/lithermes-plugin/skills/lit-typographic-motion/bin/motion.mjs +56 -2
  128. package/assets/lithermes-plugin/skills/lit-typographic-motion/bin/runtime.mjs +129 -4
  129. package/assets/lithermes-plugin/skills/lit-typographic-motion/engine/THIRD_PARTY_NOTICES +9 -0
  130. package/assets/lithermes-plugin/skills/lit-typographic-motion/engine/blender/runner.py +218 -0
  131. package/assets/lithermes-plugin/skills/lit-typographic-motion/engine/blender.mjs +154 -0
  132. package/assets/lithermes-plugin/skills/lit-typographic-motion/engine/board.mjs +132 -0
  133. package/assets/lithermes-plugin/skills/lit-typographic-motion/engine/completion.mjs +48 -5
  134. package/assets/lithermes-plugin/skills/lit-typographic-motion/engine/gate.mjs +13 -0
  135. package/assets/lithermes-plugin/skills/lit-typographic-motion/engine/house.mjs +44 -0
  136. package/assets/lithermes-plugin/skills/lit-typographic-motion/engine/scaffold.mjs +238 -0
  137. package/assets/lithermes-plugin/skills/lit-typographic-motion/engine/score.mjs +643 -0
  138. package/assets/lithermes-plugin/skills/lit-typographic-motion/engine/sound-dsp.mjs +21 -0
  139. package/assets/lithermes-plugin/skills/lit-typographic-motion/engine/sound.mjs +171 -0
  140. package/assets/lithermes-plugin/skills/lit-typographic-motion/engine/stage-qa.mjs +23 -3
  141. package/assets/lithermes-plugin/skills/lit-typographic-motion/engine/stage.mjs +124 -17
  142. package/assets/lithermes-plugin/skills/lit-typographic-motion/engine/styles.mjs +240 -0
  143. package/assets/lithermes-plugin/skills/lit-typographic-motion/engine/treatment.mjs +152 -10
  144. package/assets/lithermes-plugin/skills/lit-typographic-motion/engine/vendor/three/LICENSE +21 -0
  145. package/assets/lithermes-plugin/skills/lit-typographic-motion/engine/vendor/three/addons/environments/RoomEnvironment.js +144 -0
  146. package/assets/lithermes-plugin/skills/lit-typographic-motion/engine/vendor/three/addons/geometries/RoundedBoxGeometry.js +155 -0
  147. package/assets/lithermes-plugin/skills/lit-typographic-motion/engine/vendor/three/three.module.js +54571 -0
  148. package/assets/lithermes-plugin/skills/lit-typographic-motion/recipes/hero-3d/expected.json +67 -0
  149. package/assets/lithermes-plugin/skills/lit-typographic-motion/recipes/hero-3d/index.html +139 -0
  150. package/assets/lithermes-plugin/skills/lit-typographic-motion/references/depth.md +74 -0
  151. package/assets/lithermes-plugin/skills/lit-typographic-motion/references/studio.md +87 -0
  152. package/assets/lithermes-plugin/skills/lit-typographic-motion/references/style-bibles.md +9 -2
  153. package/assets/lithermes-plugin/skills/lit-typographic-motion/references/treatment.md +24 -8
  154. package/assets/lithermes-plugin/skills/lit-typographic-motion/styles/paper.json +41 -0
  155. package/assets/lithermes-plugin/skills/lit-typographic-motion/styles/swiss-signal.json +41 -0
  156. package/assets/lithermes-plugin/skills/lit-typographic-motion/styles/terminalcore.json +42 -0
  157. package/assets/lithermes-plugin/skills/lit-typographic-motion/styles/tidal.json +41 -0
  158. package/assets/lithermes-plugin/skills/litresearch/SKILL.md +4 -0
  159. package/assets/lithermes-plugin/skills/readme-studio/SKILL.md +1 -1
  160. package/assets/lithermes-plugin/skills/review-work/SKILL.md +2 -0
  161. package/assets/lithermes-plugin/skills/start-work/SKILL.md +2 -1
  162. package/assets/lithermes-plugin/skills/visual-qa/references/complete-contract.md +3 -3
  163. package/package.json +1 -1
  164. package/readme-assets/badge-version.svg +1 -1
  165. package/src/lib/skillPayload.js +1 -1
@@ -0,0 +1,222 @@
1
+ {
2
+ "schema_id": "litfamily.frontend-style/v1",
3
+ "id": "neo-brutalism",
4
+ "name": "Neo-brutalism",
5
+ "summary": "A loud, friendly register: flat saturated colour blocks on a lavender canvas, 3 px ink outlines on every surface, hard zero-blur offset shadows in ink, sunflower-yellow panel heads and accent with ink text, chunky 900-weight display type and buttons that press down into their shadow. Playful, legible, never soft.",
6
+ "use_when": [
7
+ "opt-in only: the brief names neo-brutalism, neo-brutalist, neubrutalism or the Korean 네오브루탈리즘",
8
+ "consumer, creator, community or education products that want energy and personality",
9
+ "launch pages, pricing pages and onboarding that should feel bold and hand-made rather than corporate"
10
+ ],
11
+ "avoid_when": [
12
+ "regulated, clinical, financial or enterprise tones",
13
+ "very dense data screens where outlines on every cell would turn into noise (keep tables quiet inside one outlined wrap)",
14
+ "the brief asks for brutalism without neo (that is computational-brutalism)"
15
+ ],
16
+ "keywords": [
17
+ "neo-brutalism",
18
+ "neo-brutalist",
19
+ "neobrutalism",
20
+ "neobrutalist",
21
+ "neo brutalism",
22
+ "neo brutalist",
23
+ "neubrutalism",
24
+ "neu-brutalism",
25
+ "neo-brutal",
26
+ "네오브루탈리즘",
27
+ "네오 브루탈리즘",
28
+ "네오브루탈",
29
+ "네오 브루탈",
30
+ "뉴브루탈리즘",
31
+ "네오브루탈리스트"
32
+ ],
33
+ "signature": [
34
+ "thick ink outlines: 3 px on surfaces, 2 px on controls, the same ink in light and dark",
35
+ "hard offset shadows with zero blur (6 px on surfaces, 3 px on controls) in ink; this is the recorded neo-brutalist register CF-403 accepts",
36
+ "buttons press into their shadow on :active (translate 3 px, shadow to 0)",
37
+ "flat saturated fills: panel heads are solid yellow bars with ink text; ui-panel--accent, ui-panel--accent-2 (electric blue) and ui-panel--support colour the featured blocks",
38
+ "chunky type: 900-weight display with tight leading, 800-weight headings and figures, sentence case",
39
+ "tilted ui-sticker labels as the accent art, never over body text",
40
+ "bouncy but short motion (overshoot ease, 100–280 ms)"
41
+ ],
42
+ "forbid": [
43
+ "blurred, soft or coloured drop shadows (DS-007: the lock declares offset elevation)",
44
+ "gradients, glass, glow and translucency",
45
+ "thin grey borders on surfaces (outlines are ink)",
46
+ "more than four accent hue families in one view",
47
+ "rotated body text, or a sticker covering text",
48
+ "outlines and shadows on every table cell or list row"
49
+ ],
50
+ "fonts": {
51
+ "text": "Pretendard",
52
+ "display": "Pretendard",
53
+ "mono": "JetBrains Mono"
54
+ },
55
+ "type": {
56
+ "scale_px": {
57
+ "xs": 12,
58
+ "sm": 13,
59
+ "md": 14,
60
+ "base": 16,
61
+ "lg": 18,
62
+ "xl": 20,
63
+ "2xl": 24,
64
+ "3xl": 30,
65
+ "4xl": 38,
66
+ "5xl": 48
67
+ },
68
+ "display_px": {
69
+ "min": 40,
70
+ "max": 88
71
+ },
72
+ "moment_px": {
73
+ "max": 152
74
+ },
75
+ "weights": {
76
+ "text": 400,
77
+ "medium": 600,
78
+ "strong": 800,
79
+ "display": 900
80
+ },
81
+ "tracking_em": {
82
+ "display": -0.03,
83
+ "label": 0
84
+ },
85
+ "leading": {
86
+ "body": 1.55,
87
+ "tight": 1.25,
88
+ "display_latin": 1,
89
+ "display_korean": 1.15
90
+ }
91
+ },
92
+ "space_px": [
93
+ 4,
94
+ 8,
95
+ 12,
96
+ 16,
97
+ 20,
98
+ 24,
99
+ 32,
100
+ 40,
101
+ 48,
102
+ 64,
103
+ 80,
104
+ 96,
105
+ 128
106
+ ],
107
+ "radius_px": {
108
+ "xs": 4,
109
+ "sm": 8,
110
+ "md": 12,
111
+ "lg": 16,
112
+ "pill": 999
113
+ },
114
+ "shadow": {
115
+ "raised": "6px 6px 0 0 var(--c-ink)",
116
+ "overlay": "8px 8px 0 0 var(--c-ink)"
117
+ },
118
+ "motion": {
119
+ "fast_ms": 100,
120
+ "ui_ms": 160,
121
+ "enter_ms": 280,
122
+ "exit_ms": 120,
123
+ "ease": "cubic-bezier(0.3, 1.4, 0.5, 1)"
124
+ },
125
+ "shape": {
126
+ "border_px": {
127
+ "rule": 3,
128
+ "surface": 3,
129
+ "control": 2
130
+ },
131
+ "surface_line": "ink",
132
+ "control_edge": "ink",
133
+ "elevation": "offset",
134
+ "offset_px": {
135
+ "surface": 6,
136
+ "control": 3
137
+ },
138
+ "press": "shift",
139
+ "meta_font": "text",
140
+ "meta_case": "none",
141
+ "display_case": "none",
142
+ "canvas_pattern": "none",
143
+ "heading_font": "display",
144
+ "panel_head": "accent",
145
+ "section_marks": "none"
146
+ },
147
+ "color": {
148
+ "light": {
149
+ "canvas": "#efecff",
150
+ "surface": "#ffffff",
151
+ "sunken": "#e2ddff",
152
+ "ink": "#111111",
153
+ "ink-2": "#2b2b33",
154
+ "ink-3": "#4a4a57",
155
+ "line": "#c9c3ec",
156
+ "line-strong": "#111111",
157
+ "control": "#5c5a70",
158
+ "accent": "#ffd23f",
159
+ "accent-hover": "#ffc400",
160
+ "on-accent": "#111111",
161
+ "accent-wash": "#fff1b8",
162
+ "accent-ink": "#5a32d6",
163
+ "accent-2": "#1f6feb",
164
+ "accent-2-ink": "#1a56b8",
165
+ "accent-2-wash": "#dce8fd",
166
+ "on-accent-2": "#ffffff",
167
+ "support": "#ffb3d1",
168
+ "support-ink": "#111111",
169
+ "focus": "#5a32d6",
170
+ "positive": "#12733a",
171
+ "positive-wash": "#c9f2d6",
172
+ "warning": "#7a4f00",
173
+ "warning-wash": "#ffe7a8",
174
+ "negative": "#c2121c",
175
+ "negative-wash": "#ffd3d3",
176
+ "info": "#1d4fd6",
177
+ "info-wash": "#d6e2ff",
178
+ "chart-1": "#5a32d6",
179
+ "chart-2": "#ffd23f",
180
+ "chart-3": "#ff6b9d",
181
+ "chart-4": "#111111",
182
+ "chart-5": "#2bb673"
183
+ },
184
+ "dark": {
185
+ "canvas": "#17161f",
186
+ "surface": "#211f2b",
187
+ "sunken": "#100f16",
188
+ "ink": "#f7f5ff",
189
+ "ink-2": "#d2cfe3",
190
+ "ink-3": "#a9a5c0",
191
+ "line": "#3a3750",
192
+ "line-strong": "#f7f5ff",
193
+ "control": "#8a86a6",
194
+ "accent": "#ffd23f",
195
+ "accent-hover": "#ffdf6b",
196
+ "on-accent": "#111111",
197
+ "accent-wash": "#3a3110",
198
+ "accent-ink": "#b9a3ff",
199
+ "accent-2": "#5b9bff",
200
+ "accent-2-ink": "#82b3ff",
201
+ "accent-2-wash": "#132544",
202
+ "on-accent-2": "#07142a",
203
+ "support": "#5c2a44",
204
+ "support-ink": "#ffd6e7",
205
+ "focus": "#ffd23f",
206
+ "positive": "#5fe08f",
207
+ "positive-wash": "#11301d",
208
+ "warning": "#ffcf5a",
209
+ "warning-wash": "#33270a",
210
+ "negative": "#ff8080",
211
+ "negative-wash": "#3a1414",
212
+ "info": "#8fb0ff",
213
+ "info-wash": "#15213d",
214
+ "chart-1": "#b9a3ff",
215
+ "chart-2": "#ffd23f",
216
+ "chart-3": "#ff8fbd",
217
+ "chart-4": "#f7f5ff",
218
+ "chart-5": "#5fe08f"
219
+ }
220
+ },
221
+ "accent_art": "sticker"
222
+ }
@@ -0,0 +1,226 @@
1
+ // frontend-ui-ux kit: behaviour that every build otherwise re-invents. No dependencies, no
2
+ // network. Colours come from the locked tokens (CSS custom properties), never from literals.
3
+ // UI.bars(el, { labels, series: [{ name, values, role }], marker, unit, caption })
4
+ // UI.lines(el, { labels, series: [{ name, values, role }], marker, unit, caption })
5
+ // <table data-ui-sortable> header <button class="ui-sort"> cells sort by data-value or text
6
+ // <div role="tablist" data-ui-tabs> arrow keys, Home and End move between tabs
7
+ (function () {
8
+ "use strict";
9
+ const NS = "http://www.w3.org/2000/svg";
10
+ const svg = (tag, attrs = {}) => {
11
+ const node = document.createElementNS(NS, tag);
12
+ for (const [key, value] of Object.entries(attrs)) node.setAttribute(key, String(value));
13
+ return node;
14
+ };
15
+ const roleColor = (role, index) => `var(--c-${role || `chart-${(index % 5) + 1}`})`;
16
+ const niceMax = (value) => {
17
+ if (value <= 0) return 1;
18
+ const power = 10 ** Math.floor(Math.log10(value));
19
+ const step = [1, 2, 2.5, 5, 10].find((n) => n * power >= value / 4) * power;
20
+ return Math.ceil(value / step) * step;
21
+ };
22
+ const fmt = (value, unit) => `${Number(value).toLocaleString()}${unit ?? ""}`;
23
+
24
+ function frame(el, opts, maxValue) {
25
+ el.classList.add("ui-chart");
26
+ el.replaceChildren();
27
+ const width = Math.max(280, Math.round(el.getBoundingClientRect().width) || 640);
28
+ const height = opts.height ?? (width < 480 ? 200 : 240);
29
+ const pad = { top: 16, right: 8, bottom: 28, left: 36 };
30
+ const plotW = width - pad.left - pad.right;
31
+ const plotH = height - pad.top - pad.bottom;
32
+ const root = svg("svg", { viewBox: `0 0 ${width} ${height}`, width, height, role: "img", "aria-label": opts.caption ?? "Chart" });
33
+ // Whole-number data keeps whole-number ticks: round the top up to a multiple of the four steps.
34
+ const top = opts.integer ? Math.max(4, Math.ceil(niceMax(maxValue) / 4) * 4) : niceMax(maxValue);
35
+ const axis = svg("g", { class: "ui-axis" });
36
+ for (let i = 0; i <= 4; i += 1) {
37
+ const y = pad.top + plotH - (plotH * i) / 4;
38
+ root.append(svg("line", { class: i === 0 ? "ui-baseline" : "ui-grid-line", x1: pad.left, x2: width - pad.right, y1: y, y2: y }));
39
+ const label = svg("text", { x: pad.left - 8, y: y + 4, "text-anchor": "end" });
40
+ label.textContent = fmt((top * i) / 4, "");
41
+ axis.append(label);
42
+ }
43
+ root.append(axis);
44
+ return { root, axis, width, height, pad, plotW, plotH, top };
45
+ }
46
+
47
+ function legendAndTable(el, opts) {
48
+ if (opts.series.length > 1) {
49
+ const legend = document.createElement("div");
50
+ legend.className = "ui-legend";
51
+ opts.series.forEach((series, index) => {
52
+ const item = document.createElement("span");
53
+ const swatch = document.createElement("i");
54
+ swatch.style.setProperty("--swatch", roleColor(series.role, index));
55
+ item.append(swatch, document.createTextNode(series.name));
56
+ legend.append(item);
57
+ });
58
+ el.prepend(legend);
59
+ }
60
+ const details = document.createElement("details");
61
+ const summary = document.createElement("summary");
62
+ summary.className = "ui-meta";
63
+ summary.textContent = opts.tableLabel ?? "Show as table";
64
+ const table = document.createElement("table");
65
+ table.className = "ui-table ui-table--compact";
66
+ const head = document.createElement("tr");
67
+ for (const text of [opts.indexLabel ?? "", ...opts.series.map((s) => s.name)]) {
68
+ const th = document.createElement("th");
69
+ th.textContent = text;
70
+ head.append(th);
71
+ }
72
+ const thead = document.createElement("thead");
73
+ thead.append(head);
74
+ const tbody = document.createElement("tbody");
75
+ opts.labels.forEach((label, row) => {
76
+ const tr = document.createElement("tr");
77
+ const th = document.createElement("th");
78
+ th.scope = "row";
79
+ th.textContent = label;
80
+ tr.append(th);
81
+ for (const series of opts.series) {
82
+ const td = document.createElement("td");
83
+ td.className = "is-num";
84
+ td.textContent = fmt(series.values[row], opts.unit);
85
+ tr.append(td);
86
+ }
87
+ tbody.append(tr);
88
+ });
89
+ table.append(thead, tbody);
90
+ details.append(summary, table);
91
+ el.append(details);
92
+ }
93
+
94
+ function xLabels(f, labels, step) {
95
+ const every = Math.max(1, Math.ceil(labels.length / (f.plotW / 44)));
96
+ labels.forEach((label, index) => {
97
+ if (index % every) return;
98
+ const text = svg("text", { x: f.pad.left + step * index + (step / 2) * (f.bandCenter ? 1 : 0), y: f.height - 8, "text-anchor": "middle" });
99
+ text.textContent = label;
100
+ f.axis.append(text);
101
+ });
102
+ }
103
+
104
+ function marker(f, opts, x) {
105
+ if (!opts.marker) return;
106
+ f.root.append(svg("line", { class: "ui-marker", x1: x, x2: x, y1: f.pad.top - 4, y2: f.pad.top + f.plotH }));
107
+ const text = svg("text", { class: "ui-marker-label", x: x + 4, y: f.pad.top + 6 });
108
+ text.textContent = opts.marker.label;
109
+ f.root.append(text);
110
+ }
111
+
112
+ const drawn = new Map();
113
+ let resizeTimer = 0;
114
+ addEventListener("resize", () => {
115
+ clearTimeout(resizeTimer);
116
+ resizeTimer = setTimeout(() => { for (const [el, draw] of drawn) draw(); }, 150);
117
+ });
118
+ const remember = (el, draw) => { drawn.set(el, draw); draw(); };
119
+
120
+ function bars(el, opts) { remember(el, () => drawBars(el, opts)); }
121
+ function lines(el, opts) { remember(el, () => drawLines(el, opts)); }
122
+
123
+ function drawBars(el, opts) {
124
+ const stacked = Boolean(opts.stacked);
125
+ const totals = opts.labels.map((_, i) => opts.series.reduce((sum, s) => sum + (stacked ? s.values[i] : 0), 0));
126
+ const max = stacked ? Math.max(...totals) : Math.max(...opts.series.flatMap((s) => s.values));
127
+ const f = frame(el, { ...opts, integer: opts.series.every((s) => s.values.every(Number.isInteger)) }, max);
128
+ f.bandCenter = true;
129
+ const step = f.plotW / opts.labels.length;
130
+ const groupW = step * 0.64;
131
+ const barW = stacked ? groupW : groupW / opts.series.length;
132
+ opts.labels.forEach((label, i) => {
133
+ let base = 0;
134
+ opts.series.forEach((series, s) => {
135
+ const value = series.values[i];
136
+ const h = (value / f.top) * f.plotH;
137
+ const x = f.pad.left + step * i + (step - groupW) / 2 + (stacked ? 0 : barW * s);
138
+ const y = f.pad.top + f.plotH - h - (stacked ? (base / f.top) * f.plotH : 0);
139
+ const rect = svg("rect", { x, y, width: Math.max(1, barW - (stacked ? 0 : 2)), height: Math.max(0, h), rx: 2, style: `fill: ${roleColor(series.role, s)}` });
140
+ const title = svg("title");
141
+ title.textContent = `${label}: ${series.name} ${fmt(value, opts.unit)}`;
142
+ rect.append(title);
143
+ f.root.append(rect);
144
+ base += stacked ? value : 0;
145
+ });
146
+ });
147
+ xLabels(f, opts.labels, step);
148
+ if (opts.marker) marker(f, opts, f.pad.left + step * opts.marker.index + step / 2);
149
+ el.append(f.root);
150
+ legendAndTable(el, opts);
151
+ }
152
+
153
+ function drawLines(el, opts) {
154
+ const max = Math.max(...opts.series.flatMap((s) => s.values));
155
+ const f = frame(el, { ...opts, integer: opts.series.every((s) => s.values.every(Number.isInteger)) }, max);
156
+ const step = f.plotW / Math.max(1, opts.labels.length - 1);
157
+ opts.series.forEach((series, s) => {
158
+ const points = series.values.map((value, i) => `${f.pad.left + step * i},${f.pad.top + f.plotH - (value / f.top) * f.plotH}`);
159
+ f.root.append(svg("polyline", { points: points.join(" "), style: `fill: none; stroke: ${roleColor(series.role, s)}`, "stroke-width": 2, "stroke-linejoin": "round", "stroke-linecap": "round" }));
160
+ });
161
+ f.bandCenter = false;
162
+ xLabels(f, opts.labels, step);
163
+ if (opts.marker) marker(f, opts, f.pad.left + step * opts.marker.index);
164
+ el.append(f.root);
165
+ legendAndTable(el, opts);
166
+ }
167
+
168
+ function sortable(table) {
169
+ const tbody = table.tBodies[0];
170
+ table.querySelectorAll("thead th .ui-sort").forEach((button) => {
171
+ button.type = "button";
172
+ button.addEventListener("click", () => {
173
+ const th = button.closest("th");
174
+ const index = [...th.parentElement.children].indexOf(th);
175
+ const next = th.getAttribute("aria-sort") === "ascending" ? "descending" : "ascending";
176
+ table.querySelectorAll("thead th[aria-sort]").forEach((cell) => cell.removeAttribute("aria-sort"));
177
+ th.setAttribute("aria-sort", next);
178
+ const key = (row) => {
179
+ const cell = row.children[index];
180
+ const raw = cell?.dataset.value ?? cell?.textContent.trim() ?? "";
181
+ const number = Number(raw);
182
+ return raw !== "" && !Number.isNaN(number) ? number : raw.toLocaleLowerCase();
183
+ };
184
+ const rows = [...tbody.rows].sort((a, b) => {
185
+ const x = key(a);
186
+ const y = key(b);
187
+ const order = typeof x === "number" && typeof y === "number" ? x - y : String(x).localeCompare(String(y));
188
+ return next === "ascending" ? order : -order;
189
+ });
190
+ tbody.append(...rows);
191
+ table.dispatchEvent(new CustomEvent("ui:sorted", { detail: { index, order: next } }));
192
+ });
193
+ });
194
+ }
195
+
196
+ function tabs(list) {
197
+ const items = [...list.querySelectorAll('[role="tab"]')];
198
+ const select = (tab) => {
199
+ for (const item of items) {
200
+ const on = item === tab;
201
+ item.setAttribute("aria-selected", String(on));
202
+ item.tabIndex = on ? 0 : -1;
203
+ const panel = document.getElementById(item.getAttribute("aria-controls"));
204
+ if (panel) panel.hidden = !on;
205
+ }
206
+ };
207
+ items.forEach((tab, index) => {
208
+ tab.addEventListener("click", () => select(tab));
209
+ tab.addEventListener("keydown", (event) => {
210
+ const move = { ArrowRight: 1, ArrowLeft: -1, Home: -index, End: items.length - 1 - index }[event.key];
211
+ if (move === undefined) return;
212
+ event.preventDefault();
213
+ const next = items[(index + move + items.length) % items.length];
214
+ next.focus();
215
+ select(next);
216
+ });
217
+ });
218
+ select(items.find((tab) => tab.getAttribute("aria-selected") === "true") ?? items[0]);
219
+ }
220
+
221
+ document.addEventListener("DOMContentLoaded", () => {
222
+ document.querySelectorAll("table[data-ui-sortable]").forEach(sortable);
223
+ document.querySelectorAll("[data-ui-tabs]").forEach(tabs);
224
+ });
225
+ window.UI = { bars, lines, sortable, tabs };
226
+ })();
@@ -23,9 +23,7 @@ This index is the read map for `SKILL.md`. Load the short, task-specific referen
23
23
  | [adaptive-layout.md](adaptive-layout.md) | Viewport, container, zoom, locale, or input mode changes layout. |
24
24
  | [system-foundations.md](system-foundations.md) | Tokens, primitives, variants, or theme boundaries are changing. |
25
25
  | [visual-language.md](visual-language.md) | Type, color, imagery, icons, depth, or chart choices need rules. |
26
- | [brand-and-imagery.md](brand-and-imagery.md) | Brand authority, reference images, or shipped assets are involved. |
27
-
28
- ## Interaction, motion, and review
26
+ | [brand-and-imagery.md](brand-and-imagery.md) | Brand authority, reference images, or shipped assets are involved. |## Interaction, motion, and review
29
27
 
30
28
  | Reference | Use when |
31
29
  | --- | --- |
@@ -36,7 +34,7 @@ This index is the read map for `SKILL.md`. Load the short, task-specific referen
36
34
  | [evidence-review.md](evidence-review.md) | An independent review, findings, or evidence handoff is requested. |
37
35
  | [complete-contract.md](complete-contract.md) | Full Design Contract schemas, field guidance, and evidence helpers are required. |
38
36
  | [taste-direction.md](taste-direction.md) | Additional visual direction and variance guidance is needed. |
39
- | [craft-floor.md](craft-floor.md) | Numbered craft checks, responsive passes, and thresholds guide implementation or review. |
37
+ | [craft-floor.md](craft-floor.md) | Numbered craft checks, responsive passes, and thresholds — including the DS-001..008 design-lock rules — guide implementation or review. |
40
38
  | [slop-register.md](slop-register.md) | Detectable generic patterns and reviewer prompts guide the cheaper fix. |
41
39
 
42
40
  ## Worked-example slot
@@ -209,7 +209,7 @@ asking; a reference nobody can find does not exist.
209
209
 
210
210
  ### Rendered probe and mode loop
211
211
 
212
- Use the absolute installed probe command supplied by the route context or SKILL.md after a page is served locally. The driver verifies the pinned browser capability, opens seven isolated viewport passes, saves screenshots, and reports findings in report.json plus a review table. A missing or unverified browser exits 2 with `BLOCKED: browser unavailable`; source checks still run, but every rendered check remains not verified. Never install a browser or fetch a dependency during the session. The probe is product evidence; independent `visual-qa` acceptance remains a separate verdict.
212
+ Use the absolute installed probe command supplied by the route context or SKILL.md after a page is served locally. The driver verifies the pinned browser capability, opens seven isolated viewport passes, saves screenshots, and reports findings in report.json plus a review table. A missing or unverified browser exits 2 with `BLOCKED: browser unavailable`; source checks still run, but every rendered check remains not verified. Never install a browser or fetch a dependency during the session. The probe is product evidence; independent `visual-qa` acceptance remains a separate verdict. For build, lock the look first: `scripts/design-lock.mjs init --family <landing|workspace|settings> --moment <kind> --moment-note "<what>" --dir <project> --scaffold`, then build from the kit layouts with only locked tokens; the probe enforces the lock from the page itself (DS-001/002/003/006/008 in `references/craft-floor.md`).
213
213
 
214
214
  Select the request's frontend mode before editing. build is the default and may author the requested UI. polish begins with a baseline probe and changes only the value of a flagged spacing, color, type, or motion rule; preserve structure and information architecture. audit runs the probe and reports, with zero source edits. harden tests only cue-backed axes: content length, content shape, quantity, container, state, and environment. For each axis record `Scenario | Observed | Owner`, or `not applicable: <reason>`. Repair only a defect the stress pass found. Explicit video, slides, or unrelated prose requests belong to their own routes.
215
215
 
@@ -445,7 +445,7 @@ isolated Hermes home. Use `--hermes-home`; never `--home`.
445
445
 
446
446
  ```text
447
447
  $ node packages/lithermes-installer/bin/lithermes.js install --yes --offline --no-hud --hermes-home "$ISOLATED"
448
- Installed LitHermes 1.0.29
448
+ Installed LitHermes 1.0.30
449
449
  plugin: $ISOLATED/plugins/lithermes
450
450
  model config: updated
451
451
 
@@ -462,8 +462,8 @@ installed payload: PASS
462
462
  enabled config: PASS
463
463
 
464
464
  $ hermes lithermes doctor
465
- [OK] plugin.yaml readable (version 1.0.29)
466
- [OK] skills bundled: 37
465
+ [OK] plugin.yaml readable (version 1.0.30)
466
+ [OK] skills bundled: 40
467
467
  [OK] litgoal durable runtime importable
468
468
  ```
469
469
 
@@ -72,3 +72,13 @@ The responsive pass runs at 320, 390, 768, and 1440 CSS pixels in light mode; re
72
72
  | RS-010 | Horizontal-scroll peek | A scrollable rail with no other visible scroll cue (prev/next controls, pagination dots/tabs, a position counter) reveals 16–32px of the next off-screen item rather than ending flush | DET | LOW |
73
73
  | RS-011 | RTL pass gated by content | An RTL/bidi mirror check runs only when the brief's real content or shipped locales include an RTL script; logical CSS properties are used throughout so the gated pass is mostly a dir="rtl" toggle | JUDG (the gate), DET (the logical-property audit once gated in) | MEDIUM if a physical-direction property appears where the gate says RTL applies |
74
74
  | RS-012 | Re-check discipline across states | A finding recorded at one viewport/theme/zoom state is re-sampled at a second state before being reported as a stable pass | JUDG (procedural) | downgrades a lone-state pass to not_verified, not a hard fail |
75
+ | DS-001 | Design lock applied | Every page links the locked `ui/tokens.css` before any other stylesheet | DET (static: link scan; live: computed token presence) | HIGH |
76
+ | DS-002 | Font family inside the lock | `font-family` is `var(--font-text)`, `var(--font-display)`, `var(--font-mono)` or a lock-declared variant; token definitions and `@font-face` blocks are exempt | DET (static outside token definitions; live: computed family) | HIGH |
77
+ | DS-003 | Colour inside the locked palette | No literal colour outside the token file and `:root` variable definitions; all paint comes from `var(--c-*)` roles | DET (static literal scan; live: computed channel tolerance) | HIGH |
78
+ | DS-004 | Font size on the locked scale | A computed font size matches a `var(--fs-*)` step within 0.5px, or is the one display title | DET (live computed only) | MEDIUM |
79
+ | DS-005 | Corner radius on the lock | A computed radius matches a `var(--radius-*)` value within 0.5px or is fully round | DET (live computed only) | LOW |
80
+ | DS-006 | No starter slot left behind | No `{{slot}}` marker text remains in the served markup | DET (static pattern; live: rendered text) | HIGH |
81
+ | DS-007 | Elevation inside the lock grammar | Shadows come from `var(--shadow-*)`; a flat lock takes no blurred or offset shadow, an offset lock takes no blurred one | DET (live computed mostly; hairline borders exempt) | MEDIUM |
82
+ | DS-008 | Signature moment present and on content | The lock records one moment kind; exactly its element carries `data-ui-moment="<kind>"` in the first screen on a read-once page | DET (static marker; live: area, viewport share, first-screen) | HIGH |
83
+
84
+ The probe applies the DS rows wherever a design.lock.json file governs the page tree — it looks for the lock beside or above the page — and skips them where no lock governs the tree. Threshold data lives in `scripts/probe-rules.json` under `designLock`.