medesign 0.0.0-stage → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +128 -2
- package/bin/medesign.js +200 -0
- package/integrations/claude-code/SKILL.md +20 -0
- package/integrations/cursor/medesign.mdc +26 -0
- package/medesign.config.js +46 -0
- package/package.json +62 -4
- package/presets/apple/design-tokens.css +115 -0
- package/presets/apple/guidelines.md +19 -0
- package/presets/apple/preset.json +53 -0
- package/presets/metha/design-tokens.css +127 -0
- package/presets/metha/guidelines.md +23 -0
- package/presets/metha/preset.json +53 -0
- package/presets/schema.json +102 -0
- package/presets/tesla/design-tokens.css +112 -0
- package/presets/tesla/guidelines.md +17 -0
- package/presets/tesla/preset.json +53 -0
- package/references/ai-tells.md +127 -0
- package/references/appendices.md +220 -0
- package/references/architecture.md +39 -0
- package/references/argon-design-archetypes.md +317 -0
- package/references/banner-sizes-and-styles.md +118 -0
- package/references/block-library.md +61 -0
- package/references/brand-design-tokens.md +42 -0
- package/references/catalog.json +108 -0
- package/references/cip-deliverable-guide.md +95 -0
- package/references/cip-design.md +121 -0
- package/references/cip-prompt-engineering.md +84 -0
- package/references/cip-style-guide.md +68 -0
- package/references/cli-architecture.md +146 -0
- package/references/components.md +240 -0
- package/references/dark-mode.md +23 -0
- package/references/design-core.md +42 -0
- package/references/design-md-protocol.md +75 -0
- package/references/design-routing.md +207 -0
- package/references/eng-imagery-content.md +71 -0
- package/references/eng-layout.md +28 -0
- package/references/eng-other.md +26 -0
- package/references/eng-states-theme.md +22 -0
- package/references/eng-type-color.md +44 -0
- package/references/icon-design.md +122 -0
- package/references/image-mockup-direction.md +53 -0
- package/references/image-to-code.md +46 -0
- package/references/impeccable-polish.md +85 -0
- package/references/intake.md +90 -0
- package/references/logo-color-psychology.md +101 -0
- package/references/logo-design.md +110 -0
- package/references/logo-prompt-engineering.md +158 -0
- package/references/logo-style-guide.md +109 -0
- package/references/mesurv-dna.md +104 -0
- package/references/micro-interactions-and-auto-animate.md +71 -0
- package/references/modern-craft-invariants.md +332 -0
- package/references/motion-tokens.md +99 -0
- package/references/preflight.md +110 -0
- package/references/proactive-motion.md +167 -0
- package/references/quality-gate.md +147 -0
- package/references/redesign-audit.md +38 -0
- package/references/redesign.md +52 -0
- package/references/slides-copywriting-formulas.md +84 -0
- package/references/slides-create.md +4 -0
- package/references/slides-html-template.md +295 -0
- package/references/slides-layout-patterns.md +137 -0
- package/references/slides-strategies.md +94 -0
- package/references/slides.md +42 -0
- package/references/social-photos-design.md +329 -0
- package/references/spatial-canvas-engine.md +160 -0
- package/references/stitch-system.md +184 -0
- package/references/style-extraction.md +17 -0
- package/references/styles/brutalist.md +88 -0
- package/references/styles/minimalist.md +81 -0
- package/references/styles/soft.md +94 -0
- package/references/threeui-spatial-engine.md +224 -0
- package/references/ui-styling-shadcn.md +336 -0
- package/references/ui-ux-vocabulary-vault.json +1223 -0
- package/references/ui-ux-vocabulary-vault.md +438 -0
- package/references/vocab-protocol.md +52 -0
- package/references/vocabulary.md +78 -0
- package/scripts/export-tokens.js +403 -0
- package/tests/browser-audit.js +442 -0
- package/tests/linter.js +412 -0
- package/tests/schemas/sarif-2.1.0.schema.json +2915 -0
- package/tests/visual-testbed.html +681 -0
|
@@ -0,0 +1,681 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="th" class="dark">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8">
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
|
+
<title>ME-DESIGN vNext - Optical Craft & Blind Test Workbench</title>
|
|
7
|
+
<link rel="preconnect" href="https://fonts.googleapis.com">
|
|
8
|
+
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
|
9
|
+
<link href="https://fonts.googleapis.com/css2?family=Geist+Mono:wght@400;500;600&family=Plus+Jakarta+Sans:wght@400;500;600;700&family=Prompt:wght@300;400;500;600&display=swap" rel="stylesheet">
|
|
10
|
+
<style>
|
|
11
|
+
@property --corner-r {
|
|
12
|
+
syntax: "<length>";
|
|
13
|
+
inherits: false;
|
|
14
|
+
initial-value: 8px;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
:root {
|
|
18
|
+
color-scheme: light dark;
|
|
19
|
+
--font-sans: "Plus Jakarta Sans", "Prompt", system-ui, sans-serif;
|
|
20
|
+
--font-mono: "Geist Mono", monospace;
|
|
21
|
+
|
|
22
|
+
/* Dark Mode Functional Tokens (vNext Manifesto) */
|
|
23
|
+
--canvas: #09090b;
|
|
24
|
+
--surface-base: oklch(0.14 0.008 260);
|
|
25
|
+
--surface-raised: color-mix(in oklch, var(--surface-base) 88%, white);
|
|
26
|
+
--surface-inset: oklch(0.11 0.006 260);
|
|
27
|
+
--border-subtle: color-mix(in oklch, var(--surface-base) 82%, white);
|
|
28
|
+
--border-focus: oklch(0.72 0.16 155);
|
|
29
|
+
|
|
30
|
+
--accent-terracotta: oklch(0.68 0.18 42);
|
|
31
|
+
--accent-mint: oklch(0.78 0.16 155);
|
|
32
|
+
--text-1: #f4f4f5;
|
|
33
|
+
--text-2: #cbd5e1;
|
|
34
|
+
--text-3: #94a3b8;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
@media (prefers-color-scheme: light) {
|
|
38
|
+
:root {
|
|
39
|
+
--canvas: #f8f9fa;
|
|
40
|
+
--surface-base: #f1f3f5;
|
|
41
|
+
--surface-raised: #ffffff;
|
|
42
|
+
--surface-inset: #e9ecef;
|
|
43
|
+
--border-subtle: #dee2e6;
|
|
44
|
+
--border-focus: oklch(0.55 0.18 155);
|
|
45
|
+
--text-1: #111827;
|
|
46
|
+
--text-2: #374151;
|
|
47
|
+
--text-3: #4b5563;
|
|
48
|
+
--accent-terracotta: oklch(0.55 0.18 42);
|
|
49
|
+
--accent-mint: oklch(0.42 0.16 155);
|
|
50
|
+
}
|
|
51
|
+
.metric-val.aa { color: #0369a1 !important; }
|
|
52
|
+
.badge-vnext { color: #0369a1 !important; border-color: rgba(3, 105, 161, 0.3) !important; background: rgba(3, 105, 161, 0.08) !important; }
|
|
53
|
+
.table-id-cyan { color: #0369a1 !important; }
|
|
54
|
+
tr#row-1 { background: rgba(3, 105, 161, 0.08) !important; }
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
.table-id-cyan { color: #22d3ee; }
|
|
58
|
+
|
|
59
|
+
* { box-sizing: border-box; margin: 0; padding: 0; }
|
|
60
|
+
body {
|
|
61
|
+
background-color: var(--canvas);
|
|
62
|
+
color: var(--text-1);
|
|
63
|
+
font-family: var(--font-sans);
|
|
64
|
+
min-height: 100dvh;
|
|
65
|
+
padding: 2rem 1.5rem;
|
|
66
|
+
line-height: 1.6;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
.container {
|
|
70
|
+
max-width: 1200px;
|
|
71
|
+
margin: 0 auto;
|
|
72
|
+
display: flex;
|
|
73
|
+
flex-direction: column;
|
|
74
|
+
gap: 2.5rem;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
header {
|
|
78
|
+
display: flex;
|
|
79
|
+
justify-content: space-between;
|
|
80
|
+
align-items: flex-start;
|
|
81
|
+
border-bottom: 1px solid var(--border-subtle);
|
|
82
|
+
padding-bottom: 1.5rem;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
.badge-vnext {
|
|
86
|
+
display: inline-flex;
|
|
87
|
+
align-items: center;
|
|
88
|
+
gap: 0.5rem;
|
|
89
|
+
padding: 0.25rem 0.75rem;
|
|
90
|
+
border-radius: 9999px;
|
|
91
|
+
background: color-mix(in oklch, var(--accent-mint) 12%, transparent);
|
|
92
|
+
border: 1px solid color-mix(in oklch, var(--accent-mint) 35%, transparent);
|
|
93
|
+
color: var(--accent-mint);
|
|
94
|
+
font-size: 0.75rem;
|
|
95
|
+
font-family: var(--font-mono);
|
|
96
|
+
font-weight: 500;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
h1 {
|
|
100
|
+
font-size: 1.75rem;
|
|
101
|
+
font-weight: 700;
|
|
102
|
+
letter-spacing: -0.025em;
|
|
103
|
+
margin-top: 0.5rem;
|
|
104
|
+
}
|
|
105
|
+
.subtitle { color: var(--text-2); font-size: 0.95rem; }
|
|
106
|
+
|
|
107
|
+
/* Lab Card Grid */
|
|
108
|
+
.lab-grid {
|
|
109
|
+
display: grid;
|
|
110
|
+
grid-template-columns: repeat(auto-fit, minmax(540px, 1fr));
|
|
111
|
+
gap: 1.5rem;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
.lab-card {
|
|
115
|
+
background: var(--surface-base);
|
|
116
|
+
border: 1px solid var(--border-subtle);
|
|
117
|
+
border-radius: 14px;
|
|
118
|
+
padding: 1.5rem;
|
|
119
|
+
display: flex;
|
|
120
|
+
flex-direction: column;
|
|
121
|
+
gap: 1.25rem;
|
|
122
|
+
box-shadow: 0 4px 20px -2px rgba(0, 0, 0, 0.4);
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
.lab-header {
|
|
126
|
+
display: flex;
|
|
127
|
+
justify-content: space-between;
|
|
128
|
+
align-items: center;
|
|
129
|
+
}
|
|
130
|
+
.lab-title {
|
|
131
|
+
font-size: 1.1rem;
|
|
132
|
+
font-weight: 600;
|
|
133
|
+
letter-spacing: -0.015em;
|
|
134
|
+
display: flex;
|
|
135
|
+
align-items: center;
|
|
136
|
+
gap: 0.5rem;
|
|
137
|
+
}
|
|
138
|
+
.lab-tag {
|
|
139
|
+
font-size: 0.75rem;
|
|
140
|
+
font-family: var(--font-mono);
|
|
141
|
+
background: var(--surface-inset);
|
|
142
|
+
padding: 0.2rem 0.5rem;
|
|
143
|
+
border-radius: 6px;
|
|
144
|
+
color: var(--text-2);
|
|
145
|
+
border: 1px solid var(--border-subtle);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
/* Comparison Box */
|
|
149
|
+
.cmp-stage {
|
|
150
|
+
display: grid;
|
|
151
|
+
grid-template-columns: 1fr 1fr;
|
|
152
|
+
gap: 1rem;
|
|
153
|
+
background: var(--surface-inset);
|
|
154
|
+
padding: 1rem;
|
|
155
|
+
border-radius: 10px;
|
|
156
|
+
border: 1px dashed var(--border-subtle);
|
|
157
|
+
}
|
|
158
|
+
.cmp-col {
|
|
159
|
+
display: flex;
|
|
160
|
+
flex-direction: column;
|
|
161
|
+
gap: 0.75rem;
|
|
162
|
+
align-items: center;
|
|
163
|
+
text-align: center;
|
|
164
|
+
}
|
|
165
|
+
.cmp-label {
|
|
166
|
+
font-size: 0.75rem;
|
|
167
|
+
font-family: var(--font-mono);
|
|
168
|
+
text-transform: uppercase;
|
|
169
|
+
letter-spacing: 0.05em;
|
|
170
|
+
color: var(--text-3);
|
|
171
|
+
}
|
|
172
|
+
.cmp-label.pro { color: var(--accent-mint); }
|
|
173
|
+
.cmp-label.con { color: #f87171; }
|
|
174
|
+
|
|
175
|
+
/* LAB 1: Area-Proportional Scaling */
|
|
176
|
+
.btn-slop {
|
|
177
|
+
width: 180px;
|
|
178
|
+
height: 48px;
|
|
179
|
+
background: #3b82f6;
|
|
180
|
+
color: white;
|
|
181
|
+
border: none;
|
|
182
|
+
border-radius: 8px;
|
|
183
|
+
font-weight: 600;
|
|
184
|
+
cursor: pointer;
|
|
185
|
+
transition: transform 100ms ease;
|
|
186
|
+
}
|
|
187
|
+
.btn-slop:active {
|
|
188
|
+
/* medesign-disable-next-line MD003 */
|
|
189
|
+
transform: scale(0.95); /* Generic Slop: Crushes hit-area and over-displaces */
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
/* Pro: Isolated Hit Container + clamp displacement */
|
|
193
|
+
.btn-pro-container {
|
|
194
|
+
position: relative;
|
|
195
|
+
min-height: 44px;
|
|
196
|
+
width: 180px;
|
|
197
|
+
height: 48px;
|
|
198
|
+
display: inline-flex;
|
|
199
|
+
cursor: pointer;
|
|
200
|
+
}
|
|
201
|
+
.btn-pro-surface {
|
|
202
|
+
width: 100%;
|
|
203
|
+
height: 100%;
|
|
204
|
+
background: var(--accent-mint);
|
|
205
|
+
color: #042f1e;
|
|
206
|
+
border-radius: 8px;
|
|
207
|
+
display: flex;
|
|
208
|
+
align-items: center;
|
|
209
|
+
justify-content: center;
|
|
210
|
+
font-weight: 600;
|
|
211
|
+
transition: transform 80ms cubic-bezier(0.2, 0, 0, 1);
|
|
212
|
+
--press-scale: 0.985; /* clamp(0.96, 1 - 2.5/180, 0.995) = 0.986 */
|
|
213
|
+
}
|
|
214
|
+
.btn-pro-container:active .btn-pro-surface {
|
|
215
|
+
transform: scale(var(--press-scale));
|
|
216
|
+
}
|
|
217
|
+
.btn-pro-container:focus-visible {
|
|
218
|
+
outline: 2px solid var(--border-focus);
|
|
219
|
+
outline-offset: 3px;
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
/* LAB 2: Color Science Midpoint */
|
|
223
|
+
.gradient-bar {
|
|
224
|
+
width: 100%;
|
|
225
|
+
height: 44px;
|
|
226
|
+
border-radius: 8px;
|
|
227
|
+
position: relative;
|
|
228
|
+
border: 1px solid rgba(255,255,255,0.1);
|
|
229
|
+
}
|
|
230
|
+
.grad-srgb {
|
|
231
|
+
background: linear-gradient(90deg, #3b82f6, #ef4444); /* Muddy middle */
|
|
232
|
+
}
|
|
233
|
+
.grad-oklab {
|
|
234
|
+
background: linear-gradient(in oklab 90deg, #3b82f6, #ef4444); /* Smooth uniform */
|
|
235
|
+
}
|
|
236
|
+
.grad-oklch {
|
|
237
|
+
background: linear-gradient(in oklch shorter hue 90deg, #3b82f6, #ef4444); /* Saturated */
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
/* LAB 3: Typography Thai Diacritic Headroom */
|
|
241
|
+
.thai-crop-bad {
|
|
242
|
+
font-size: 1.15rem;
|
|
243
|
+
background: #1e1e24;
|
|
244
|
+
border: 1px solid #333;
|
|
245
|
+
padding: 0 12px;
|
|
246
|
+
height: 38px;
|
|
247
|
+
line-height: 1.25;
|
|
248
|
+
overflow: hidden; /* Simulates clipping of top tone marks */
|
|
249
|
+
}
|
|
250
|
+
.thai-crop-good {
|
|
251
|
+
font-size: 1.15rem;
|
|
252
|
+
background: #1e1e24;
|
|
253
|
+
border: 1px solid var(--accent-mint);
|
|
254
|
+
padding: 3px 12px 1px 12px; /* Optical Headroom */
|
|
255
|
+
height: 38px;
|
|
256
|
+
line-height: 1.38;
|
|
257
|
+
display: inline-flex;
|
|
258
|
+
align-items: center;
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
/* LAB 4: Motion Profiles */
|
|
262
|
+
.motion-box {
|
|
263
|
+
width: 44px;
|
|
264
|
+
height: 44px;
|
|
265
|
+
background: var(--surface-raised);
|
|
266
|
+
border: 1px solid var(--border-subtle);
|
|
267
|
+
border-radius: 8px;
|
|
268
|
+
display: flex;
|
|
269
|
+
align-items: center;
|
|
270
|
+
justify-content: center;
|
|
271
|
+
font-size: 0.75rem;
|
|
272
|
+
font-family: var(--font-mono);
|
|
273
|
+
transition-property: transform;
|
|
274
|
+
}
|
|
275
|
+
.box-precision { transition: transform 90ms ease-out; }
|
|
276
|
+
.box-soft { transition: transform 280ms cubic-bezier(0.16, 1, 0.3, 1); }
|
|
277
|
+
.box-spring { transition: transform 420ms cubic-bezier(0.34, 1.56, 0.64, 1); }
|
|
278
|
+
.box-instant { transition: none !important; }
|
|
279
|
+
|
|
280
|
+
.motion-trigger-row {
|
|
281
|
+
display: flex;
|
|
282
|
+
gap: 0.5rem;
|
|
283
|
+
flex-wrap: wrap;
|
|
284
|
+
}
|
|
285
|
+
.pill-btn {
|
|
286
|
+
min-height: 44px;
|
|
287
|
+
display: inline-flex;
|
|
288
|
+
align-items: center;
|
|
289
|
+
justify-content: center;
|
|
290
|
+
padding: 0.35rem 0.85rem;
|
|
291
|
+
background: var(--surface-inset);
|
|
292
|
+
border: 1px solid var(--border-subtle);
|
|
293
|
+
border-radius: 6px;
|
|
294
|
+
color: var(--text-2);
|
|
295
|
+
font-size: 0.8rem;
|
|
296
|
+
cursor: pointer;
|
|
297
|
+
font-family: var(--font-mono);
|
|
298
|
+
outline-offset: 2px;
|
|
299
|
+
transition: color 140ms ease, border-color 140ms ease;
|
|
300
|
+
}
|
|
301
|
+
.pill-btn:focus-visible {
|
|
302
|
+
outline: 2px solid var(--border-focus);
|
|
303
|
+
}
|
|
304
|
+
.pill-btn:hover { color: var(--text-1); border-color: var(--text-2); }
|
|
305
|
+
|
|
306
|
+
/* 4-Tier Audit Score Simulator */
|
|
307
|
+
.audit-bar {
|
|
308
|
+
background: var(--surface-base);
|
|
309
|
+
border: 1px solid var(--border-subtle);
|
|
310
|
+
border-radius: 12px;
|
|
311
|
+
padding: 1.25rem 1.5rem;
|
|
312
|
+
display: flex;
|
|
313
|
+
align-items: center;
|
|
314
|
+
justify-content: space-between;
|
|
315
|
+
gap: 1.5rem;
|
|
316
|
+
flex-wrap: wrap;
|
|
317
|
+
}
|
|
318
|
+
.audit-metric {
|
|
319
|
+
display: flex;
|
|
320
|
+
flex-direction: column;
|
|
321
|
+
gap: 0.2rem;
|
|
322
|
+
}
|
|
323
|
+
.metric-name { font-size: 0.75rem; color: var(--text-3); font-family: var(--font-mono); text-transform: uppercase; }
|
|
324
|
+
.metric-val { font-size: 1.1rem; font-weight: 700; color: var(--accent-mint); font-family: var(--font-mono); }
|
|
325
|
+
.metric-val.aa { color: #38bdf8; }
|
|
326
|
+
|
|
327
|
+
.code-snippet {
|
|
328
|
+
background: #000;
|
|
329
|
+
border: 1px solid var(--border-subtle);
|
|
330
|
+
padding: 0.75rem;
|
|
331
|
+
border-radius: 6px;
|
|
332
|
+
font-family: var(--font-mono);
|
|
333
|
+
font-size: 0.75rem;
|
|
334
|
+
color: #34d399;
|
|
335
|
+
width: 100%;
|
|
336
|
+
overflow-x: auto;
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
@media (prefers-reduced-motion: reduce) {
|
|
340
|
+
*, *::before, *::after {
|
|
341
|
+
animation-duration: 0.01ms !important;
|
|
342
|
+
animation-iteration-count: 1 !important;
|
|
343
|
+
transition-duration: 0.01ms !important;
|
|
344
|
+
scroll-behavior: auto !important;
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
</style>
|
|
349
|
+
</head>
|
|
350
|
+
<body>
|
|
351
|
+
|
|
352
|
+
<div class="container">
|
|
353
|
+
<header>
|
|
354
|
+
<div>
|
|
355
|
+
<span class="badge-vnext">ME-DESIGN vNext Engine</span>
|
|
356
|
+
<h1>Optical Craft & Blind-Test Workbench</h1>
|
|
357
|
+
<p class="subtitle">ระบบทดสอบทางสายตาและเครื่องมือตรวจสอบ Optical Mathematics เทียบกับ Generic AI Slop</p>
|
|
358
|
+
</div>
|
|
359
|
+
<div class="audit-metric" style="align-items: flex-end;">
|
|
360
|
+
<span class="metric-name">Quality Gate Status</span>
|
|
361
|
+
<span class="metric-val">4-TIER PASS (100%)</span>
|
|
362
|
+
</div>
|
|
363
|
+
</header>
|
|
364
|
+
|
|
365
|
+
<!-- 4-Tier Live Score HUD -->
|
|
366
|
+
<div class="audit-bar">
|
|
367
|
+
<div class="audit-metric">
|
|
368
|
+
<span class="metric-name">Tier 1: Contrast AA/AAA</span>
|
|
369
|
+
<span class="metric-val">10.8 : 1 (AAA)</span>
|
|
370
|
+
</div>
|
|
371
|
+
<div class="audit-metric">
|
|
372
|
+
<span class="metric-name">Tier 1: Hit Target 44px</span>
|
|
373
|
+
<span class="metric-val">PASS (HIG-Safe)</span>
|
|
374
|
+
</div>
|
|
375
|
+
<div class="audit-metric">
|
|
376
|
+
<span class="metric-name">Tier 2: Press Displacement</span>
|
|
377
|
+
<span class="metric-val aa">1.35px Optical</span>
|
|
378
|
+
</div>
|
|
379
|
+
<div class="audit-metric">
|
|
380
|
+
<span class="metric-name">Tier 2: Motion Exit Ratio</span>
|
|
381
|
+
<span class="metric-val aa">0.65x (180ms)</span>
|
|
382
|
+
</div>
|
|
383
|
+
<div class="audit-metric">
|
|
384
|
+
<span class="metric-name">Tier 3: Color Interpolation</span>
|
|
385
|
+
<span class="metric-val">OKLCH / OKLab</span>
|
|
386
|
+
</div>
|
|
387
|
+
</div>
|
|
388
|
+
|
|
389
|
+
<!-- 4 Lab Experiments -->
|
|
390
|
+
<div class="lab-grid">
|
|
391
|
+
|
|
392
|
+
<!-- LAB 1: Area-Proportional Scaling -->
|
|
393
|
+
<div class="lab-card">
|
|
394
|
+
<div class="lab-header">
|
|
395
|
+
<span class="lab-title">01. Area-Proportional Press Scaling</span>
|
|
396
|
+
<span class="lab-tag">Rule 1 Invariant</span>
|
|
397
|
+
</div>
|
|
398
|
+
<p style="font-size: 0.85rem; color: var(--text-2);">
|
|
399
|
+
ลองกดปุ่มค้างไว้เพื่อดูความต่าง: ด้านซ้ายใช้ Generic `scale(0.95)` ซึ่งทำให้ Hit Area หดตัวและขอบกระตุก ส่วนด้านขวาใช้ `clamp()` แปรผันผกผัน พร้อมแยก Interactive Hit Container
|
|
400
|
+
</p>
|
|
401
|
+
|
|
402
|
+
<div class="cmp-stage">
|
|
403
|
+
<div class="cmp-col">
|
|
404
|
+
<span class="cmp-label con">Generic AI Slop (scale-95)</span>
|
|
405
|
+
<button class="btn-slop">Press & Hold</button>
|
|
406
|
+
<span style="font-size: 0.75rem; color: #f87171;">ยุบตัว 9.0px (รุนแรงเกินไป)</span>
|
|
407
|
+
</div>
|
|
408
|
+
<div class="cmp-col">
|
|
409
|
+
<span class="cmp-label pro">ME-DESIGN (clamp + isolated)</span>
|
|
410
|
+
<div class="btn-pro-container" tabindex="0">
|
|
411
|
+
<div class="btn-pro-surface">Press & Hold</div>
|
|
412
|
+
</div>
|
|
413
|
+
<span style="font-size: 0.75rem; color: var(--accent-mint);">ยุบตัว 1.35px (Optical 2-3px)</span>
|
|
414
|
+
</div>
|
|
415
|
+
</div>
|
|
416
|
+
|
|
417
|
+
<div class="code-snippet">
|
|
418
|
+
/* ME-DESIGN vNext Isolated Press Scaling */
|
|
419
|
+
.btn-surface { transform: scale(clamp(0.96, 1 - 2.5/max(W,H), 0.995)); }
|
|
420
|
+
</div>
|
|
421
|
+
</div>
|
|
422
|
+
|
|
423
|
+
<!-- LAB 2: Color Science Midpoint Spectrogram -->
|
|
424
|
+
<div class="lab-card">
|
|
425
|
+
<div class="lab-header">
|
|
426
|
+
<span class="lab-title">02. Color Interpolation Space (Blue -> Red)</span>
|
|
427
|
+
<span class="lab-tag">Perceptual Intent</span>
|
|
428
|
+
</div>
|
|
429
|
+
<p style="font-size: 0.85rem; color: var(--text-2);">
|
|
430
|
+
เปรียบเทียบ Gradient ข้ามขั้ว: แถบบน (sRGB Hex) จะเกิด Middle-Gray Muddy Band สีม่วงหม่นตรงกลาง แถบล่าง (OKLab / OKLCH) รักษาความสว่างและความสดของแสง
|
|
431
|
+
</p>
|
|
432
|
+
|
|
433
|
+
<div style="display: flex; flex-direction: column; gap: 0.75rem;">
|
|
434
|
+
<div>
|
|
435
|
+
<span class="cmp-label con">sRGB Hex (Middle-Gray Dead Zone)</span>
|
|
436
|
+
<div class="gradient-bar grad-srgb"></div>
|
|
437
|
+
</div>
|
|
438
|
+
<div>
|
|
439
|
+
<span class="cmp-label pro">OKLab (Uniform Lightness Blending)</span>
|
|
440
|
+
<div class="gradient-bar grad-oklab"></div>
|
|
441
|
+
</div>
|
|
442
|
+
<div>
|
|
443
|
+
<span class="cmp-label pro">OKLCH Shorter Hue (Vibrant Trajectory)</span>
|
|
444
|
+
<div class="gradient-bar grad-oklch"></div>
|
|
445
|
+
</div>
|
|
446
|
+
</div>
|
|
447
|
+
|
|
448
|
+
<div class="code-snippet">
|
|
449
|
+
/* Midpoint Inspection: 25%, 50%, 75% checked for zero mud */
|
|
450
|
+
linear-gradient(in oklab 90deg, #3b82f6, #ef4444);
|
|
451
|
+
</div>
|
|
452
|
+
</div>
|
|
453
|
+
|
|
454
|
+
<!-- LAB 3: Typography & Thai Diacritic Headroom -->
|
|
455
|
+
<div class="lab-card">
|
|
456
|
+
<div class="lab-header">
|
|
457
|
+
<span class="lab-title">03. Thai Diacritic Clearance Invariant</span>
|
|
458
|
+
<span class="lab-tag">Script Engine</span>
|
|
459
|
+
</div>
|
|
460
|
+
<p style="font-size: 0.85rem; color: var(--text-2);">
|
|
461
|
+
ตัวอักษรไทยที่มีสระบนและวรรณยุกต์ (ปิ๊, ผู้, ที่) หากตัดด้วย `text-box-trim` แบบภาษาอังกฤษ วรรณยุกต์จะถูกเฉือนขาด ต้องสำรอง Optical Headroom 2-4px
|
|
462
|
+
</p>
|
|
463
|
+
|
|
464
|
+
<div class="cmp-stage">
|
|
465
|
+
<div class="cmp-col">
|
|
466
|
+
<span class="cmp-label con">Trimmed Without Headroom</span>
|
|
467
|
+
<div class="thai-crop-bad">พื้นที่ติดตั้ง ปิ๊ง!</div>
|
|
468
|
+
<span style="font-size: 0.75rem; color: #f87171;">ไม้โทและสระอิถูกเฉือน</span>
|
|
469
|
+
</div>
|
|
470
|
+
<div class="cmp-col">
|
|
471
|
+
<span class="cmp-label pro">Script-Aware Headroom (2px)</span>
|
|
472
|
+
<div class="thai-crop-good">พื้นที่ติดตั้ง ปิ๊ง!</div>
|
|
473
|
+
<span style="font-size: 0.75rem; color: var(--accent-mint);">วรรณยุกต์คมชัด 100%</span>
|
|
474
|
+
</div>
|
|
475
|
+
</div>
|
|
476
|
+
|
|
477
|
+
<div class="code-snippet">
|
|
478
|
+
@supports (text-box: trim-both text alphabetic) {
|
|
479
|
+
.ui-label-th { text-box: trim-both text alphabetic; padding-top: 2px; }
|
|
480
|
+
}
|
|
481
|
+
</div>
|
|
482
|
+
</div>
|
|
483
|
+
|
|
484
|
+
<!-- LAB 4: 4 Motion Profiles -->
|
|
485
|
+
<div class="lab-card">
|
|
486
|
+
<div class="lab-header">
|
|
487
|
+
<span class="lab-title">04. The 4 Behavioral Motion Profiles</span>
|
|
488
|
+
<span class="lab-tag">Motion Engine</span>
|
|
489
|
+
</div>
|
|
490
|
+
<p style="font-size: 0.85rem; color: var(--text-2);">
|
|
491
|
+
ทดสอบความรู้สึกทางกายภาพของการเปลี่ยนสถานะ คลิกปุ่มด้านล่างเพื่อทดสอบ 4 Motion Profiles
|
|
492
|
+
</p>
|
|
493
|
+
|
|
494
|
+
<div style="display: flex; justify-content: space-around; padding: 1rem 0; background: var(--surface-inset); border-radius: 8px;">
|
|
495
|
+
<div style="display: flex; flex-direction: column; align-items: center; gap: 0.5rem;">
|
|
496
|
+
<div class="motion-box box-precision" id="box-1">P</div>
|
|
497
|
+
<span style="font-size: 0.7rem; font-family: var(--font-mono);">precision</span>
|
|
498
|
+
</div>
|
|
499
|
+
<div style="display: flex; flex-direction: column; align-items: center; gap: 0.5rem;">
|
|
500
|
+
<div class="motion-box box-soft" id="box-2">S</div>
|
|
501
|
+
<span style="font-size: 0.7rem; font-family: var(--font-mono);">soft-settle</span>
|
|
502
|
+
</div>
|
|
503
|
+
<div style="display: flex; flex-direction: column; align-items: center; gap: 0.5rem;">
|
|
504
|
+
<div class="motion-box box-spring" id="box-3">SP</div>
|
|
505
|
+
<span style="font-size: 0.7rem; font-family: var(--font-mono);">spring</span>
|
|
506
|
+
</div>
|
|
507
|
+
<div style="display: flex; flex-direction: column; align-items: center; gap: 0.5rem;">
|
|
508
|
+
<div class="motion-box box-instant" id="box-4">I</div>
|
|
509
|
+
<span style="font-size: 0.7rem; font-family: var(--font-mono);">instant</span>
|
|
510
|
+
</div>
|
|
511
|
+
</div>
|
|
512
|
+
|
|
513
|
+
<div class="motion-trigger-row">
|
|
514
|
+
<button class="pill-btn" onclick="triggerMotion()">Trigger Animation</button>
|
|
515
|
+
<button class="pill-btn" onclick="resetMotion()">Reset</button>
|
|
516
|
+
</div>
|
|
517
|
+
|
|
518
|
+
<div class="code-snippet">
|
|
519
|
+
/* 4 Profiles: precision (0-100ms), soft-settle (280ms), spring (WAAPI/linear), instant (0ms) */
|
|
520
|
+
</div>
|
|
521
|
+
</div>
|
|
522
|
+
|
|
523
|
+
|
|
524
|
+
<!-- LAB 5: Operational Engineering Blueprint (Archetypes 31 & 32) -->
|
|
525
|
+
<div class="lab-card" style="grid-column: 1 / -1;">
|
|
526
|
+
<div class="lab-header">
|
|
527
|
+
<span class="lab-title">05. Geospatial Situation Awareness & Mission-Critical HMI (Archetypes 31 & 32)</span>
|
|
528
|
+
<span class="lab-tag">5-Axis Operational Blueprint</span>
|
|
529
|
+
</div>
|
|
530
|
+
<p style="font-size: 0.85rem; color: var(--text-2);">
|
|
531
|
+
การประกอบร่าง 5-Axis Matrix: Operational (Geospatial) × Visual (Linear Minimal) × Spatial (Map + Table Workbench) × Motion (Precision 90ms) × Governance (Tier 1 Passed). คลิกเลือกแปลงที่ดินในตารางเพื่อดูการซิงก์ตำแหน่งบนแผนที่ (Linked Views)
|
|
532
|
+
</p>
|
|
533
|
+
|
|
534
|
+
<!-- ISA-101 Alarm & Telemetry Status Bar -->
|
|
535
|
+
<div style="display: flex; justify-content: space-between; align-items: center; background: #121316; border: 1px solid var(--border-subtle); padding: 0.5rem 1rem; border-radius: 8px;">
|
|
536
|
+
<div style="display: flex; gap: 1rem; align-items: center; font-size: 0.8rem; font-family: var(--font-mono);">
|
|
537
|
+
<span style="color: #64748b; display: inline-flex; align-items: center; gap: 0.35rem;">
|
|
538
|
+
<span style="width: 8px; height: 8px; border-radius: 50%; background: #22c55e;"></span> GNSS RTK FIX
|
|
539
|
+
</span>
|
|
540
|
+
<span style="color: #64748b;">CRS: EPSG:32647 (WGS84 UTM 47N)</span>
|
|
541
|
+
<span style="color: #64748b;">1-Sigma: Hz 0.008m | Vt 0.012m</span>
|
|
542
|
+
</div>
|
|
543
|
+
<div style="display: flex; gap: 0.5rem;">
|
|
544
|
+
<span style="background: rgba(245, 158, 11, 0.15); border: 1px solid rgba(245, 158, 11, 0.4); color: #f59e0b; padding: 0.2rem 0.5rem; border-radius: 4px; font-size: 0.75rem; font-family: var(--font-mono);">ISA-101: 1 Advisory</span>
|
|
545
|
+
<span style="background: rgba(34, 197, 94, 0.15); border: 1px solid rgba(34, 197, 94, 0.4); color: #22c55e; padding: 0.2rem 0.5rem; border-radius: 4px; font-size: 0.75rem; font-family: var(--font-mono);">0 Critical</span>
|
|
546
|
+
</div>
|
|
547
|
+
</div>
|
|
548
|
+
|
|
549
|
+
<!-- Linked Map + Controls + Table Stage -->
|
|
550
|
+
<div style="display: grid; grid-template-columns: 1.4fr 1fr; gap: 1rem;">
|
|
551
|
+
<!-- Map Canvas Simulator -->
|
|
552
|
+
<div style="height: 240px; background: #0c0d10; border: 1px solid var(--border-subtle); border-radius: 8px; position: relative; overflow: hidden; display: flex; align-items: center; justify-content: center;">
|
|
553
|
+
<svg id="cadastral-map" width="100%" height="100%" viewBox="0 0 400 240" style="position: absolute; inset: 0;">
|
|
554
|
+
<!-- Grid Hairlines -->
|
|
555
|
+
<defs>
|
|
556
|
+
<pattern id="grid" width="40" height="40" patternUnits="userSpaceOnUse">
|
|
557
|
+
<path d="M 40 0 L 0 0 0 40" fill="none" stroke="rgba(255,255,255,0.04)" stroke-width="1"/>
|
|
558
|
+
</pattern>
|
|
559
|
+
</defs>
|
|
560
|
+
<rect width="100%" height="100%" fill="url(#grid)" />
|
|
561
|
+
<!-- Parcels -->
|
|
562
|
+
<polygon id="poly-1" points="60,40 160,50 140,140 50,120" fill="rgba(6,182,212,0.12)" stroke="#06b6d4" stroke-width="1.5" style="cursor: pointer; transition: all 120ms ease;"/>
|
|
563
|
+
<polygon id="poly-2" points="175,55 280,45 295,150 155,145" fill="rgba(245,158,11,0.12)" stroke="#f59e0b" stroke-width="1.5" style="cursor: pointer; transition: all 120ms ease;"/>
|
|
564
|
+
<polygon id="poly-3" points="80,155 220,165 200,220 70,210" fill="rgba(16,185,129,0.12)" stroke="#10b981" stroke-width="1.5" style="cursor: pointer; transition: all 120ms ease;"/>
|
|
565
|
+
<text x="90" y="95" fill="#06b6d4" font-size="11" font-family="monospace">PARCEL-101</text>
|
|
566
|
+
<text x="210" y="105" fill="#f59e0b" font-size="11" font-family="monospace">PARCEL-102</text>
|
|
567
|
+
<text x="125" y="190" fill="#10b981" font-size="11" font-family="monospace">PARCEL-103</text>
|
|
568
|
+
</svg>
|
|
569
|
+
<div style="position: absolute; bottom: 8px; right: 10px; font-size: 0.7rem; font-family: var(--font-mono); color: var(--text-3); background: rgba(0,0,0,0.6); padding: 2px 6px; border-radius: 4px;">
|
|
570
|
+
Scale 1:1,000 | 100dvh Canvas
|
|
571
|
+
</div>
|
|
572
|
+
</div>
|
|
573
|
+
|
|
574
|
+
<!-- Inspector & Selected Metadata -->
|
|
575
|
+
<div style="background: var(--surface-inset); border: 1px solid var(--border-subtle); border-radius: 8px; padding: 1rem; display: flex; flex-direction: column; justify-content: space-between;">
|
|
576
|
+
<div>
|
|
577
|
+
<div style="font-size: 0.75rem; font-family: var(--font-mono); color: var(--text-3); text-transform: uppercase;">Selected Feature Inspector</div>
|
|
578
|
+
<div id="inspector-title" style="font-size: 1.15rem; font-weight: 700; color: var(--accent-mint); margin-top: 0.25rem;">PARCEL-101</div>
|
|
579
|
+
<div style="margin-top: 0.75rem; display: flex; flex-direction: column; gap: 0.35rem; font-size: 0.8rem; font-family: var(--font-mono); color: var(--text-2);">
|
|
580
|
+
<div>UTM Easting: <span id="insp-easting" style="color: var(--text-1); font-weight: 600;">672,410.824 m</span></div>
|
|
581
|
+
<div>UTM Northing: <span id="insp-northing" style="color: var(--text-1); font-weight: 600;">1,524,891.105 m</span></div>
|
|
582
|
+
<div>Area (Computed): <span id="insp-area" style="color: var(--text-1); font-weight: 600;">1,248.50 sq.m</span></div>
|
|
583
|
+
<div>Survey Method: <span style="color: var(--text-1);">Network RTK CORS</span></div>
|
|
584
|
+
</div>
|
|
585
|
+
</div>
|
|
586
|
+
<button class="pill-btn" style="width: 100%; justify-content: center; background: var(--surface-base); border-color: var(--accent-mint); color: var(--accent-mint); font-weight: 600;" onclick="alert('Exporting Land Parcel GeoJSON...')">Export Cadastral Proof (.GeoJSON)</button>
|
|
587
|
+
</div>
|
|
588
|
+
</div>
|
|
589
|
+
|
|
590
|
+
<!-- Linked Data Table -->
|
|
591
|
+
<table style="width: 100%; border-collapse: collapse; font-size: 0.8rem; font-family: var(--font-mono); text-align: left;">
|
|
592
|
+
<thead>
|
|
593
|
+
<tr style="border-bottom: 1px solid var(--border-subtle); color: var(--text-2);">
|
|
594
|
+
<th style="padding: 0.5rem;">ID</th>
|
|
595
|
+
<th style="padding: 0.5rem;">PARCEL NO.</th>
|
|
596
|
+
<th style="padding: 0.5rem;">EASTING (M)</th>
|
|
597
|
+
<th style="padding: 0.5rem;">NORTHING (M)</th>
|
|
598
|
+
<th style="padding: 0.5rem;">TOLERANCE</th>
|
|
599
|
+
<th style="padding: 0.5rem;">STATUS</th>
|
|
600
|
+
</tr>
|
|
601
|
+
</thead>
|
|
602
|
+
<tbody>
|
|
603
|
+
<tr id="row-1" style="border-bottom: 1px solid rgba(255,255,255,0.05); cursor: pointer; background: rgba(6,182,212,0.08);" onclick="selectParcel(1, 'PARCEL-101', '672,410.824 m', '1,524,891.105 m', '1,248.50 sq.m', '#06b6d4')">
|
|
604
|
+
<td class="table-id-cyan" style="padding: 0.5rem; font-weight: 600;">01</td>
|
|
605
|
+
<td style="padding: 0.5rem; font-weight: 600;">PARCEL-101</td>
|
|
606
|
+
<td style="padding: 0.5rem;">672,410.824</td>
|
|
607
|
+
<td style="padding: 0.5rem;">1,524,891.105</td>
|
|
608
|
+
<td style="padding: 0.5rem; color: #10b981;">±0.008 m</td>
|
|
609
|
+
<td style="padding: 0.5rem;"><span style="color: #10b981;">VERIFIED</span></td>
|
|
610
|
+
</tr>
|
|
611
|
+
<tr id="row-2" style="border-bottom: 1px solid rgba(255,255,255,0.05); cursor: pointer;" onclick="selectParcel(2, 'PARCEL-102', '672,550.120 m', '1,524,912.440 m', '1,890.20 sq.m', '#f59e0b')">
|
|
612
|
+
<td style="padding: 0.5rem; color: #f59e0b;">02</td>
|
|
613
|
+
<td style="padding: 0.5rem; font-weight: 600;">PARCEL-102</td>
|
|
614
|
+
<td style="padding: 0.5rem;">672,550.120</td>
|
|
615
|
+
<td style="padding: 0.5rem;">1,524,912.440</td>
|
|
616
|
+
<td style="padding: 0.5rem; color: #f59e0b;">±0.018 m</td>
|
|
617
|
+
<td style="padding: 0.5rem;"><span style="color: #f59e0b;">ADVISORY</span></td>
|
|
618
|
+
</tr>
|
|
619
|
+
<tr id="row-3" style="cursor: pointer;" onclick="selectParcel(3, 'PARCEL-103', '672,490.660 m', '1,524,780.310 m', '940.80 sq.m', '#10b981')">
|
|
620
|
+
<td style="padding: 0.5rem; color: #10b981;">03</td>
|
|
621
|
+
<td style="padding: 0.5rem; font-weight: 600;">PARCEL-103</td>
|
|
622
|
+
<td style="padding: 0.5rem;">672,490.660</td>
|
|
623
|
+
<td style="padding: 0.5rem;">1,524,780.310</td>
|
|
624
|
+
<td style="padding: 0.5rem; color: #10b981;">±0.005 m</td>
|
|
625
|
+
<td style="padding: 0.5rem;"><span style="color: #10b981;">VERIFIED</span></td>
|
|
626
|
+
</tr>
|
|
627
|
+
</tbody>
|
|
628
|
+
</table>
|
|
629
|
+
|
|
630
|
+
<div class="code-snippet">
|
|
631
|
+
/* Bento Named Areas Blueprint (Zero CLS Guarantee) */
|
|
632
|
+
.workspace { grid-template-areas: "map controls" "table table"; grid-auto-flow: row; }
|
|
633
|
+
</div>
|
|
634
|
+
</div>
|
|
635
|
+
|
|
636
|
+
</div>
|
|
637
|
+
</div>
|
|
638
|
+
|
|
639
|
+
<script>
|
|
640
|
+
let toggled = false;
|
|
641
|
+
function triggerMotion() {
|
|
642
|
+
toggled = !toggled;
|
|
643
|
+
const dist = toggled ? 'translateY(-16px)' : 'translateY(0px)';
|
|
644
|
+
document.getElementById('box-1').style.transform = dist;
|
|
645
|
+
document.getElementById('box-2').style.transform = dist;
|
|
646
|
+
document.getElementById('box-3').style.transform = dist;
|
|
647
|
+
document.getElementById('box-4').style.transform = dist;
|
|
648
|
+
}
|
|
649
|
+
function resetMotion() {
|
|
650
|
+
toggled = false;
|
|
651
|
+
document.getElementById('box-1').style.transform = 'translateY(0px)';
|
|
652
|
+
document.getElementById('box-2').style.transform = 'translateY(0px)';
|
|
653
|
+
document.getElementById('box-3').style.transform = 'translateY(0px)';
|
|
654
|
+
document.getElementById('box-4').style.transform = 'translateY(0px)';
|
|
655
|
+
}
|
|
656
|
+
</script>
|
|
657
|
+
<script>
|
|
658
|
+
function selectParcel(id, title, east, north, area, color) {
|
|
659
|
+
document.getElementById('inspector-title').innerText = title;
|
|
660
|
+
document.getElementById('inspector-title').style.color = color;
|
|
661
|
+
document.getElementById('insp-easting').innerText = east;
|
|
662
|
+
document.getElementById('insp-northing').innerText = north;
|
|
663
|
+
document.getElementById('insp-area').innerText = area;
|
|
664
|
+
|
|
665
|
+
[1, 2, 3].forEach(i => {
|
|
666
|
+
const row = document.getElementById('row-' + i);
|
|
667
|
+
const poly = document.getElementById('poly-' + i);
|
|
668
|
+
if (i === id) {
|
|
669
|
+
row.style.background = 'rgba(255,255,255,0.08)';
|
|
670
|
+
poly.setAttribute('stroke-width', '3');
|
|
671
|
+
poly.style.filter = 'drop-shadow(0 0 8px ' + color + ')';
|
|
672
|
+
} else {
|
|
673
|
+
row.style.background = 'transparent';
|
|
674
|
+
poly.setAttribute('stroke-width', '1.5');
|
|
675
|
+
poly.style.filter = 'none';
|
|
676
|
+
}
|
|
677
|
+
});
|
|
678
|
+
}
|
|
679
|
+
</script>
|
|
680
|
+
</body>
|
|
681
|
+
</html>
|