@willcgage/module-schematic 0.17.0 → 0.18.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.d.cts CHANGED
@@ -132,6 +132,35 @@ interface SchematicControlPoint {
132
132
  crossings?: string[];
133
133
  signals?: SchematicSignal[];
134
134
  }
135
+ /** What a rendered industry shows beside its name: a car count, a length in
136
+ * inches, or nothing (name only). Authored per industry. */
137
+ type IndustryLabelMode = "none" | "cars" | "inches";
138
+ /**
139
+ * An industry — a rail-served customer that spots cars, authored as a SPAN on a
140
+ * track (a spur/siding, or the main). Positional like everything else: it lives
141
+ * in the same module-local inch frame and is rendered into the shared 2-D view,
142
+ * offset to `side`. The span length gives its car capacity; the dispatcher and
143
+ * crews read where cars set out. Mirrors a `freemon_industries` row.
144
+ */
145
+ interface SchematicIndustry {
146
+ id: string;
147
+ name: string;
148
+ /** Industry type value from the lookup (e.g. "team_track", "grain"). */
149
+ type?: string | null;
150
+ /** The track this industry spots cars on (a spur/siding id, or the main). */
151
+ track: string;
152
+ /** The car-spot span along that track, inches from endplate A. */
153
+ fromPos: number;
154
+ toPos: number;
155
+ /** Which side of the track the building + label sit on. */
156
+ side?: SignalSide;
157
+ /** Secondary readout at the label — a car count, a length, or none. */
158
+ labelMode?: IndustryLabelMode;
159
+ /** Car types this industry receives (car-type value strings). */
160
+ carTypes?: string[];
161
+ /** The `freemon_industries` row this is (single source of truth); null = new. */
162
+ moduleIndustryId?: number | null;
163
+ }
135
164
  interface ModuleSchematicDoc {
136
165
  version: number;
137
166
  module?: string;
@@ -156,6 +185,8 @@ interface ModuleSchematicDoc {
156
185
  /** Grade crossings / diamonds (#170). */
157
186
  crossings?: SchematicCrossing[];
158
187
  controlPoints?: SchematicControlPoint[];
188
+ /** Rail-served industries — car-spot spans on a track (#industries). */
189
+ industries?: SchematicIndustry[];
159
190
  /** Benchwork FOOTPRINT outline — the module's physical board shape as a
160
191
  * polygon in module-local inches, in the same frame as the endplate poses
161
192
  * (endplate A's track point at the origin, the mainline along +x, perpendicular
@@ -243,6 +274,13 @@ declare const N_SCALE_RATIO = 160;
243
274
  declare function inchesToScaleFeet(inches: number, ratio?: number): number;
244
275
  /** Scale feet of prototype track → real inches on the module. */
245
276
  declare function scaleFeetToInches(feet: number, ratio?: number): number;
277
+ /** Length a spotted car occupies on N-scale track, inches. A 40-ft car body is
278
+ * ~3.0″; ~3.3″ over the couplers — the real spacing a cut of cars takes. The
279
+ * single constant every repo reads so a track's car count matches everywhere. */
280
+ declare const N_CAR_LENGTH_INCHES = 3.3;
281
+ /** How many cars fit in a span, from its drawn length — the derived capacity a
282
+ * siding or an industry spot holds (never typed). */
283
+ declare function carCapacity(fromPos: number, toPos: number, carLengthInches?: number): number;
246
284
  /** Parse a jsonb value into a schematic doc, or null if it isn't one. */
247
285
  declare function asModuleSchematic(x: unknown): ModuleSchematicDoc | null;
248
286
  interface EditorTrack {
@@ -294,6 +332,20 @@ interface EditorCrossing {
294
332
  trackA: string;
295
333
  trackB: string;
296
334
  }
335
+ /** An industry as the authoring form binds it — a car-spot span on a track. */
336
+ interface EditorIndustry {
337
+ id: string;
338
+ name: string;
339
+ type: string;
340
+ track: string;
341
+ fromPos: number;
342
+ toPos: number;
343
+ side: SignalSide;
344
+ labelMode: IndustryLabelMode;
345
+ carTypes: string[];
346
+ /** freemon_industries row (single source of truth), or null for a new one. */
347
+ moduleIndustryId: number | null;
348
+ }
297
349
  /** A 3rd+ endplate — a branch/junction connection off the module (#170).
298
350
  * A module may have several (e.g. a set carrying a second railroad through:
299
351
  * MoPac enters at one branch endplate and leaves at another). */
@@ -339,6 +391,8 @@ interface EditorState {
339
391
  * Empty = no authored outline (fall back to the endplate-width band). */
340
392
  outline: BenchworkPoint[];
341
393
  controlPoints: EditorControlPoint[];
394
+ /** Rail-served industries — car-spot spans on a track (#industries). */
395
+ industries: EditorIndustry[];
342
396
  }
343
397
  /** Build the empty editor state for a module of the given length. */
344
398
  declare function emptyEditorState(lengthInches: number): EditorState;
@@ -469,6 +523,23 @@ interface BranchConnector {
469
523
  posFrac: number;
470
524
  side: "up" | "down";
471
525
  }
526
+ /** An industry — draw a car-spot span beside its track's lane, on `side`, with
527
+ * a name label + an optional car/length readout (#industries). */
528
+ interface DrawIndustry {
529
+ id: string;
530
+ name: string;
531
+ type: string | null;
532
+ /** Span as fractions of module length (sorted West→East). */
533
+ fromFrac: number;
534
+ toFrac: number;
535
+ /** Lane of the track it spots on, so it draws beside the right track. */
536
+ lane: number;
537
+ side: SignalSide;
538
+ labelMode: IndustryLabelMode;
539
+ /** Cars that spot here, derived from the drawn span length. */
540
+ cars: number;
541
+ carTypes: string[];
542
+ }
472
543
  interface ModuleFeatures {
473
544
  /** Whether either endplate declares a double-track main. */
474
545
  doubleMain: boolean;
@@ -493,6 +564,8 @@ interface ModuleFeatures {
493
564
  crossovers: DrawCrossover[];
494
565
  /** Branch endplates — junction connectors off the module (#170). */
495
566
  branchConnectors: BranchConnector[];
567
+ /** Rail-served industries — car-spot spans beside their track (#industries). */
568
+ industries: DrawIndustry[];
496
569
  /** Main 2's extent when it doesn't run the full module — a single↔double
497
570
  * transition (Main 2 starts/ends at the mainline turnout). Null = full
498
571
  * length (or no Main 2). Renderers draw the partial line + its diverge. */
@@ -598,4 +671,4 @@ declare function poseOverridesFromDoc(doc: ModuleSchematicDoc): Record<string, {
598
671
  heading: number;
599
672
  }>;
600
673
 
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 };
674
+ 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, scaleFeetToInches, stateToDoc };
package/dist/index.d.ts CHANGED
@@ -132,6 +132,35 @@ interface SchematicControlPoint {
132
132
  crossings?: string[];
133
133
  signals?: SchematicSignal[];
134
134
  }
135
+ /** What a rendered industry shows beside its name: a car count, a length in
136
+ * inches, or nothing (name only). Authored per industry. */
137
+ type IndustryLabelMode = "none" | "cars" | "inches";
138
+ /**
139
+ * An industry — a rail-served customer that spots cars, authored as a SPAN on a
140
+ * track (a spur/siding, or the main). Positional like everything else: it lives
141
+ * in the same module-local inch frame and is rendered into the shared 2-D view,
142
+ * offset to `side`. The span length gives its car capacity; the dispatcher and
143
+ * crews read where cars set out. Mirrors a `freemon_industries` row.
144
+ */
145
+ interface SchematicIndustry {
146
+ id: string;
147
+ name: string;
148
+ /** Industry type value from the lookup (e.g. "team_track", "grain"). */
149
+ type?: string | null;
150
+ /** The track this industry spots cars on (a spur/siding id, or the main). */
151
+ track: string;
152
+ /** The car-spot span along that track, inches from endplate A. */
153
+ fromPos: number;
154
+ toPos: number;
155
+ /** Which side of the track the building + label sit on. */
156
+ side?: SignalSide;
157
+ /** Secondary readout at the label — a car count, a length, or none. */
158
+ labelMode?: IndustryLabelMode;
159
+ /** Car types this industry receives (car-type value strings). */
160
+ carTypes?: string[];
161
+ /** The `freemon_industries` row this is (single source of truth); null = new. */
162
+ moduleIndustryId?: number | null;
163
+ }
135
164
  interface ModuleSchematicDoc {
136
165
  version: number;
137
166
  module?: string;
@@ -156,6 +185,8 @@ interface ModuleSchematicDoc {
156
185
  /** Grade crossings / diamonds (#170). */
157
186
  crossings?: SchematicCrossing[];
158
187
  controlPoints?: SchematicControlPoint[];
188
+ /** Rail-served industries — car-spot spans on a track (#industries). */
189
+ industries?: SchematicIndustry[];
159
190
  /** Benchwork FOOTPRINT outline — the module's physical board shape as a
160
191
  * polygon in module-local inches, in the same frame as the endplate poses
161
192
  * (endplate A's track point at the origin, the mainline along +x, perpendicular
@@ -243,6 +274,13 @@ declare const N_SCALE_RATIO = 160;
243
274
  declare function inchesToScaleFeet(inches: number, ratio?: number): number;
244
275
  /** Scale feet of prototype track → real inches on the module. */
245
276
  declare function scaleFeetToInches(feet: number, ratio?: number): number;
277
+ /** Length a spotted car occupies on N-scale track, inches. A 40-ft car body is
278
+ * ~3.0″; ~3.3″ over the couplers — the real spacing a cut of cars takes. The
279
+ * single constant every repo reads so a track's car count matches everywhere. */
280
+ declare const N_CAR_LENGTH_INCHES = 3.3;
281
+ /** How many cars fit in a span, from its drawn length — the derived capacity a
282
+ * siding or an industry spot holds (never typed). */
283
+ declare function carCapacity(fromPos: number, toPos: number, carLengthInches?: number): number;
246
284
  /** Parse a jsonb value into a schematic doc, or null if it isn't one. */
247
285
  declare function asModuleSchematic(x: unknown): ModuleSchematicDoc | null;
248
286
  interface EditorTrack {
@@ -294,6 +332,20 @@ interface EditorCrossing {
294
332
  trackA: string;
295
333
  trackB: string;
296
334
  }
335
+ /** An industry as the authoring form binds it — a car-spot span on a track. */
336
+ interface EditorIndustry {
337
+ id: string;
338
+ name: string;
339
+ type: string;
340
+ track: string;
341
+ fromPos: number;
342
+ toPos: number;
343
+ side: SignalSide;
344
+ labelMode: IndustryLabelMode;
345
+ carTypes: string[];
346
+ /** freemon_industries row (single source of truth), or null for a new one. */
347
+ moduleIndustryId: number | null;
348
+ }
297
349
  /** A 3rd+ endplate — a branch/junction connection off the module (#170).
298
350
  * A module may have several (e.g. a set carrying a second railroad through:
299
351
  * MoPac enters at one branch endplate and leaves at another). */
@@ -339,6 +391,8 @@ interface EditorState {
339
391
  * Empty = no authored outline (fall back to the endplate-width band). */
340
392
  outline: BenchworkPoint[];
341
393
  controlPoints: EditorControlPoint[];
394
+ /** Rail-served industries — car-spot spans on a track (#industries). */
395
+ industries: EditorIndustry[];
342
396
  }
343
397
  /** Build the empty editor state for a module of the given length. */
344
398
  declare function emptyEditorState(lengthInches: number): EditorState;
@@ -469,6 +523,23 @@ interface BranchConnector {
469
523
  posFrac: number;
470
524
  side: "up" | "down";
471
525
  }
526
+ /** An industry — draw a car-spot span beside its track's lane, on `side`, with
527
+ * a name label + an optional car/length readout (#industries). */
528
+ interface DrawIndustry {
529
+ id: string;
530
+ name: string;
531
+ type: string | null;
532
+ /** Span as fractions of module length (sorted West→East). */
533
+ fromFrac: number;
534
+ toFrac: number;
535
+ /** Lane of the track it spots on, so it draws beside the right track. */
536
+ lane: number;
537
+ side: SignalSide;
538
+ labelMode: IndustryLabelMode;
539
+ /** Cars that spot here, derived from the drawn span length. */
540
+ cars: number;
541
+ carTypes: string[];
542
+ }
472
543
  interface ModuleFeatures {
473
544
  /** Whether either endplate declares a double-track main. */
474
545
  doubleMain: boolean;
@@ -493,6 +564,8 @@ interface ModuleFeatures {
493
564
  crossovers: DrawCrossover[];
494
565
  /** Branch endplates — junction connectors off the module (#170). */
495
566
  branchConnectors: BranchConnector[];
567
+ /** Rail-served industries — car-spot spans beside their track (#industries). */
568
+ industries: DrawIndustry[];
496
569
  /** Main 2's extent when it doesn't run the full module — a single↔double
497
570
  * transition (Main 2 starts/ends at the mainline turnout). Null = full
498
571
  * length (or no Main 2). Renderers draw the partial line + its diverge. */
@@ -598,4 +671,4 @@ declare function poseOverridesFromDoc(doc: ModuleSchematicDoc): Record<string, {
598
671
  heading: number;
599
672
  }>;
600
673
 
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 };
674
+ 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, scaleFeetToInches, stateToDoc };
package/dist/index.js CHANGED
@@ -147,6 +147,11 @@ function inchesToScaleFeet(inches, ratio = N_SCALE_RATIO) {
147
147
  function scaleFeetToInches(feet, ratio = N_SCALE_RATIO) {
148
148
  return feet * 12 / ratio;
149
149
  }
150
+ var N_CAR_LENGTH_INCHES = 3.3;
151
+ function carCapacity(fromPos, toPos, carLengthInches = N_CAR_LENGTH_INCHES) {
152
+ if (!(carLengthInches > 0)) return 0;
153
+ return Math.max(0, Math.floor(Math.abs(toPos - fromPos) / carLengthInches));
154
+ }
150
155
  function asModuleSchematic(x) {
151
156
  if (!x || typeof x !== "object") return null;
152
157
  const d = x;
@@ -168,7 +173,8 @@ function emptyEditorState(lengthInches) {
168
173
  poseOverrides: {},
169
174
  endplateWidths: {},
170
175
  outline: [],
171
- controlPoints: []
176
+ controlPoints: [],
177
+ industries: []
172
178
  };
173
179
  }
174
180
  function isTransitionTurnout(t) {
@@ -338,6 +344,21 @@ function stateToDoc(state, recordNumber) {
338
344
  side: s.side
339
345
  }))
340
346
  })),
347
+ // Industries — car-spot spans on a track; only when any are authored.
348
+ ...state.industries.length > 0 ? {
349
+ industries: state.industries.map((ind) => ({
350
+ id: ind.id,
351
+ name: ind.name,
352
+ ...ind.type ? { type: ind.type } : {},
353
+ track: ind.track,
354
+ fromPos: ind.fromPos,
355
+ toPos: ind.toPos,
356
+ side: ind.side,
357
+ ...ind.labelMode && ind.labelMode !== "none" ? { labelMode: ind.labelMode } : {},
358
+ ...ind.carTypes.length ? { carTypes: ind.carTypes } : {},
359
+ moduleIndustryId: ind.moduleIndustryId
360
+ }))
361
+ } : {},
341
362
  // Benchwork footprint outline (module-local inches); only when it's a real
342
363
  // ring (≥ 3 vertices).
343
364
  ...state.outline.length >= 3 ? { outline: state.outline } : {}
@@ -451,7 +472,19 @@ function docToState(doc, fallbackLength, moduleTracks = []) {
451
472
  divergeTrack: t.divergeTrack,
452
473
  kind: t.kind ?? "right"
453
474
  })),
454
- controlPoints: readControlPoints(d, sc)
475
+ controlPoints: readControlPoints(d, sc),
476
+ industries: (d.industries ?? []).map((ind) => ({
477
+ id: ind.id,
478
+ name: ind.name ?? "",
479
+ type: ind.type ?? "",
480
+ track: ind.track,
481
+ fromPos: sc(ind.fromPos ?? 0),
482
+ toPos: ind.toPos != null ? sc(ind.toPos) : len,
483
+ side: ind.side ?? "above",
484
+ labelMode: ind.labelMode ?? "none",
485
+ carTypes: Array.isArray(ind.carTypes) ? ind.carTypes : [],
486
+ moduleIndustryId: ind.moduleIndustryId ?? null
487
+ }))
455
488
  };
456
489
  }
457
490
  function readControlPoints(d, sc = (p) => p) {
@@ -750,6 +783,22 @@ function moduleFeatures(doc) {
750
783
  posFrac: clampFrac(e.at.pos),
751
784
  side: e.at.side === "down" ? "down" : "up"
752
785
  }));
786
+ const industries = (doc.industries ?? []).map((ind) => {
787
+ const from = ind.fromPos ?? 0;
788
+ const to = ind.toPos ?? len;
789
+ return {
790
+ id: ind.id,
791
+ name: ind.name ?? "",
792
+ type: ind.type ?? null,
793
+ fromFrac: clampFrac(Math.min(from, to)),
794
+ toFrac: clampFrac(Math.max(from, to)),
795
+ lane: trackLane.get(ind.track) ?? 0,
796
+ side: ind.side ?? "above",
797
+ labelMode: ind.labelMode ?? "none",
798
+ cars: carCapacity(from, to),
799
+ carTypes: Array.isArray(ind.carTypes) ? ind.carTypes : []
800
+ };
801
+ });
753
802
  const allLanes = [
754
803
  0,
755
804
  doubleMain ? 1 : 0,
@@ -790,6 +839,7 @@ function moduleFeatures(doc) {
790
839
  crossings,
791
840
  crossovers,
792
841
  branchConnectors,
842
+ industries,
793
843
  laneMin: Math.min(...allLanes),
794
844
  laneMax: Math.max(...allLanes)
795
845
  };
@@ -892,6 +942,6 @@ function poseOverridesFromDoc(doc) {
892
942
  return out;
893
943
  }
894
944
 
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 };
945
+ 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, scaleFeetToInches, stateToDoc };
896
946
  //# sourceMappingURL=index.js.map
897
947
  //# sourceMappingURL=index.js.map