@jjlmoya/utils-forensic-science 1.4.0 → 1.5.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.
Files changed (34) hide show
  1. package/package.json +1 -1
  2. package/src/category/index.ts +3 -1
  3. package/src/entries.ts +5 -1
  4. package/src/index.ts +1 -0
  5. package/src/tests/locale_completeness.test.ts +2 -2
  6. package/src/tests/tool_validation.test.ts +2 -2
  7. package/src/tool/fire-pattern-origin-analyzer/bibliography.astro +6 -0
  8. package/src/tool/fire-pattern-origin-analyzer/bibliography.ts +12 -0
  9. package/src/tool/fire-pattern-origin-analyzer/component.astro +196 -0
  10. package/src/tool/fire-pattern-origin-analyzer/entry.ts +32 -0
  11. package/src/tool/fire-pattern-origin-analyzer/fire-pattern-origin-analyzer.css +681 -0
  12. package/src/tool/fire-pattern-origin-analyzer/i18n/de.ts +250 -0
  13. package/src/tool/fire-pattern-origin-analyzer/i18n/en.ts +250 -0
  14. package/src/tool/fire-pattern-origin-analyzer/i18n/es.ts +250 -0
  15. package/src/tool/fire-pattern-origin-analyzer/i18n/fr.ts +250 -0
  16. package/src/tool/fire-pattern-origin-analyzer/i18n/id.ts +250 -0
  17. package/src/tool/fire-pattern-origin-analyzer/i18n/it.ts +250 -0
  18. package/src/tool/fire-pattern-origin-analyzer/i18n/ja.ts +250 -0
  19. package/src/tool/fire-pattern-origin-analyzer/i18n/ko.ts +250 -0
  20. package/src/tool/fire-pattern-origin-analyzer/i18n/nl.ts +250 -0
  21. package/src/tool/fire-pattern-origin-analyzer/i18n/pl.ts +250 -0
  22. package/src/tool/fire-pattern-origin-analyzer/i18n/pt.ts +250 -0
  23. package/src/tool/fire-pattern-origin-analyzer/i18n/ru.ts +250 -0
  24. package/src/tool/fire-pattern-origin-analyzer/i18n/sv.ts +250 -0
  25. package/src/tool/fire-pattern-origin-analyzer/i18n/tr.ts +250 -0
  26. package/src/tool/fire-pattern-origin-analyzer/i18n/zh.ts +246 -0
  27. package/src/tool/fire-pattern-origin-analyzer/index.ts +11 -0
  28. package/src/tool/fire-pattern-origin-analyzer/logic.ts +123 -0
  29. package/src/tool/fire-pattern-origin-analyzer/render.ts +159 -0
  30. package/src/tool/fire-pattern-origin-analyzer/seo.astro +15 -0
  31. package/src/tool/fire-pattern-origin-analyzer/view-bindings.ts +171 -0
  32. package/src/tool/fire-pattern-origin-analyzer/view-model.ts +244 -0
  33. package/src/tool/fire-pattern-origin-analyzer/view.ts +30 -0
  34. package/src/tools.ts +3 -1
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jjlmoya/utils-forensic-science",
3
- "version": "1.4.0",
3
+ "version": "1.5.0",
4
4
  "type": "module",
5
5
  "main": "./src/index.ts",
6
6
  "types": "./src/index.ts",
@@ -12,6 +12,7 @@ import { forensicGlassBeckeLineSimulator } from '../tool/forensic-glass-becke-li
12
12
  import { forensicFiberComparisonMicroscope } from '../tool/forensic-fiber-comparison-microscope/index';
13
13
  import { bloodstainPatternOriginAnalyzer } from '../tool/bloodstain-pattern-origin-analyzer/index';
14
14
  import { forensicFingerprintMinutiaeIdentifier } from '../tool/forensic-fingerprint-minutiae-identifier/index';
15
+ import { firePatternOriginAnalyzer } from '../tool/fire-pattern-origin-analyzer/index';
15
16
 
16
17
  export const forensicCategory: ScienceCategoryEntry = {
17
18
  icon: 'mdi:fingerprint',
@@ -28,7 +29,8 @@ export const forensicCategory: ScienceCategoryEntry = {
28
29
  forensicGlassBeckeLineSimulator,
29
30
  forensicFiberComparisonMicroscope,
30
31
  bloodstainPatternOriginAnalyzer,
31
- forensicFingerprintMinutiaeIdentifier
32
+ forensicFingerprintMinutiaeIdentifier,
33
+ firePatternOriginAnalyzer
32
34
  ],
33
35
  i18n: {
34
36
  de: () => import('./i18n/de').then((m) => m.content),
package/src/entries.ts CHANGED
@@ -24,6 +24,8 @@ export { bloodstainPatternOriginAnalyzer } from './tool/bloodstain-pattern-origi
24
24
  export type { BloodstainPatternUI, BloodstainPatternLocaleContent } from './tool/bloodstain-pattern-origin-analyzer/entry';
25
25
  export { forensicFingerprintMinutiaeIdentifier } from './tool/forensic-fingerprint-minutiae-identifier/entry';
26
26
  export type { FingerprintMinutiaeUI, FingerprintMinutiaeLocaleContent } from './tool/forensic-fingerprint-minutiae-identifier/entry';
27
+ export { firePatternOriginAnalyzer } from './tool/fire-pattern-origin-analyzer/entry';
28
+ export type { FirePatternOriginAnalyzerUI, FirePatternOriginAnalyzerLocaleContent } from './tool/fire-pattern-origin-analyzer/entry';
27
29
 
28
30
  import { forensicAgeEstimator } from './tool/forensic-age-estimator/entry';
29
31
  import { widmarkAlcoholSimulator } from './tool/widmark-alcohol-simulator/entry';
@@ -38,6 +40,7 @@ import { forensicGlassBeckeLineSimulator } from './tool/forensic-glass-becke-lin
38
40
  import { forensicFiberComparisonMicroscope } from './tool/forensic-fiber-comparison-microscope/entry';
39
41
  import { bloodstainPatternOriginAnalyzer } from './tool/bloodstain-pattern-origin-analyzer/entry';
40
42
  import { forensicFingerprintMinutiaeIdentifier } from './tool/forensic-fingerprint-minutiae-identifier/entry';
43
+ import { firePatternOriginAnalyzer } from './tool/fire-pattern-origin-analyzer/entry';
41
44
 
42
45
  export const ALL_ENTRIES = [
43
46
  forensicAgeEstimator,
@@ -52,5 +55,6 @@ export const ALL_ENTRIES = [
52
55
  forensicGlassBeckeLineSimulator,
53
56
  forensicFiberComparisonMicroscope,
54
57
  bloodstainPatternOriginAnalyzer,
55
- forensicFingerprintMinutiaeIdentifier
58
+ forensicFingerprintMinutiaeIdentifier,
59
+ firePatternOriginAnalyzer
56
60
  ];
package/src/index.ts CHANGED
@@ -13,6 +13,7 @@ export { FORENSIC_GLASS_BECKE_LINE_SIMULATOR_TOOL } from './tool/forensic-glass-
13
13
  export { FORENSIC_FIBER_COMPARISON_MICROSCOPE_TOOL } from './tool/forensic-fiber-comparison-microscope/index';
14
14
  export { BLOODSTAIN_PATTERN_ORIGIN_ANALYZER_TOOL } from './tool/bloodstain-pattern-origin-analyzer/index';
15
15
  export { FORENSIC_FINGERPRINT_MINUTIAE_IDENTIFIER_TOOL } from './tool/forensic-fingerprint-minutiae-identifier/index';
16
+ export { FIRE_PATTERN_ORIGIN_ANALYZER_TOOL } from './tool/fire-pattern-origin-analyzer/index';
16
17
 
17
18
  export type {
18
19
  KnownLocale,
@@ -18,7 +18,7 @@ describe('Locale Completeness Validation', () => {
18
18
  });
19
19
  });
20
20
 
21
- it('all 13 tools registered', () => {
22
- expect(ALL_TOOLS.length).toBe(13);
21
+ it('all 14 tools registered', () => {
22
+ expect(ALL_TOOLS.length).toBe(14);
23
23
  });
24
24
  });
@@ -4,8 +4,8 @@ import { scienceCategory } from '../data';
4
4
 
5
5
  describe('Tool Validation Suite', () => {
6
6
  describe('Library Registration', () => {
7
- it('should have 13 tools in ALL_TOOLS', () => {
8
- expect(ALL_TOOLS.length).toBe(13);
7
+ it('should have 14 tools in ALL_TOOLS', () => {
8
+ expect(ALL_TOOLS.length).toBe(14);
9
9
  });
10
10
 
11
11
  it('scienceCategory should be defined', () => {
@@ -0,0 +1,6 @@
1
+ ---
2
+ import { Bibliography as BibliographyRenderer } from '@jjlmoya/utils-shared';
3
+ import { bibliography } from './bibliography';
4
+ ---
5
+
6
+ <BibliographyRenderer links={bibliography} />
@@ -0,0 +1,12 @@
1
+ import type { BibliographyEntry } from '../../types';
2
+
3
+ export const bibliography: BibliographyEntry[] = [
4
+ {
5
+ name: 'NFPA 921: Guide for Fire and Explosion Investigations.',
6
+ url: 'https://www.nfpa.org/codes-and-standards/nfpa-921-standard-development/921',
7
+ },
8
+ {
9
+ name: 'NIJ: Fire and Arson Scene Evidence, A Guide for Public Safety Personnel.',
10
+ url: 'https://www.ojp.gov/pdffiles1/nij/181584.pdf',
11
+ }
12
+ ];
@@ -0,0 +1,196 @@
1
+ ---
2
+ import './fire-pattern-origin-analyzer.css';
3
+
4
+ interface Props {
5
+ ui: Record<string, string>;
6
+ }
7
+
8
+ const { ui } = Astro.props;
9
+ ---
10
+
11
+ <section class="fire-origin" data-fire-origin-tool data-has-plan="false">
12
+ <div class="fire-workspace">
13
+ <div class="fire-topbar">
14
+ <label class="fire-command fire-command-load">
15
+ <input id="fire-plan-upload" type="file" accept="image/*" />
16
+ <span>{ui.loadPlan}</span>
17
+ </label>
18
+ <button type="button" class="fire-command" id="fire-reset" disabled>{ui.resetVectors}</button>
19
+ <button type="button" class="fire-command fire-command-export" id="fire-export" disabled>{ui.generateReport}</button>
20
+ </div>
21
+
22
+ <div class="fire-plan-shell">
23
+ <div class="fire-layer-dots" role="group" aria-label={ui.visibleLayers}>
24
+ <button type="button" class="fire-layer-dot" data-fire-layer-toggle="vPattern" data-active="true" aria-label={ui.vPattern} disabled></button>
25
+ <button type="button" class="fire-layer-dot" data-fire-layer-toggle="deepChar" data-active="true" aria-label={ui.deepChar} disabled></button>
26
+ <button type="button" class="fire-layer-dot" data-fire-layer-toggle="sootShadow" data-active="true" aria-label={ui.sootShadow} disabled></button>
27
+ <button type="button" class="fire-layer-dot" data-fire-layer-toggle="cleanBurn" data-active="true" aria-label={ui.cleanBurn} disabled></button>
28
+ </div>
29
+
30
+ <div class="fire-pointer-overlay" id="fire-pointer-overlay">
31
+ <span>{ui.pointerLabel}</span>
32
+ <strong id="fire-pointer-coordinate">--, --</strong>
33
+ </div>
34
+
35
+ <div class="fire-origin-overlay" id="fire-origin-overlay">
36
+ <span>{ui.estimatedOrigin}</span>
37
+ <strong id="fire-origin-coordinate">--, --</strong>
38
+ </div>
39
+
40
+ <button type="button" class="fire-dropzone" id="fire-dropzone">{ui.dropPlan}</button>
41
+
42
+ <div class="fire-radial-menu" id="fire-radial-menu" hidden>
43
+ <button type="button" data-fire-pattern="vPattern">{ui.vPattern}</button>
44
+ <button type="button" data-fire-pattern="deepChar">{ui.deepChar}</button>
45
+ <button type="button" data-fire-pattern="cleanBurn">{ui.cleanBurn}</button>
46
+ <button type="button" data-fire-pattern="sootShadow">{ui.sootShadow}</button>
47
+ </div>
48
+
49
+ <svg id="fire-plan-svg" viewBox="0 0 1000 680" role="img" aria-label={ui.planAria}>
50
+ <defs>
51
+ <pattern id="fire-grid" width="50" height="50" patternUnits="userSpaceOnUse">
52
+ <path d="M 50 0 L 0 0 0 50" fill="none" stroke="currentColor" stroke-width="1" opacity="0.14"></path>
53
+ </pattern>
54
+ </defs>
55
+ <image id="fire-plan-image" x="0" y="0" width="1000" height="680" preserveAspectRatio="xMidYMid slice"></image>
56
+ <rect class="fire-grid-fill" x="0" y="0" width="1000" height="680" fill="url(#fire-grid)"></rect>
57
+ </svg>
58
+ <canvas id="fire-overlay-canvas" width="1000" height="680"></canvas>
59
+ </div>
60
+
61
+ <footer class="fire-statusbar">
62
+ <span>{ui.vectorsLabel}: <strong id="fire-vector-count">0</strong></span>
63
+ <span>{ui.confidenceLabel}: <strong id="fire-confidence-score">0.0%</strong></span>
64
+ <span>{ui.varianceLabel}: <strong id="fire-origin-variance">+-0.0 m</strong></span>
65
+ <span>{ui.modeLabel}: <strong id="fire-mode-label">{ui.awaitingVector}</strong></span>
66
+ </footer>
67
+
68
+ <details class="fire-guide" open>
69
+ <summary>{ui.guideSummary}</summary>
70
+ <div class="fire-guide-body" aria-label={ui.guideTitle}>
71
+ <div class="fire-guide-panels">
72
+ <details open>
73
+ <summary>{ui.flowPanelTitle}</summary>
74
+ <div class="fire-guide-flow">
75
+ <article>
76
+ <strong>{ui.flow1Kicker}</strong>
77
+ <span>{ui.flow1Icon}</span>
78
+ <h3>{ui.flow1Title}</h3>
79
+ <p>{ui.flow1Text}</p>
80
+ </article>
81
+ <article>
82
+ <strong>{ui.flow2Kicker}</strong>
83
+ <span>{ui.flow2Icon}</span>
84
+ <h3>{ui.flow2Title}</h3>
85
+ <p>{ui.flow2Text}</p>
86
+ </article>
87
+ <article>
88
+ <strong>{ui.flow3Kicker}</strong>
89
+ <span>{ui.flow3Icon}</span>
90
+ <h3>{ui.flow3Title}</h3>
91
+ <p>{ui.flow3Text}</p>
92
+ </article>
93
+ <article>
94
+ <strong>{ui.flow4Kicker}</strong>
95
+ <span>{ui.flow4Icon}</span>
96
+ <h3>{ui.flow4Title}</h3>
97
+ <p>{ui.flow4Text}</p>
98
+ </article>
99
+ </div>
100
+ </details>
101
+
102
+ <details open>
103
+ <summary>{ui.legendPanelTitle}</summary>
104
+ <div class="fire-guide-legend" aria-label={ui.indicatorsTitle}>
105
+ <article class="fire-guide-chip fire-guide-chip-v">
106
+ <span></span>
107
+ <strong>{ui.vPattern}</strong>
108
+ <small>{ui.vPatternShort}</small>
109
+ </article>
110
+ <article class="fire-guide-chip fire-guide-chip-char">
111
+ <span></span>
112
+ <strong>{ui.deepChar}</strong>
113
+ <small>{ui.deepCharShort}</small>
114
+ </article>
115
+ <article class="fire-guide-chip fire-guide-chip-soot">
116
+ <span></span>
117
+ <strong>{ui.sootShadow}</strong>
118
+ <small>{ui.sootShadowShort}</small>
119
+ </article>
120
+ <article class="fire-guide-chip fire-guide-chip-clean">
121
+ <span></span>
122
+ <strong>{ui.cleanBurn}</strong>
123
+ <small>{ui.cleanBurnShort}</small>
124
+ </article>
125
+ </div>
126
+ </details>
127
+
128
+ <details open>
129
+ <summary>{ui.readoutPanelTitle}</summary>
130
+ <div class="fire-guide-readouts">
131
+ <article>
132
+ <strong>{ui.vectorsLabel}</strong>
133
+ <p>{ui.resultsPoint1}</p>
134
+ </article>
135
+ <article>
136
+ <strong>{ui.confidenceLabel}</strong>
137
+ <p>{ui.resultsPoint2}</p>
138
+ </article>
139
+ <article>
140
+ <strong>{ui.varianceLabel}</strong>
141
+ <p>{ui.resultsPoint3}</p>
142
+ </article>
143
+ <article>
144
+ <strong>{ui.modeLabel}</strong>
145
+ <p>{ui.resultsPoint4}</p>
146
+ </article>
147
+ </div>
148
+ </details>
149
+
150
+ <details open>
151
+ <summary>{ui.basicsTitle}</summary>
152
+ <div class="fire-guide-panel-copy">
153
+ <p>{ui.basicsIntro}</p>
154
+ </div>
155
+ </details>
156
+
157
+ <details>
158
+ <summary>{ui.indicatorsTitle}</summary>
159
+ <div class="fire-guide-definitions">
160
+ <article>
161
+ <h3>{ui.vPattern}</h3>
162
+ <p>{ui.vPatternExplain}</p>
163
+ </article>
164
+ <article>
165
+ <h3>{ui.deepChar}</h3>
166
+ <p>{ui.deepCharExplain}</p>
167
+ </article>
168
+ <article>
169
+ <h3>{ui.sootShadow}</h3>
170
+ <p>{ui.sootShadowExplain}</p>
171
+ </article>
172
+ <article>
173
+ <h3>{ui.cleanBurn}</h3>
174
+ <p>{ui.cleanBurnExplain}</p>
175
+ </article>
176
+ </div>
177
+ </details>
178
+
179
+ <details>
180
+ <summary>{ui.resultsTitle}</summary>
181
+ <div class="fire-guide-panel-copy">
182
+ <p>{ui.resultsIntro}</p>
183
+ </div>
184
+ </details>
185
+ </div>
186
+ </div>
187
+ </details>
188
+ </div>
189
+ </section>
190
+
191
+ <script id="fire-origin-ui" type="application/json" set:html={JSON.stringify(ui)}></script>
192
+ <script>
193
+ import { initFirePatternOriginAnalyzer } from './view';
194
+
195
+ initFirePatternOriginAnalyzer(JSON.parse(document.getElementById('fire-origin-ui')?.textContent || '{}'));
196
+ </script>
@@ -0,0 +1,32 @@
1
+ import type { ScienceToolEntry, ToolLocaleContent } from '../../types';
2
+
3
+ export interface FirePatternOriginAnalyzerUI {
4
+ [key: string]: string;
5
+ }
6
+
7
+ export type FirePatternOriginAnalyzerLocaleContent = ToolLocaleContent<FirePatternOriginAnalyzerUI>;
8
+
9
+ export const firePatternOriginAnalyzer: ScienceToolEntry<FirePatternOriginAnalyzerUI> = {
10
+ id: 'fire-pattern-origin-analyzer',
11
+ icons: {
12
+ bg: 'mdi:fire-alert',
13
+ fg: 'mdi:vector-polyline',
14
+ },
15
+ i18n: {
16
+ de: () => import('./i18n/de').then((m) => m.content),
17
+ en: () => import('./i18n/en').then((m) => m.content),
18
+ es: () => import('./i18n/es').then((m) => m.content),
19
+ fr: () => import('./i18n/fr').then((m) => m.content),
20
+ id: () => import('./i18n/id').then((m) => m.content),
21
+ it: () => import('./i18n/it').then((m) => m.content),
22
+ ja: () => import('./i18n/ja').then((m) => m.content),
23
+ ko: () => import('./i18n/ko').then((m) => m.content),
24
+ nl: () => import('./i18n/nl').then((m) => m.content),
25
+ pl: () => import('./i18n/pl').then((m) => m.content),
26
+ pt: () => import('./i18n/pt').then((m) => m.content),
27
+ ru: () => import('./i18n/ru').then((m) => m.content),
28
+ sv: () => import('./i18n/sv').then((m) => m.content),
29
+ tr: () => import('./i18n/tr').then((m) => m.content),
30
+ zh: () => import('./i18n/zh').then((m) => m.content),
31
+ },
32
+ };