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.
@@ -0,0 +1,1024 @@
1
+ # Gaugeit.js troubleshooting guide for AI agents
2
+
3
+ This guide diagnoses common Gaugeit.js 0.1.1 integration, rendering, lifecycle,
4
+ packaging, and contribution failures. Start from the observed symptom. Do not guess at
5
+ new API names to work around a configuration mistake.
6
+
7
+ ## Gauge does not appear
8
+
9
+ ### Check that the host exists
10
+
11
+ This fails when creation runs before the element exists:
12
+
13
+ ```js
14
+ Gaugeit.createGauge('#gauge', {
15
+ value: 50
16
+ });
17
+ ```
18
+
19
+ Verify:
20
+
21
+ ```js
22
+ const host = document.querySelector('#gauge');
23
+
24
+ if (!host) {
25
+ throw new Error('Gauge host was not found.');
26
+ }
27
+
28
+ const gauge = Gaugeit.createGauge(host, {
29
+ value: 50
30
+ });
31
+ ```
32
+
33
+ Place the script after the host, use `defer`, use a module script, or wait for
34
+ `DOMContentLoaded`.
35
+
36
+ ### Check the selector
37
+
38
+ `createGauge()` accepts an element or valid CSS selector. A selector typo throws a
39
+ target-not-found error. Do not pass a React component, jQuery wrapper, NodeList, or
40
+ plain object.
41
+
42
+ ### Check host layout
43
+
44
+ The SVG is responsive to the host. Verify that the host and its ancestors are not
45
+ collapsed, hidden by CSS, or assigned zero width/height.
46
+
47
+ For contain mode, provide both dimensions:
48
+
49
+ ```css
50
+ #gauge {
51
+ width: 320px;
52
+ height: 220px;
53
+ }
54
+ ```
55
+
56
+ ```js
57
+ layout: {
58
+ mode: 'contain'
59
+ }
60
+ ```
61
+
62
+ ### Check CSS
63
+
64
+ UMD, ESM, CommonJS, React, custom element, and Composer two-file usage require Gaugeit
65
+ CSS.
66
+
67
+ Browser:
68
+
69
+ ```html
70
+ <link rel="stylesheet" href="./dist/gaugeit.min.css">
71
+ ```
72
+
73
+ npm:
74
+
75
+ ```js
76
+ import 'gaugeit.js/css';
77
+ ```
78
+
79
+ Standalone already injects CSS. Missing CSS may produce incorrect sizing or animation
80
+ behavior even when SVG nodes exist.
81
+
82
+ ## `Gaugeit is not defined`
83
+
84
+ Possible causes:
85
+
86
+ - UMD/standalone script failed to load;
87
+ - application script executes before the distribution;
88
+ - wrong global spelling;
89
+ - ESM file was loaded as a classic script;
90
+ - a CDN URL is wrong.
91
+
92
+ Correct UMD order:
93
+
94
+ ```html
95
+ <script src="./dist/gaugeit.umd.min.js"></script>
96
+ <script>
97
+ Gaugeit.createGauge('#gauge', {
98
+ value: 50
99
+ });
100
+ </script>
101
+ ```
102
+
103
+ The global is exactly:
104
+
105
+ ```text
106
+ Gaugeit
107
+ ```
108
+
109
+ Not:
110
+
111
+ ```text
112
+ GaugeIt
113
+ GaugeIT
114
+ gaugeit
115
+ ```
116
+
117
+ ## `Gaugeit` versus `GaugeIt` filename or symbol confusion
118
+
119
+ Project files and exports intentionally use:
120
+
121
+ ```text
122
+ Gaugeit
123
+ ```
124
+
125
+ Examples:
126
+
127
+ ```text
128
+ adapters/react/Gaugeit.js
129
+ import Gaugeit from 'gaugeit.js/react'
130
+ window.Gaugeit
131
+ ```
132
+
133
+ Windows may hide case-only filename mistakes that fail on Linux CI. Preserve exact
134
+ case in imports and package exports.
135
+
136
+ ## ESM import fails in a browser
137
+
138
+ This bare import does not work in a normal browser without a resolver:
139
+
140
+ ```js
141
+ import { createGauge } from 'gaugeit.js';
142
+ ```
143
+
144
+ Use one of:
145
+
146
+ - a bundler;
147
+ - an import map;
148
+ - a server resolver;
149
+ - an explicit browser path:
150
+
151
+ ```js
152
+ import { createGauge } from './dist/gaugeit.esm.js';
153
+ ```
154
+
155
+ Load the file as a module:
156
+
157
+ ```html
158
+ <script type="module" src="./app.js"></script>
159
+ ```
160
+
161
+ Do not load ESM as a classic script.
162
+
163
+ ## CommonJS works but gauge is unstyled
164
+
165
+ The CommonJS entry resolves JavaScript only:
166
+
167
+ ```js
168
+ const { createGauge } = require('gaugeit.js');
169
+ ```
170
+
171
+ Add the CSS to the application bundle or page. The `require()` call does not inject it.
172
+
173
+ ## Standalone and separate CSS are both loaded
174
+
175
+ This is usually unnecessary. Standalone injects the canonical stylesheet. Loading
176
+ separate Gaugeit CSS as well can make debugging overrides harder.
177
+
178
+ Choose either:
179
+
180
+ ```text
181
+ UMD + CSS
182
+ ```
183
+
184
+ or:
185
+
186
+ ```text
187
+ standalone JavaScript
188
+ ```
189
+
190
+ unless duplicate inclusion is intentional and understood.
191
+
192
+ ## CDN installation changes unexpectedly
193
+
194
+ Use an exact version:
195
+
196
+ ```text
197
+ gaugeit.js@0.1.1
198
+ ```
199
+
200
+ Do not use an unversioned URL in production. Verify the complete file path:
201
+
202
+ ```text
203
+ dist/gaugeit.umd.min.js
204
+ dist/gaugeit.min.css
205
+ dist/gaugeit.standalone.min.js
206
+ ```
207
+
208
+ CDN propagation may take a short time after npm publication. Check the npm package
209
+ first when a newly published CDN file is missing.
210
+
211
+ ## npm import path is rejected
212
+
213
+ Use package exports:
214
+
215
+ ```js
216
+ import { createGauge } from 'gaugeit.js';
217
+ import 'gaugeit.js/css';
218
+ import Gaugeit from 'gaugeit.js/react';
219
+ import { defineGaugeitElement } from 'gaugeit.js/web-component';
220
+ ```
221
+
222
+ Do not import private repository paths such as:
223
+
224
+ ```js
225
+ import { createGauge } from 'gaugeit.js/src/index.js';
226
+ ```
227
+
228
+ Package export maps intentionally limit supported subpaths.
229
+
230
+ ## React gauge keeps rebuilding
231
+
232
+ The React adapter replaces the complete options object when its identity changes.
233
+ This creates a new object every render:
234
+
235
+ ```jsx
236
+ <Gaugeit options={{ type: 'arc', min: 0, max: 100 }} />
237
+ ```
238
+
239
+ Prefer:
240
+
241
+ ```jsx
242
+ const options = useMemo(() => ({
243
+ type: 'arc',
244
+ min: 0,
245
+ max: 100
246
+ }), []);
247
+
248
+ return <Gaugeit options={options} />;
249
+ ```
250
+
251
+ A changing options object is valid when the configuration truly changes. Stabilization
252
+ is a performance and lifecycle decision, not a requirement for correctness.
253
+
254
+ ## React value does not match `options.value`
255
+
256
+ An explicit `value` prop is authoritative:
257
+
258
+ ```jsx
259
+ <Gaugeit
260
+ value={72}
261
+ options={{
262
+ value: 10
263
+ }}
264
+ />
265
+ ```
266
+
267
+ The displayed target is 72. Avoid duplicating value in both places.
268
+
269
+ ## React ref is null
270
+
271
+ The forwarded ref becomes the live instance after mount. Do not read it during initial
272
+ render. Use it from effects or event handlers:
273
+
274
+ ```jsx
275
+ const gaugeRef = useRef(null);
276
+
277
+ function update() {
278
+ gaugeRef.current?.setValue(80);
279
+ }
280
+ ```
281
+
282
+ ## Gauge updates inefficiently
283
+
284
+ For numeric samples, use:
285
+
286
+ ```js
287
+ gauge.setValue(nextValue);
288
+ ```
289
+
290
+ Do not repeatedly do:
291
+
292
+ ```js
293
+ gauge.updateOptions({
294
+ value: nextValue
295
+ });
296
+ ```
297
+
298
+ unless static configuration also needs rebuilding.
299
+
300
+ ## `updateOptions()` leaves old styling behind
301
+
302
+ `updateOptions()` deep-merges a patch. Omitted keys remain from earlier user options.
303
+
304
+ Use `replaceOptions()` for a complete declarative mode switch:
305
+
306
+ ```js
307
+ gauge.replaceOptions({
308
+ type: 'classic',
309
+ value: 50
310
+ });
311
+ ```
312
+
313
+ ## Zone list does not append
314
+
315
+ Arrays are replaced, not concatenated:
316
+
317
+ ```js
318
+ gauge.updateOptions({
319
+ zones: newZones
320
+ });
321
+ ```
322
+
323
+ replaces the previous list. Build the complete desired array in application code.
324
+
325
+ ## Transparent zone still shows a track
326
+
327
+ Check:
328
+
329
+ ```js
330
+ track: {
331
+ showUnderZones: false
332
+ }
333
+ ```
334
+
335
+ A transparent or missing zone color produces a true gap only when the base track is not
336
+ painted under zones.
337
+
338
+ Accepted gap colors include:
339
+
340
+ ```text
341
+ transparent
342
+ none
343
+ empty or missing color
344
+ ```
345
+
346
+ ## Overlapping zone color is unexpected
347
+
348
+ Later matching zones win. Reorder the zone list or make ranges non-overlapping.
349
+
350
+ This also affects color-by-zone pointer, indicator, and tape behavior.
351
+
352
+ ## Pointer moves in the wrong direction
353
+
354
+ Use:
355
+
356
+ ```js
357
+ invert: true
358
+ ```
359
+
360
+ Do not reverse zones manually. Inversion changes visual mapping while numeric zones
361
+ stay attached to their values.
362
+
363
+ Verify the configured `startAngle` and `endAngle` if a custom radial sweep is also
364
+ present.
365
+
366
+ ## Linear scale moves vertically in the wrong direction
367
+
368
+ Public linear Y coordinates increase upward from `linear.originY`.
369
+
370
+ Correct mental model:
371
+
372
+ ```text
373
+ positive public Y -> visually upward
374
+ negative public Y -> visually downward
375
+ ```
376
+
377
+ Do not use raw SVG downward-positive assumptions in `startY`, `endY`,
378
+ `labelOffset`, `zoneOffset`, readout Y, or `centerOffset`.
379
+
380
+ ## Linear axis disappears or has invalid geometry
381
+
382
+ The start and end points must differ. Runtime repairs a zero-length axis to one unit,
383
+ but the resulting visual is unlikely to match intent.
384
+
385
+ Check:
386
+
387
+ ```js
388
+ linear: {
389
+ startX,
390
+ startY,
391
+ endX,
392
+ endY
393
+ }
394
+ ```
395
+
396
+ ## Center-zero reference is not centered
397
+
398
+ Verify:
399
+
400
+ - range contains `centerZero.zeroValue`;
401
+ - `symmetric: true` is enabled when equal magnitude is required;
402
+ - selected type is `center-zero` or `classic-linear-zero`;
403
+ - marker visibility and coordinates were not overridden incorrectly.
404
+
405
+ Example:
406
+
407
+ ```js
408
+ {
409
+ type: 'center-zero',
410
+ min: -100,
411
+ max: 100,
412
+ centerZero: {
413
+ zeroValue: 0,
414
+ symmetric: true
415
+ }
416
+ }
417
+ ```
418
+
419
+ ## Rolling tape behaves like the wrong instrument
420
+
421
+ Use exact type:
422
+
423
+ ```js
424
+ type: 'rolling-tape'
425
+ ```
426
+
427
+ The tape has a moving strip and fixed reference line. It does not use radial pointer
428
+ options.
429
+
430
+ Adjust `tape.interval`, `minorSubdivisions`, and `majorSpacing`, not
431
+ `pointer.length`.
432
+
433
+ ## Readout is missing
434
+
435
+ This is insufficient:
436
+
437
+ ```js
438
+ readout: {
439
+ visible: true
440
+ }
441
+ ```
442
+
443
+ Enable each required child:
444
+
445
+ ```js
446
+ readout: {
447
+ visible: true,
448
+ title: {
449
+ visible: true,
450
+ text: 'PRESSURE'
451
+ },
452
+ value: {
453
+ visible: true
454
+ },
455
+ unit: {
456
+ visible: true,
457
+ text: 'bar'
458
+ }
459
+ }
460
+ ```
461
+
462
+ ## Readout automatic position is unexpected
463
+
464
+ `x: 'auto'` centers. `y: 'auto'` uses `position` and `margin`.
465
+
466
+ `offsetX` and `offsetY` refine automatic coordinates only. Numeric coordinates are
467
+ final and do not inherit automatic offsets.
468
+
469
+ Type presets may supply different fallback coordinates. Read the selected type defaults
470
+ when exact placement matters.
471
+
472
+ ## Light does not turn on
473
+
474
+ Check trigger mode.
475
+
476
+ Manual:
477
+
478
+ ```js
479
+ light: {
480
+ visible: true,
481
+ on: true,
482
+ trigger: {
483
+ mode: 'manual'
484
+ }
485
+ }
486
+ ```
487
+
488
+ Threshold:
489
+
490
+ ```js
491
+ light: {
492
+ visible: true,
493
+ trigger: {
494
+ mode: 'above',
495
+ value: 80
496
+ }
497
+ }
498
+ ```
499
+
500
+ `on` is ignored by `below`, `above`, and `between`.
501
+
502
+ Also verify `visible: true`.
503
+
504
+ ## Light does not pulse
505
+
506
+ Pulse is visible only while the light is active.
507
+
508
+ Check:
509
+
510
+ ```js
511
+ light: {
512
+ visible: true,
513
+ pulse: true,
514
+ blink: false,
515
+ trigger: {
516
+ mode: 'manual'
517
+ },
518
+ on: true
519
+ }
520
+ ```
521
+
522
+ Blink takes precedence over pulse. If both are true, the light blinks instead of
523
+ pulsing.
524
+
525
+ Reduced-motion preference suppresses motion. Test system/browser accessibility
526
+ settings before treating this as a rendering defect.
527
+
528
+ ## Light does not blink
529
+
530
+ Verify:
531
+
532
+ - active trigger;
533
+ - `blink: true`;
534
+ - `blinkInterval >= 100`;
535
+ - reduced-motion is not active.
536
+
537
+ The off half-cycle shows the physical unlit lens rather than making the whole lamp
538
+ transparent.
539
+
540
+ ## Light flicker is not visible
541
+
542
+ Verify:
543
+
544
+ ```js
545
+ flicker: true
546
+ ```
547
+
548
+ and at least one of:
549
+
550
+ ```js
551
+ flickerIntensity > 0
552
+ flickerGlowRadius > 0
553
+ ```
554
+
555
+ Flicker runs only while active and is disabled under reduced motion.
556
+
557
+ The default effect is intentionally subtle.
558
+
559
+ ## Glow size does not follow lamp size
560
+
561
+ In 0.1.1, `glowRadius` is independent:
562
+
563
+ ```js
564
+ light: {
565
+ radius: 8,
566
+ glowRadius: 24
567
+ }
568
+ ```
569
+
570
+ Set:
571
+
572
+ ```js
573
+ glowRadius: null
574
+ ```
575
+
576
+ to derive `radius * 1.82`.
577
+
578
+ Changing only `radius` does not automatically change an explicit numeric
579
+ `glowRadius`.
580
+
581
+ ## Glow is clipped
582
+
583
+ This should not happen with normalized built-in options because bounds reserve halo
584
+ and blur.
585
+
586
+ For repository changes, compare rendering math in `src/layers/light.js` with bounds in
587
+ `src/geometry/bounds.js`. A new halo extent, blur formula, or flicker variation requires
588
+ matching bounds changes and tests.
589
+
590
+ For application custom layers, add correct geometry within the instrument or create a
591
+ type that provides enough layout padding/bounds support.
592
+
593
+ ## Animation does not run
594
+
595
+ Check:
596
+
597
+ ```js
598
+ animation: {
599
+ enabled: true,
600
+ duration: 850
601
+ }
602
+ ```
603
+
604
+ Per update, do not pass:
605
+
606
+ ```js
607
+ { animate: false }
608
+ ```
609
+
610
+ Reduced-motion may suppress animation when `respectReducedMotion` is true.
611
+
612
+ No animation is visible when source and target values are identical.
613
+
614
+ ## Startup animation begins from the wrong point
615
+
616
+ Configure:
617
+
618
+ ```js
619
+ animation: {
620
+ animateOnInit: true,
621
+ startFrom: 'min'
622
+ }
623
+ ```
624
+
625
+ Allowed values:
626
+
627
+ ```text
628
+ min
629
+ max
630
+ value
631
+ numeric value
632
+ ```
633
+
634
+ `startFrom: 'value'` intentionally starts at the target and therefore has no visible
635
+ startup travel.
636
+
637
+ ## Jitter changes application data
638
+
639
+ It should not. Verify application code is reading:
640
+
641
+ ```js
642
+ gauge.getValue()
643
+ gauge.getDisplayedValue()
644
+ ```
645
+
646
+ and not parsing generated pointer transforms.
647
+
648
+ Jitter is visual-only. If readout or ARIA values jitter after a repository change, the
649
+ dynamic layer is using `state.pointerValue` in the wrong place.
650
+
651
+ ## Gauge continues work offscreen
652
+
653
+ Defaults are:
654
+
655
+ ```js
656
+ performance: {
657
+ pauseWhenHidden: true,
658
+ pauseWhenOffscreen: true
659
+ }
660
+ ```
661
+
662
+ IntersectionObserver may be unavailable in some environments. Manual `pause()` remains
663
+ available.
664
+
665
+ Repository tests should use controlled lifecycle stubs rather than assuming browser
666
+ observer availability.
667
+
668
+ ## Instance leaks after component removal
669
+
670
+ An application that creates a gauge manually must destroy it:
671
+
672
+ ```js
673
+ const gauge = Gaugeit.createGauge(host, options);
674
+
675
+ // component cleanup
676
+ gauge.destroy();
677
+ ```
678
+
679
+ The React adapter and custom element already own cleanup.
680
+
681
+ Custom layers with timers or observers must return a controller with `destroy()`.
682
+
683
+ ## Auto mounting creates duplicates
684
+
685
+ `Gaugeit.autoMount()` is duplicate-safe for managed elements. Duplicate SVG usually
686
+ means application code also called `createGauge()` independently or cloned generated
687
+ content.
688
+
689
+ Use:
690
+
691
+ ```js
692
+ Gaugeit.getMountedGauge(host)
693
+ ```
694
+
695
+ to inspect ownership.
696
+
697
+ ## Custom element options do not update
698
+
699
+ Observed attributes:
700
+
701
+ ```text
702
+ value
703
+ min
704
+ max
705
+ type
706
+ options
707
+ ```
708
+
709
+ The `options` attribute must be valid JSON. Attribute changes replace the declarative
710
+ option object.
711
+
712
+ Property assignment for value:
713
+
714
+ ```js
715
+ element.value = 72;
716
+ ```
717
+
718
+ ## Laravel or Twig JSON parsing fails
719
+
720
+ Encode data as JSON and escape it for the HTML attribute context.
721
+
722
+ Blade:
723
+
724
+ ```blade
725
+ data-options='@json($options)'
726
+ ```
727
+
728
+ Twig:
729
+
730
+ ```twig
731
+ data-options="{{ options|json_encode|e('html_attr') }}"
732
+ ```
733
+
734
+ Plain PHP:
735
+
736
+ ```php
737
+ htmlspecialchars(json_encode($options, JSON_THROW_ON_ERROR), ENT_QUOTES, 'UTF-8')
738
+ ```
739
+
740
+ Do not render PHP array syntax into a browser JSON parser.
741
+
742
+ ## Composer command is missing
743
+
744
+ Confirm installation:
745
+
746
+ ```bash
747
+ composer show kasperi/gaugeit-js
748
+ ```
749
+
750
+ Use the platform-appropriate vendor binary:
751
+
752
+ Unix-like:
753
+
754
+ ```bash
755
+ vendor/bin/gaugeit-install-assets public/assets/vendor/gaugeit
756
+ ```
757
+
758
+ Windows Composer normally exposes a callable wrapper under `vendor\bin`.
759
+
760
+ Verify PHP 8.1 or newer.
761
+
762
+ ## Composer assets are installed but browser returns 404
763
+
764
+ The installer writes to the filesystem path you provide. The web server must expose
765
+ that path.
766
+
767
+ Check:
768
+
769
+ - destination is under the actual public document root;
770
+ - framework asset helper matches the destination;
771
+ - deployment included generated public assets;
772
+ - URL casing matches filesystem casing.
773
+
774
+ ## `npm run test:chromium` fails with `spawn chromium ENOENT`
775
+
776
+ The optional test expects a globally available executable named `chromium`.
777
+
778
+ This does not mean the library test failed in a browser. It means the process could not
779
+ start Chromium.
780
+
781
+ Options:
782
+
783
+ - install Chromium and add it to PATH;
784
+ - adjust the local environment to expose the expected executable;
785
+ - rely on `npm run check` for the portable required suite.
786
+
787
+ Do not weaken CI because an optional local executable is missing.
788
+
789
+ ## Local `npm run check` passes but GitHub CI fails at reproducibility
790
+
791
+ Typical symptom:
792
+
793
+ ```text
794
+ git diff --exit-code -- dist package-lock.json
795
+ ```
796
+
797
+ shows source-map differences.
798
+
799
+ Check:
800
+
801
+ - source files use LF, not CRLF;
802
+ - Git `core.autocrlf` did not rewrite canonical inputs;
803
+ - generated files do not contain absolute paths;
804
+ - file ordering is deterministic;
805
+ - no timestamps or randomness enter build output;
806
+ - local `dist/` was rebuilt after the final source edit.
807
+
808
+ Repository policy:
809
+
810
+ ```text
811
+ .editorconfig -> LF
812
+ .gitattributes -> text eol=lf
813
+ ```
814
+
815
+ Run:
816
+
817
+ ```bash
818
+ npm run check
819
+ git diff -- dist package-lock.json
820
+ ```
821
+
822
+ and inspect the generated changes before pushing. To reproduce CI's exit-code check
823
+ locally, stage the intended generated artifacts first and then run:
824
+
825
+ ```bash
826
+ git diff --exit-code -- dist package-lock.json
827
+ ```
828
+
829
+ CI performs this check from a clean checkout, so any post-build diff there is
830
+ unexpected.
831
+
832
+ ## `dist/` changes after a documentation-only edit
833
+
834
+ Ordinary docs should not change runtime distribution. If `npm run check` changes
835
+ `dist/`, either:
836
+
837
+ - canonical source had uncommitted changes;
838
+ - previous generated output was stale;
839
+ - line endings or build environment changed;
840
+ - a build script includes documentation unexpectedly.
841
+
842
+ Inspect the diff before committing.
843
+
844
+ ## Generated files were edited manually
845
+
846
+ Discard manual generated edits, change canonical source, and rebuild:
847
+
848
+ ```bash
849
+ git restore dist
850
+ npm run build
851
+ ```
852
+
853
+ If canonical source changes are already present, do not restore those. The goal is to
854
+ remove only hand edits from `dist/`.
855
+
856
+ ## TypeScript declarations do not match runtime
857
+
858
+ Canonical core declarations are:
859
+
860
+ ```text
861
+ src/index.d.ts
862
+ ```
863
+
864
+ The React adapter has a separate canonical declaration:
865
+
866
+ ```text
867
+ adapters/react/Gaugeit.d.ts
868
+ ```
869
+
870
+ Generated core copy:
871
+
872
+ ```text
873
+ dist/gaugeit.d.ts
874
+ ```
875
+
876
+ Update the declaration that owns the affected API, then run:
877
+
878
+ ```bash
879
+ npm run typecheck
880
+ npm run build
881
+ ```
882
+
883
+ and add package-usage tests when an export or option changes.
884
+
885
+ ## Package dry run omits expected files
886
+
887
+ Check `package.json` `files` and `exports`.
888
+
889
+ Run:
890
+
891
+ ```bash
892
+ npm pack --dry-run
893
+ ```
894
+
895
+ AI documentation under `docs/` is included because the package publishes `docs`.
896
+ Top-level files not listed in `files` may be absent from the npm tarball even when they
897
+ exist in GitHub.
898
+
899
+ ## npm publication returns 403 requiring 2FA
900
+
901
+ The package contents may be valid even though publication is rejected.
902
+
903
+ Use an npm account with publication 2FA or an appropriate granular token. A failed
904
+ 403 attempt does not publish the version.
905
+
906
+ After successful publication, verify:
907
+
908
+ ```bash
909
+ npm view gaugeit.js@0.1.1 name version
910
+ npm view gaugeit.js dist-tags
911
+ ```
912
+
913
+ ## Packagist does not show the release
914
+
915
+ Composer package versions come from Git tags.
916
+
917
+ Verify:
918
+
919
+ - GitHub repository is public and correct;
920
+ - `composer.json` is valid;
921
+ - tag exists remotely;
922
+ - Packagist package points to the correct repository;
923
+ - tag corresponds to the intended commit.
924
+
925
+ Do not add a hard-coded `version` field to `composer.json` merely to fix tag discovery.
926
+
927
+ ## Custom type is not found
928
+
929
+ Register before instance creation:
930
+
931
+ ```js
932
+ Gaugeit.registerGaugeType('my-type', definition);
933
+ Gaugeit.createGauge('#gauge', {
934
+ type: 'my-type'
935
+ });
936
+ ```
937
+
938
+ Verify non-empty `layers`. Every layer must expose `render(context)`.
939
+
940
+ ## Custom layer is behind or above the wrong content
941
+
942
+ Layer array order is SVG paint order. Reorder layers.
943
+
944
+ For example, pointer above readout:
945
+
946
+ ```js
947
+ layers: [
948
+ Gaugeit.layers.face,
949
+ Gaugeit.layers.zones,
950
+ Gaugeit.layers.ticks,
951
+ Gaugeit.layers.labels,
952
+ Gaugeit.layers.readout,
953
+ Gaugeit.layers.pointer
954
+ ]
955
+ ```
956
+
957
+ Do not use numeric CSS z-index as a substitute.
958
+
959
+ ## Custom layer ignores clipping
960
+
961
+ Create its group through:
962
+
963
+ ```js
964
+ renderer.group('my-layer')
965
+ ```
966
+
967
+ and place it after a face layer that establishes clipping. Appending directly to an
968
+ unmanaged SVG node can bypass renderer ownership and clip-path application.
969
+
970
+ ## Custom timer survives `destroy()`
971
+
972
+ Return cleanup:
973
+
974
+ ```js
975
+ return {
976
+ update() {
977
+ // ...
978
+ },
979
+
980
+ destroy() {
981
+ clearInterval(timer);
982
+ }
983
+ };
984
+ ```
985
+
986
+ Test destruction explicitly.
987
+
988
+ ## A bug fix has no regression test
989
+
990
+ Add the smallest test that demonstrates the defect. Choose the nearest suite:
991
+
992
+ ```text
993
+ options.test.js
994
+ geometry.test.js
995
+ zones.test.js
996
+ linear.test.js
997
+ light.test.js
998
+ lifecycle.test.js
999
+ distribution.test.js
1000
+ react-adapter.test.js
1001
+ ```
1002
+
1003
+ A bug fix is incomplete when only the implementation changed.
1004
+
1005
+ ## Final diagnostic sequence
1006
+
1007
+ For application integration:
1008
+
1009
+ 1. verify distribution and CSS;
1010
+ 2. verify exact global/import name;
1011
+ 3. verify host exists and has layout;
1012
+ 4. reduce options to `{ type, min, max, value }`;
1013
+ 5. add nested options back one section at a time;
1014
+ 6. inspect host-scoped Gaugeit events;
1015
+ 7. test destruction and recreation.
1016
+
1017
+ For repository changes:
1018
+
1019
+ 1. inspect canonical source;
1020
+ 2. run focused tests;
1021
+ 3. update declarations and docs;
1022
+ 4. run `npm run check`;
1023
+ 5. run reproducibility diff;
1024
+ 6. inspect `git diff` for accidental files.