gaugeit.js 0.1.0 → 0.1.1
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/README.md +51 -27
- package/SECURITY.md +2 -2
- package/dist/gaugeit.cjs +158 -104
- package/dist/gaugeit.cjs.map +3 -3
- package/dist/gaugeit.css +32 -20
- package/dist/gaugeit.d.ts +17 -0
- package/dist/gaugeit.esm.js +158 -104
- package/dist/gaugeit.esm.js.map +3 -3
- package/dist/gaugeit.esm.min.js +2 -2
- package/dist/gaugeit.esm.min.js.map +3 -3
- package/dist/gaugeit.min.cjs +2 -2
- package/dist/gaugeit.min.cjs.map +3 -3
- package/dist/gaugeit.min.css +1 -1
- package/dist/gaugeit.standalone.js +159 -105
- package/dist/gaugeit.standalone.js.map +3 -3
- package/dist/gaugeit.standalone.min.js +35 -23
- package/dist/gaugeit.standalone.min.js.map +3 -3
- package/dist/gaugeit.umd.js +158 -104
- package/dist/gaugeit.umd.js.map +3 -3
- package/dist/gaugeit.umd.min.js +2 -2
- package/dist/gaugeit.umd.min.js.map +3 -3
- package/dist/manifest.json +20 -20
- package/docs/ai/ai-full.md +5097 -0
- package/docs/ai/contributor-guide.md +928 -0
- package/docs/ai/index.md +73 -0
- package/docs/ai/integration-recipes.md +1117 -0
- package/docs/ai/library-usage.md +875 -0
- package/docs/ai/options-reference.md +1107 -0
- package/docs/ai/troubleshooting.md +1024 -0
- package/docs/api.md +34 -7
- package/docs/architecture.md +10 -2
- package/docs/creating-gauge-types.md +2 -1
- package/docs/development.md +2 -2
- package/docs/framework-integration.md +2 -2
- package/package.json +1 -1
|
@@ -0,0 +1,928 @@
|
|
|
1
|
+
# Gaugeit.js contributor guide for coding agents
|
|
2
|
+
|
|
3
|
+
This guide explains how to modify and extend Gaugeit.js 0.1.1 without breaking its
|
|
4
|
+
public API, distribution model, responsive layout, or cross-platform reproducibility.
|
|
5
|
+
|
|
6
|
+
Read root `AGENTS.md` first. Existing human-oriented references remain important:
|
|
7
|
+
|
|
8
|
+
- `docs/architecture.md`
|
|
9
|
+
- `docs/creating-gauge-types.md`
|
|
10
|
+
- `docs/development.md`
|
|
11
|
+
- `docs/api.md`
|
|
12
|
+
- `CONTRIBUTING.md`
|
|
13
|
+
|
|
14
|
+
## Architecture summary
|
|
15
|
+
|
|
16
|
+
Gaugeit.js separates application state from visual composition:
|
|
17
|
+
|
|
18
|
+
```text
|
|
19
|
+
public API
|
|
20
|
+
-> managed instance creation
|
|
21
|
+
-> Gauge lifecycle and animation core
|
|
22
|
+
-> option resolution and selected type
|
|
23
|
+
-> ordered rendering layers
|
|
24
|
+
-> SVG renderer and dynamic controllers
|
|
25
|
+
-> generated responsive instrument
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
The core owns values, animation, jitter, lifecycle, events, accessibility, and cleanup.
|
|
29
|
+
Types own defaults and ordered layer lists. Layers own SVG. Geometry helpers own
|
|
30
|
+
deterministic math. This separation is a project invariant.
|
|
31
|
+
|
|
32
|
+
## Canonical source and generated output
|
|
33
|
+
|
|
34
|
+
Canonical files:
|
|
35
|
+
|
|
36
|
+
```text
|
|
37
|
+
src/index.js
|
|
38
|
+
src/core/
|
|
39
|
+
src/geometry/
|
|
40
|
+
src/layers/
|
|
41
|
+
src/renderer/
|
|
42
|
+
src/types/
|
|
43
|
+
src/gaugeit.css
|
|
44
|
+
src/index.d.ts
|
|
45
|
+
adapters/
|
|
46
|
+
bin/
|
|
47
|
+
scripts/
|
|
48
|
+
tests/
|
|
49
|
+
README.md
|
|
50
|
+
docs/
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
Generated files:
|
|
54
|
+
|
|
55
|
+
```text
|
|
56
|
+
dist/gaugeit.cjs
|
|
57
|
+
dist/gaugeit.cjs.map
|
|
58
|
+
dist/gaugeit.min.cjs
|
|
59
|
+
dist/gaugeit.min.cjs.map
|
|
60
|
+
dist/gaugeit.esm.js
|
|
61
|
+
dist/gaugeit.esm.js.map
|
|
62
|
+
dist/gaugeit.esm.min.js
|
|
63
|
+
dist/gaugeit.esm.min.js.map
|
|
64
|
+
dist/gaugeit.umd.js
|
|
65
|
+
dist/gaugeit.umd.js.map
|
|
66
|
+
dist/gaugeit.umd.min.js
|
|
67
|
+
dist/gaugeit.umd.min.js.map
|
|
68
|
+
dist/gaugeit.standalone.js
|
|
69
|
+
dist/gaugeit.standalone.js.map
|
|
70
|
+
dist/gaugeit.standalone.min.js
|
|
71
|
+
dist/gaugeit.standalone.min.js.map
|
|
72
|
+
dist/gaugeit.css
|
|
73
|
+
dist/gaugeit.min.css
|
|
74
|
+
dist/gaugeit.d.ts
|
|
75
|
+
dist/manifest.json
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
Never hand-edit generated files. A source change is incomplete until the generated
|
|
79
|
+
distribution is rebuilt and committed.
|
|
80
|
+
|
|
81
|
+
## Option resolution pipeline
|
|
82
|
+
|
|
83
|
+
The runtime resolves options in `src/core/options.js`.
|
|
84
|
+
|
|
85
|
+
### Stage 1: determine type
|
|
86
|
+
|
|
87
|
+
The requested `type` is converted to a string and looked up in the registry. Unknown
|
|
88
|
+
types do not receive a silent fallback because a typo would otherwise hide an
|
|
89
|
+
integration error.
|
|
90
|
+
|
|
91
|
+
### Stage 2: merge defaults
|
|
92
|
+
|
|
93
|
+
Resolution order:
|
|
94
|
+
|
|
95
|
+
```text
|
|
96
|
+
BASE_DEFAULTS
|
|
97
|
+
+ selected type defaults
|
|
98
|
+
+ raw instance options
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
The merge rules in `src/core/utils.js` are:
|
|
102
|
+
|
|
103
|
+
- plain objects merge recursively;
|
|
104
|
+
- arrays are replaced;
|
|
105
|
+
- callback functions are preserved;
|
|
106
|
+
- unsafe keys `__proto__`, `prototype`, and `constructor` are ignored;
|
|
107
|
+
- cross-realm plain objects remain accepted.
|
|
108
|
+
|
|
109
|
+
### Stage 3: restore nested shapes
|
|
110
|
+
|
|
111
|
+
Malformed nested values are restored from fallback objects. This prevents common
|
|
112
|
+
configuration mistakes such as:
|
|
113
|
+
|
|
114
|
+
```js
|
|
115
|
+
{ pointer: null }
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
from crashing later layer code.
|
|
119
|
+
|
|
120
|
+
### Stage 4: optional type configuration
|
|
121
|
+
|
|
122
|
+
A type may expose:
|
|
123
|
+
|
|
124
|
+
```js
|
|
125
|
+
configure(options, {
|
|
126
|
+
requested,
|
|
127
|
+
typeDefaults
|
|
128
|
+
})
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
This runs after merge and before final validation.
|
|
132
|
+
|
|
133
|
+
Use the hook only to derive unspecified fallback values. The resizable built-in linear
|
|
134
|
+
and tape types use it to scale preset geometry from requested dimensions. Do not
|
|
135
|
+
overwrite coordinates explicitly provided by the instance.
|
|
136
|
+
|
|
137
|
+
### Stage 5: validate and normalize
|
|
138
|
+
|
|
139
|
+
Validation:
|
|
140
|
+
|
|
141
|
+
- repairs invalid numeric ranges;
|
|
142
|
+
- clamps sizes and opacity;
|
|
143
|
+
- checks enum values;
|
|
144
|
+
- normalizes zones;
|
|
145
|
+
- swaps reversed trigger bounds;
|
|
146
|
+
- derives light glow radius when null;
|
|
147
|
+
- enforces minimum intervals;
|
|
148
|
+
- preserves compatibility aliases.
|
|
149
|
+
|
|
150
|
+
Do not move ordinary defensive normalization into rendering layers. Layers should
|
|
151
|
+
receive resolved runtime options.
|
|
152
|
+
|
|
153
|
+
## User option ownership
|
|
154
|
+
|
|
155
|
+
`Gauge` stores two related configurations:
|
|
156
|
+
|
|
157
|
+
- `userOptions`: original declarative overrides;
|
|
158
|
+
- `options`: fully resolved runtime configuration.
|
|
159
|
+
|
|
160
|
+
`updateOptions(patch)` deep-merges into `userOptions`.
|
|
161
|
+
|
|
162
|
+
`replaceOptions(options)` replaces `userOptions` with a fresh object.
|
|
163
|
+
|
|
164
|
+
Both re-resolve the selected type, reconfigure lifecycle observers, render static
|
|
165
|
+
content again, and preserve the current target value unless an explicit new value is
|
|
166
|
+
provided.
|
|
167
|
+
|
|
168
|
+
When adding a public option, consider both patch and replacement semantics.
|
|
169
|
+
|
|
170
|
+
## Type registry
|
|
171
|
+
|
|
172
|
+
`GaugeTypeRegistry` stores:
|
|
173
|
+
|
|
174
|
+
```js
|
|
175
|
+
{
|
|
176
|
+
name,
|
|
177
|
+
defaults,
|
|
178
|
+
layers,
|
|
179
|
+
description,
|
|
180
|
+
configure
|
|
181
|
+
}
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
Registration validates:
|
|
185
|
+
|
|
186
|
+
- non-empty type name;
|
|
187
|
+
- plain-object definition;
|
|
188
|
+
- non-empty layer array;
|
|
189
|
+
- every layer exposes `render(context)`.
|
|
190
|
+
|
|
191
|
+
Public registry operations:
|
|
192
|
+
|
|
193
|
+
```js
|
|
194
|
+
registry.register(name, definition)
|
|
195
|
+
registry.get(name)
|
|
196
|
+
registry.has(name)
|
|
197
|
+
registry.names()
|
|
198
|
+
registry.describe()
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
Built-ins are registered in `src/types/register-builtins.js` during module
|
|
202
|
+
initialization.
|
|
203
|
+
|
|
204
|
+
When adding a built-in type:
|
|
205
|
+
|
|
206
|
+
1. create `src/types/<name>.js`;
|
|
207
|
+
2. provide description, defaults, layers, and optional configure hook;
|
|
208
|
+
3. register it in `register-builtins.js`;
|
|
209
|
+
4. expose it through `builtInTypes`;
|
|
210
|
+
5. ensure all public colors and dimensions remain overridable;
|
|
211
|
+
6. add type-specific tests;
|
|
212
|
+
7. update README, API and AI docs;
|
|
213
|
+
8. rebuild `dist/`.
|
|
214
|
+
|
|
215
|
+
## Type defaults
|
|
216
|
+
|
|
217
|
+
A type should express its visual identity through defaults, not custom branches in the
|
|
218
|
+
core.
|
|
219
|
+
|
|
220
|
+
Prefer:
|
|
221
|
+
|
|
222
|
+
```js
|
|
223
|
+
export const exampleGaugeType = {
|
|
224
|
+
description: '...',
|
|
225
|
+
defaults: {
|
|
226
|
+
geometry: { ... },
|
|
227
|
+
face: { ... },
|
|
228
|
+
pointer: { ... }
|
|
229
|
+
},
|
|
230
|
+
layers: [ ... ]
|
|
231
|
+
};
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
Avoid:
|
|
235
|
+
|
|
236
|
+
```js
|
|
237
|
+
if (options.type === 'example') {
|
|
238
|
+
// special behavior in the generic core
|
|
239
|
+
}
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
A new geometry family may require new pure helpers and layers, but the lifecycle core
|
|
243
|
+
should remain type-agnostic.
|
|
244
|
+
|
|
245
|
+
## Layer execution and paint order
|
|
246
|
+
|
|
247
|
+
A layer has the public shape:
|
|
248
|
+
|
|
249
|
+
```js
|
|
250
|
+
{
|
|
251
|
+
id: 'layer-name',
|
|
252
|
+
|
|
253
|
+
render(context) {
|
|
254
|
+
// append static SVG
|
|
255
|
+
|
|
256
|
+
return {
|
|
257
|
+
update(value, state) {
|
|
258
|
+
// optional dynamic work
|
|
259
|
+
},
|
|
260
|
+
|
|
261
|
+
destroy() {
|
|
262
|
+
// optional cleanup
|
|
263
|
+
}
|
|
264
|
+
};
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
```
|
|
268
|
+
|
|
269
|
+
Render context contains:
|
|
270
|
+
|
|
271
|
+
```js
|
|
272
|
+
{
|
|
273
|
+
gauge,
|
|
274
|
+
options,
|
|
275
|
+
renderer,
|
|
276
|
+
registry
|
|
277
|
+
}
|
|
278
|
+
```
|
|
279
|
+
|
|
280
|
+
Layer-array order is SVG paint order. Later groups appear above earlier groups.
|
|
281
|
+
|
|
282
|
+
Built-in radial types intentionally order:
|
|
283
|
+
|
|
284
|
+
```text
|
|
285
|
+
face
|
|
286
|
+
zones
|
|
287
|
+
ticks
|
|
288
|
+
labels
|
|
289
|
+
light
|
|
290
|
+
readout
|
|
291
|
+
pointer
|
|
292
|
+
```
|
|
293
|
+
|
|
294
|
+
so the pointer paints above the readout.
|
|
295
|
+
|
|
296
|
+
Built-in linear types place the indicator after readout for the same reason.
|
|
297
|
+
|
|
298
|
+
Do not attempt to solve SVG stacking with a numeric CSS `z-index`. Use layer order and
|
|
299
|
+
the existing pointer/indicator cap `stackOrder`.
|
|
300
|
+
|
|
301
|
+
## Static versus dynamic work
|
|
302
|
+
|
|
303
|
+
Static layer examples:
|
|
304
|
+
|
|
305
|
+
- face;
|
|
306
|
+
- zones;
|
|
307
|
+
- ticks;
|
|
308
|
+
- labels;
|
|
309
|
+
- fixed zero marker.
|
|
310
|
+
|
|
311
|
+
Dynamic layer examples:
|
|
312
|
+
|
|
313
|
+
- radial pointer;
|
|
314
|
+
- linear indicator;
|
|
315
|
+
- rolling tape slots;
|
|
316
|
+
- readout value;
|
|
317
|
+
- light state.
|
|
318
|
+
|
|
319
|
+
Static geometry should be computed once during `render()`. `update()` should mutate
|
|
320
|
+
only the smallest owned set of nodes.
|
|
321
|
+
|
|
322
|
+
Avoid rebuilding whole SVG groups in every animation frame.
|
|
323
|
+
|
|
324
|
+
## Renderer ownership
|
|
325
|
+
|
|
326
|
+
`SvgRenderer`:
|
|
327
|
+
|
|
328
|
+
- creates the generated root and SVG;
|
|
329
|
+
- creates unique IDs for definitions;
|
|
330
|
+
- owns layer groups;
|
|
331
|
+
- owns controller registration;
|
|
332
|
+
- owns a small reference map;
|
|
333
|
+
- applies content clipping;
|
|
334
|
+
- calculates and applies final viewBox;
|
|
335
|
+
- removes generated content on destruction.
|
|
336
|
+
|
|
337
|
+
Use:
|
|
338
|
+
|
|
339
|
+
```js
|
|
340
|
+
const group = renderer.group('my-layer', {
|
|
341
|
+
'aria-hidden': 'true'
|
|
342
|
+
});
|
|
343
|
+
```
|
|
344
|
+
|
|
345
|
+
instead of appending directly to the host or another application-owned node.
|
|
346
|
+
|
|
347
|
+
The renderer may apply a face clip path to groups created after the face layer. Bypass
|
|
348
|
+
of `renderer.group()` can break clipping and ownership.
|
|
349
|
+
|
|
350
|
+
## Renderer references
|
|
351
|
+
|
|
352
|
+
A layer may store generated nodes or values:
|
|
353
|
+
|
|
354
|
+
```js
|
|
355
|
+
renderer.setReference('name', value);
|
|
356
|
+
const value = renderer.getReference('name');
|
|
357
|
+
```
|
|
358
|
+
|
|
359
|
+
Use references sparingly for coordination within one generated instrument. Do not use
|
|
360
|
+
global registries for per-instance SVG nodes.
|
|
361
|
+
|
|
362
|
+
## Dynamic controller state
|
|
363
|
+
|
|
364
|
+
Controller signature:
|
|
365
|
+
|
|
366
|
+
```js
|
|
367
|
+
update(value, state)
|
|
368
|
+
```
|
|
369
|
+
|
|
370
|
+
`value` is the rendered base value after animation and precision handling.
|
|
371
|
+
|
|
372
|
+
State fields:
|
|
373
|
+
|
|
374
|
+
```js
|
|
375
|
+
{
|
|
376
|
+
gauge,
|
|
377
|
+
targetValue,
|
|
378
|
+
baseValue,
|
|
379
|
+
pointerValue,
|
|
380
|
+
animated,
|
|
381
|
+
jitterOffset
|
|
382
|
+
}
|
|
383
|
+
```
|
|
384
|
+
|
|
385
|
+
Choose intentionally:
|
|
386
|
+
|
|
387
|
+
- `targetValue`: stable application intent;
|
|
388
|
+
- `value` or `baseValue`: animated displayed semantics;
|
|
389
|
+
- `pointerValue`: animated value plus visual jitter.
|
|
390
|
+
|
|
391
|
+
Readouts and accessibility should not use `pointerValue`. A realistic moving needle or
|
|
392
|
+
tape should.
|
|
393
|
+
|
|
394
|
+
The shared light exposes this decision as `light.trigger.source`.
|
|
395
|
+
|
|
396
|
+
## Gauge lifecycle
|
|
397
|
+
|
|
398
|
+
Construction:
|
|
399
|
+
|
|
400
|
+
1. resolve target;
|
|
401
|
+
2. resolve user options;
|
|
402
|
+
3. create renderer;
|
|
403
|
+
4. establish initial target/base/display/pointer state;
|
|
404
|
+
5. render static layers;
|
|
405
|
+
6. install lifecycle observers;
|
|
406
|
+
7. perform startup animation if enabled.
|
|
407
|
+
|
|
408
|
+
### `setValue()`
|
|
409
|
+
|
|
410
|
+
- normalizes according to overflow;
|
|
411
|
+
- updates target and resolved value;
|
|
412
|
+
- updates immediately or creates one animation;
|
|
413
|
+
- emits `gaugeit:change`;
|
|
414
|
+
- schedules the frame loop only when needed.
|
|
415
|
+
|
|
416
|
+
### Frame loop
|
|
417
|
+
|
|
418
|
+
One `requestAnimationFrame` loop per active gauge:
|
|
419
|
+
|
|
420
|
+
1. advance base animation;
|
|
421
|
+
2. choose a new jitter target at configured frequency;
|
|
422
|
+
3. smooth jitter offset;
|
|
423
|
+
4. calculate displayed and pointer-only values;
|
|
424
|
+
5. update dynamic controllers;
|
|
425
|
+
6. update accessibility and display events;
|
|
426
|
+
7. stop when no animation or jitter remains.
|
|
427
|
+
|
|
428
|
+
### Pause and lifecycle suspension
|
|
429
|
+
|
|
430
|
+
Manual `pause()` and `resume()` preserve elapsed animation time.
|
|
431
|
+
|
|
432
|
+
Page visibility and intersection observers suspend work when configured. Option
|
|
433
|
+
replacement reconfigures observers.
|
|
434
|
+
|
|
435
|
+
### Destruction
|
|
436
|
+
|
|
437
|
+
`destroy()` must:
|
|
438
|
+
|
|
439
|
+
- cancel animation frame;
|
|
440
|
+
- clear animation;
|
|
441
|
+
- disconnect observers;
|
|
442
|
+
- remove listeners;
|
|
443
|
+
- call controller cleanup;
|
|
444
|
+
- remove generated DOM;
|
|
445
|
+
- remove managed-instance mapping;
|
|
446
|
+
- emit destruction event.
|
|
447
|
+
|
|
448
|
+
Any new layer timer, observer, or listener must be released by its controller
|
|
449
|
+
`destroy()`.
|
|
450
|
+
|
|
451
|
+
## Animation model
|
|
452
|
+
|
|
453
|
+
Application value and visual realism are separate:
|
|
454
|
+
|
|
455
|
+
```text
|
|
456
|
+
target value
|
|
457
|
+
-> base animation
|
|
458
|
+
-> displayed value
|
|
459
|
+
-> optional jitter offset
|
|
460
|
+
-> pointer value
|
|
461
|
+
```
|
|
462
|
+
|
|
463
|
+
This ensures:
|
|
464
|
+
|
|
465
|
+
- `getValue()` is stable;
|
|
466
|
+
- `getDisplayedValue()` may animate but never jitters;
|
|
467
|
+
- readout and ARIA values never jitter;
|
|
468
|
+
- meaningful events never jitter;
|
|
469
|
+
- moving artwork may jitter.
|
|
470
|
+
|
|
471
|
+
Do not merge jitter into the application value.
|
|
472
|
+
|
|
473
|
+
## Easing
|
|
474
|
+
|
|
475
|
+
Named easing resolution belongs in `src/core/easing.js`. Public `easingNames` expose
|
|
476
|
+
supported names. A caller may also provide a callback.
|
|
477
|
+
|
|
478
|
+
When adding an easing:
|
|
479
|
+
|
|
480
|
+
- keep input/output semantics compatible with progress `0 ... 1`;
|
|
481
|
+
- update tests and documentation;
|
|
482
|
+
- do not add an animation dependency.
|
|
483
|
+
|
|
484
|
+
## Radial geometry
|
|
485
|
+
|
|
486
|
+
Primary helpers in `src/geometry/scale.js` include:
|
|
487
|
+
|
|
488
|
+
```text
|
|
489
|
+
degreesToRadians
|
|
490
|
+
polarPoint
|
|
491
|
+
gaugeSweep
|
|
492
|
+
centeredArcAngles
|
|
493
|
+
valueToAngle
|
|
494
|
+
angleToValue
|
|
495
|
+
arcPath
|
|
496
|
+
taperedArcPath
|
|
497
|
+
niceInterval
|
|
498
|
+
buildScaleValues
|
|
499
|
+
buildMinorValues
|
|
500
|
+
resolveZoneSegments
|
|
501
|
+
findZoneForValue
|
|
502
|
+
```
|
|
503
|
+
|
|
504
|
+
Important invariants:
|
|
505
|
+
|
|
506
|
+
- clockwise and counter-clockwise sweeps work;
|
|
507
|
+
- sweep is limited to one full revolution;
|
|
508
|
+
- complete circles use two SVG arc commands;
|
|
509
|
+
- closed scales may deduplicate one endpoint;
|
|
510
|
+
- inversion changes mapping, not numeric zone definitions;
|
|
511
|
+
- later overlapping zones win;
|
|
512
|
+
- transparent intervals remain true gaps;
|
|
513
|
+
- tapered zones preserve width progression across split intervals.
|
|
514
|
+
|
|
515
|
+
Keep pure helpers DOM-independent.
|
|
516
|
+
|
|
517
|
+
## Linear geometry
|
|
518
|
+
|
|
519
|
+
Primary helpers in `src/geometry/linear.js` include:
|
|
520
|
+
|
|
521
|
+
```text
|
|
522
|
+
linearYToSvg
|
|
523
|
+
linearAxis
|
|
524
|
+
valueToLinearRatio
|
|
525
|
+
valueToLinearPoint
|
|
526
|
+
linearPointToValue
|
|
527
|
+
offsetLinearPoint
|
|
528
|
+
linearNormalOffset
|
|
529
|
+
linearIndicatorNormalOffset
|
|
530
|
+
linearNormalSpan
|
|
531
|
+
```
|
|
532
|
+
|
|
533
|
+
Public Y semantics are positive-up around `linear.originY`.
|
|
534
|
+
|
|
535
|
+
The two-point axis supports horizontal, vertical, and diagonal instruments. Do not
|
|
536
|
+
assume a horizontal axis in new layers.
|
|
537
|
+
|
|
538
|
+
Use tangent and normal vectors from `linearAxis()` instead of special-casing
|
|
539
|
+
orientation.
|
|
540
|
+
|
|
541
|
+
## Rolling-tape geometry
|
|
542
|
+
|
|
543
|
+
Primary helpers in `src/geometry/tape.js` include:
|
|
544
|
+
|
|
545
|
+
```text
|
|
546
|
+
tapeWindowBox
|
|
547
|
+
resolveTapeInterval
|
|
548
|
+
tapeMinorStep
|
|
549
|
+
tapeMinorSpacing
|
|
550
|
+
tapeValueOffset
|
|
551
|
+
```
|
|
552
|
+
|
|
553
|
+
The rolling-tape layer uses a bounded recyclable slot set around the current value.
|
|
554
|
+
Never render one node per possible numeric value.
|
|
555
|
+
|
|
556
|
+
The fixed indicator remains stationary. The strip and labels move.
|
|
557
|
+
|
|
558
|
+
## Light geometry and timing
|
|
559
|
+
|
|
560
|
+
Pure helpers in `src/geometry/light.js` resolve:
|
|
561
|
+
|
|
562
|
+
- logical position;
|
|
563
|
+
- manual, below, above, and between trigger state.
|
|
564
|
+
|
|
565
|
+
The layer owns:
|
|
566
|
+
|
|
567
|
+
- palettes;
|
|
568
|
+
- gradients and blur;
|
|
569
|
+
- physical unlit lens;
|
|
570
|
+
- active lens;
|
|
571
|
+
- halo;
|
|
572
|
+
- blink/pulse CSS state;
|
|
573
|
+
- randomized flicker timer;
|
|
574
|
+
- controller cleanup.
|
|
575
|
+
|
|
576
|
+
Version 0.1.1 separates:
|
|
577
|
+
|
|
578
|
+
- physical `radius`;
|
|
579
|
+
- halo `glowRadius`;
|
|
580
|
+
- lens `opacity`;
|
|
581
|
+
- halo `glowOpacity`;
|
|
582
|
+
- halo `glowSharpness`.
|
|
583
|
+
|
|
584
|
+
Bounds must reserve the rendered halo plus blur. If rendering math changes, update
|
|
585
|
+
`includeLight()` in `src/geometry/bounds.js` and tests.
|
|
586
|
+
|
|
587
|
+
Blink wins over pulse. Flicker may overlay either. All moving effects respect reduced
|
|
588
|
+
motion.
|
|
589
|
+
|
|
590
|
+
## Intrinsic bounds
|
|
591
|
+
|
|
592
|
+
Bounds are a correctness feature, not cosmetic metadata.
|
|
593
|
+
|
|
594
|
+
`calculateGaugeBounds()` conservatively includes:
|
|
595
|
+
|
|
596
|
+
- configured logical geometry when requested;
|
|
597
|
+
- face and shadow;
|
|
598
|
+
- track and zones;
|
|
599
|
+
- ticks;
|
|
600
|
+
- labels;
|
|
601
|
+
- pointer or indicator travel;
|
|
602
|
+
- zero marker;
|
|
603
|
+
- rolling-tape window;
|
|
604
|
+
- readout text estimates;
|
|
605
|
+
- light hardware, halo, and blur.
|
|
606
|
+
|
|
607
|
+
The renderer may union deterministic bounds with `getBBox()` when available.
|
|
608
|
+
|
|
609
|
+
When adding a visual extent:
|
|
610
|
+
|
|
611
|
+
1. identify every position it may occupy;
|
|
612
|
+
2. include stroke width, blur, cap, shadow, and animation variation;
|
|
613
|
+
3. update deterministic bounds;
|
|
614
|
+
4. test finite responsive layout;
|
|
615
|
+
5. verify no clipping in intrinsic and contain modes.
|
|
616
|
+
|
|
617
|
+
Do not rely solely on browser `getBBox()` because Node tests and some environments do
|
|
618
|
+
not provide it.
|
|
619
|
+
|
|
620
|
+
## Face clipping
|
|
621
|
+
|
|
622
|
+
A face with `clipContent: true` defines a reusable inner-bezel clip path. Subsequent
|
|
623
|
+
groups inherit it through the renderer.
|
|
624
|
+
|
|
625
|
+
Content-fitted faces calculate their size from conservative content bounds before the
|
|
626
|
+
clip is applied.
|
|
627
|
+
|
|
628
|
+
When adding a new custom layer to a clipped type:
|
|
629
|
+
|
|
630
|
+
- create it with `renderer.group()`;
|
|
631
|
+
- place it after the face layer;
|
|
632
|
+
- do not let intentionally clipped geometry inflate document layout beyond the face.
|
|
633
|
+
|
|
634
|
+
## Accessibility
|
|
635
|
+
|
|
636
|
+
The generated root is a meter:
|
|
637
|
+
|
|
638
|
+
```text
|
|
639
|
+
role="meter"
|
|
640
|
+
aria-label
|
|
641
|
+
aria-valuemin
|
|
642
|
+
aria-valuemax
|
|
643
|
+
aria-valuenow
|
|
644
|
+
aria-valuetext, when configured
|
|
645
|
+
```
|
|
646
|
+
|
|
647
|
+
The SVG also receives title and optional description nodes.
|
|
648
|
+
|
|
649
|
+
New meaningful visual state must be represented by existing value semantics or an
|
|
650
|
+
additional accessible description. Decorative layers should be `aria-hidden`.
|
|
651
|
+
|
|
652
|
+
Do not use visual jitter, flicker, or animation as the only carrier of information.
|
|
653
|
+
|
|
654
|
+
## DOM events
|
|
655
|
+
|
|
656
|
+
Events emitted from the host:
|
|
657
|
+
|
|
658
|
+
```text
|
|
659
|
+
gaugeit:render
|
|
660
|
+
gaugeit:change
|
|
661
|
+
gaugeit:displaychange
|
|
662
|
+
gaugeit:animationstart
|
|
663
|
+
gaugeit:animationend
|
|
664
|
+
gaugeit:settled
|
|
665
|
+
gaugeit:typechange
|
|
666
|
+
gaugeit:pause
|
|
667
|
+
gaugeit:resume
|
|
668
|
+
gaugeit:destroy
|
|
669
|
+
```
|
|
670
|
+
|
|
671
|
+
Keep event names namespaced. When changing detail payloads, consider compatibility and
|
|
672
|
+
update declarations/docs/tests where applicable.
|
|
673
|
+
|
|
674
|
+
## Auto mounting and managed instances
|
|
675
|
+
|
|
676
|
+
`createGauge()` and `autoMount()` use managed instance ownership. A new managed gauge
|
|
677
|
+
on the same host destroys the old one. Repeated auto-mounting returns the existing
|
|
678
|
+
instance.
|
|
679
|
+
|
|
680
|
+
Keep the WeakMap lifecycle safe:
|
|
681
|
+
|
|
682
|
+
- a destroyed instance must remove itself;
|
|
683
|
+
- an old replaced instance must not remove a newer mapping;
|
|
684
|
+
- custom element disconnection destroys its instance.
|
|
685
|
+
|
|
686
|
+
## React adapter boundary
|
|
687
|
+
|
|
688
|
+
The React adapter:
|
|
689
|
+
|
|
690
|
+
- imports the ESM distribution;
|
|
691
|
+
- creates one gauge on mount;
|
|
692
|
+
- replaces options when prop identity changes;
|
|
693
|
+
- applies explicit value changes separately;
|
|
694
|
+
- forwards the live instance;
|
|
695
|
+
- destroys on unmount.
|
|
696
|
+
|
|
697
|
+
The core must never import React.
|
|
698
|
+
|
|
699
|
+
When changing adapter behavior:
|
|
700
|
+
|
|
701
|
+
- preserve browser-ready ESM output;
|
|
702
|
+
- update `adapters/react/Gaugeit.d.ts`;
|
|
703
|
+
- test controlled values and forwarded ref;
|
|
704
|
+
- avoid stale-instance cleanup races.
|
|
705
|
+
|
|
706
|
+
## Composer boundary
|
|
707
|
+
|
|
708
|
+
The Composer package distributes prebuilt browser assets and one PHP command-line
|
|
709
|
+
installer.
|
|
710
|
+
|
|
711
|
+
The installer:
|
|
712
|
+
|
|
713
|
+
- supports default, standalone, and all modes;
|
|
714
|
+
- creates destination directories;
|
|
715
|
+
- handles spaces in paths;
|
|
716
|
+
- replaces assets atomically through temporary files;
|
|
717
|
+
- cleans only known assets;
|
|
718
|
+
- preserves unrelated files;
|
|
719
|
+
- returns meaningful exit codes.
|
|
720
|
+
|
|
721
|
+
Do not add automatic public-directory writes to dependency installation.
|
|
722
|
+
|
|
723
|
+
## Adding a new option
|
|
724
|
+
|
|
725
|
+
Use this checklist:
|
|
726
|
+
|
|
727
|
+
1. Add the base default in `src/core/defaults.js` unless it is type-only.
|
|
728
|
+
2. Add validation and normalization in `src/core/options.js`.
|
|
729
|
+
3. Add TypeScript declaration in `src/index.d.ts`.
|
|
730
|
+
4. Consume the resolved value in the correct layer, geometry, renderer, or core.
|
|
731
|
+
5. Update bounds if visual extents change.
|
|
732
|
+
6. Update CSS if the option controls styling.
|
|
733
|
+
7. Add focused option tests.
|
|
734
|
+
8. Add rendering/lifecycle tests.
|
|
735
|
+
9. Update `docs/api.md`, README examples, and `docs/ai/options-reference.md`.
|
|
736
|
+
10. Rebuild all distributions.
|
|
737
|
+
11. Run `npm run check`.
|
|
738
|
+
12. Verify clean reproducibility.
|
|
739
|
+
|
|
740
|
+
For compatibility, use explicit aliases only when preserving an established public
|
|
741
|
+
contract. Do not create undocumented aliases for convenience.
|
|
742
|
+
|
|
743
|
+
## Adding a new layer
|
|
744
|
+
|
|
745
|
+
1. Decide whether the layer is static or dynamic.
|
|
746
|
+
2. Create `src/layers/<name>.js`.
|
|
747
|
+
3. Use `renderer.group()`.
|
|
748
|
+
4. Use `svgElement()` or `createElementNS`; never `innerHTML`.
|
|
749
|
+
5. Return a controller only if dynamic state exists.
|
|
750
|
+
6. Clean all owned resources in controller `destroy()`.
|
|
751
|
+
7. Add pure geometry helpers if calculations can be DOM-independent.
|
|
752
|
+
8. Add bounds support.
|
|
753
|
+
9. Export through `src/index.js` if intended for custom types.
|
|
754
|
+
10. Add declarations when public.
|
|
755
|
+
11. Insert into type arrays at the intended paint position.
|
|
756
|
+
12. Add unit and DOM tests.
|
|
757
|
+
13. Document usage.
|
|
758
|
+
|
|
759
|
+
## Adding a new gauge type
|
|
760
|
+
|
|
761
|
+
1. Reuse an existing geometry family if possible.
|
|
762
|
+
2. Express visual identity in defaults.
|
|
763
|
+
3. Add a `configure()` hook only for derived fallback geometry.
|
|
764
|
+
4. Select layers in exact paint order.
|
|
765
|
+
5. Include the shared light layer if normal annunciator support is desired.
|
|
766
|
+
6. Keep all colors and principal dimensions overridable.
|
|
767
|
+
7. Register and expose the type.
|
|
768
|
+
8. Test default rendering, option override, finite bounds, and distribution behavior.
|
|
769
|
+
9. Add screenshot/example/documentation.
|
|
770
|
+
10. Rebuild and validate.
|
|
771
|
+
|
|
772
|
+
## TypeScript declarations
|
|
773
|
+
|
|
774
|
+
`src/index.d.ts` is canonical for the core package API.
|
|
775
|
+
`adapters/react/Gaugeit.d.ts` is canonical for React props and the forwarded ref.
|
|
776
|
+
|
|
777
|
+
Update `src/index.d.ts` when changing:
|
|
778
|
+
|
|
779
|
+
- option keys;
|
|
780
|
+
- accepted enum values;
|
|
781
|
+
- public methods;
|
|
782
|
+
- event-facing types if added;
|
|
783
|
+
- layer contexts;
|
|
784
|
+
- geometry exports;
|
|
785
|
+
- registry definitions.
|
|
786
|
+
|
|
787
|
+
Update `adapters/react/Gaugeit.d.ts` when changing React props or the forwarded ref
|
|
788
|
+
type.
|
|
789
|
+
|
|
790
|
+
Run:
|
|
791
|
+
|
|
792
|
+
```bash
|
|
793
|
+
npm run typecheck
|
|
794
|
+
```
|
|
795
|
+
|
|
796
|
+
The build copies declarations into `dist/gaugeit.d.ts`. Do not edit that copy.
|
|
797
|
+
|
|
798
|
+
## Test selection
|
|
799
|
+
|
|
800
|
+
Use focused tests while iterating.
|
|
801
|
+
|
|
802
|
+
| Change | Likely tests |
|
|
803
|
+
| --- | --- |
|
|
804
|
+
| defaults or normalization | `tests/options.test.js` |
|
|
805
|
+
| radial geometry | `tests/geometry.test.js`, `tests/zones.test.js` |
|
|
806
|
+
| linear behavior | `tests/linear.test.js`, `tests/advanced-types.test.js` |
|
|
807
|
+
| light behavior | `tests/light.test.js`, `tests/advanced-types.test.js` |
|
|
808
|
+
| lifecycle | `tests/lifecycle.test.js` |
|
|
809
|
+
| registry/type exposure | `tests/registry.test.js` |
|
|
810
|
+
| CSS hooks | `tests/css.test.js` |
|
|
811
|
+
| output inventory/build | `tests/distribution.test.js` |
|
|
812
|
+
| npm/Composer metadata | `tests/package-metadata.test.js` |
|
|
813
|
+
| React adapter | `tests/react-adapter.test.js` |
|
|
814
|
+
| examples | `tests/example-page.test.js`, `tests/framework-examples.test.js` |
|
|
815
|
+
| repository rules | `tests/repository-hygiene.test.js` |
|
|
816
|
+
|
|
817
|
+
The main Node test command includes `tests/*.test.js` with concurrency one:
|
|
818
|
+
|
|
819
|
+
```bash
|
|
820
|
+
npm test
|
|
821
|
+
```
|
|
822
|
+
|
|
823
|
+
DOM smoke:
|
|
824
|
+
|
|
825
|
+
```bash
|
|
826
|
+
npm run test:browser
|
|
827
|
+
```
|
|
828
|
+
|
|
829
|
+
Optional real Chromium smoke:
|
|
830
|
+
|
|
831
|
+
```bash
|
|
832
|
+
npm run test:chromium
|
|
833
|
+
```
|
|
834
|
+
|
|
835
|
+
## Build output
|
|
836
|
+
|
|
837
|
+
Run:
|
|
838
|
+
|
|
839
|
+
```bash
|
|
840
|
+
npm run clean
|
|
841
|
+
npm run build
|
|
842
|
+
```
|
|
843
|
+
|
|
844
|
+
or use the full:
|
|
845
|
+
|
|
846
|
+
```bash
|
|
847
|
+
npm run check
|
|
848
|
+
```
|
|
849
|
+
|
|
850
|
+
The build must remain deterministic:
|
|
851
|
+
|
|
852
|
+
- stable file ordering;
|
|
853
|
+
- no timestamps in generated content;
|
|
854
|
+
- no random output;
|
|
855
|
+
- normalized LF inputs;
|
|
856
|
+
- no absolute local paths;
|
|
857
|
+
- same source-map contents on Linux and Windows;
|
|
858
|
+
- manifest sizes matching files.
|
|
859
|
+
|
|
860
|
+
CI performs:
|
|
861
|
+
|
|
862
|
+
```bash
|
|
863
|
+
npm ci
|
|
864
|
+
npm run check
|
|
865
|
+
git diff --exit-code -- dist package-lock.json
|
|
866
|
+
```
|
|
867
|
+
|
|
868
|
+
A build that passes locally but changes generated source maps on Linux is not complete.
|
|
869
|
+
|
|
870
|
+
## Documentation changes
|
|
871
|
+
|
|
872
|
+
Update only the smallest set of authoritative documents, but do not leave contradictory
|
|
873
|
+
copies.
|
|
874
|
+
|
|
875
|
+
When changing public options:
|
|
876
|
+
|
|
877
|
+
```text
|
|
878
|
+
README.md
|
|
879
|
+
docs/api.md
|
|
880
|
+
src/index.d.ts
|
|
881
|
+
docs/ai/options-reference.md
|
|
882
|
+
relevant recipes and troubleshooting
|
|
883
|
+
```
|
|
884
|
+
|
|
885
|
+
When changing architecture:
|
|
886
|
+
|
|
887
|
+
```text
|
|
888
|
+
docs/architecture.md
|
|
889
|
+
docs/creating-gauge-types.md
|
|
890
|
+
docs/ai/contributor-guide.md
|
|
891
|
+
AGENTS.md, if repository rules changed
|
|
892
|
+
```
|
|
893
|
+
|
|
894
|
+
`docs/ai/ai-full.md` is the single-file context bundle and must be regenerated or
|
|
895
|
+
updated whenever its component AI guides change.
|
|
896
|
+
|
|
897
|
+
## Release-aware changes
|
|
898
|
+
|
|
899
|
+
Do not rewrite an already published npm version. A released version is immutable.
|
|
900
|
+
|
|
901
|
+
For a new release:
|
|
902
|
+
|
|
903
|
+
- update package version and public version constant consistently;
|
|
904
|
+
- update changelog;
|
|
905
|
+
- update exact CDN examples;
|
|
906
|
+
- rebuild `dist/`;
|
|
907
|
+
- run all validation;
|
|
908
|
+
- create and push the Git tag only after green CI;
|
|
909
|
+
- publish npm;
|
|
910
|
+
- update Packagist from the Git tag.
|
|
911
|
+
|
|
912
|
+
Release mechanics remain explicit maintainer actions. CI validates but does not publish.
|
|
913
|
+
|
|
914
|
+
## Definition of done for contributors
|
|
915
|
+
|
|
916
|
+
A coding agent may say a task is complete only when:
|
|
917
|
+
|
|
918
|
+
- behavior is implemented in canonical source;
|
|
919
|
+
- public compatibility is preserved or intentionally documented;
|
|
920
|
+
- focused tests and regression tests pass;
|
|
921
|
+
- full `npm run check` passes;
|
|
922
|
+
- declarations match runtime;
|
|
923
|
+
- docs and examples match behavior;
|
|
924
|
+
- visual bounds cover new extents;
|
|
925
|
+
- cleanup covers all new resources;
|
|
926
|
+
- generated distribution is rebuilt;
|
|
927
|
+
- reproducibility diff is clean;
|
|
928
|
+
- no accidental files or unrelated edits are present.
|