@willcgage/module-schematic 0.17.0 → 0.19.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +108 -5
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +109 -2
- package/dist/index.d.ts +109 -2
- package/dist/index.js +105 -6
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.cts
CHANGED
|
@@ -78,6 +78,11 @@ interface SchematicTrack {
|
|
|
78
78
|
* endplate A (past the throat = in the loop), lane is the ladder/arc index —
|
|
79
79
|
* one record drives both the unrolled fan and a geometric render. */
|
|
80
80
|
inLoop?: boolean;
|
|
81
|
+
/** Authored 2-D path for this track (module-local inches, open path with
|
|
82
|
+
* arcs) — the PHYSICAL shape a bent/rotated spur draws. Absent = derive from
|
|
83
|
+
* the main centre-line + lane, as before. Physical view only; the operations
|
|
84
|
+
* view stays positional (#2d-track). */
|
|
85
|
+
path?: BenchworkPoint[] | null;
|
|
81
86
|
}
|
|
82
87
|
interface SchematicTurnout {
|
|
83
88
|
id: string;
|
|
@@ -132,6 +137,35 @@ interface SchematicControlPoint {
|
|
|
132
137
|
crossings?: string[];
|
|
133
138
|
signals?: SchematicSignal[];
|
|
134
139
|
}
|
|
140
|
+
/** What a rendered industry shows beside its name: a car count, a length in
|
|
141
|
+
* inches, or nothing (name only). Authored per industry. */
|
|
142
|
+
type IndustryLabelMode = "none" | "cars" | "inches";
|
|
143
|
+
/**
|
|
144
|
+
* An industry — a rail-served customer that spots cars, authored as a SPAN on a
|
|
145
|
+
* track (a spur/siding, or the main). Positional like everything else: it lives
|
|
146
|
+
* in the same module-local inch frame and is rendered into the shared 2-D view,
|
|
147
|
+
* offset to `side`. The span length gives its car capacity; the dispatcher and
|
|
148
|
+
* crews read where cars set out. Mirrors a `freemon_industries` row.
|
|
149
|
+
*/
|
|
150
|
+
interface SchematicIndustry {
|
|
151
|
+
id: string;
|
|
152
|
+
name: string;
|
|
153
|
+
/** Industry type value from the lookup (e.g. "team_track", "grain"). */
|
|
154
|
+
type?: string | null;
|
|
155
|
+
/** The track this industry spots cars on (a spur/siding id, or the main). */
|
|
156
|
+
track: string;
|
|
157
|
+
/** The car-spot span along that track, inches from endplate A. */
|
|
158
|
+
fromPos: number;
|
|
159
|
+
toPos: number;
|
|
160
|
+
/** Which side of the track the building + label sit on. */
|
|
161
|
+
side?: SignalSide;
|
|
162
|
+
/** Secondary readout at the label — a car count, a length, or none. */
|
|
163
|
+
labelMode?: IndustryLabelMode;
|
|
164
|
+
/** Car types this industry receives (car-type value strings). */
|
|
165
|
+
carTypes?: string[];
|
|
166
|
+
/** The `freemon_industries` row this is (single source of truth); null = new. */
|
|
167
|
+
moduleIndustryId?: number | null;
|
|
168
|
+
}
|
|
135
169
|
interface ModuleSchematicDoc {
|
|
136
170
|
version: number;
|
|
137
171
|
module?: string;
|
|
@@ -156,6 +190,8 @@ interface ModuleSchematicDoc {
|
|
|
156
190
|
/** Grade crossings / diamonds (#170). */
|
|
157
191
|
crossings?: SchematicCrossing[];
|
|
158
192
|
controlPoints?: SchematicControlPoint[];
|
|
193
|
+
/** Rail-served industries — car-spot spans on a track (#industries). */
|
|
194
|
+
industries?: SchematicIndustry[];
|
|
159
195
|
/** Benchwork FOOTPRINT outline — the module's physical board shape as a
|
|
160
196
|
* polygon in module-local inches, in the same frame as the endplate poses
|
|
161
197
|
* (endplate A's track point at the origin, the mainline along +x, perpendicular
|
|
@@ -164,6 +200,10 @@ interface ModuleSchematicDoc {
|
|
|
164
200
|
outline?: BenchworkPoint[];
|
|
165
201
|
/** @deprecated pre-grouping flat signals; read for back-compat. */
|
|
166
202
|
signals?: SchematicSignal[];
|
|
203
|
+
/** Authored mainline centre-line (module-local inches, open path with arcs).
|
|
204
|
+
* Present = the owner drew the real shape; absent = derive from geometry.
|
|
205
|
+
* Physical view only — the operations view stays derived (#2d-track). */
|
|
206
|
+
mainPath?: BenchworkPoint[] | null;
|
|
167
207
|
}
|
|
168
208
|
/** A benchwork-outline vertex, module-local inches. The edge from this vertex
|
|
169
209
|
* to the NEXT one is a straight line, unless `bulge` is set — then it's a
|
|
@@ -191,6 +231,19 @@ declare function sampleBenchworkOutline(pts: BenchworkPoint[], segsPerArc?: numb
|
|
|
191
231
|
x: number;
|
|
192
232
|
y: number;
|
|
193
233
|
}[];
|
|
234
|
+
/**
|
|
235
|
+
* Expand an OPEN track path (whose edges may be arcs) into a dense polyline —
|
|
236
|
+
* the open-ended sibling of sampleBenchworkOutline (which closes the ring).
|
|
237
|
+
* Used for authored track centre-lines (a drawn mainline or spur). The final
|
|
238
|
+
* vertex is always emitted so the path reaches its end.
|
|
239
|
+
*/
|
|
240
|
+
declare function samplePath(pts: BenchworkPoint[], segsPerArc?: number): {
|
|
241
|
+
x: number;
|
|
242
|
+
y: number;
|
|
243
|
+
}[];
|
|
244
|
+
/** Normalise an authored track path from a doc, or null if it isn't a real path
|
|
245
|
+
* (needs ≥ 2 valid points). Keeps per-vertex bulge. */
|
|
246
|
+
declare function trackPath(path: BenchworkPoint[] | null | undefined): BenchworkPoint[] | null;
|
|
194
247
|
interface ModuleFootprintInput {
|
|
195
248
|
/** Mainline length (falls back to footprint length), inches. */
|
|
196
249
|
lengthInches: number;
|
|
@@ -201,6 +254,10 @@ interface ModuleFootprintInput {
|
|
|
201
254
|
endplateWidths?: Record<string, number>;
|
|
202
255
|
/** Authored benchwork outline (module-local inches), or absent for the band. */
|
|
203
256
|
outline?: BenchworkPoint[] | null;
|
|
257
|
+
/** Authored mainline centre-line (module-local inches, open path with arcs).
|
|
258
|
+
* When present it wins over the geometry-derived centre-line — the owner drew
|
|
259
|
+
* the real shape (#2d-track, physical view only). */
|
|
260
|
+
mainPath?: BenchworkPoint[] | null;
|
|
204
261
|
}
|
|
205
262
|
interface OutlineFace {
|
|
206
263
|
/** The endplate face's two corners + midpoint (the track point). */
|
|
@@ -218,7 +275,9 @@ interface ModuleFootprint {
|
|
|
218
275
|
/** Authored outline (arc-sampled closed ring) or null → render the band. */
|
|
219
276
|
outline: BenchworkPoint[] | null;
|
|
220
277
|
}
|
|
221
|
-
/** Module-local main track centre-line (A→B), sampling arcs for curves/corners.
|
|
278
|
+
/** Module-local main track centre-line (A→B), sampling arcs for curves/corners.
|
|
279
|
+
* An authored `mainPath` wins — the owner drew the real shape; otherwise the
|
|
280
|
+
* centre-line is derived from the geometry fields (length + type/degrees/offset). */
|
|
222
281
|
declare function moduleCenterline(input: ModuleFootprintInput): BenchworkPoint[];
|
|
223
282
|
/** Benchwork band: the centre-line offset ±half-width, tapering widthA→widthB. */
|
|
224
283
|
declare function benchworkBand(center: BenchworkPoint[], widthA?: number, widthB?: number): BenchworkPoint[];
|
|
@@ -243,6 +302,13 @@ declare const N_SCALE_RATIO = 160;
|
|
|
243
302
|
declare function inchesToScaleFeet(inches: number, ratio?: number): number;
|
|
244
303
|
/** Scale feet of prototype track → real inches on the module. */
|
|
245
304
|
declare function scaleFeetToInches(feet: number, ratio?: number): number;
|
|
305
|
+
/** Length a spotted car occupies on N-scale track, inches. A 40-ft car body is
|
|
306
|
+
* ~3.0″; ~3.3″ over the couplers — the real spacing a cut of cars takes. The
|
|
307
|
+
* single constant every repo reads so a track's car count matches everywhere. */
|
|
308
|
+
declare const N_CAR_LENGTH_INCHES = 3.3;
|
|
309
|
+
/** How many cars fit in a span, from its drawn length — the derived capacity a
|
|
310
|
+
* siding or an industry spot holds (never typed). */
|
|
311
|
+
declare function carCapacity(fromPos: number, toPos: number, carLengthInches?: number): number;
|
|
246
312
|
/** Parse a jsonb value into a schematic doc, or null if it isn't one. */
|
|
247
313
|
declare function asModuleSchematic(x: unknown): ModuleSchematicDoc | null;
|
|
248
314
|
interface EditorTrack {
|
|
@@ -257,6 +323,9 @@ interface EditorTrack {
|
|
|
257
323
|
trackName: string;
|
|
258
324
|
/** Inside the balloon of a loop module (#165). */
|
|
259
325
|
inLoop?: boolean;
|
|
326
|
+
/** Authored 2-D path (module-local inches) — a bent/rotated spur's real
|
|
327
|
+
* shape. Absent = derive from the main + lane (#2d-track). */
|
|
328
|
+
path?: BenchworkPoint[];
|
|
260
329
|
}
|
|
261
330
|
/** A module_tracks row as loaded for the editor. */
|
|
262
331
|
interface ModuleTrackRow {
|
|
@@ -294,6 +363,20 @@ interface EditorCrossing {
|
|
|
294
363
|
trackA: string;
|
|
295
364
|
trackB: string;
|
|
296
365
|
}
|
|
366
|
+
/** An industry as the authoring form binds it — a car-spot span on a track. */
|
|
367
|
+
interface EditorIndustry {
|
|
368
|
+
id: string;
|
|
369
|
+
name: string;
|
|
370
|
+
type: string;
|
|
371
|
+
track: string;
|
|
372
|
+
fromPos: number;
|
|
373
|
+
toPos: number;
|
|
374
|
+
side: SignalSide;
|
|
375
|
+
labelMode: IndustryLabelMode;
|
|
376
|
+
carTypes: string[];
|
|
377
|
+
/** freemon_industries row (single source of truth), or null for a new one. */
|
|
378
|
+
moduleIndustryId: number | null;
|
|
379
|
+
}
|
|
297
380
|
/** A 3rd+ endplate — a branch/junction connection off the module (#170).
|
|
298
381
|
* A module may have several (e.g. a set carrying a second railroad through:
|
|
299
382
|
* MoPac enters at one branch endplate and leaves at another). */
|
|
@@ -339,6 +422,11 @@ interface EditorState {
|
|
|
339
422
|
* Empty = no authored outline (fall back to the endplate-width band). */
|
|
340
423
|
outline: BenchworkPoint[];
|
|
341
424
|
controlPoints: EditorControlPoint[];
|
|
425
|
+
/** Rail-served industries — car-spot spans on a track (#industries). */
|
|
426
|
+
industries: EditorIndustry[];
|
|
427
|
+
/** Authored mainline centre-line (module-local inches) — empty = derive from
|
|
428
|
+
* geometry. The owner-drawn real shape (#2d-track, physical view only). */
|
|
429
|
+
mainPath: BenchworkPoint[];
|
|
342
430
|
}
|
|
343
431
|
/** Build the empty editor state for a module of the given length. */
|
|
344
432
|
declare function emptyEditorState(lengthInches: number): EditorState;
|
|
@@ -469,6 +557,23 @@ interface BranchConnector {
|
|
|
469
557
|
posFrac: number;
|
|
470
558
|
side: "up" | "down";
|
|
471
559
|
}
|
|
560
|
+
/** An industry — draw a car-spot span beside its track's lane, on `side`, with
|
|
561
|
+
* a name label + an optional car/length readout (#industries). */
|
|
562
|
+
interface DrawIndustry {
|
|
563
|
+
id: string;
|
|
564
|
+
name: string;
|
|
565
|
+
type: string | null;
|
|
566
|
+
/** Span as fractions of module length (sorted West→East). */
|
|
567
|
+
fromFrac: number;
|
|
568
|
+
toFrac: number;
|
|
569
|
+
/** Lane of the track it spots on, so it draws beside the right track. */
|
|
570
|
+
lane: number;
|
|
571
|
+
side: SignalSide;
|
|
572
|
+
labelMode: IndustryLabelMode;
|
|
573
|
+
/** Cars that spot here, derived from the drawn span length. */
|
|
574
|
+
cars: number;
|
|
575
|
+
carTypes: string[];
|
|
576
|
+
}
|
|
472
577
|
interface ModuleFeatures {
|
|
473
578
|
/** Whether either endplate declares a double-track main. */
|
|
474
579
|
doubleMain: boolean;
|
|
@@ -493,6 +598,8 @@ interface ModuleFeatures {
|
|
|
493
598
|
crossovers: DrawCrossover[];
|
|
494
599
|
/** Branch endplates — junction connectors off the module (#170). */
|
|
495
600
|
branchConnectors: BranchConnector[];
|
|
601
|
+
/** Rail-served industries — car-spot spans beside their track (#industries). */
|
|
602
|
+
industries: DrawIndustry[];
|
|
496
603
|
/** Main 2's extent when it doesn't run the full module — a single↔double
|
|
497
604
|
* transition (Main 2 starts/ends at the mainline turnout). Null = full
|
|
498
605
|
* length (or no Main 2). Renderers draw the partial line + its diverge. */
|
|
@@ -598,4 +705,4 @@ declare function poseOverridesFromDoc(doc: ModuleSchematicDoc): Record<string, {
|
|
|
598
705
|
heading: number;
|
|
599
706
|
}>;
|
|
600
707
|
|
|
601
|
-
export { type BenchworkPoint, type BranchConnector, type DrawCrossing, type DrawCrossover, type DrawSignal, type DrawTrack, type DrawTurnout, type EditorBranch, type EditorControlPoint, type EditorCpSignal, type EditorCrossing, type EditorState, type EditorTrack, type EditorTurnout, type EndplateBConfig, type EndplatePose, FREEMO_ENDPLATE_WIDTH_MIN_INCHES, FREEMO_ENDPLATE_WIDTH_RECOMMENDED_INCHES, type GeometryType, MAIN2_TRACK_ID, MAIN_TRACK_ID, type ModuleFeatures, type ModuleFootprint, type ModuleFootprintInput, type ModuleGeometryInput, type ModuleSchematicDoc, type ModuleTrackRow, N_SCALE_RATIO, type OutlineFace, type SchematicBlock, type SchematicControlPoint, type SchematicCrossing, type SchematicEndplate, type SchematicEndplateTrack, type SchematicSignal, type SchematicTrack, type SchematicTurnout, type SignalFacing, type SignalSide, type TrackConfig, type TrackRole, type TurnoutKind, asModuleSchematic, benchworkBand, benchworkOutline, buildCrossover, buildPassingSiding, buildTransition, deriveEndplatePoses, divergeSideForHand, docToState, emptyEditorState, endplateFaceSegments, endplateWidthInches, geometryTurnDegrees, inchesToScaleFeet, isLoopDoc, isTransitionTurnout, moduleCenterline, moduleFeatures, moduleFootprint, nextId, poseNeedsManual, poseOverridesFromDoc, sampleBenchworkOutline, scaleFeetToInches, stateToDoc };
|
|
708
|
+
export { type BenchworkPoint, type BranchConnector, type DrawCrossing, type DrawCrossover, type DrawIndustry, type DrawSignal, type DrawTrack, type DrawTurnout, type EditorBranch, type EditorControlPoint, type EditorCpSignal, type EditorCrossing, type EditorIndustry, type EditorState, type EditorTrack, type EditorTurnout, type EndplateBConfig, type EndplatePose, FREEMO_ENDPLATE_WIDTH_MIN_INCHES, FREEMO_ENDPLATE_WIDTH_RECOMMENDED_INCHES, type GeometryType, type IndustryLabelMode, MAIN2_TRACK_ID, MAIN_TRACK_ID, type ModuleFeatures, type ModuleFootprint, type ModuleFootprintInput, type ModuleGeometryInput, type ModuleSchematicDoc, type ModuleTrackRow, N_CAR_LENGTH_INCHES, N_SCALE_RATIO, type OutlineFace, type SchematicBlock, type SchematicControlPoint, type SchematicCrossing, type SchematicEndplate, type SchematicEndplateTrack, type SchematicIndustry, type SchematicSignal, type SchematicTrack, type SchematicTurnout, type SignalFacing, type SignalSide, type TrackConfig, type TrackRole, type TurnoutKind, asModuleSchematic, benchworkBand, benchworkOutline, buildCrossover, buildPassingSiding, buildTransition, carCapacity, deriveEndplatePoses, divergeSideForHand, docToState, emptyEditorState, endplateFaceSegments, endplateWidthInches, geometryTurnDegrees, inchesToScaleFeet, isLoopDoc, isTransitionTurnout, moduleCenterline, moduleFeatures, moduleFootprint, nextId, poseNeedsManual, poseOverridesFromDoc, sampleBenchworkOutline, samplePath, scaleFeetToInches, stateToDoc, trackPath };
|
package/dist/index.d.ts
CHANGED
|
@@ -78,6 +78,11 @@ interface SchematicTrack {
|
|
|
78
78
|
* endplate A (past the throat = in the loop), lane is the ladder/arc index —
|
|
79
79
|
* one record drives both the unrolled fan and a geometric render. */
|
|
80
80
|
inLoop?: boolean;
|
|
81
|
+
/** Authored 2-D path for this track (module-local inches, open path with
|
|
82
|
+
* arcs) — the PHYSICAL shape a bent/rotated spur draws. Absent = derive from
|
|
83
|
+
* the main centre-line + lane, as before. Physical view only; the operations
|
|
84
|
+
* view stays positional (#2d-track). */
|
|
85
|
+
path?: BenchworkPoint[] | null;
|
|
81
86
|
}
|
|
82
87
|
interface SchematicTurnout {
|
|
83
88
|
id: string;
|
|
@@ -132,6 +137,35 @@ interface SchematicControlPoint {
|
|
|
132
137
|
crossings?: string[];
|
|
133
138
|
signals?: SchematicSignal[];
|
|
134
139
|
}
|
|
140
|
+
/** What a rendered industry shows beside its name: a car count, a length in
|
|
141
|
+
* inches, or nothing (name only). Authored per industry. */
|
|
142
|
+
type IndustryLabelMode = "none" | "cars" | "inches";
|
|
143
|
+
/**
|
|
144
|
+
* An industry — a rail-served customer that spots cars, authored as a SPAN on a
|
|
145
|
+
* track (a spur/siding, or the main). Positional like everything else: it lives
|
|
146
|
+
* in the same module-local inch frame and is rendered into the shared 2-D view,
|
|
147
|
+
* offset to `side`. The span length gives its car capacity; the dispatcher and
|
|
148
|
+
* crews read where cars set out. Mirrors a `freemon_industries` row.
|
|
149
|
+
*/
|
|
150
|
+
interface SchematicIndustry {
|
|
151
|
+
id: string;
|
|
152
|
+
name: string;
|
|
153
|
+
/** Industry type value from the lookup (e.g. "team_track", "grain"). */
|
|
154
|
+
type?: string | null;
|
|
155
|
+
/** The track this industry spots cars on (a spur/siding id, or the main). */
|
|
156
|
+
track: string;
|
|
157
|
+
/** The car-spot span along that track, inches from endplate A. */
|
|
158
|
+
fromPos: number;
|
|
159
|
+
toPos: number;
|
|
160
|
+
/** Which side of the track the building + label sit on. */
|
|
161
|
+
side?: SignalSide;
|
|
162
|
+
/** Secondary readout at the label — a car count, a length, or none. */
|
|
163
|
+
labelMode?: IndustryLabelMode;
|
|
164
|
+
/** Car types this industry receives (car-type value strings). */
|
|
165
|
+
carTypes?: string[];
|
|
166
|
+
/** The `freemon_industries` row this is (single source of truth); null = new. */
|
|
167
|
+
moduleIndustryId?: number | null;
|
|
168
|
+
}
|
|
135
169
|
interface ModuleSchematicDoc {
|
|
136
170
|
version: number;
|
|
137
171
|
module?: string;
|
|
@@ -156,6 +190,8 @@ interface ModuleSchematicDoc {
|
|
|
156
190
|
/** Grade crossings / diamonds (#170). */
|
|
157
191
|
crossings?: SchematicCrossing[];
|
|
158
192
|
controlPoints?: SchematicControlPoint[];
|
|
193
|
+
/** Rail-served industries — car-spot spans on a track (#industries). */
|
|
194
|
+
industries?: SchematicIndustry[];
|
|
159
195
|
/** Benchwork FOOTPRINT outline — the module's physical board shape as a
|
|
160
196
|
* polygon in module-local inches, in the same frame as the endplate poses
|
|
161
197
|
* (endplate A's track point at the origin, the mainline along +x, perpendicular
|
|
@@ -164,6 +200,10 @@ interface ModuleSchematicDoc {
|
|
|
164
200
|
outline?: BenchworkPoint[];
|
|
165
201
|
/** @deprecated pre-grouping flat signals; read for back-compat. */
|
|
166
202
|
signals?: SchematicSignal[];
|
|
203
|
+
/** Authored mainline centre-line (module-local inches, open path with arcs).
|
|
204
|
+
* Present = the owner drew the real shape; absent = derive from geometry.
|
|
205
|
+
* Physical view only — the operations view stays derived (#2d-track). */
|
|
206
|
+
mainPath?: BenchworkPoint[] | null;
|
|
167
207
|
}
|
|
168
208
|
/** A benchwork-outline vertex, module-local inches. The edge from this vertex
|
|
169
209
|
* to the NEXT one is a straight line, unless `bulge` is set — then it's a
|
|
@@ -191,6 +231,19 @@ declare function sampleBenchworkOutline(pts: BenchworkPoint[], segsPerArc?: numb
|
|
|
191
231
|
x: number;
|
|
192
232
|
y: number;
|
|
193
233
|
}[];
|
|
234
|
+
/**
|
|
235
|
+
* Expand an OPEN track path (whose edges may be arcs) into a dense polyline —
|
|
236
|
+
* the open-ended sibling of sampleBenchworkOutline (which closes the ring).
|
|
237
|
+
* Used for authored track centre-lines (a drawn mainline or spur). The final
|
|
238
|
+
* vertex is always emitted so the path reaches its end.
|
|
239
|
+
*/
|
|
240
|
+
declare function samplePath(pts: BenchworkPoint[], segsPerArc?: number): {
|
|
241
|
+
x: number;
|
|
242
|
+
y: number;
|
|
243
|
+
}[];
|
|
244
|
+
/** Normalise an authored track path from a doc, or null if it isn't a real path
|
|
245
|
+
* (needs ≥ 2 valid points). Keeps per-vertex bulge. */
|
|
246
|
+
declare function trackPath(path: BenchworkPoint[] | null | undefined): BenchworkPoint[] | null;
|
|
194
247
|
interface ModuleFootprintInput {
|
|
195
248
|
/** Mainline length (falls back to footprint length), inches. */
|
|
196
249
|
lengthInches: number;
|
|
@@ -201,6 +254,10 @@ interface ModuleFootprintInput {
|
|
|
201
254
|
endplateWidths?: Record<string, number>;
|
|
202
255
|
/** Authored benchwork outline (module-local inches), or absent for the band. */
|
|
203
256
|
outline?: BenchworkPoint[] | null;
|
|
257
|
+
/** Authored mainline centre-line (module-local inches, open path with arcs).
|
|
258
|
+
* When present it wins over the geometry-derived centre-line — the owner drew
|
|
259
|
+
* the real shape (#2d-track, physical view only). */
|
|
260
|
+
mainPath?: BenchworkPoint[] | null;
|
|
204
261
|
}
|
|
205
262
|
interface OutlineFace {
|
|
206
263
|
/** The endplate face's two corners + midpoint (the track point). */
|
|
@@ -218,7 +275,9 @@ interface ModuleFootprint {
|
|
|
218
275
|
/** Authored outline (arc-sampled closed ring) or null → render the band. */
|
|
219
276
|
outline: BenchworkPoint[] | null;
|
|
220
277
|
}
|
|
221
|
-
/** Module-local main track centre-line (A→B), sampling arcs for curves/corners.
|
|
278
|
+
/** Module-local main track centre-line (A→B), sampling arcs for curves/corners.
|
|
279
|
+
* An authored `mainPath` wins — the owner drew the real shape; otherwise the
|
|
280
|
+
* centre-line is derived from the geometry fields (length + type/degrees/offset). */
|
|
222
281
|
declare function moduleCenterline(input: ModuleFootprintInput): BenchworkPoint[];
|
|
223
282
|
/** Benchwork band: the centre-line offset ±half-width, tapering widthA→widthB. */
|
|
224
283
|
declare function benchworkBand(center: BenchworkPoint[], widthA?: number, widthB?: number): BenchworkPoint[];
|
|
@@ -243,6 +302,13 @@ declare const N_SCALE_RATIO = 160;
|
|
|
243
302
|
declare function inchesToScaleFeet(inches: number, ratio?: number): number;
|
|
244
303
|
/** Scale feet of prototype track → real inches on the module. */
|
|
245
304
|
declare function scaleFeetToInches(feet: number, ratio?: number): number;
|
|
305
|
+
/** Length a spotted car occupies on N-scale track, inches. A 40-ft car body is
|
|
306
|
+
* ~3.0″; ~3.3″ over the couplers — the real spacing a cut of cars takes. The
|
|
307
|
+
* single constant every repo reads so a track's car count matches everywhere. */
|
|
308
|
+
declare const N_CAR_LENGTH_INCHES = 3.3;
|
|
309
|
+
/** How many cars fit in a span, from its drawn length — the derived capacity a
|
|
310
|
+
* siding or an industry spot holds (never typed). */
|
|
311
|
+
declare function carCapacity(fromPos: number, toPos: number, carLengthInches?: number): number;
|
|
246
312
|
/** Parse a jsonb value into a schematic doc, or null if it isn't one. */
|
|
247
313
|
declare function asModuleSchematic(x: unknown): ModuleSchematicDoc | null;
|
|
248
314
|
interface EditorTrack {
|
|
@@ -257,6 +323,9 @@ interface EditorTrack {
|
|
|
257
323
|
trackName: string;
|
|
258
324
|
/** Inside the balloon of a loop module (#165). */
|
|
259
325
|
inLoop?: boolean;
|
|
326
|
+
/** Authored 2-D path (module-local inches) — a bent/rotated spur's real
|
|
327
|
+
* shape. Absent = derive from the main + lane (#2d-track). */
|
|
328
|
+
path?: BenchworkPoint[];
|
|
260
329
|
}
|
|
261
330
|
/** A module_tracks row as loaded for the editor. */
|
|
262
331
|
interface ModuleTrackRow {
|
|
@@ -294,6 +363,20 @@ interface EditorCrossing {
|
|
|
294
363
|
trackA: string;
|
|
295
364
|
trackB: string;
|
|
296
365
|
}
|
|
366
|
+
/** An industry as the authoring form binds it — a car-spot span on a track. */
|
|
367
|
+
interface EditorIndustry {
|
|
368
|
+
id: string;
|
|
369
|
+
name: string;
|
|
370
|
+
type: string;
|
|
371
|
+
track: string;
|
|
372
|
+
fromPos: number;
|
|
373
|
+
toPos: number;
|
|
374
|
+
side: SignalSide;
|
|
375
|
+
labelMode: IndustryLabelMode;
|
|
376
|
+
carTypes: string[];
|
|
377
|
+
/** freemon_industries row (single source of truth), or null for a new one. */
|
|
378
|
+
moduleIndustryId: number | null;
|
|
379
|
+
}
|
|
297
380
|
/** A 3rd+ endplate — a branch/junction connection off the module (#170).
|
|
298
381
|
* A module may have several (e.g. a set carrying a second railroad through:
|
|
299
382
|
* MoPac enters at one branch endplate and leaves at another). */
|
|
@@ -339,6 +422,11 @@ interface EditorState {
|
|
|
339
422
|
* Empty = no authored outline (fall back to the endplate-width band). */
|
|
340
423
|
outline: BenchworkPoint[];
|
|
341
424
|
controlPoints: EditorControlPoint[];
|
|
425
|
+
/** Rail-served industries — car-spot spans on a track (#industries). */
|
|
426
|
+
industries: EditorIndustry[];
|
|
427
|
+
/** Authored mainline centre-line (module-local inches) — empty = derive from
|
|
428
|
+
* geometry. The owner-drawn real shape (#2d-track, physical view only). */
|
|
429
|
+
mainPath: BenchworkPoint[];
|
|
342
430
|
}
|
|
343
431
|
/** Build the empty editor state for a module of the given length. */
|
|
344
432
|
declare function emptyEditorState(lengthInches: number): EditorState;
|
|
@@ -469,6 +557,23 @@ interface BranchConnector {
|
|
|
469
557
|
posFrac: number;
|
|
470
558
|
side: "up" | "down";
|
|
471
559
|
}
|
|
560
|
+
/** An industry — draw a car-spot span beside its track's lane, on `side`, with
|
|
561
|
+
* a name label + an optional car/length readout (#industries). */
|
|
562
|
+
interface DrawIndustry {
|
|
563
|
+
id: string;
|
|
564
|
+
name: string;
|
|
565
|
+
type: string | null;
|
|
566
|
+
/** Span as fractions of module length (sorted West→East). */
|
|
567
|
+
fromFrac: number;
|
|
568
|
+
toFrac: number;
|
|
569
|
+
/** Lane of the track it spots on, so it draws beside the right track. */
|
|
570
|
+
lane: number;
|
|
571
|
+
side: SignalSide;
|
|
572
|
+
labelMode: IndustryLabelMode;
|
|
573
|
+
/** Cars that spot here, derived from the drawn span length. */
|
|
574
|
+
cars: number;
|
|
575
|
+
carTypes: string[];
|
|
576
|
+
}
|
|
472
577
|
interface ModuleFeatures {
|
|
473
578
|
/** Whether either endplate declares a double-track main. */
|
|
474
579
|
doubleMain: boolean;
|
|
@@ -493,6 +598,8 @@ interface ModuleFeatures {
|
|
|
493
598
|
crossovers: DrawCrossover[];
|
|
494
599
|
/** Branch endplates — junction connectors off the module (#170). */
|
|
495
600
|
branchConnectors: BranchConnector[];
|
|
601
|
+
/** Rail-served industries — car-spot spans beside their track (#industries). */
|
|
602
|
+
industries: DrawIndustry[];
|
|
496
603
|
/** Main 2's extent when it doesn't run the full module — a single↔double
|
|
497
604
|
* transition (Main 2 starts/ends at the mainline turnout). Null = full
|
|
498
605
|
* length (or no Main 2). Renderers draw the partial line + its diverge. */
|
|
@@ -598,4 +705,4 @@ declare function poseOverridesFromDoc(doc: ModuleSchematicDoc): Record<string, {
|
|
|
598
705
|
heading: number;
|
|
599
706
|
}>;
|
|
600
707
|
|
|
601
|
-
export { type BenchworkPoint, type BranchConnector, type DrawCrossing, type DrawCrossover, type DrawSignal, type DrawTrack, type DrawTurnout, type EditorBranch, type EditorControlPoint, type EditorCpSignal, type EditorCrossing, type EditorState, type EditorTrack, type EditorTurnout, type EndplateBConfig, type EndplatePose, FREEMO_ENDPLATE_WIDTH_MIN_INCHES, FREEMO_ENDPLATE_WIDTH_RECOMMENDED_INCHES, type GeometryType, MAIN2_TRACK_ID, MAIN_TRACK_ID, type ModuleFeatures, type ModuleFootprint, type ModuleFootprintInput, type ModuleGeometryInput, type ModuleSchematicDoc, type ModuleTrackRow, N_SCALE_RATIO, type OutlineFace, type SchematicBlock, type SchematicControlPoint, type SchematicCrossing, type SchematicEndplate, type SchematicEndplateTrack, type SchematicSignal, type SchematicTrack, type SchematicTurnout, type SignalFacing, type SignalSide, type TrackConfig, type TrackRole, type TurnoutKind, asModuleSchematic, benchworkBand, benchworkOutline, buildCrossover, buildPassingSiding, buildTransition, deriveEndplatePoses, divergeSideForHand, docToState, emptyEditorState, endplateFaceSegments, endplateWidthInches, geometryTurnDegrees, inchesToScaleFeet, isLoopDoc, isTransitionTurnout, moduleCenterline, moduleFeatures, moduleFootprint, nextId, poseNeedsManual, poseOverridesFromDoc, sampleBenchworkOutline, scaleFeetToInches, stateToDoc };
|
|
708
|
+
export { type BenchworkPoint, type BranchConnector, type DrawCrossing, type DrawCrossover, type DrawIndustry, type DrawSignal, type DrawTrack, type DrawTurnout, type EditorBranch, type EditorControlPoint, type EditorCpSignal, type EditorCrossing, type EditorIndustry, type EditorState, type EditorTrack, type EditorTurnout, type EndplateBConfig, type EndplatePose, FREEMO_ENDPLATE_WIDTH_MIN_INCHES, FREEMO_ENDPLATE_WIDTH_RECOMMENDED_INCHES, type GeometryType, type IndustryLabelMode, MAIN2_TRACK_ID, MAIN_TRACK_ID, type ModuleFeatures, type ModuleFootprint, type ModuleFootprintInput, type ModuleGeometryInput, type ModuleSchematicDoc, type ModuleTrackRow, N_CAR_LENGTH_INCHES, N_SCALE_RATIO, type OutlineFace, type SchematicBlock, type SchematicControlPoint, type SchematicCrossing, type SchematicEndplate, type SchematicEndplateTrack, type SchematicIndustry, type SchematicSignal, type SchematicTrack, type SchematicTurnout, type SignalFacing, type SignalSide, type TrackConfig, type TrackRole, type TurnoutKind, asModuleSchematic, benchworkBand, benchworkOutline, buildCrossover, buildPassingSiding, buildTransition, carCapacity, deriveEndplatePoses, divergeSideForHand, docToState, emptyEditorState, endplateFaceSegments, endplateWidthInches, geometryTurnDegrees, inchesToScaleFeet, isLoopDoc, isTransitionTurnout, moduleCenterline, moduleFeatures, moduleFootprint, nextId, poseNeedsManual, poseOverridesFromDoc, sampleBenchworkOutline, samplePath, scaleFeetToInches, stateToDoc, trackPath };
|
package/dist/index.js
CHANGED
|
@@ -43,6 +43,45 @@ function sampleBenchworkOutline(pts, segsPerArc = 20) {
|
|
|
43
43
|
}
|
|
44
44
|
return out;
|
|
45
45
|
}
|
|
46
|
+
function samplePath(pts, segsPerArc = 20) {
|
|
47
|
+
const n = pts.length;
|
|
48
|
+
if (n < 2) return pts.map((p) => ({ x: p.x, y: p.y }));
|
|
49
|
+
const out = [];
|
|
50
|
+
for (let i = 0; i < n - 1; i++) {
|
|
51
|
+
const p0 = pts[i];
|
|
52
|
+
const p1 = pts[i + 1];
|
|
53
|
+
out.push({ x: p0.x, y: p0.y });
|
|
54
|
+
const bulge = p0.bulge ?? 0;
|
|
55
|
+
if (!bulge) continue;
|
|
56
|
+
const dx = p1.x - p0.x;
|
|
57
|
+
const dy = p1.y - p0.y;
|
|
58
|
+
const c = Math.hypot(dx, dy);
|
|
59
|
+
if (c < 1e-6) continue;
|
|
60
|
+
const nx = -dy / c;
|
|
61
|
+
const ny = dx / c;
|
|
62
|
+
const mid = { x: (p0.x + p1.x) / 2 + nx * bulge, y: (p0.y + p1.y) / 2 + ny * bulge };
|
|
63
|
+
const circ = circleThrough(p0, mid, p1);
|
|
64
|
+
if (!circ) continue;
|
|
65
|
+
const a0 = Math.atan2(p0.y - circ.cy, p0.x - circ.cx);
|
|
66
|
+
const am = Math.atan2(mid.y - circ.cy, mid.x - circ.cx);
|
|
67
|
+
const a1 = Math.atan2(p1.y - circ.cy, p1.x - circ.cx);
|
|
68
|
+
const sweep = arcSweep(a0, a1, am);
|
|
69
|
+
for (let s = 1; s < segsPerArc; s++) {
|
|
70
|
+
const a = a0 + sweep * s / segsPerArc;
|
|
71
|
+
out.push({ x: circ.cx + circ.r * Math.cos(a), y: circ.cy + circ.r * Math.sin(a) });
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
out.push({ x: pts[n - 1].x, y: pts[n - 1].y });
|
|
75
|
+
return out;
|
|
76
|
+
}
|
|
77
|
+
function trackPath(path) {
|
|
78
|
+
const pts = (path ?? []).filter((p) => p && Number.isFinite(p.x) && Number.isFinite(p.y)).map((p) => ({
|
|
79
|
+
x: p.x,
|
|
80
|
+
y: p.y,
|
|
81
|
+
...Number.isFinite(p.bulge) && p.bulge ? { bulge: p.bulge } : {}
|
|
82
|
+
}));
|
|
83
|
+
return pts.length >= 2 ? pts : null;
|
|
84
|
+
}
|
|
46
85
|
function circleThrough(a, b, c) {
|
|
47
86
|
const d = 2 * (a.x * (b.y - c.y) + b.x * (c.y - a.y) + c.x * (a.y - b.y));
|
|
48
87
|
if (Math.abs(d) < 1e-9) return null;
|
|
@@ -65,6 +104,8 @@ function arcSweep(a0, a1, am) {
|
|
|
65
104
|
}
|
|
66
105
|
var DEG_FP = Math.PI / 180;
|
|
67
106
|
function moduleCenterline(input) {
|
|
107
|
+
const drawn = trackPath(input.mainPath);
|
|
108
|
+
if (drawn) return samplePath(drawn);
|
|
68
109
|
const L = input.lengthInches > 0 ? input.lengthInches : 24;
|
|
69
110
|
const gt = input.geometryType;
|
|
70
111
|
if (gt === "dead_end") return [{ x: 0, y: 0 }];
|
|
@@ -147,6 +188,11 @@ function inchesToScaleFeet(inches, ratio = N_SCALE_RATIO) {
|
|
|
147
188
|
function scaleFeetToInches(feet, ratio = N_SCALE_RATIO) {
|
|
148
189
|
return feet * 12 / ratio;
|
|
149
190
|
}
|
|
191
|
+
var N_CAR_LENGTH_INCHES = 3.3;
|
|
192
|
+
function carCapacity(fromPos, toPos, carLengthInches = N_CAR_LENGTH_INCHES) {
|
|
193
|
+
if (!(carLengthInches > 0)) return 0;
|
|
194
|
+
return Math.max(0, Math.floor(Math.abs(toPos - fromPos) / carLengthInches));
|
|
195
|
+
}
|
|
150
196
|
function asModuleSchematic(x) {
|
|
151
197
|
if (!x || typeof x !== "object") return null;
|
|
152
198
|
const d = x;
|
|
@@ -168,7 +214,9 @@ function emptyEditorState(lengthInches) {
|
|
|
168
214
|
poseOverrides: {},
|
|
169
215
|
endplateWidths: {},
|
|
170
216
|
outline: [],
|
|
171
|
-
controlPoints: []
|
|
217
|
+
controlPoints: [],
|
|
218
|
+
industries: [],
|
|
219
|
+
mainPath: []
|
|
172
220
|
};
|
|
173
221
|
}
|
|
174
222
|
function isTransitionTurnout(t) {
|
|
@@ -305,7 +353,8 @@ function stateToDoc(state, recordNumber) {
|
|
|
305
353
|
moduleTrackId: t.moduleTrackId,
|
|
306
354
|
trackName: t.trackName || void 0,
|
|
307
355
|
capacityFeet: Math.round(inchesToScaleFeet(Math.abs(t.toPos - t.fromPos))),
|
|
308
|
-
...state.loop && t.inLoop ? { inLoop: true } : {}
|
|
356
|
+
...state.loop && t.inLoop ? { inLoop: true } : {},
|
|
357
|
+
...t.path && t.path.length >= 2 ? { path: t.path } : {}
|
|
309
358
|
}))
|
|
310
359
|
],
|
|
311
360
|
turnouts: state.turnouts.map((t) => ({
|
|
@@ -338,9 +387,26 @@ function stateToDoc(state, recordNumber) {
|
|
|
338
387
|
side: s.side
|
|
339
388
|
}))
|
|
340
389
|
})),
|
|
390
|
+
// Industries — car-spot spans on a track; only when any are authored.
|
|
391
|
+
...state.industries.length > 0 ? {
|
|
392
|
+
industries: state.industries.map((ind) => ({
|
|
393
|
+
id: ind.id,
|
|
394
|
+
name: ind.name,
|
|
395
|
+
...ind.type ? { type: ind.type } : {},
|
|
396
|
+
track: ind.track,
|
|
397
|
+
fromPos: ind.fromPos,
|
|
398
|
+
toPos: ind.toPos,
|
|
399
|
+
side: ind.side,
|
|
400
|
+
...ind.labelMode && ind.labelMode !== "none" ? { labelMode: ind.labelMode } : {},
|
|
401
|
+
...ind.carTypes.length ? { carTypes: ind.carTypes } : {},
|
|
402
|
+
moduleIndustryId: ind.moduleIndustryId
|
|
403
|
+
}))
|
|
404
|
+
} : {},
|
|
341
405
|
// Benchwork footprint outline (module-local inches); only when it's a real
|
|
342
406
|
// ring (≥ 3 vertices).
|
|
343
|
-
...state.outline.length >= 3 ? { outline: state.outline } : {}
|
|
407
|
+
...state.outline.length >= 3 ? { outline: state.outline } : {},
|
|
408
|
+
// Authored mainline path (module-local inches); only when it's a real path.
|
|
409
|
+
...state.mainPath.length >= 2 ? { mainPath: state.mainPath } : {}
|
|
344
410
|
};
|
|
345
411
|
}
|
|
346
412
|
function docToState(doc, fallbackLength, moduleTracks = []) {
|
|
@@ -370,7 +436,9 @@ function docToState(doc, fallbackLength, moduleTracks = []) {
|
|
|
370
436
|
toPos: t.toPos != null ? sc(t.toPos) : len,
|
|
371
437
|
moduleTrackId,
|
|
372
438
|
trackName: t.trackName ?? nameOf(moduleTrackId),
|
|
373
|
-
...t.inLoop ? { inLoop: true } : {}
|
|
439
|
+
...t.inLoop ? { inLoop: true } : {},
|
|
440
|
+
// Authored path kept as-drawn (a physical shape, not rescaled with length).
|
|
441
|
+
...trackPath(t.path) ? { path: trackPath(t.path) } : {}
|
|
374
442
|
});
|
|
375
443
|
}
|
|
376
444
|
}
|
|
@@ -419,6 +487,7 @@ function docToState(doc, fallbackLength, moduleTracks = []) {
|
|
|
419
487
|
y: p.y,
|
|
420
488
|
...Number.isFinite(p.bulge) && p.bulge ? { bulge: p.bulge } : {}
|
|
421
489
|
}));
|
|
490
|
+
const mainPath = trackPath(d.mainPath) ?? [];
|
|
422
491
|
return {
|
|
423
492
|
lengthInches: len,
|
|
424
493
|
loop,
|
|
@@ -435,6 +504,7 @@ function docToState(doc, fallbackLength, moduleTracks = []) {
|
|
|
435
504
|
poseOverrides,
|
|
436
505
|
endplateWidths,
|
|
437
506
|
outline,
|
|
507
|
+
mainPath,
|
|
438
508
|
crossings: (d.crossings ?? []).map((x) => ({
|
|
439
509
|
id: x.id,
|
|
440
510
|
name: x.name ?? "",
|
|
@@ -451,7 +521,19 @@ function docToState(doc, fallbackLength, moduleTracks = []) {
|
|
|
451
521
|
divergeTrack: t.divergeTrack,
|
|
452
522
|
kind: t.kind ?? "right"
|
|
453
523
|
})),
|
|
454
|
-
controlPoints: readControlPoints(d, sc)
|
|
524
|
+
controlPoints: readControlPoints(d, sc),
|
|
525
|
+
industries: (d.industries ?? []).map((ind) => ({
|
|
526
|
+
id: ind.id,
|
|
527
|
+
name: ind.name ?? "",
|
|
528
|
+
type: ind.type ?? "",
|
|
529
|
+
track: ind.track,
|
|
530
|
+
fromPos: sc(ind.fromPos ?? 0),
|
|
531
|
+
toPos: ind.toPos != null ? sc(ind.toPos) : len,
|
|
532
|
+
side: ind.side ?? "above",
|
|
533
|
+
labelMode: ind.labelMode ?? "none",
|
|
534
|
+
carTypes: Array.isArray(ind.carTypes) ? ind.carTypes : [],
|
|
535
|
+
moduleIndustryId: ind.moduleIndustryId ?? null
|
|
536
|
+
}))
|
|
455
537
|
};
|
|
456
538
|
}
|
|
457
539
|
function readControlPoints(d, sc = (p) => p) {
|
|
@@ -750,6 +832,22 @@ function moduleFeatures(doc) {
|
|
|
750
832
|
posFrac: clampFrac(e.at.pos),
|
|
751
833
|
side: e.at.side === "down" ? "down" : "up"
|
|
752
834
|
}));
|
|
835
|
+
const industries = (doc.industries ?? []).map((ind) => {
|
|
836
|
+
const from = ind.fromPos ?? 0;
|
|
837
|
+
const to = ind.toPos ?? len;
|
|
838
|
+
return {
|
|
839
|
+
id: ind.id,
|
|
840
|
+
name: ind.name ?? "",
|
|
841
|
+
type: ind.type ?? null,
|
|
842
|
+
fromFrac: clampFrac(Math.min(from, to)),
|
|
843
|
+
toFrac: clampFrac(Math.max(from, to)),
|
|
844
|
+
lane: trackLane.get(ind.track) ?? 0,
|
|
845
|
+
side: ind.side ?? "above",
|
|
846
|
+
labelMode: ind.labelMode ?? "none",
|
|
847
|
+
cars: carCapacity(from, to),
|
|
848
|
+
carTypes: Array.isArray(ind.carTypes) ? ind.carTypes : []
|
|
849
|
+
};
|
|
850
|
+
});
|
|
753
851
|
const allLanes = [
|
|
754
852
|
0,
|
|
755
853
|
doubleMain ? 1 : 0,
|
|
@@ -790,6 +888,7 @@ function moduleFeatures(doc) {
|
|
|
790
888
|
crossings,
|
|
791
889
|
crossovers,
|
|
792
890
|
branchConnectors,
|
|
891
|
+
industries,
|
|
793
892
|
laneMin: Math.min(...allLanes),
|
|
794
893
|
laneMax: Math.max(...allLanes)
|
|
795
894
|
};
|
|
@@ -892,6 +991,6 @@ function poseOverridesFromDoc(doc) {
|
|
|
892
991
|
return out;
|
|
893
992
|
}
|
|
894
993
|
|
|
895
|
-
export { FREEMO_ENDPLATE_WIDTH_MIN_INCHES, FREEMO_ENDPLATE_WIDTH_RECOMMENDED_INCHES, MAIN2_TRACK_ID, MAIN_TRACK_ID, N_SCALE_RATIO, asModuleSchematic, benchworkBand, benchworkOutline, buildCrossover, buildPassingSiding, buildTransition, deriveEndplatePoses, divergeSideForHand, docToState, emptyEditorState, endplateFaceSegments, endplateWidthInches, geometryTurnDegrees, inchesToScaleFeet, isLoopDoc, isTransitionTurnout, moduleCenterline, moduleFeatures, moduleFootprint, nextId, poseNeedsManual, poseOverridesFromDoc, sampleBenchworkOutline, scaleFeetToInches, stateToDoc };
|
|
994
|
+
export { FREEMO_ENDPLATE_WIDTH_MIN_INCHES, FREEMO_ENDPLATE_WIDTH_RECOMMENDED_INCHES, MAIN2_TRACK_ID, MAIN_TRACK_ID, N_CAR_LENGTH_INCHES, N_SCALE_RATIO, asModuleSchematic, benchworkBand, benchworkOutline, buildCrossover, buildPassingSiding, buildTransition, carCapacity, deriveEndplatePoses, divergeSideForHand, docToState, emptyEditorState, endplateFaceSegments, endplateWidthInches, geometryTurnDegrees, inchesToScaleFeet, isLoopDoc, isTransitionTurnout, moduleCenterline, moduleFeatures, moduleFootprint, nextId, poseNeedsManual, poseOverridesFromDoc, sampleBenchworkOutline, samplePath, scaleFeetToInches, stateToDoc, trackPath };
|
|
896
995
|
//# sourceMappingURL=index.js.map
|
|
897
996
|
//# sourceMappingURL=index.js.map
|