@orbat-mapper/control-measures 0.2.0-alpha.0 → 0.2.0-alpha.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 +83 -34
- package/dist/index.d.mts +87 -0
- package/dist/index.mjs +552 -0
- package/media/airborne-attack.svg +1 -0
- package/media/ambush.svg +1 -0
- package/media/antitank-ditch-completed.svg +1 -0
- package/media/antitank-ditch-under-construction.svg +1 -0
- package/media/antitank-wall.svg +1 -0
- package/media/attack-by-fire.svg +1 -0
- package/media/attack-helicopter.svg +1 -0
- package/media/block-arrow.svg +1 -0
- package/media/block-mission-task.svg +1 -0
- package/media/block.svg +1 -0
- package/media/breach.svg +1 -0
- package/media/bypass.svg +1 -0
- package/media/canalize.svg +1 -0
- package/media/classic-arrow.svg +1 -0
- package/media/clear.svg +1 -0
- package/media/delay.svg +1 -0
- package/media/disrupt.svg +1 -0
- package/media/final-protective-fire-left.svg +1 -0
- package/media/final-protective-fire-right.svg +1 -0
- package/media/fix.svg +1 -0
- package/media/flot.svg +1 -0
- package/media/fortified-area.svg +1 -0
- package/media/fortified-line.svg +1 -0
- package/media/isolate.svg +1 -0
- package/media/main-attack.svg +1 -0
- package/media/obstacle-bypass-difficult.svg +1 -0
- package/media/obstacle-bypass-easy.svg +1 -0
- package/media/obstacle-bypass-impossible.svg +1 -0
- package/media/principal-direction-of-fire.svg +1 -0
- package/media/search-area.svg +1 -0
- package/media/support-by-fire.svg +1 -0
- package/media/supporting-attack.svg +1 -0
- package/media/turn.svg +1 -0
- package/package.json +7 -2
package/README.md
CHANGED
|
@@ -1,14 +1,13 @@
|
|
|
1
1
|
# @orbat-mapper/control-measures
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Generates tactical control measures as GeoJSON, following MIL-STD-2525 and
|
|
4
|
+
APP-6 conventions.
|
|
4
5
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
- Registry-driven: a single `renderControlMeasure(cm, options)` entry point, plus a metadata catalog for discovering every measure and its options.
|
|
11
|
-
- Validation controls: optional `validationMode` per render.
|
|
6
|
+
The output is plain GeoJSON, so it drops into Leaflet, MapLibre, OpenLayers,
|
|
7
|
+
or any other consumer without a mapping dependency of its own. Everything
|
|
8
|
+
goes through one entry point, `renderControlMeasure(cm, options)`, backed by
|
|
9
|
+
a metadata catalog for discovering the available measures and their options,
|
|
10
|
+
plus an optional `validationMode` per render for catching bad input.
|
|
12
11
|
|
|
13
12
|
## Installation
|
|
14
13
|
|
|
@@ -22,8 +21,8 @@ pnpm add @orbat-mapper/control-measures
|
|
|
22
21
|
|
|
23
22
|
## Quick Start
|
|
24
23
|
|
|
25
|
-
|
|
26
|
-
|
|
24
|
+
Describe a control measure as a `ControlMeasure` object — `kind`,
|
|
25
|
+
`controlPoints`, and optional `options` — then render it:
|
|
27
26
|
|
|
28
27
|
```ts
|
|
29
28
|
import { renderControlMeasure, type ControlMeasure } from "@orbat-mapper/control-measures";
|
|
@@ -49,8 +48,7 @@ const render = renderControlMeasure(mainAttack, { validationMode: "warn" });
|
|
|
49
48
|
|
|
50
49
|
## Discovering measures and options
|
|
51
50
|
|
|
52
|
-
|
|
53
|
-
available control measures and their parameters:
|
|
51
|
+
Skip the per-measure imports and query the catalog instead:
|
|
54
52
|
|
|
55
53
|
```ts
|
|
56
54
|
import {
|
|
@@ -82,28 +80,79 @@ useful for strict integrations and tests.
|
|
|
82
80
|
|
|
83
81
|
## Supported control measures
|
|
84
82
|
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
| `
|
|
93
|
-
|
|
|
94
|
-
| `
|
|
95
|
-
| `
|
|
96
|
-
| `
|
|
97
|
-
| `
|
|
98
|
-
| `
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
| `
|
|
103
|
-
|
|
|
104
|
-
| `
|
|
105
|
-
| `
|
|
106
|
-
| `
|
|
83
|
+
Grouped by APP-6/MIL-STD-2525 entity type, with each measure's 2525E symbol
|
|
84
|
+
code.
|
|
85
|
+
|
|
86
|
+
<!-- AUTO-GENERATED:measures-table -->
|
|
87
|
+
|
|
88
|
+
### Maneuver Lines
|
|
89
|
+
|
|
90
|
+
| Preview | `kind` | Measure | 2525E Value |
|
|
91
|
+
| --- | --- | --- | --- |
|
|
92
|
+
| <img src="media/flot.svg" width="96" height="48" alt=""> | `flot` | Forward line of own troops (FLOT) | `140100` |
|
|
93
|
+
| <img src="media/final-protective-fire-left.svg" width="96" height="48" alt=""> | `final-protective-fire-left` | Final Protective Fire (Left) | `140501` |
|
|
94
|
+
| <img src="media/final-protective-fire-right.svg" width="96" height="48" alt=""> | `final-protective-fire-right` | Final Protective Fire (Right) | `140502` |
|
|
95
|
+
| <img src="media/principal-direction-of-fire.svg" width="96" height="48" alt=""> | `principal-direction-of-fire` | Principal Direction of Fire | `140503` |
|
|
96
|
+
| <img src="media/ambush.svg" width="96" height="48" alt=""> | `ambush` | Ambush | `141700` |
|
|
97
|
+
|
|
98
|
+
### Maneuver Areas
|
|
99
|
+
|
|
100
|
+
| Preview | `kind` | Measure | 2525E Value |
|
|
101
|
+
| --- | --- | --- | --- |
|
|
102
|
+
| <img src="media/fortified-area.svg" width="96" height="48" alt=""> | `fortified-area` | Fortified Area | `151000` |
|
|
103
|
+
| <img src="media/airborne-attack.svg" width="96" height="48" alt=""> | `airborne-attack` | Airborne Attack | `151401` |
|
|
104
|
+
| <img src="media/attack-helicopter.svg" width="96" height="48" alt=""> | `attack-helicopter` | Attack Helicopter | `151402` |
|
|
105
|
+
| <img src="media/main-attack.svg" width="96" height="48" alt=""> | `main-attack` | Main Attack | `151403` |
|
|
106
|
+
| <img src="media/supporting-attack.svg" width="96" height="48" alt=""> | `supporting-attack` | Supporting Attack | `151404` |
|
|
107
|
+
| <img src="media/attack-by-fire.svg" width="96" height="48" alt=""> | `attack-by-fire` | Attack by Fire | `152000` |
|
|
108
|
+
| <img src="media/support-by-fire.svg" width="96" height="48" alt=""> | `support-by-fire` | Support By Fire | `152100` |
|
|
109
|
+
| <img src="media/search-area.svg" width="96" height="48" alt=""> | `search-area` | Search Area | `152200` |
|
|
110
|
+
|
|
111
|
+
### Protection Areas
|
|
112
|
+
|
|
113
|
+
| Preview | `kind` | Measure | 2525E Value |
|
|
114
|
+
| --- | --- | --- | --- |
|
|
115
|
+
| <img src="media/block.svg" width="96" height="48" alt=""> | `block` | Block | `270501` |
|
|
116
|
+
| <img src="media/disrupt.svg" width="96" height="48" alt=""> | `disrupt` | Disrupt | `270502` |
|
|
117
|
+
| <img src="media/fix.svg" width="96" height="48" alt=""> | `fix` | Fix | `270503` |
|
|
118
|
+
| <img src="media/turn.svg" width="96" height="48" alt=""> | `turn` | Turn | `270504` |
|
|
119
|
+
| <img src="media/obstacle-bypass-easy.svg" width="96" height="48" alt=""> | `obstacle-bypass-easy` | Obstacle Bypass Easy | `270601` |
|
|
120
|
+
| <img src="media/obstacle-bypass-difficult.svg" width="96" height="48" alt=""> | `obstacle-bypass-difficult` | Obstacle Bypass Difficult | `270602` |
|
|
121
|
+
| <img src="media/obstacle-bypass-impossible.svg" width="96" height="48" alt=""> | `obstacle-bypass-impossible` | Obstacle Bypass Impossible | `270603` |
|
|
122
|
+
|
|
123
|
+
### Protection Lines
|
|
124
|
+
|
|
125
|
+
| Preview | `kind` | Measure | 2525E Value |
|
|
126
|
+
| --- | --- | --- | --- |
|
|
127
|
+
| <img src="media/antitank-ditch-under-construction.svg" width="96" height="48" alt=""> | `antitank-ditch-under-construction` | Ditch - Under Construction | `290201` |
|
|
128
|
+
| <img src="media/antitank-ditch-completed.svg" width="96" height="48" alt=""> | `antitank-ditch-completed` | Ditch - Completed | `290202` |
|
|
129
|
+
| <img src="media/antitank-wall.svg" width="96" height="48" alt=""> | `antitank-wall` | Antitank Wall | `290204` |
|
|
130
|
+
| <img src="media/fortified-line.svg" width="96" height="48" alt=""> | `fortified-line` | Fortified Line | `290900` |
|
|
131
|
+
|
|
132
|
+
### Mission Tasks
|
|
133
|
+
|
|
134
|
+
| Preview | `kind` | Measure | 2525E Value |
|
|
135
|
+
| --- | --- | --- | --- |
|
|
136
|
+
| <img src="media/block-mission-task.svg" width="96" height="48" alt=""> | `block-mission-task` | Block | `340100` |
|
|
137
|
+
| <img src="media/breach.svg" width="96" height="48" alt=""> | `breach` | Breach | `340200` |
|
|
138
|
+
| <img src="media/bypass.svg" width="96" height="48" alt=""> | `bypass` | Bypass | `340300` |
|
|
139
|
+
| <img src="media/canalize.svg" width="96" height="48" alt=""> | `canalize` | Canalize | `340400` |
|
|
140
|
+
| <img src="media/clear.svg" width="96" height="48" alt=""> | `clear` | Clear | `340500` |
|
|
141
|
+
| <img src="media/delay.svg" width="96" height="48" alt=""> | `delay` | Delay | `340800` |
|
|
142
|
+
| <img src="media/isolate.svg" width="96" height="48" alt=""> | `isolate` | Isolate | `341500` |
|
|
143
|
+
|
|
144
|
+
### Generic Arrows
|
|
145
|
+
|
|
146
|
+
| Preview | `kind` | Measure | 2525E Value |
|
|
147
|
+
| --- | --- | --- | --- |
|
|
148
|
+
| <img src="media/block-arrow.svg" width="96" height="48" alt=""> | `block-arrow` | Block Arrow | `990001` |
|
|
149
|
+
| <img src="media/classic-arrow.svg" width="96" height="48" alt=""> | `classic-arrow` | Classic Arrow | `990002` |
|
|
150
|
+
|
|
151
|
+
<!-- /AUTO-GENERATED:measures-table -->
|
|
152
|
+
|
|
153
|
+
This table and the preview SVGs are generated; run
|
|
154
|
+
`pnpm --filter @orbat-mapper/control-measures generate-docs` after adding or
|
|
155
|
+
changing a measure to refresh both.
|
|
107
156
|
|
|
108
157
|
## License
|
|
109
158
|
|
package/dist/index.d.mts
CHANGED
|
@@ -277,6 +277,91 @@ declare const DEFAULT_SUPPORTING_ATTACK_OPTIONS: Required<SupportingAttackOption
|
|
|
277
277
|
*/
|
|
278
278
|
declare function createSupportingAttack(coordinates: Position[], options?: SupportingAttackOptions): FeatureCollection<LineString>;
|
|
279
279
|
//#endregion
|
|
280
|
+
//#region src/generators/cm99-generic-arrows/classicArrow.d.ts
|
|
281
|
+
/**
|
|
282
|
+
* A plain, clean arrow for illustrations — not a doctrinal symbol. The shaft is
|
|
283
|
+
* a straight polyline through the drawn control points (Line1 contract) and the
|
|
284
|
+
* tip carries a solid triangular arrowhead. No wobble, no curve: the canonical
|
|
285
|
+
* "draw an arrow" graphic.
|
|
286
|
+
*/
|
|
287
|
+
/**
|
|
288
|
+
* Arrowhead silhouette:
|
|
289
|
+
* - `triangle` — solid triangle with a flat back (the default).
|
|
290
|
+
* - `barbed` — swept-back barbs with a forward notch (classic arrowhead).
|
|
291
|
+
* - `concave` — a sharper barbed head with a deep forward notch.
|
|
292
|
+
* - `diamond` — a rhombus, widest at its middle.
|
|
293
|
+
* - `harpoon` — an asymmetric single-sided barb.
|
|
294
|
+
* - `swallowtail` — barbs that sweep back into two trailing tails.
|
|
295
|
+
* - `chevron` — a thick hollow "V".
|
|
296
|
+
* - `circle` — a round dot terminator.
|
|
297
|
+
* - `tee` — a flat crossbar terminator (no point).
|
|
298
|
+
* - `open` — an unfilled "V", drawn as two strokes meeting at the tip.
|
|
299
|
+
*/
|
|
300
|
+
type ClassicArrowHeadStyle = "triangle" | "barbed" | "concave" | "diamond" | "harpoon" | "swallowtail" | "chevron" | "circle" | "tee" | "open";
|
|
301
|
+
interface ClassicArrowOptions {
|
|
302
|
+
/** Arrowhead silhouette. */
|
|
303
|
+
headStyle?: ClassicArrowHeadStyle;
|
|
304
|
+
/** Round the shaft's corners by curving it through the control points. */
|
|
305
|
+
smooth?: boolean;
|
|
306
|
+
/** Arrowhead length as a fraction of the total path length. */
|
|
307
|
+
headLength?: number;
|
|
308
|
+
/** Arrowhead base width as a fraction of the total path length. */
|
|
309
|
+
headWidth?: number;
|
|
310
|
+
}
|
|
311
|
+
/**
|
|
312
|
+
* Generates a GeoJSON FeatureCollection for the Classic Arrow: a shaft
|
|
313
|
+
* LineString (trimmed so it doesn't poke through the head) plus a head feature
|
|
314
|
+
* whose silhouette follows `headStyle` — a filled Polygon for the solid heads,
|
|
315
|
+
* or an open "V" LineString for `open`.
|
|
316
|
+
*/
|
|
317
|
+
declare function createClassicArrow(coordinates: Position[], options?: ClassicArrowOptions): FeatureCollection<LineString | Polygon, {
|
|
318
|
+
part: "shaft" | "head";
|
|
319
|
+
fill?: boolean;
|
|
320
|
+
}>;
|
|
321
|
+
//#endregion
|
|
322
|
+
//#region src/generators/cm99-generic-arrows/blockArrow.d.ts
|
|
323
|
+
/**
|
|
324
|
+
* A solid "block" arrow for illustrations — not a doctrinal symbol. The whole
|
|
325
|
+
* arrow is one filled polygon: a shaft band of controllable width that runs
|
|
326
|
+
* through the drawn control points (Line1 contract) and flares into a wider
|
|
327
|
+
* triangular head at the tip.
|
|
328
|
+
*/
|
|
329
|
+
/**
|
|
330
|
+
* Arrowhead silhouette (all carved from the one filled body):
|
|
331
|
+
* - `triangle` — a flat-backed triangular head (the default).
|
|
332
|
+
* - `barbed` — swept-back barbs with the shaft entering at a forward notch.
|
|
333
|
+
* - `concave` — a sharper barbed head with a deeper notch.
|
|
334
|
+
* - `diamond` — a kite that flares to its widest mid-head.
|
|
335
|
+
* - `harpoon` — an asymmetric single-sided barb.
|
|
336
|
+
* - `swallowtail` — barbs that sweep back into two trailing tails.
|
|
337
|
+
* - `tee` — a flat crossbar terminator (no point).
|
|
338
|
+
*/
|
|
339
|
+
type BlockArrowHeadStyle = "triangle" | "barbed" | "concave" | "diamond" | "harpoon" | "swallowtail" | "tee";
|
|
340
|
+
interface BlockArrowOptions {
|
|
341
|
+
/** Shaft band width as a fraction of the total path length. */
|
|
342
|
+
shaftWidth?: number;
|
|
343
|
+
/** Arrowhead silhouette. */
|
|
344
|
+
headStyle?: BlockArrowHeadStyle;
|
|
345
|
+
/** Arrowhead base width as a fraction of the total path length. */
|
|
346
|
+
headWidth?: number;
|
|
347
|
+
/** Arrowhead length as a fraction of the total path length. */
|
|
348
|
+
headLength?: number;
|
|
349
|
+
/** Round the shaft's corners by curving it through the control points. */
|
|
350
|
+
smooth?: boolean;
|
|
351
|
+
/** Fill the body solid; when false the arrow is drawn as an outline only. */
|
|
352
|
+
filled?: boolean;
|
|
353
|
+
}
|
|
354
|
+
/**
|
|
355
|
+
* Generates a GeoJSON FeatureCollection for the Block Arrow: a single filled
|
|
356
|
+
* Polygon whose outline runs up the left side of the shaft, around the head
|
|
357
|
+
* (whose silhouette follows `headStyle`) to the tip and back, then down the
|
|
358
|
+
* right side of the shaft.
|
|
359
|
+
*/
|
|
360
|
+
declare function createBlockArrow(coordinates: Position[], options?: BlockArrowOptions): FeatureCollection<Polygon, {
|
|
361
|
+
part: "body";
|
|
362
|
+
fill: boolean;
|
|
363
|
+
}>;
|
|
364
|
+
//#endregion
|
|
280
365
|
//#region src/generators/cm15-maneuver-areas/airborneAttack.d.ts
|
|
281
366
|
type AirborneAttackOptions = AttackOptions;
|
|
282
367
|
declare const DEFAULT_AIRBORNE_ATTACK_OPTIONS: Required<AirborneAttackOptions>;
|
|
@@ -906,6 +991,8 @@ declare const DEFINITIONS: {
|
|
|
906
991
|
}>>;
|
|
907
992
|
"main-attack": ControlMeasureDefinition<"main-attack", typeof createMainAttack>;
|
|
908
993
|
"supporting-attack": ControlMeasureDefinition<"supporting-attack", typeof createSupportingAttack>;
|
|
994
|
+
"classic-arrow": ControlMeasureDefinition<"classic-arrow", typeof createClassicArrow>;
|
|
995
|
+
"block-arrow": ControlMeasureDefinition<"block-arrow", typeof createBlockArrow>;
|
|
909
996
|
"airborne-attack": ControlMeasureDefinition<"airborne-attack", typeof createAirborneAttack>;
|
|
910
997
|
"attack-helicopter": ControlMeasureDefinition<"attack-helicopter", typeof createAttackHelicopter>;
|
|
911
998
|
"support-by-fire": ControlMeasureDefinition<"support-by-fire", typeof createSupportByFire>;
|
package/dist/index.mjs
CHANGED
|
@@ -1821,6 +1821,276 @@ const BLOCK = defineControlMeasure({
|
|
|
1821
1821
|
rule: blockDrawRule
|
|
1822
1822
|
});
|
|
1823
1823
|
//#endregion
|
|
1824
|
+
//#region src/internal/sketch.ts
|
|
1825
|
+
/**
|
|
1826
|
+
* Projects `coordinates` and derives the arrow's tip, heading and total length.
|
|
1827
|
+
* Returns `null` for degenerate input (fewer than two points, a zero-length
|
|
1828
|
+
* path, or a zero-length final segment) so the caller can decide what to emit.
|
|
1829
|
+
*/
|
|
1830
|
+
function arrowAxis(coordinates) {
|
|
1831
|
+
if (coordinates.length < 2) return null;
|
|
1832
|
+
const pts = coordinates.map((c) => project(c[0], c[1]));
|
|
1833
|
+
let pathLength = 0;
|
|
1834
|
+
for (let i = 0; i < pts.length - 1; i++) pathLength += Math.hypot(pts[i + 1][0] - pts[i][0], pts[i + 1][1] - pts[i][1]);
|
|
1835
|
+
const tip = pts[pts.length - 1];
|
|
1836
|
+
const prev = pts[pts.length - 2];
|
|
1837
|
+
const hx = tip[0] - prev[0];
|
|
1838
|
+
const hy = tip[1] - prev[1];
|
|
1839
|
+
const segLength = Math.hypot(hx, hy);
|
|
1840
|
+
if (segLength === 0 || pathLength === 0) return null;
|
|
1841
|
+
const dir = [hx / segLength, hy / segLength];
|
|
1842
|
+
const perp = [-dir[1], dir[0]];
|
|
1843
|
+
return {
|
|
1844
|
+
pts,
|
|
1845
|
+
pathLength,
|
|
1846
|
+
tip,
|
|
1847
|
+
dir,
|
|
1848
|
+
perp,
|
|
1849
|
+
segLength
|
|
1850
|
+
};
|
|
1851
|
+
}
|
|
1852
|
+
/**
|
|
1853
|
+
* Centripetal Catmull-Rom spline through `points`, sampled `samples` times per
|
|
1854
|
+
* segment. Endpoints are duplicated so the curve passes through them, so the
|
|
1855
|
+
* first and last points are preserved exactly. With `samples <= 1` (or fewer
|
|
1856
|
+
* than 3 points) it returns the input unchanged.
|
|
1857
|
+
*/
|
|
1858
|
+
function catmullRom(points, samples) {
|
|
1859
|
+
if (points.length < 3 || samples <= 1) return points;
|
|
1860
|
+
const pts = [
|
|
1861
|
+
points[0],
|
|
1862
|
+
...points,
|
|
1863
|
+
points[points.length - 1]
|
|
1864
|
+
];
|
|
1865
|
+
const out = [points[0]];
|
|
1866
|
+
for (let i = 1; i < pts.length - 2; i++) {
|
|
1867
|
+
const p0 = pts[i - 1];
|
|
1868
|
+
const p1 = pts[i];
|
|
1869
|
+
const p2 = pts[i + 1];
|
|
1870
|
+
const p3 = pts[i + 2];
|
|
1871
|
+
for (let s = 1; s <= samples; s++) {
|
|
1872
|
+
const t = s / samples;
|
|
1873
|
+
const t2 = t * t;
|
|
1874
|
+
const t3 = t2 * t;
|
|
1875
|
+
const x = .5 * (2 * p1[0] + (-p0[0] + p2[0]) * t + (2 * p0[0] - 5 * p1[0] + 4 * p2[0] - p3[0]) * t2 + (-p0[0] + 3 * p1[0] - 3 * p2[0] + p3[0]) * t3);
|
|
1876
|
+
const y = .5 * (2 * p1[1] + (-p0[1] + p2[1]) * t + (2 * p0[1] - 5 * p1[1] + 4 * p2[1] - p3[1]) * t2 + (-p0[1] + 3 * p1[1] - 3 * p2[1] + p3[1]) * t3);
|
|
1877
|
+
out.push([x, y]);
|
|
1878
|
+
}
|
|
1879
|
+
}
|
|
1880
|
+
return out;
|
|
1881
|
+
}
|
|
1882
|
+
//#endregion
|
|
1883
|
+
//#region src/generators/cm99-generic-arrows/blockArrow.ts
|
|
1884
|
+
const DEFAULT_BLOCK_ARROW_OPTIONS = {
|
|
1885
|
+
shaftWidth: .06,
|
|
1886
|
+
headStyle: "triangle",
|
|
1887
|
+
headWidth: .18,
|
|
1888
|
+
headLength: .22,
|
|
1889
|
+
smooth: false,
|
|
1890
|
+
filled: true
|
|
1891
|
+
};
|
|
1892
|
+
const BLOCK_ARROW_METADATA = {
|
|
1893
|
+
id: "block-arrow",
|
|
1894
|
+
name: "Block Arrow",
|
|
1895
|
+
description: "Solid filled arrow with a controllable shaft width and selectable head (triangle, barbed, concave, diamond, harpoon, swallowtail, tee). Not a doctrinal symbol.",
|
|
1896
|
+
entity: "Generic Arrows",
|
|
1897
|
+
entityType: "Illustrative Arrow",
|
|
1898
|
+
entitySubtype: "Block Arrow",
|
|
1899
|
+
value: "990001",
|
|
1900
|
+
minCoordinates: 2,
|
|
1901
|
+
geometry: "line",
|
|
1902
|
+
geometryTypes: ["Polygon"],
|
|
1903
|
+
drawRule: "Line1",
|
|
1904
|
+
params: [
|
|
1905
|
+
{
|
|
1906
|
+
key: "shaftWidth",
|
|
1907
|
+
label: "Shaft width",
|
|
1908
|
+
description: "Shaft band width as a fraction of the total path length.",
|
|
1909
|
+
type: "number",
|
|
1910
|
+
min: .01,
|
|
1911
|
+
max: .3,
|
|
1912
|
+
step: .01
|
|
1913
|
+
},
|
|
1914
|
+
{
|
|
1915
|
+
key: "headStyle",
|
|
1916
|
+
label: "Head style",
|
|
1917
|
+
description: "Arrowhead silhouette.",
|
|
1918
|
+
type: "enum",
|
|
1919
|
+
options: [
|
|
1920
|
+
{
|
|
1921
|
+
label: "Triangle",
|
|
1922
|
+
value: "triangle"
|
|
1923
|
+
},
|
|
1924
|
+
{
|
|
1925
|
+
label: "Barbed",
|
|
1926
|
+
value: "barbed"
|
|
1927
|
+
},
|
|
1928
|
+
{
|
|
1929
|
+
label: "Concave",
|
|
1930
|
+
value: "concave"
|
|
1931
|
+
},
|
|
1932
|
+
{
|
|
1933
|
+
label: "Diamond",
|
|
1934
|
+
value: "diamond"
|
|
1935
|
+
},
|
|
1936
|
+
{
|
|
1937
|
+
label: "Harpoon",
|
|
1938
|
+
value: "harpoon"
|
|
1939
|
+
},
|
|
1940
|
+
{
|
|
1941
|
+
label: "Swallowtail",
|
|
1942
|
+
value: "swallowtail"
|
|
1943
|
+
},
|
|
1944
|
+
{
|
|
1945
|
+
label: "Tee",
|
|
1946
|
+
value: "tee"
|
|
1947
|
+
}
|
|
1948
|
+
]
|
|
1949
|
+
},
|
|
1950
|
+
{
|
|
1951
|
+
key: "headWidth",
|
|
1952
|
+
label: "Head width",
|
|
1953
|
+
description: "Arrowhead base width as a fraction of the total path length.",
|
|
1954
|
+
type: "number",
|
|
1955
|
+
min: .05,
|
|
1956
|
+
max: .5,
|
|
1957
|
+
step: .01
|
|
1958
|
+
},
|
|
1959
|
+
{
|
|
1960
|
+
key: "headLength",
|
|
1961
|
+
label: "Head length",
|
|
1962
|
+
description: "Arrowhead length as a fraction of the total path length.",
|
|
1963
|
+
type: "number",
|
|
1964
|
+
min: .05,
|
|
1965
|
+
max: .5,
|
|
1966
|
+
step: .01
|
|
1967
|
+
},
|
|
1968
|
+
{
|
|
1969
|
+
key: "smooth",
|
|
1970
|
+
label: "Smooth",
|
|
1971
|
+
description: "Round the shaft's corners by curving it through the control points.",
|
|
1972
|
+
type: "boolean"
|
|
1973
|
+
},
|
|
1974
|
+
{
|
|
1975
|
+
key: "filled",
|
|
1976
|
+
label: "Filled",
|
|
1977
|
+
description: "Fill the body solid; when off the arrow is drawn as an outline only.",
|
|
1978
|
+
type: "boolean"
|
|
1979
|
+
}
|
|
1980
|
+
]
|
|
1981
|
+
};
|
|
1982
|
+
/**
|
|
1983
|
+
* Generates a GeoJSON FeatureCollection for the Block Arrow: a single filled
|
|
1984
|
+
* Polygon whose outline runs up the left side of the shaft, around the head
|
|
1985
|
+
* (whose silhouette follows `headStyle`) to the tip and back, then down the
|
|
1986
|
+
* right side of the shaft.
|
|
1987
|
+
*/
|
|
1988
|
+
function createBlockArrow(coordinates, options = {}) {
|
|
1989
|
+
const { shaftWidth, headStyle, headWidth, headLength, smooth, filled } = {
|
|
1990
|
+
...DEFAULT_BLOCK_ARROW_OPTIONS,
|
|
1991
|
+
...options
|
|
1992
|
+
};
|
|
1993
|
+
const axis = arrowAxis(coordinates);
|
|
1994
|
+
if (!axis) return {
|
|
1995
|
+
type: "FeatureCollection",
|
|
1996
|
+
features: []
|
|
1997
|
+
};
|
|
1998
|
+
const { pts, pathLength, tip, dir, perp, segLength } = axis;
|
|
1999
|
+
const headLen = Math.min(pathLength * headLength, segLength * .95);
|
|
2000
|
+
const halfShaft = pathLength * shaftWidth / 2;
|
|
2001
|
+
const halfHead = pathLength * headWidth / 2;
|
|
2002
|
+
const onAxis = (d, side = 0) => [tip[0] - dir[0] * d + perp[0] * side, tip[1] - dir[1] * d + perp[1] * side];
|
|
2003
|
+
let shaftEndDist;
|
|
2004
|
+
let headPts;
|
|
2005
|
+
switch (headStyle) {
|
|
2006
|
+
case "barbed":
|
|
2007
|
+
shaftEndDist = headLen * .55;
|
|
2008
|
+
headPts = [
|
|
2009
|
+
onAxis(headLen, halfHead),
|
|
2010
|
+
tip,
|
|
2011
|
+
onAxis(headLen, -halfHead)
|
|
2012
|
+
];
|
|
2013
|
+
break;
|
|
2014
|
+
case "concave":
|
|
2015
|
+
shaftEndDist = headLen * .3;
|
|
2016
|
+
headPts = [
|
|
2017
|
+
onAxis(headLen, halfHead),
|
|
2018
|
+
tip,
|
|
2019
|
+
onAxis(headLen, -halfHead)
|
|
2020
|
+
];
|
|
2021
|
+
break;
|
|
2022
|
+
case "diamond":
|
|
2023
|
+
shaftEndDist = headLen;
|
|
2024
|
+
headPts = [
|
|
2025
|
+
onAxis(headLen * .5, halfHead),
|
|
2026
|
+
tip,
|
|
2027
|
+
onAxis(headLen * .5, -halfHead)
|
|
2028
|
+
];
|
|
2029
|
+
break;
|
|
2030
|
+
case "harpoon":
|
|
2031
|
+
shaftEndDist = headLen;
|
|
2032
|
+
headPts = [onAxis(headLen, halfHead), tip];
|
|
2033
|
+
break;
|
|
2034
|
+
case "swallowtail": {
|
|
2035
|
+
const tailDist = Math.min(headLen * 1.25, segLength * .95);
|
|
2036
|
+
shaftEndDist = headLen * .6;
|
|
2037
|
+
headPts = [
|
|
2038
|
+
onAxis(tailDist, halfHead),
|
|
2039
|
+
tip,
|
|
2040
|
+
onAxis(tailDist, -halfHead)
|
|
2041
|
+
];
|
|
2042
|
+
break;
|
|
2043
|
+
}
|
|
2044
|
+
case "tee":
|
|
2045
|
+
shaftEndDist = headLen * .4;
|
|
2046
|
+
headPts = [
|
|
2047
|
+
onAxis(headLen * .4, halfHead),
|
|
2048
|
+
onAxis(0, halfHead),
|
|
2049
|
+
onAxis(0, -halfHead),
|
|
2050
|
+
onAxis(headLen * .4, -halfHead)
|
|
2051
|
+
];
|
|
2052
|
+
break;
|
|
2053
|
+
default:
|
|
2054
|
+
shaftEndDist = headLen;
|
|
2055
|
+
headPts = [
|
|
2056
|
+
onAxis(headLen, halfHead),
|
|
2057
|
+
tip,
|
|
2058
|
+
onAxis(headLen, -halfHead)
|
|
2059
|
+
];
|
|
2060
|
+
break;
|
|
2061
|
+
}
|
|
2062
|
+
let spine = [...pts.slice(0, -1), onAxis(shaftEndDist)];
|
|
2063
|
+
if (smooth) spine = catmullRom(spine, 12);
|
|
2064
|
+
const leftSide = offsetPolyline(spine, halfShaft);
|
|
2065
|
+
const rightSide = offsetPolyline(spine, -halfShaft);
|
|
2066
|
+
const ring = [
|
|
2067
|
+
...leftSide,
|
|
2068
|
+
...headPts,
|
|
2069
|
+
...rightSide.slice().reverse()
|
|
2070
|
+
];
|
|
2071
|
+
ring.push(ring[0]);
|
|
2072
|
+
return {
|
|
2073
|
+
type: "FeatureCollection",
|
|
2074
|
+
features: [{
|
|
2075
|
+
type: "Feature",
|
|
2076
|
+
properties: {
|
|
2077
|
+
part: "body",
|
|
2078
|
+
fill: filled
|
|
2079
|
+
},
|
|
2080
|
+
geometry: {
|
|
2081
|
+
type: "Polygon",
|
|
2082
|
+
coordinates: [ring.map((p) => unproject(p[0], p[1]))]
|
|
2083
|
+
}
|
|
2084
|
+
}]
|
|
2085
|
+
};
|
|
2086
|
+
}
|
|
2087
|
+
const BLOCK_ARROW = defineControlMeasure({
|
|
2088
|
+
metadata: BLOCK_ARROW_METADATA,
|
|
2089
|
+
generator: createBlockArrow,
|
|
2090
|
+
defaultOptions: DEFAULT_BLOCK_ARROW_OPTIONS,
|
|
2091
|
+
rule: line1DrawRule
|
|
2092
|
+
});
|
|
2093
|
+
//#endregion
|
|
1824
2094
|
//#region src/internal/angle-utils.ts
|
|
1825
2095
|
/**
|
|
1826
2096
|
* Wraps an angle (radians) into the half-open range (-π, π].
|
|
@@ -2323,6 +2593,286 @@ const CANALIZE = defineControlMeasure({
|
|
|
2323
2593
|
rule: point12DrawRule
|
|
2324
2594
|
});
|
|
2325
2595
|
//#endregion
|
|
2596
|
+
//#region src/generators/cm99-generic-arrows/classicArrow.ts
|
|
2597
|
+
const DEFAULT_CLASSIC_ARROW_OPTIONS = {
|
|
2598
|
+
headStyle: "triangle",
|
|
2599
|
+
smooth: false,
|
|
2600
|
+
headLength: .2,
|
|
2601
|
+
headWidth: .14
|
|
2602
|
+
};
|
|
2603
|
+
const CLASSIC_ARROW_METADATA = {
|
|
2604
|
+
id: "classic-arrow",
|
|
2605
|
+
name: "Classic Arrow",
|
|
2606
|
+
description: "Clean straight arrow with a selectable head (triangle, barbed, concave, diamond, harpoon, swallowtail, chevron, circle, tee, open). Not a doctrinal symbol.",
|
|
2607
|
+
entity: "Generic Arrows",
|
|
2608
|
+
entityType: "Illustrative Arrow",
|
|
2609
|
+
entitySubtype: "Classic Arrow",
|
|
2610
|
+
value: "990002",
|
|
2611
|
+
minCoordinates: 2,
|
|
2612
|
+
geometry: "line",
|
|
2613
|
+
geometryTypes: ["LineString", "Polygon"],
|
|
2614
|
+
drawRule: "Line1",
|
|
2615
|
+
params: [
|
|
2616
|
+
{
|
|
2617
|
+
key: "smooth",
|
|
2618
|
+
label: "Smooth",
|
|
2619
|
+
description: "Round the shaft's corners by curving it through the control points.",
|
|
2620
|
+
type: "boolean"
|
|
2621
|
+
},
|
|
2622
|
+
{
|
|
2623
|
+
key: "headStyle",
|
|
2624
|
+
label: "Head style",
|
|
2625
|
+
description: "Arrowhead silhouette.",
|
|
2626
|
+
type: "enum",
|
|
2627
|
+
options: [
|
|
2628
|
+
{
|
|
2629
|
+
label: "Triangle",
|
|
2630
|
+
value: "triangle"
|
|
2631
|
+
},
|
|
2632
|
+
{
|
|
2633
|
+
label: "Barbed",
|
|
2634
|
+
value: "barbed"
|
|
2635
|
+
},
|
|
2636
|
+
{
|
|
2637
|
+
label: "Concave",
|
|
2638
|
+
value: "concave"
|
|
2639
|
+
},
|
|
2640
|
+
{
|
|
2641
|
+
label: "Diamond",
|
|
2642
|
+
value: "diamond"
|
|
2643
|
+
},
|
|
2644
|
+
{
|
|
2645
|
+
label: "Harpoon",
|
|
2646
|
+
value: "harpoon"
|
|
2647
|
+
},
|
|
2648
|
+
{
|
|
2649
|
+
label: "Swallowtail",
|
|
2650
|
+
value: "swallowtail"
|
|
2651
|
+
},
|
|
2652
|
+
{
|
|
2653
|
+
label: "Chevron",
|
|
2654
|
+
value: "chevron"
|
|
2655
|
+
},
|
|
2656
|
+
{
|
|
2657
|
+
label: "Circle",
|
|
2658
|
+
value: "circle"
|
|
2659
|
+
},
|
|
2660
|
+
{
|
|
2661
|
+
label: "Tee",
|
|
2662
|
+
value: "tee"
|
|
2663
|
+
},
|
|
2664
|
+
{
|
|
2665
|
+
label: "Open",
|
|
2666
|
+
value: "open"
|
|
2667
|
+
}
|
|
2668
|
+
]
|
|
2669
|
+
},
|
|
2670
|
+
{
|
|
2671
|
+
key: "headLength",
|
|
2672
|
+
label: "Head length",
|
|
2673
|
+
description: "Arrowhead length as a fraction of the total path length.",
|
|
2674
|
+
type: "number",
|
|
2675
|
+
min: .05,
|
|
2676
|
+
max: .5,
|
|
2677
|
+
step: .01
|
|
2678
|
+
},
|
|
2679
|
+
{
|
|
2680
|
+
key: "headWidth",
|
|
2681
|
+
label: "Head width",
|
|
2682
|
+
description: "Arrowhead base width as a fraction of the total path length.",
|
|
2683
|
+
type: "number",
|
|
2684
|
+
min: .05,
|
|
2685
|
+
max: .5,
|
|
2686
|
+
step: .01
|
|
2687
|
+
}
|
|
2688
|
+
]
|
|
2689
|
+
};
|
|
2690
|
+
/**
|
|
2691
|
+
* Generates a GeoJSON FeatureCollection for the Classic Arrow: a shaft
|
|
2692
|
+
* LineString (trimmed so it doesn't poke through the head) plus a head feature
|
|
2693
|
+
* whose silhouette follows `headStyle` — a filled Polygon for the solid heads,
|
|
2694
|
+
* or an open "V" LineString for `open`.
|
|
2695
|
+
*/
|
|
2696
|
+
function createClassicArrow(coordinates, options = {}) {
|
|
2697
|
+
if (coordinates.length < 2) return {
|
|
2698
|
+
type: "FeatureCollection",
|
|
2699
|
+
features: []
|
|
2700
|
+
};
|
|
2701
|
+
const { headStyle, smooth, headLength, headWidth } = {
|
|
2702
|
+
...DEFAULT_CLASSIC_ARROW_OPTIONS,
|
|
2703
|
+
...options
|
|
2704
|
+
};
|
|
2705
|
+
const axis = arrowAxis(coordinates);
|
|
2706
|
+
if (!axis) return {
|
|
2707
|
+
type: "FeatureCollection",
|
|
2708
|
+
features: [{
|
|
2709
|
+
type: "Feature",
|
|
2710
|
+
properties: { part: "shaft" },
|
|
2711
|
+
geometry: {
|
|
2712
|
+
type: "LineString",
|
|
2713
|
+
coordinates: coordinates.map((c) => [c[0], c[1]])
|
|
2714
|
+
}
|
|
2715
|
+
}]
|
|
2716
|
+
};
|
|
2717
|
+
const { pts, pathLength, tip, dir, perp, segLength } = axis;
|
|
2718
|
+
const headLen = Math.min(pathLength * headLength, segLength * .95);
|
|
2719
|
+
const headHalf = pathLength * headWidth / 2;
|
|
2720
|
+
const onAxis = (d) => [tip[0] - dir[0] * d, tip[1] - dir[1] * d];
|
|
2721
|
+
const off = (p, s) => [p[0] + perp[0] * s, p[1] + perp[1] * s];
|
|
2722
|
+
const base = onAxis(headLen);
|
|
2723
|
+
const cornerL = off(base, headHalf);
|
|
2724
|
+
const cornerR = off(base, -headHalf);
|
|
2725
|
+
const ll = (p) => unproject(p[0], p[1]);
|
|
2726
|
+
let headRing;
|
|
2727
|
+
let headFilled = true;
|
|
2728
|
+
let shaftEnd = base;
|
|
2729
|
+
switch (headStyle) {
|
|
2730
|
+
case "barbed": {
|
|
2731
|
+
const notch = onAxis(headLen * .55);
|
|
2732
|
+
headRing = [
|
|
2733
|
+
tip,
|
|
2734
|
+
cornerL,
|
|
2735
|
+
notch,
|
|
2736
|
+
cornerR
|
|
2737
|
+
];
|
|
2738
|
+
shaftEnd = notch;
|
|
2739
|
+
break;
|
|
2740
|
+
}
|
|
2741
|
+
case "concave": {
|
|
2742
|
+
const notch = onAxis(headLen * .3);
|
|
2743
|
+
headRing = [
|
|
2744
|
+
tip,
|
|
2745
|
+
cornerL,
|
|
2746
|
+
notch,
|
|
2747
|
+
cornerR
|
|
2748
|
+
];
|
|
2749
|
+
shaftEnd = notch;
|
|
2750
|
+
break;
|
|
2751
|
+
}
|
|
2752
|
+
case "harpoon":
|
|
2753
|
+
headRing = [
|
|
2754
|
+
tip,
|
|
2755
|
+
cornerL,
|
|
2756
|
+
base
|
|
2757
|
+
];
|
|
2758
|
+
shaftEnd = base;
|
|
2759
|
+
break;
|
|
2760
|
+
case "circle": {
|
|
2761
|
+
const radius = headHalf;
|
|
2762
|
+
const center = onAxis(radius);
|
|
2763
|
+
const segments = 24;
|
|
2764
|
+
headRing = [];
|
|
2765
|
+
for (let i = 0; i < segments; i++) {
|
|
2766
|
+
const a = i / segments * Math.PI * 2;
|
|
2767
|
+
headRing.push([center[0] + Math.cos(a) * radius, center[1] + Math.sin(a) * radius]);
|
|
2768
|
+
}
|
|
2769
|
+
shaftEnd = onAxis(Math.min(radius * 2, segLength * .95));
|
|
2770
|
+
break;
|
|
2771
|
+
}
|
|
2772
|
+
case "diamond": {
|
|
2773
|
+
const widest = onAxis(headLen * .5);
|
|
2774
|
+
headRing = [
|
|
2775
|
+
tip,
|
|
2776
|
+
off(widest, headHalf),
|
|
2777
|
+
base,
|
|
2778
|
+
off(widest, -headHalf)
|
|
2779
|
+
];
|
|
2780
|
+
shaftEnd = base;
|
|
2781
|
+
break;
|
|
2782
|
+
}
|
|
2783
|
+
case "swallowtail": {
|
|
2784
|
+
const tail = onAxis(Math.min(headLen * 1.25, segLength * .95));
|
|
2785
|
+
const notch = onAxis(headLen * .6);
|
|
2786
|
+
headRing = [
|
|
2787
|
+
tip,
|
|
2788
|
+
off(tail, headHalf),
|
|
2789
|
+
notch,
|
|
2790
|
+
off(tail, -headHalf)
|
|
2791
|
+
];
|
|
2792
|
+
shaftEnd = notch;
|
|
2793
|
+
break;
|
|
2794
|
+
}
|
|
2795
|
+
case "chevron": {
|
|
2796
|
+
const innerApex = onAxis(headLen * .5);
|
|
2797
|
+
headRing = [
|
|
2798
|
+
tip,
|
|
2799
|
+
cornerL,
|
|
2800
|
+
off(base, headHalf * .45),
|
|
2801
|
+
innerApex,
|
|
2802
|
+
off(base, -headHalf * .45),
|
|
2803
|
+
cornerR
|
|
2804
|
+
];
|
|
2805
|
+
shaftEnd = innerApex;
|
|
2806
|
+
break;
|
|
2807
|
+
}
|
|
2808
|
+
case "tee": {
|
|
2809
|
+
const barBack = onAxis(headLen * .4);
|
|
2810
|
+
headRing = [
|
|
2811
|
+
off(tip, headHalf),
|
|
2812
|
+
off(tip, -headHalf),
|
|
2813
|
+
off(barBack, -headHalf),
|
|
2814
|
+
off(barBack, headHalf)
|
|
2815
|
+
];
|
|
2816
|
+
shaftEnd = barBack;
|
|
2817
|
+
break;
|
|
2818
|
+
}
|
|
2819
|
+
case "open":
|
|
2820
|
+
headRing = [
|
|
2821
|
+
cornerL,
|
|
2822
|
+
tip,
|
|
2823
|
+
cornerR
|
|
2824
|
+
];
|
|
2825
|
+
headFilled = false;
|
|
2826
|
+
shaftEnd = tip;
|
|
2827
|
+
break;
|
|
2828
|
+
default:
|
|
2829
|
+
headRing = [
|
|
2830
|
+
tip,
|
|
2831
|
+
cornerL,
|
|
2832
|
+
cornerR
|
|
2833
|
+
];
|
|
2834
|
+
shaftEnd = base;
|
|
2835
|
+
break;
|
|
2836
|
+
}
|
|
2837
|
+
const shaftVertices = [...pts.slice(0, -1), shaftEnd];
|
|
2838
|
+
const shaftPts = smooth ? catmullRom(shaftVertices, 12) : shaftVertices;
|
|
2839
|
+
const headFeature = headFilled ? {
|
|
2840
|
+
type: "Feature",
|
|
2841
|
+
properties: {
|
|
2842
|
+
part: "head",
|
|
2843
|
+
fill: true
|
|
2844
|
+
},
|
|
2845
|
+
geometry: {
|
|
2846
|
+
type: "Polygon",
|
|
2847
|
+
coordinates: [[...headRing, headRing[0]].map(ll)]
|
|
2848
|
+
}
|
|
2849
|
+
} : {
|
|
2850
|
+
type: "Feature",
|
|
2851
|
+
properties: { part: "head" },
|
|
2852
|
+
geometry: {
|
|
2853
|
+
type: "LineString",
|
|
2854
|
+
coordinates: headRing.map(ll)
|
|
2855
|
+
}
|
|
2856
|
+
};
|
|
2857
|
+
return {
|
|
2858
|
+
type: "FeatureCollection",
|
|
2859
|
+
features: [{
|
|
2860
|
+
type: "Feature",
|
|
2861
|
+
properties: { part: "shaft" },
|
|
2862
|
+
geometry: {
|
|
2863
|
+
type: "LineString",
|
|
2864
|
+
coordinates: shaftPts.map(ll)
|
|
2865
|
+
}
|
|
2866
|
+
}, headFeature]
|
|
2867
|
+
};
|
|
2868
|
+
}
|
|
2869
|
+
const CLASSIC_ARROW = defineControlMeasure({
|
|
2870
|
+
metadata: CLASSIC_ARROW_METADATA,
|
|
2871
|
+
generator: createClassicArrow,
|
|
2872
|
+
defaultOptions: DEFAULT_CLASSIC_ARROW_OPTIONS,
|
|
2873
|
+
rule: line1DrawRule
|
|
2874
|
+
});
|
|
2875
|
+
//#endregion
|
|
2326
2876
|
//#region src/generators/cm34-mission-tasks/clear.ts
|
|
2327
2877
|
/**
|
|
2328
2878
|
* Default options for the CLEAR symbol.
|
|
@@ -4712,6 +5262,8 @@ const DEFINITIONS = {
|
|
|
4712
5262
|
"search-area": SEARCH_AREA,
|
|
4713
5263
|
"main-attack": MAIN_ATTACK,
|
|
4714
5264
|
"supporting-attack": SUPPORTING_ATTACK,
|
|
5265
|
+
"classic-arrow": CLASSIC_ARROW,
|
|
5266
|
+
"block-arrow": BLOCK_ARROW,
|
|
4715
5267
|
"airborne-attack": AIRBORNE_ATTACK,
|
|
4716
5268
|
"attack-helicopter": ATTACK_HELICOPTER,
|
|
4717
5269
|
"support-by-fire": SUPPORT_BY_FIRE,
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 96 48" width="96" height="48" role="img" aria-label="Airborne Attack"><rect width="96" height="48" rx="6" fill="#f8fafc" stroke="#e2e8f0"/><path d="M74.60 35.40 L59.40 35.40 L40.40 12.60 L40.40 5.00 L21.40 24.00 L40.40 43.00 L40.40 35.40 L59.40 12.60 L74.60 12.60" fill="none" stroke="#1e293b" stroke-width="1.25" stroke-linejoin="round" stroke-linecap="round"/></svg>
|
package/media/ambush.svg
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 96 48" width="96" height="48" role="img" aria-label="Ambush"><rect width="96" height="48" rx="6" fill="#f8fafc" stroke="#e2e8f0"/><path d="M51.17 20.83 L29.00 43.00" fill="none" stroke="#1e293b" stroke-width="1.25" stroke-linejoin="round" stroke-linecap="round"/><path d="M34.70 41.10 L29.00 43.00 L30.90 37.30" fill="none" stroke="#1e293b" stroke-width="1.25" stroke-linejoin="round" stroke-linecap="round"/><path d="M67.00 30.33 L65.75 29.90 L64.52 29.43 L63.33 28.94 L62.16 28.42 L61.02 27.87 L59.91 27.29 L58.82 26.69 L57.77 26.06 L56.74 25.39 L55.74 24.70 L54.77 23.98 L53.83 23.24 L52.91 22.46 L52.02 21.66 L51.17 20.83 L50.34 19.98 L49.54 19.09 L48.76 18.17 L48.02 17.23 L47.30 16.26 L46.61 15.26 L45.94 14.23 L45.31 13.18 L44.71 12.09 L44.13 10.98 L43.58 9.84 L43.06 8.67 L42.57 7.48 L42.10 6.25 L41.67 5.00" fill="none" stroke="#1e293b" stroke-width="1.25" stroke-linejoin="round" stroke-linecap="round"/><path d="M61.02 27.87 L64.82 24.07" fill="none" stroke="#1e293b" stroke-width="1.25" stroke-linejoin="round" stroke-linecap="round"/><path d="M55.74 24.70 L59.54 20.90" fill="none" stroke="#1e293b" stroke-width="1.25" stroke-linejoin="round" stroke-linecap="round"/><path d="M51.17 20.83 L54.97 17.03" fill="none" stroke="#1e293b" stroke-width="1.25" stroke-linejoin="round" stroke-linecap="round"/><path d="M47.30 16.26 L51.10 12.46" fill="none" stroke="#1e293b" stroke-width="1.25" stroke-linejoin="round" stroke-linecap="round"/><path d="M44.13 10.98 L47.93 7.18" fill="none" stroke="#1e293b" stroke-width="1.25" stroke-linejoin="round" stroke-linecap="round"/></svg>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 96 48" width="96" height="48" role="img" aria-label="Ditch - Completed"><rect width="96" height="48" rx="6" fill="#f8fafc" stroke="#e2e8f0"/><path d="M5.00 25.93 L7.26 22.07 L9.52 25.93 L5.00 25.93 Z" fill="#1e293b" fill-opacity="1" stroke="#1e293b" stroke-width="1.25" stroke-linejoin="round"/><path d="M9.52 25.93 L11.79 22.07 L14.06 25.93 L9.52 25.93 Z" fill="#1e293b" fill-opacity="1" stroke="#1e293b" stroke-width="1.25" stroke-linejoin="round"/><path d="M14.06 25.93 L16.32 22.07 L18.58 25.93 L14.06 25.93 Z" fill="#1e293b" fill-opacity="1" stroke="#1e293b" stroke-width="1.25" stroke-linejoin="round"/><path d="M18.58 25.93 L20.84 22.07 L23.10 25.93 L18.58 25.93 Z" fill="#1e293b" fill-opacity="1" stroke="#1e293b" stroke-width="1.25" stroke-linejoin="round"/><path d="M23.10 25.93 L25.36 22.07 L27.64 25.93 L23.10 25.93 Z" fill="#1e293b" fill-opacity="1" stroke="#1e293b" stroke-width="1.25" stroke-linejoin="round"/><path d="M27.64 25.93 L29.90 22.07 L32.16 25.93 L27.64 25.93 Z" fill="#1e293b" fill-opacity="1" stroke="#1e293b" stroke-width="1.25" stroke-linejoin="round"/><path d="M32.16 25.93 L34.42 22.07 L36.68 25.93 L32.16 25.93 Z" fill="#1e293b" fill-opacity="1" stroke="#1e293b" stroke-width="1.25" stroke-linejoin="round"/><path d="M36.68 25.93 L38.94 22.07 L41.21 25.93 L36.68 25.93 Z" fill="#1e293b" fill-opacity="1" stroke="#1e293b" stroke-width="1.25" stroke-linejoin="round"/><path d="M41.21 25.93 L43.48 22.07 L45.74 25.93 L41.21 25.93 Z" fill="#1e293b" fill-opacity="1" stroke="#1e293b" stroke-width="1.25" stroke-linejoin="round"/><path d="M45.74 25.93 L48.00 22.07 L50.26 25.93 L45.74 25.93 Z" fill="#1e293b" fill-opacity="1" stroke="#1e293b" stroke-width="1.25" stroke-linejoin="round"/><path d="M50.26 25.93 L52.52 22.07 L54.79 25.93 L50.26 25.93 Z" fill="#1e293b" fill-opacity="1" stroke="#1e293b" stroke-width="1.25" stroke-linejoin="round"/><path d="M54.79 25.93 L57.06 22.07 L59.32 25.93 L54.79 25.93 Z" fill="#1e293b" fill-opacity="1" stroke="#1e293b" stroke-width="1.25" stroke-linejoin="round"/><path d="M59.32 25.93 L61.58 22.07 L63.84 25.93 L59.32 25.93 Z" fill="#1e293b" fill-opacity="1" stroke="#1e293b" stroke-width="1.25" stroke-linejoin="round"/><path d="M63.84 25.93 L66.10 22.07 L68.36 25.93 L63.84 25.93 Z" fill="#1e293b" fill-opacity="1" stroke="#1e293b" stroke-width="1.25" stroke-linejoin="round"/><path d="M68.36 25.93 L70.64 22.07 L72.90 25.93 L68.36 25.93 Z" fill="#1e293b" fill-opacity="1" stroke="#1e293b" stroke-width="1.25" stroke-linejoin="round"/><path d="M72.90 25.93 L75.16 22.07 L77.42 25.93 L72.90 25.93 Z" fill="#1e293b" fill-opacity="1" stroke="#1e293b" stroke-width="1.25" stroke-linejoin="round"/><path d="M77.42 25.93 L79.68 22.07 L81.94 25.93 L77.42 25.93 Z" fill="#1e293b" fill-opacity="1" stroke="#1e293b" stroke-width="1.25" stroke-linejoin="round"/><path d="M81.94 25.93 L84.21 22.07 L86.48 25.93 L81.94 25.93 Z" fill="#1e293b" fill-opacity="1" stroke="#1e293b" stroke-width="1.25" stroke-linejoin="round"/><path d="M86.48 25.93 L88.74 22.07 L91.00 25.93 L86.48 25.93 Z" fill="#1e293b" fill-opacity="1" stroke="#1e293b" stroke-width="1.25" stroke-linejoin="round"/></svg>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 96 48" width="96" height="48" role="img" aria-label="Ditch - Under Construction"><rect width="96" height="48" rx="6" fill="#f8fafc" stroke="#e2e8f0"/><path d="M5.00 25.93 L91.00 25.93" fill="none" stroke="#1e293b" stroke-width="1.25" stroke-linejoin="round" stroke-linecap="round"/><path d="M5.00 25.93 L7.26 22.07 L9.52 25.93" fill="none" stroke="#1e293b" stroke-width="1.25" stroke-linejoin="round" stroke-linecap="round"/><path d="M9.52 25.93 L11.79 22.07 L14.06 25.93" fill="none" stroke="#1e293b" stroke-width="1.25" stroke-linejoin="round" stroke-linecap="round"/><path d="M14.06 25.93 L16.32 22.07 L18.58 25.93" fill="none" stroke="#1e293b" stroke-width="1.25" stroke-linejoin="round" stroke-linecap="round"/><path d="M18.58 25.93 L20.84 22.07 L23.10 25.93" fill="none" stroke="#1e293b" stroke-width="1.25" stroke-linejoin="round" stroke-linecap="round"/><path d="M23.10 25.93 L25.36 22.07 L27.64 25.93" fill="none" stroke="#1e293b" stroke-width="1.25" stroke-linejoin="round" stroke-linecap="round"/><path d="M27.64 25.93 L29.90 22.07 L32.16 25.93" fill="none" stroke="#1e293b" stroke-width="1.25" stroke-linejoin="round" stroke-linecap="round"/><path d="M32.16 25.93 L34.42 22.07 L36.68 25.93" fill="none" stroke="#1e293b" stroke-width="1.25" stroke-linejoin="round" stroke-linecap="round"/><path d="M36.68 25.93 L38.94 22.07 L41.21 25.93" fill="none" stroke="#1e293b" stroke-width="1.25" stroke-linejoin="round" stroke-linecap="round"/><path d="M41.21 25.93 L43.48 22.07 L45.74 25.93" fill="none" stroke="#1e293b" stroke-width="1.25" stroke-linejoin="round" stroke-linecap="round"/><path d="M45.74 25.93 L48.00 22.07 L50.26 25.93" fill="none" stroke="#1e293b" stroke-width="1.25" stroke-linejoin="round" stroke-linecap="round"/><path d="M50.26 25.93 L52.52 22.07 L54.79 25.93" fill="none" stroke="#1e293b" stroke-width="1.25" stroke-linejoin="round" stroke-linecap="round"/><path d="M54.79 25.93 L57.06 22.07 L59.32 25.93" fill="none" stroke="#1e293b" stroke-width="1.25" stroke-linejoin="round" stroke-linecap="round"/><path d="M59.32 25.93 L61.58 22.07 L63.84 25.93" fill="none" stroke="#1e293b" stroke-width="1.25" stroke-linejoin="round" stroke-linecap="round"/><path d="M63.84 25.93 L66.10 22.07 L68.36 25.93" fill="none" stroke="#1e293b" stroke-width="1.25" stroke-linejoin="round" stroke-linecap="round"/><path d="M68.36 25.93 L70.64 22.07 L72.90 25.93" fill="none" stroke="#1e293b" stroke-width="1.25" stroke-linejoin="round" stroke-linecap="round"/><path d="M72.90 25.93 L75.16 22.07 L77.42 25.93" fill="none" stroke="#1e293b" stroke-width="1.25" stroke-linejoin="round" stroke-linecap="round"/><path d="M77.42 25.93 L79.68 22.07 L81.94 25.93" fill="none" stroke="#1e293b" stroke-width="1.25" stroke-linejoin="round" stroke-linecap="round"/><path d="M81.94 25.93 L84.21 22.07 L86.48 25.93" fill="none" stroke="#1e293b" stroke-width="1.25" stroke-linejoin="round" stroke-linecap="round"/><path d="M86.48 25.93 L88.74 22.07 L91.00 25.93" fill="none" stroke="#1e293b" stroke-width="1.25" stroke-linejoin="round" stroke-linecap="round"/></svg>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 96 48" width="96" height="48" role="img" aria-label="Antitank Wall"><rect width="96" height="48" rx="6" fill="#f8fafc" stroke="#e2e8f0"/><path d="M5.00 22.07 L7.47 22.07 L9.30 25.93 L11.13 22.07 L16.07 22.07 L17.90 25.93 L19.73 22.07 L24.67 22.07 L26.50 25.93 L28.33 22.07 L33.27 22.07 L35.10 25.93 L36.93 22.07 L41.87 22.07 L43.70 25.93 L45.53 22.07 L50.47 22.07 L52.30 25.93 L54.13 22.07 L59.07 22.07 L60.90 25.93 L62.73 22.07 L67.67 22.07 L69.50 25.93 L71.33 22.07 L76.27 22.07 L78.10 25.93 L79.93 22.07 L84.87 22.07 L86.70 25.93 L88.53 22.07 L91.00 22.07" fill="none" stroke="#1e293b" stroke-width="1.25" stroke-linejoin="round" stroke-linecap="round"/></svg>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 96 48" width="96" height="48" role="img" aria-label="Attack by Fire"><rect width="96" height="48" rx="6" fill="#f8fafc" stroke="#e2e8f0"/><path d="M58.62 33.13 L67.00 33.13" fill="none" stroke="#1e293b" stroke-width="1.25" stroke-linejoin="round" stroke-linecap="round"/><path d="M38.87 13.38 L38.87 5.00" fill="none" stroke="#1e293b" stroke-width="1.25" stroke-linejoin="round" stroke-linecap="round"/><path d="M48.75 23.25 L29.00 43.00" fill="none" stroke="#1e293b" stroke-width="1.25" stroke-linejoin="round" stroke-linecap="round"/><path d="M58.62 33.13 L38.87 13.38" fill="none" stroke="#1e293b" stroke-width="1.25" stroke-linejoin="round" stroke-linecap="round"/><path d="M37.89 40.04 L29.00 43.00 L31.96 34.11" fill="none" stroke="#1e293b" stroke-width="1.25" stroke-linejoin="round" stroke-linecap="round"/></svg>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 96 48" width="96" height="48" role="img" aria-label="Attack Helicopter"><rect width="96" height="48" rx="6" fill="#f8fafc" stroke="#e2e8f0"/><path d="M74.60 35.40 L59.40 35.40 L40.40 12.60 L40.40 5.00 L21.40 24.00 L40.40 43.00 L40.40 35.40 L59.40 12.60 L74.60 12.60" fill="none" stroke="#1e293b" stroke-width="1.25" stroke-linejoin="round" stroke-linecap="round"/><path d="M49.90 36.83 L49.90 6.90" fill="none" stroke="#1e293b" stroke-width="1.25" stroke-linejoin="round" stroke-linecap="round"/><path d="M49.90 41.10 L53.32 36.83 L46.48 36.83 L49.90 41.10 Z" fill="#1e293b" fill-opacity="1" stroke="#1e293b" stroke-width="1.25" stroke-linejoin="round"/><path d="M44.77 6.90 L55.03 6.90" fill="none" stroke="#1e293b" stroke-width="1.25" stroke-linejoin="round" stroke-linecap="round"/><path d="M49.90 24.00 L46.48 26.05 L46.48 21.95 L49.90 24.00 Z" fill="#1e293b" fill-opacity="1" stroke="#1e293b" stroke-width="1.25" stroke-linejoin="round"/><path d="M49.90 24.00 L53.32 26.05 L53.32 21.95 L49.90 24.00 Z" fill="#1e293b" fill-opacity="1" stroke="#1e293b" stroke-width="1.25" stroke-linejoin="round"/></svg>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 96 48" width="96" height="48" role="img" aria-label="Block Arrow"><rect width="96" height="48" rx="6" fill="#f8fafc" stroke="#e2e8f0"/><path d="M5.00 21.42 L72.08 21.42 L72.08 16.26 L91.00 24.00 L72.08 31.74 L72.08 26.58 L5.00 26.58 L5.00 21.42 Z" fill="#1e293b" fill-opacity="1" stroke="#1e293b" stroke-width="1.25" stroke-linejoin="round"/></svg>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 96 48" width="96" height="48" role="img" aria-label="Block"><rect width="96" height="48" rx="6" fill="#f8fafc" stroke="#e2e8f0"/><path d="M76.50 5.00 L76.50 43.00" fill="none" stroke="#1e293b" stroke-width="1.25" stroke-linejoin="round" stroke-linecap="round"/><path d="M76.50 24.00 L51.80 24.00" fill="none" stroke="#1e293b" stroke-width="1.25" stroke-linejoin="round" stroke-linecap="round"/><path d="M44.20 24.00 L19.50 24.00" fill="none" stroke="#1e293b" stroke-width="1.25" stroke-linejoin="round" stroke-linecap="round"/><text x="48" y="24" fill="#1e293b" font-size="11" font-weight="600" text-anchor="middle" dominant-baseline="central" transform="rotate(0.000 48.000 24.000)">B</text></svg>
|
package/media/block.svg
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 96 48" width="96" height="48" role="img" aria-label="Block"><rect width="96" height="48" rx="6" fill="#f8fafc" stroke="#e2e8f0"/><path d="M76.50 5.00 L76.50 43.00 L76.50 24.00 L19.50 24.00" fill="none" stroke="#1e293b" stroke-width="1.25" stroke-linejoin="round" stroke-linecap="round"/></svg>
|
package/media/breach.svg
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 96 48" width="96" height="48" role="img" aria-label="Breach"><rect width="96" height="48" rx="6" fill="#f8fafc" stroke="#e2e8f0"/><path d="M17.28 35.72 L10.00 43.00" fill="none" stroke="#1e293b" stroke-width="1.25" stroke-linejoin="round" stroke-linecap="round"/><path d="M13.64 39.36 L13.64 5.00 L41.13 5.00" fill="none" stroke="#1e293b" stroke-width="1.25" stroke-linejoin="round" stroke-linecap="round"/><path d="M54.87 5.00 L82.36 5.00 L82.36 39.36" fill="none" stroke="#1e293b" stroke-width="1.25" stroke-linejoin="round" stroke-linecap="round"/><path d="M78.72 35.72 L86.00 43.00" fill="none" stroke="#1e293b" stroke-width="1.25" stroke-linejoin="round" stroke-linecap="round"/><text x="48" y="5" fill="#1e293b" font-size="11" font-weight="600" text-anchor="middle" dominant-baseline="central" transform="rotate(-270.000 48.000 5.000)">B</text></svg>
|
package/media/bypass.svg
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 96 48" width="96" height="48" role="img" aria-label="Bypass"><rect width="96" height="48" rx="6" fill="#f8fafc" stroke="#e2e8f0"/><path d="M14.56 33.88 L10.00 43.00 L5.44 33.88" fill="none" stroke="#1e293b" stroke-width="1.25" stroke-linejoin="round" stroke-linecap="round"/><path d="M10.00 43.00 L10.00 5.00 L40.40 5.00" fill="none" stroke="#1e293b" stroke-width="1.25" stroke-linejoin="round" stroke-linecap="round"/><path d="M55.60 5.00 L86.00 5.00 L86.00 43.00" fill="none" stroke="#1e293b" stroke-width="1.25" stroke-linejoin="round" stroke-linecap="round"/><path d="M90.56 33.88 L86.00 43.00 L81.44 33.88" fill="none" stroke="#1e293b" stroke-width="1.25" stroke-linejoin="round" stroke-linecap="round"/><text x="48" y="5" fill="#1e293b" font-size="11" font-weight="600" text-anchor="middle" dominant-baseline="central" transform="rotate(-270.000 48.000 5.000)">B</text></svg>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 96 48" width="96" height="48" role="img" aria-label="Canalize"><rect width="96" height="48" rx="6" fill="#f8fafc" stroke="#e2e8f0"/><path d="M17.28 43.00 L10.00 35.72" fill="none" stroke="#1e293b" stroke-width="1.25" stroke-linejoin="round" stroke-linecap="round"/><path d="M13.64 39.36 L13.64 5.00 L41.13 5.00" fill="none" stroke="#1e293b" stroke-width="1.25" stroke-linejoin="round" stroke-linecap="round"/><path d="M54.87 5.00 L82.36 5.00 L82.36 39.36" fill="none" stroke="#1e293b" stroke-width="1.25" stroke-linejoin="round" stroke-linecap="round"/><path d="M78.72 43.00 L86.00 35.72" fill="none" stroke="#1e293b" stroke-width="1.25" stroke-linejoin="round" stroke-linecap="round"/><text x="48" y="5" fill="#1e293b" font-size="11" font-weight="600" text-anchor="middle" dominant-baseline="central" transform="rotate(-270.000 48.000 5.000)">C</text></svg>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 96 48" width="96" height="48" role="img" aria-label="Classic Arrow"><rect width="96" height="48" rx="6" fill="#f8fafc" stroke="#e2e8f0"/><path d="M5.00 24.00 L73.80 24.00" fill="none" stroke="#1e293b" stroke-width="1.25" stroke-linejoin="round" stroke-linecap="round"/><path d="M91.00 24.00 L73.80 17.98 L73.80 30.02 L91.00 24.00 Z" fill="#1e293b" fill-opacity="1" stroke="#1e293b" stroke-width="1.25" stroke-linejoin="round"/></svg>
|
package/media/clear.svg
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 96 48" width="96" height="48" role="img" aria-label="Clear"><rect width="96" height="48" rx="6" fill="#f8fafc" stroke="#e2e8f0"/><path d="M10.00 43.00 L86.00 43.00" fill="none" stroke="#1e293b" stroke-width="1.25" stroke-linejoin="round" stroke-linecap="round"/><path d="M21.40 5.00 L21.40 43.00" fill="none" stroke="#1e293b" stroke-width="1.25" stroke-linejoin="round" stroke-linecap="round"/><path d="M29.00 31.60 L21.40 43.00 L13.80 31.60" fill="none" stroke="#1e293b" stroke-width="1.25" stroke-linejoin="round" stroke-linecap="round"/><path d="M48.00 5.00 L48.00 20.20" fill="none" stroke="#1e293b" stroke-width="1.25" stroke-linejoin="round" stroke-linecap="round"/><path d="M48.00 27.80 L48.00 43.00" fill="none" stroke="#1e293b" stroke-width="1.25" stroke-linejoin="round" stroke-linecap="round"/><path d="M55.60 31.60 L48.00 43.00 L40.40 31.60" fill="none" stroke="#1e293b" stroke-width="1.25" stroke-linejoin="round" stroke-linecap="round"/><path d="M74.60 5.00 L74.60 43.00" fill="none" stroke="#1e293b" stroke-width="1.25" stroke-linejoin="round" stroke-linecap="round"/><path d="M82.20 31.60 L74.60 43.00 L67.00 31.60" fill="none" stroke="#1e293b" stroke-width="1.25" stroke-linejoin="round" stroke-linecap="round"/><text x="48" y="24" fill="#1e293b" font-size="11" font-weight="600" text-anchor="middle" dominant-baseline="central" transform="rotate(-270.000 48.000 24.000)">C</text></svg>
|
package/media/delay.svg
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 96 48" width="96" height="48" role="img" aria-label="Delay"><rect width="96" height="48" rx="6" fill="#f8fafc" stroke="#e2e8f0"/><path d="M5.59 38.93 L33.41 38.93" fill="none" stroke="#1e293b" stroke-width="1.25" stroke-linejoin="round" stroke-linecap="round"/><path d="M45.62 38.93 L73.45 38.93" fill="none" stroke="#1e293b" stroke-width="1.25" stroke-linejoin="round" stroke-linecap="round"/><path d="M13.73 43.00 L5.59 38.93 L13.73 34.86" fill="none" stroke="#1e293b" stroke-width="1.25" stroke-linejoin="round" stroke-linecap="round"/><path d="M73.45 38.93 L75.11 38.85 L76.76 38.60 L78.37 38.20 L79.94 37.64 L81.44 36.93 L82.87 36.07 L84.21 35.08 L85.44 33.96 L86.56 32.73 L87.55 31.39 L88.41 29.96 L89.12 28.46 L89.68 26.89 L90.09 25.28 L90.33 23.63 L90.41 21.96 L90.33 20.30 L90.09 18.65 L89.68 17.04 L89.12 15.47 L88.41 13.97 L87.55 12.54 L86.56 11.20 L85.44 9.97 L84.21 8.85 L82.87 7.86 L81.44 7.00 L79.94 6.29 L78.37 5.73 L76.76 5.33 L75.11 5.08 L73.45 5.00" fill="none" stroke="#1e293b" stroke-width="1.25" stroke-linejoin="round" stroke-linecap="round"/><text x="39.51785714285714" y="38.92857142857143" fill="#1e293b" font-size="11" font-weight="600" text-anchor="middle" dominant-baseline="central" transform="rotate(0.000 39.518 38.929)">D</text></svg>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 96 48" width="96" height="48" role="img" aria-label="Disrupt"><rect width="96" height="48" rx="6" fill="#f8fafc" stroke="#e2e8f0"/><path d="M40.33 9.38 L40.33 38.62" fill="none" stroke="#1e293b" stroke-width="1.25" stroke-linejoin="round" stroke-linecap="round"/><path d="M40.33 9.38 L75.40 9.38" fill="none" stroke="#1e293b" stroke-width="1.25" stroke-linejoin="round" stroke-linecap="round"/><path d="M40.33 24.00 L60.06 24.00" fill="none" stroke="#1e293b" stroke-width="1.25" stroke-linejoin="round" stroke-linecap="round"/><path d="M40.33 38.62 L51.29 38.62" fill="none" stroke="#1e293b" stroke-width="1.25" stroke-linejoin="round" stroke-linecap="round"/><path d="M11.83 24.00 L40.33 24.00" fill="none" stroke="#1e293b" stroke-width="1.25" stroke-linejoin="round" stroke-linecap="round"/><path d="M75.40 5.00 L84.17 9.38 L75.40 13.77 L75.40 5.00 Z" fill="#1e293b" fill-opacity="1" stroke="#1e293b" stroke-width="1.25" stroke-linejoin="round"/><path d="M60.06 19.62 L68.83 24.00 L60.06 28.38 L60.06 19.62 Z" fill="#1e293b" fill-opacity="1" stroke="#1e293b" stroke-width="1.25" stroke-linejoin="round"/><path d="M51.29 34.23 L60.06 38.62 L51.29 43.00 L51.29 34.23 Z" fill="#1e293b" fill-opacity="1" stroke="#1e293b" stroke-width="1.25" stroke-linejoin="round"/></svg>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 96 48" width="96" height="48" role="img" aria-label="Final Protective Fire (Left)"><rect width="96" height="48" rx="6" fill="#f8fafc" stroke="#e2e8f0"/><path d="M48.00 43.00 L10.00 5.00" fill="none" stroke="#1e293b" stroke-width="1.25" stroke-linejoin="round" stroke-linecap="round"/><path d="M10.87 9.44 L10.00 5.00 L14.45 5.88" fill="none" stroke="#1e293b" stroke-width="1.25" stroke-linejoin="round" stroke-linecap="round"/><path d="M48.00 43.00 L86.00 5.00" fill="none" stroke="#1e293b" stroke-width="1.25" stroke-linejoin="round" stroke-linecap="round"/><path d="M81.55 5.88 L86.00 5.00 L85.13 9.44" fill="none" stroke="#1e293b" stroke-width="1.25" stroke-linejoin="round" stroke-linecap="round"/><path d="M44.20 39.20 L13.80 8.80 L14.94 7.66 L45.34 38.06 L44.20 39.20 Z" fill="#1e293b" fill-opacity="1" stroke="#1e293b" stroke-width="1.25" stroke-linejoin="round"/></svg>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 96 48" width="96" height="48" role="img" aria-label="Final Protective Fire (Right)"><rect width="96" height="48" rx="6" fill="#f8fafc" stroke="#e2e8f0"/><path d="M48.00 43.00 L10.00 5.00" fill="none" stroke="#1e293b" stroke-width="1.25" stroke-linejoin="round" stroke-linecap="round"/><path d="M10.87 9.44 L10.00 5.00 L14.45 5.88" fill="none" stroke="#1e293b" stroke-width="1.25" stroke-linejoin="round" stroke-linecap="round"/><path d="M48.00 43.00 L86.00 5.00" fill="none" stroke="#1e293b" stroke-width="1.25" stroke-linejoin="round" stroke-linecap="round"/><path d="M81.55 5.88 L86.00 5.00 L85.13 9.44" fill="none" stroke="#1e293b" stroke-width="1.25" stroke-linejoin="round" stroke-linecap="round"/><path d="M51.80 39.20 L82.20 8.80 L81.06 7.66 L50.66 38.06 L51.80 39.20 Z" fill="#1e293b" fill-opacity="1" stroke="#1e293b" stroke-width="1.25" stroke-linejoin="round"/></svg>
|
package/media/fix.svg
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 96 48" width="96" height="48" role="img" aria-label="Fix"><rect width="96" height="48" rx="6" fill="#f8fafc" stroke="#e2e8f0"/><path d="M5.00 24.00 L22.20 24.00 L32.52 31.89 L48.00 16.11 L63.48 31.89 L73.80 24.00 L91.00 24.00" fill="none" stroke="#1e293b" stroke-width="1.25" stroke-linejoin="round" stroke-linecap="round"/><path d="M91.00 24.00 L79.73 31.89" fill="none" stroke="#1e293b" stroke-width="1.25" stroke-linejoin="round" stroke-linecap="round"/><path d="M91.00 24.00 L79.73 16.11" fill="none" stroke="#1e293b" stroke-width="1.25" stroke-linejoin="round" stroke-linecap="round"/></svg>
|
package/media/flot.svg
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 96 48" width="96" height="48" role="img" aria-label="Forward line of own troops (FLOT)"><rect width="96" height="48" rx="6" fill="#f8fafc" stroke="#e2e8f0"/><path d="M5.00 27.86 L5.15 26.35 L5.58 24.90 L6.31 23.56 L7.27 22.39 L8.44 21.45 L9.76 20.72 L11.23 20.28 L12.72 20.14 L14.24 20.28 L15.68 20.72 L17.02 21.45 L18.19 22.39 L19.16 23.56 L19.86 24.90 L20.31 26.35 L20.45 27.86 L20.60 26.35 L21.05 24.90 L21.75 23.56 L22.72 22.39 L23.89 21.45 L25.23 20.72 L26.67 20.28 L28.17 20.14 L29.68 20.28 L31.13 20.72 L32.47 21.45 L33.64 22.39 L34.60 23.56 L35.31 24.90 L35.75 26.35 L35.91 27.86 L36.05 26.35 L36.49 24.90 L37.20 23.56 L38.16 22.39 L39.33 21.45 L40.67 20.72 L42.12 20.28 L43.63 20.14 L45.13 20.28 L46.59 20.72 L47.91 21.45 L49.08 22.39 L50.05 23.56 L50.77 24.90 L51.20 26.35 L51.35 27.86 L51.51 26.35 L51.94 24.90 L52.66 23.56 L53.62 22.39 L54.79 21.45 L56.12 20.72 L57.56 20.28 L59.08 20.14 L60.59 20.28 L62.04 20.72 L63.38 21.45 L64.55 22.39 L65.51 23.56 L66.21 24.90 L66.66 26.35 L66.80 27.86 L66.95 26.35 L67.38 24.90 L68.11 23.56 L69.07 22.39 L70.24 21.45 L71.58 20.72 L73.03 20.28 L74.52 20.14 L76.04 20.28 L77.48 20.72 L78.82 21.45 L79.99 22.39 L80.96 23.56 L81.66 24.90 L82.11 26.35 L82.26 27.86 L82.52 26.37 L83.28 25.06 L84.45 24.08 L85.87 23.56 L87.39 23.56 L88.82 24.08 L89.99 25.06 L90.74 26.37 L91.00 27.86" fill="none" stroke="#1e293b" stroke-width="1.25" stroke-linejoin="round" stroke-linecap="round"/></svg>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 96 48" width="96" height="48" role="img" aria-label="Fortified Area"><rect width="96" height="48" rx="6" fill="#f8fafc" stroke="#e2e8f0"/><path d="M10.00 43.00 L11.73 43.00 L11.73 39.59 L15.18 39.59 L15.18 43.00 L16.91 43.00 L18.63 43.00 L18.63 39.59 L22.09 39.59 L22.09 43.00 L23.82 43.00 L25.54 43.00 L25.54 39.59 L29.00 39.59 L29.00 43.00 L30.73 43.00 L32.46 43.00 L32.46 39.59 L35.91 39.59 L35.91 43.00 L37.63 43.00 L39.37 43.00 L39.37 39.59 L42.82 39.59 L42.82 43.00 L44.54 43.00 L46.27 43.00 L46.27 39.59 L49.73 39.59 L49.73 43.00 L51.46 43.00 L53.18 43.00 L53.18 39.59 L56.63 39.59 L56.63 43.00 L58.37 43.00 L60.09 43.00 L60.09 39.59 L63.54 39.59 L63.54 43.00 L65.27 43.00 L67.00 43.00 L67.00 39.59 L70.46 39.59 L70.46 43.00 L72.18 43.00 L73.91 43.00 L73.91 39.59 L77.37 39.59 L77.37 43.00 L79.09 43.00 L80.82 43.00 L80.82 39.59 L84.27 39.59 L84.27 43.00 L86.00 43.00 L86.00 41.42 L82.59 41.42 L82.59 38.25 L86.00 38.25 L86.00 36.67 L86.00 35.08 L82.59 35.08 L82.59 31.92 L86.00 31.92 L86.00 30.33 L86.00 28.75 L82.59 28.75 L82.59 25.58 L86.00 25.58 L86.00 24.00 L86.00 22.42 L82.59 22.42 L82.59 19.25 L86.00 19.25 L86.00 17.67 L86.00 16.08 L82.59 16.08 L82.59 12.92 L86.00 12.92 L86.00 11.33 L86.00 9.75 L82.59 9.75 L82.59 6.58 L86.00 6.58 L86.00 5.00 L84.27 5.00 L84.27 8.41 L80.82 8.41 L80.82 5.00 L79.09 5.00 L77.37 5.00 L77.37 8.41 L73.91 8.41 L73.91 5.00 L72.18 5.00 L70.46 5.00 L70.46 8.41 L67.00 8.41 L67.00 5.00 L65.27 5.00 L63.54 5.00 L63.54 8.41 L60.09 8.41 L60.09 5.00 L58.37 5.00 L56.63 5.00 L56.63 8.41 L53.18 8.41 L53.18 5.00 L51.46 5.00 L49.73 5.00 L49.73 8.41 L46.27 8.41 L46.27 5.00 L44.54 5.00 L42.82 5.00 L42.82 8.41 L39.37 8.41 L39.37 5.00 L37.63 5.00 L35.91 5.00 L35.91 8.41 L32.46 8.41 L32.46 5.00 L30.73 5.00 L29.00 5.00 L29.00 8.41 L25.54 8.41 L25.54 5.00 L23.82 5.00 L22.09 5.00 L22.09 8.41 L18.63 8.41 L18.63 5.00 L16.91 5.00 L15.18 5.00 L15.18 8.41 L11.73 8.41 L11.73 5.00 L10.00 5.00 L10.00 6.58 L13.41 6.58 L13.41 9.75 L10.00 9.75 L10.00 11.33 L10.00 12.92 L13.41 12.92 L13.41 16.08 L10.00 16.08 L10.00 17.67 L10.00 19.25 L13.41 19.25 L13.41 22.42 L10.00 22.42 L10.00 24.00 L10.00 25.58 L13.41 25.58 L13.41 28.75 L10.00 28.75 L10.00 30.33 L10.00 31.92 L13.41 31.92 L13.41 35.08 L10.00 35.08 L10.00 36.67 L10.00 38.25 L13.41 38.25 L13.41 41.42 L10.00 41.42 L10.00 43.00 Z" fill="#1e293b" fill-opacity="0" stroke="#1e293b" stroke-width="1.25" stroke-linejoin="round"/></svg>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 96 48" width="96" height="48" role="img" aria-label="Fortified Line"><rect width="96" height="48" rx="6" fill="#f8fafc" stroke="#e2e8f0"/><path d="M5.00 27.86 L8.58 27.86 L8.58 20.14 L15.75 20.14 L15.75 27.86 L19.33 27.86 L22.92 27.86 L22.92 20.14 L30.08 20.14 L30.08 27.86 L33.67 27.86 L37.25 27.86 L37.25 20.14 L44.42 20.14 L44.42 27.86 L48.00 27.86 L51.58 27.86 L51.58 20.14 L58.75 20.14 L58.75 27.86 L62.33 27.86 L65.92 27.86 L65.92 20.14 L73.08 20.14 L73.08 27.86 L76.67 27.86 L80.25 27.86 L80.25 20.14 L87.42 20.14 L87.42 27.86 L91.00 27.86" fill="none" stroke="#1e293b" stroke-width="1.25" stroke-linejoin="round" stroke-linecap="round"/></svg>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 96 48" width="96" height="48" role="img" aria-label="Isolate"><rect width="96" height="48" rx="6" fill="#f8fafc" stroke="#e2e8f0"/><path d="M67.00 24.00 L66.91 25.85 L66.64 27.69 L66.19 29.48 L65.57 31.23 L64.78 32.91 L63.83 34.50 L62.73 36.00 L61.49 37.38 L60.12 38.63 L58.64 39.74 L57.06 40.70 L55.39 41.50 L53.65 42.14 L51.85 42.60 L50.02 42.89 L48.17 43.00 L46.31 42.93 L44.48 42.67 L42.67 42.24 L40.92 41.63 L39.24 40.86 L37.63 39.93 L36.13 38.84 L34.74 37.61 L33.48 36.26 L32.35 34.78 L31.38 33.21 L30.56 31.54 L29.91 29.81 L29.43 28.02 L29.12 26.19 L29.00 24.34 L29.06 22.48 L29.30 20.64 L29.71 18.84 L30.30 17.08 L31.06 15.39 L31.98 13.78 L33.05 12.27 L34.27 10.87 L35.61 9.59 L37.08 8.45 L38.64 7.46 L40.30 6.63 L42.03 5.96 L43.82 5.46 L45.64 5.14 L47.49 5.01 L49.35 5.05 L51.19 5.27 L53.00 5.67 L54.76 6.24 L56.46 6.99 L58.08 7.89 L59.60 8.95 L61.01 10.15 L62.30 11.49 L63.45 12.94 L64.45 14.50" fill="none" stroke="#1e293b" stroke-width="1.25" stroke-linejoin="round" stroke-linecap="round"/><path d="M64.22 10.68 L64.45 14.50 L61.26 12.39" fill="none" stroke="#1e293b" stroke-width="1.25" stroke-linejoin="round" stroke-linecap="round"/><path d="M62.94 35.74 L61.07 32.48 L64.80 32.87" fill="none" stroke="#1e293b" stroke-width="1.25" stroke-linejoin="round" stroke-linecap="round"/><path d="M54.13 41.98 L54.33 38.23 L57.26 40.59" fill="none" stroke="#1e293b" stroke-width="1.25" stroke-linejoin="round" stroke-linecap="round"/><path d="M43.35 42.42 L45.56 39.39 L46.73 42.96" fill="none" stroke="#1e293b" stroke-width="1.25" stroke-linejoin="round" stroke-linecap="round"/><path d="M34.06 36.92 L37.57 35.58 L36.61 39.21" fill="none" stroke="#1e293b" stroke-width="1.25" stroke-linejoin="round" stroke-linecap="round"/><path d="M29.28 27.24 L32.95 28.03 L30.16 30.55" fill="none" stroke="#1e293b" stroke-width="1.25" stroke-linejoin="round" stroke-linecap="round"/><path d="M30.53 16.52 L33.18 19.18 L29.47 19.78" fill="none" stroke="#1e293b" stroke-width="1.25" stroke-linejoin="round" stroke-linecap="round"/><path d="M37.42 8.22 L38.19 11.89 L34.76 10.37" fill="none" stroke="#1e293b" stroke-width="1.25" stroke-linejoin="round" stroke-linecap="round"/><path d="M47.72 5.00 L46.37 8.50 L44.32 5.36" fill="none" stroke="#1e293b" stroke-width="1.25" stroke-linejoin="round" stroke-linecap="round"/><path d="M58.11 7.91 L55.07 10.12 L55.07 6.36" fill="none" stroke="#1e293b" stroke-width="1.25" stroke-linejoin="round" stroke-linecap="round"/></svg>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 96 48" width="96" height="48" role="img" aria-label="Main Attack"><rect width="96" height="48" rx="6" fill="#f8fafc" stroke="#e2e8f0"/><path d="M74.60 35.40 L59.40 35.40 L40.40 35.40" fill="none" stroke="#1e293b" stroke-width="1.25" stroke-linejoin="round" stroke-linecap="round"/><path d="M74.60 12.60 L59.40 12.60 L40.40 12.60" fill="none" stroke="#1e293b" stroke-width="1.25" stroke-linejoin="round" stroke-linecap="round"/><path d="M40.40 43.00 L21.40 24.00 L40.40 5.00 L40.40 12.60 L29.00 24.00 L40.40 35.40 L40.40 43.00" fill="none" stroke="#1e293b" stroke-width="1.25" stroke-linejoin="round" stroke-linecap="round"/></svg>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 96 48" width="96" height="48" role="img" aria-label="Obstacle Bypass Difficult"><rect width="96" height="48" rx="6" fill="#f8fafc" stroke="#e2e8f0"/><path d="M24.25 8.17 L28.05 10.80 L24.25 13.45 L28.05 16.08 L24.25 18.72 L28.05 21.36 L24.25 24.00 L28.05 26.64 L24.25 29.28 L28.05 31.92 L24.25 34.55 L28.05 37.20 L24.25 39.83" fill="none" stroke="#1e293b" stroke-width="1.25" stroke-linejoin="round" stroke-linecap="round"/><path d="M24.25 8.17 L65.42 8.17" fill="none" stroke="#1e293b" stroke-width="1.25" stroke-linejoin="round" stroke-linecap="round"/><path d="M24.25 39.83 L65.42 39.83" fill="none" stroke="#1e293b" stroke-width="1.25" stroke-linejoin="round" stroke-linecap="round"/><path d="M65.42 5.00 L71.75 8.17 L65.42 11.33 L65.42 5.00 Z" fill="#1e293b" fill-opacity="1" stroke="#1e293b" stroke-width="1.25" stroke-linejoin="round"/><path d="M65.42 36.67 L71.75 39.83 L65.42 43.00 L65.42 36.67 Z" fill="#1e293b" fill-opacity="1" stroke="#1e293b" stroke-width="1.25" stroke-linejoin="round"/></svg>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 96 48" width="96" height="48" role="img" aria-label="Obstacle Bypass Easy"><rect width="96" height="48" rx="6" fill="#f8fafc" stroke="#e2e8f0"/><path d="M24.25 8.17 L24.25 39.83" fill="none" stroke="#1e293b" stroke-width="1.25" stroke-linejoin="round" stroke-linecap="round"/><path d="M24.25 8.17 L65.42 8.17" fill="none" stroke="#1e293b" stroke-width="1.25" stroke-linejoin="round" stroke-linecap="round"/><path d="M24.25 39.83 L65.42 39.83" fill="none" stroke="#1e293b" stroke-width="1.25" stroke-linejoin="round" stroke-linecap="round"/><path d="M65.42 5.00 L71.75 8.17 L65.42 11.33 L65.42 5.00 Z" fill="#1e293b" fill-opacity="1" stroke="#1e293b" stroke-width="1.25" stroke-linejoin="round"/><path d="M65.42 36.67 L71.75 39.83 L65.42 43.00 L65.42 36.67 Z" fill="#1e293b" fill-opacity="1" stroke="#1e293b" stroke-width="1.25" stroke-linejoin="round"/></svg>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 96 48" width="96" height="48" role="img" aria-label="Obstacle Bypass Impossible"><rect width="96" height="48" rx="6" fill="#f8fafc" stroke="#e2e8f0"/><path d="M25.20 8.17 L25.20 22.73" fill="none" stroke="#1e293b" stroke-width="1.25" stroke-linejoin="round" stroke-linecap="round"/><path d="M25.20 25.27 L25.20 39.83" fill="none" stroke="#1e293b" stroke-width="1.25" stroke-linejoin="round" stroke-linecap="round"/><path d="M25.20 8.17 L66.37 8.17" fill="none" stroke="#1e293b" stroke-width="1.25" stroke-linejoin="round" stroke-linecap="round"/><path d="M25.20 39.83 L66.37 39.83" fill="none" stroke="#1e293b" stroke-width="1.25" stroke-linejoin="round" stroke-linecap="round"/><path d="M27.10 22.73 L23.30 22.73" fill="none" stroke="#1e293b" stroke-width="1.25" stroke-linejoin="round" stroke-linecap="round"/><path d="M27.10 25.27 L23.30 25.27" fill="none" stroke="#1e293b" stroke-width="1.25" stroke-linejoin="round" stroke-linecap="round"/><path d="M66.37 5.00 L72.70 8.17 L66.37 11.33 L66.37 5.00 Z" fill="#1e293b" fill-opacity="1" stroke="#1e293b" stroke-width="1.25" stroke-linejoin="round"/><path d="M66.37 36.67 L72.70 39.83 L66.37 43.00 L66.37 36.67 Z" fill="#1e293b" fill-opacity="1" stroke="#1e293b" stroke-width="1.25" stroke-linejoin="round"/></svg>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 96 48" width="96" height="48" role="img" aria-label="Principal Direction of Fire"><rect width="96" height="48" rx="6" fill="#f8fafc" stroke="#e2e8f0"/><path d="M48.00 43.00 L10.00 5.00" fill="none" stroke="#1e293b" stroke-width="1.25" stroke-linejoin="round" stroke-linecap="round"/><path d="M10.87 9.44 L10.00 5.00 L14.45 5.88" fill="none" stroke="#1e293b" stroke-width="1.25" stroke-linejoin="round" stroke-linecap="round"/><path d="M48.00 43.00 L86.00 5.00" fill="none" stroke="#1e293b" stroke-width="1.25" stroke-linejoin="round" stroke-linecap="round"/><path d="M81.55 5.88 L86.00 5.00 L85.13 9.44" fill="none" stroke="#1e293b" stroke-width="1.25" stroke-linejoin="round" stroke-linecap="round"/></svg>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 96 48" width="96" height="48" role="img" aria-label="Search Area"><rect width="96" height="48" rx="6" fill="#f8fafc" stroke="#e2e8f0"/><path d="M14.67 38.33 L51.33 43.00 L44.67 33.67 L73.40 37.32" fill="none" stroke="#1e293b" stroke-width="1.25" stroke-linejoin="round" stroke-linecap="round"/><path d="M14.67 38.33 L30.67 17.67 L32.00 25.67 L44.54 9.47" fill="none" stroke="#1e293b" stroke-width="1.25" stroke-linejoin="round" stroke-linecap="round"/><path d="M81.33 38.33 L73.90 33.35 L72.89 41.29 L81.33 38.33 Z" fill="#1e293b" fill-opacity="1" stroke="#1e293b" stroke-width="1.25" stroke-linejoin="round"/><path d="M48.00 5.00 L42.30 7.74 L46.77 11.21 L48.00 5.00 Z" fill="#1e293b" fill-opacity="1" stroke="#1e293b" stroke-width="1.25" stroke-linejoin="round"/></svg>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 96 48" width="96" height="48" role="img" aria-label="Support By Fire"><rect width="96" height="48" rx="6" fill="#f8fafc" stroke="#e2e8f0"/><path d="M26.50 33.78 L17.38 42.89" fill="none" stroke="#1e293b" stroke-width="1.25" stroke-linejoin="round" stroke-linecap="round"/><path d="M69.50 33.78 L78.62 42.89" fill="none" stroke="#1e293b" stroke-width="1.25" stroke-linejoin="round" stroke-linecap="round"/><path d="M26.50 33.78 L5.00 5.11" fill="none" stroke="#1e293b" stroke-width="1.25" stroke-linejoin="round" stroke-linecap="round"/><path d="M69.50 33.78 L91.00 5.11" fill="none" stroke="#1e293b" stroke-width="1.25" stroke-linejoin="round" stroke-linecap="round"/><path d="M26.50 33.78 L69.50 33.78" fill="none" stroke="#1e293b" stroke-width="1.25" stroke-linejoin="round" stroke-linecap="round"/><path d="M7.15 16.93 L5.00 5.11 L15.75 10.48" fill="none" stroke="#1e293b" stroke-width="1.25" stroke-linejoin="round" stroke-linecap="round"/><path d="M80.25 10.48 L91.00 5.11 L88.85 16.93" fill="none" stroke="#1e293b" stroke-width="1.25" stroke-linejoin="round" stroke-linecap="round"/></svg>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 96 48" width="96" height="48" role="img" aria-label="Supporting Attack"><rect width="96" height="48" rx="6" fill="#f8fafc" stroke="#e2e8f0"/><path d="M74.60 35.40 L59.40 35.40 L40.40 35.40 L40.40 43.00 L21.40 24.00 L40.40 5.00 L40.40 12.60 L59.40 12.60 L74.60 12.60" fill="none" stroke="#1e293b" stroke-width="1.25" stroke-linejoin="round" stroke-linecap="round"/></svg>
|
package/media/turn.svg
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 96 48" width="96" height="48" role="img" aria-label="Turn"><rect width="96" height="48" rx="6" fill="#f8fafc" stroke="#e2e8f0"/><path d="M91.00 13.89 L90.17 14.91 L89.31 15.91 L88.44 16.89 L87.53 17.84 L86.61 18.77 L85.66 19.68 L84.69 20.57 L83.69 21.43 L82.68 22.26 L81.64 23.08 L80.59 23.86 L79.52 24.62 L78.43 25.36 L77.32 26.06 L76.20 26.74 L75.06 27.39 L73.89 28.02 L72.72 28.61 L71.54 29.18 L70.34 29.71 L69.13 30.22 L67.90 30.69 L66.67 31.14 L65.42 31.56 L64.17 31.94 L62.90 32.30 L61.62 32.62 L60.34 32.91 L59.05 33.17 L57.76 33.40 L56.46 33.60 L55.16 33.76 L53.85 33.89 L52.54 33.99 L51.23 34.06 L49.92 34.10 L48.60 34.11 L47.29 34.07 L45.97 34.01 L44.66 33.92 L43.36 33.80 L42.05 33.64 L40.75 33.45 L39.45 33.23 L38.16 32.98 L36.88 32.69 L35.61 32.38 L34.34 32.02 L33.08 31.65 L31.83 31.24 L30.59 30.80 L29.36 30.33 L28.15 29.83 L26.95 29.31 L25.76 28.75 L24.58 28.16 L23.42 27.54 L22.28 26.90 L21.15 26.23 L20.03 25.53 L18.94 24.80 L17.87 24.04 L16.81 23.27 L15.77 22.46" fill="none" stroke="#1e293b" stroke-width="1.25" stroke-linejoin="round" stroke-linecap="round"/><path d="M11.48 27.84 L5.00 13.89 L20.05 17.08 L11.48 27.84 Z" fill="#1e293b" fill-opacity="1" stroke="#1e293b" stroke-width="1.25" stroke-linejoin="round"/></svg>
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@orbat-mapper/control-measures",
|
|
3
|
-
"version": "0.2.0-alpha.
|
|
3
|
+
"version": "0.2.0-alpha.1",
|
|
4
4
|
"description": "Library for drawing tactical graphics and control measures according to MIL-STD-2525 and APP-6 standards.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Orbat Mapper",
|
|
@@ -28,6 +28,7 @@
|
|
|
28
28
|
},
|
|
29
29
|
"files": [
|
|
30
30
|
"dist",
|
|
31
|
+
"media",
|
|
31
32
|
"README.md",
|
|
32
33
|
"LICENSE"
|
|
33
34
|
],
|
|
@@ -39,6 +40,7 @@
|
|
|
39
40
|
"@types/geojson": "^7946.0.16",
|
|
40
41
|
"publint": "^0.3.21",
|
|
41
42
|
"tsdown": "^0.22.2",
|
|
43
|
+
"tsx": "^4.22.4",
|
|
42
44
|
"typescript": "~5.9.3",
|
|
43
45
|
"vite": "^8.0.16",
|
|
44
46
|
"vitest": "^4.1.8"
|
|
@@ -46,6 +48,9 @@
|
|
|
46
48
|
"scripts": {
|
|
47
49
|
"build": "tsdown",
|
|
48
50
|
"test": "vitest run",
|
|
49
|
-
"lint": "eslint . --fix"
|
|
51
|
+
"lint": "eslint . --fix",
|
|
52
|
+
"generate-previews": "tsx scripts/generate-previews.ts",
|
|
53
|
+
"generate-readme-table": "tsx scripts/generate-readme-table.ts",
|
|
54
|
+
"generate-docs": "pnpm generate-previews && pnpm generate-readme-table"
|
|
50
55
|
}
|
|
51
56
|
}
|