@willcgage/module-schematic 0.13.3 → 0.14.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
@@ -43,7 +43,23 @@ interface SchematicEndplate {
43
43
  y: number;
44
44
  heading: number;
45
45
  };
46
+ /** Free-moN endplate FACE width across the track, inches — the physical size
47
+ * of the standard interface at this end. Free-moN spec: 12″ minimum, 24″
48
+ * recommended. Absent = the recommended default (modules may differ end to
49
+ * end, e.g. a transition). */
50
+ widthInches?: number | null;
46
51
  }
52
+ /** Free-moN endplate face width, inches — the connection interface size. */
53
+ declare const FREEMO_ENDPLATE_WIDTH_MIN_INCHES = 12;
54
+ declare const FREEMO_ENDPLATE_WIDTH_RECOMMENDED_INCHES = 24;
55
+ /**
56
+ * The authored face width for an endplate, or the recommended default when a
57
+ * module hasn't authored one. The single source of truth both apps read so a
58
+ * module's endplate size is drawn the same in the Repository and the layout.
59
+ */
60
+ declare function endplateWidthInches(ep: {
61
+ widthInches?: number | null;
62
+ } | null | undefined): number;
47
63
  interface SchematicTrack {
48
64
  id: string;
49
65
  role: TrackRole;
@@ -244,6 +260,9 @@ interface EditorState {
244
260
  y: number;
245
261
  heading: number;
246
262
  }>;
263
+ /** Authored endplate face widths by endplate id, inches (Free-moN 12″ min,
264
+ * 24″ recommended). Absent id = the recommended default. */
265
+ endplateWidths: Record<string, number>;
247
266
  controlPoints: EditorControlPoint[];
248
267
  }
249
268
  /** Build the empty editor state for a module of the given length. */
@@ -504,4 +523,4 @@ declare function poseOverridesFromDoc(doc: ModuleSchematicDoc): Record<string, {
504
523
  heading: number;
505
524
  }>;
506
525
 
507
- export { 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, type GeometryType, MAIN2_TRACK_ID, MAIN_TRACK_ID, type ModuleFeatures, type ModuleGeometryInput, type ModuleSchematicDoc, type ModuleTrackRow, N_SCALE_RATIO, 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, buildCrossover, buildPassingSiding, buildTransition, deriveEndplatePoses, divergeSideForHand, docToState, emptyEditorState, geometryTurnDegrees, inchesToScaleFeet, isLoopDoc, isTransitionTurnout, moduleFeatures, nextId, poseNeedsManual, poseOverridesFromDoc, scaleFeetToInches, stateToDoc };
526
+ export { 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 ModuleGeometryInput, type ModuleSchematicDoc, type ModuleTrackRow, N_SCALE_RATIO, 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, buildCrossover, buildPassingSiding, buildTransition, deriveEndplatePoses, divergeSideForHand, docToState, emptyEditorState, endplateWidthInches, geometryTurnDegrees, inchesToScaleFeet, isLoopDoc, isTransitionTurnout, moduleFeatures, nextId, poseNeedsManual, poseOverridesFromDoc, scaleFeetToInches, stateToDoc };
package/dist/index.d.ts CHANGED
@@ -43,7 +43,23 @@ interface SchematicEndplate {
43
43
  y: number;
44
44
  heading: number;
45
45
  };
46
+ /** Free-moN endplate FACE width across the track, inches — the physical size
47
+ * of the standard interface at this end. Free-moN spec: 12″ minimum, 24″
48
+ * recommended. Absent = the recommended default (modules may differ end to
49
+ * end, e.g. a transition). */
50
+ widthInches?: number | null;
46
51
  }
52
+ /** Free-moN endplate face width, inches — the connection interface size. */
53
+ declare const FREEMO_ENDPLATE_WIDTH_MIN_INCHES = 12;
54
+ declare const FREEMO_ENDPLATE_WIDTH_RECOMMENDED_INCHES = 24;
55
+ /**
56
+ * The authored face width for an endplate, or the recommended default when a
57
+ * module hasn't authored one. The single source of truth both apps read so a
58
+ * module's endplate size is drawn the same in the Repository and the layout.
59
+ */
60
+ declare function endplateWidthInches(ep: {
61
+ widthInches?: number | null;
62
+ } | null | undefined): number;
47
63
  interface SchematicTrack {
48
64
  id: string;
49
65
  role: TrackRole;
@@ -244,6 +260,9 @@ interface EditorState {
244
260
  y: number;
245
261
  heading: number;
246
262
  }>;
263
+ /** Authored endplate face widths by endplate id, inches (Free-moN 12″ min,
264
+ * 24″ recommended). Absent id = the recommended default. */
265
+ endplateWidths: Record<string, number>;
247
266
  controlPoints: EditorControlPoint[];
248
267
  }
249
268
  /** Build the empty editor state for a module of the given length. */
@@ -504,4 +523,4 @@ declare function poseOverridesFromDoc(doc: ModuleSchematicDoc): Record<string, {
504
523
  heading: number;
505
524
  }>;
506
525
 
507
- export { 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, type GeometryType, MAIN2_TRACK_ID, MAIN_TRACK_ID, type ModuleFeatures, type ModuleGeometryInput, type ModuleSchematicDoc, type ModuleTrackRow, N_SCALE_RATIO, 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, buildCrossover, buildPassingSiding, buildTransition, deriveEndplatePoses, divergeSideForHand, docToState, emptyEditorState, geometryTurnDegrees, inchesToScaleFeet, isLoopDoc, isTransitionTurnout, moduleFeatures, nextId, poseNeedsManual, poseOverridesFromDoc, scaleFeetToInches, stateToDoc };
526
+ export { 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 ModuleGeometryInput, type ModuleSchematicDoc, type ModuleTrackRow, N_SCALE_RATIO, 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, buildCrossover, buildPassingSiding, buildTransition, deriveEndplatePoses, divergeSideForHand, docToState, emptyEditorState, endplateWidthInches, geometryTurnDegrees, inchesToScaleFeet, isLoopDoc, isTransitionTurnout, moduleFeatures, nextId, poseNeedsManual, poseOverridesFromDoc, scaleFeetToInches, stateToDoc };
package/dist/index.js CHANGED
@@ -1,4 +1,10 @@
1
1
  // src/index.ts
2
+ var FREEMO_ENDPLATE_WIDTH_MIN_INCHES = 12;
3
+ var FREEMO_ENDPLATE_WIDTH_RECOMMENDED_INCHES = 24;
4
+ function endplateWidthInches(ep) {
5
+ const w = ep?.widthInches;
6
+ return typeof w === "number" && w > 0 ? w : FREEMO_ENDPLATE_WIDTH_RECOMMENDED_INCHES;
7
+ }
2
8
  function isLoopDoc(doc) {
3
9
  return doc.loop === true || doc.endplates.length === 1;
4
10
  }
@@ -30,6 +36,7 @@ function emptyEditorState(lengthInches) {
30
36
  crossings: [],
31
37
  branches: [],
32
38
  poseOverrides: {},
39
+ endplateWidths: {},
33
40
  controlPoints: []
34
41
  };
35
42
  }
@@ -91,6 +98,12 @@ function withPoses(endplates, overrides) {
91
98
  (e) => overrides[e.id] ? { ...e, pose: overrides[e.id] } : e
92
99
  );
93
100
  }
101
+ function withWidths(endplates, widths) {
102
+ return endplates.map((e) => {
103
+ const w = widths[e.id];
104
+ return typeof w === "number" && w > 0 ? { ...e, widthInches: w } : e;
105
+ });
106
+ }
94
107
  function stateToDoc(state, recordNumber) {
95
108
  return {
96
109
  version: 1,
@@ -98,42 +111,45 @@ function stateToDoc(state, recordNumber) {
98
111
  lengthInches: state.lengthInches,
99
112
  ...state.loop ? { loop: true } : {},
100
113
  ...state.loop && state.loopReturn === "main2" ? { loopReturn: "main2" } : {},
101
- endplates: withPoses(
102
- [
103
- ...state.loop ? (
104
- // Balloon loop: A is the entry. A standard endplate B on the balloon
105
- // makes it an INTERCHANGE (second route connects at the loop, e.g.
106
- // Seaford); configB "none" makes it a pure turnback.
107
- [
108
- { id: "A", label: "Entry", tracks: [{ trackId: MAIN_TRACK_ID, lane: 0, config: state.configA }] },
109
- ...state.configB !== "none" ? [{ id: "B", label: "Interchange", tracks: [{ trackId: MAIN_TRACK_ID, lane: 0, config: state.configB }] }] : []
110
- ]
111
- ) : [
112
- { id: "A", label: "West", tracks: [{ trackId: MAIN_TRACK_ID, lane: 0, config: state.configA }] },
113
- // Non-loop modules always have a real B ("none" never applies).
114
- {
115
- id: "B",
116
- label: "East",
117
- tracks: [
118
- {
119
- trackId: MAIN_TRACK_ID,
120
- lane: 0,
121
- config: state.configB === "none" ? "single" : state.configB
122
- }
114
+ endplates: withWidths(
115
+ withPoses(
116
+ [
117
+ ...state.loop ? (
118
+ // Balloon loop: A is the entry. A standard endplate B on the balloon
119
+ // makes it an INTERCHANGE (second route connects at the loop, e.g.
120
+ // Seaford); configB "none" makes it a pure turnback.
121
+ [
122
+ { id: "A", label: "Entry", tracks: [{ trackId: MAIN_TRACK_ID, lane: 0, config: state.configA }] },
123
+ ...state.configB !== "none" ? [{ id: "B", label: "Interchange", tracks: [{ trackId: MAIN_TRACK_ID, lane: 0, config: state.configB }] }] : []
123
124
  ]
124
- }
125
+ ) : [
126
+ { id: "A", label: "West", tracks: [{ trackId: MAIN_TRACK_ID, lane: 0, config: state.configA }] },
127
+ // Non-loop modules always have a real B ("none" never applies).
128
+ {
129
+ id: "B",
130
+ label: "East",
131
+ tracks: [
132
+ {
133
+ trackId: MAIN_TRACK_ID,
134
+ lane: 0,
135
+ config: state.configB === "none" ? "single" : state.configB
136
+ }
137
+ ]
138
+ }
139
+ ],
140
+ // Branch endplates C, D, … — junction connections at pos, off one side
141
+ // (#170). A set can carry several (e.g. a second railroad through).
142
+ ...state.branches.map((b, i) => ({
143
+ id: String.fromCharCode(67 + i),
144
+ // C, D, E…
145
+ label: b.label || `Branch ${i + 1}`,
146
+ tracks: [{ trackId: MAIN_TRACK_ID, lane: 0, config: b.config }],
147
+ at: { pos: b.pos, side: b.side }
148
+ }))
125
149
  ],
126
- // Branch endplates C, D, … — junction connections at pos, off one side
127
- // (#170). A set can carry several (e.g. a second railroad through).
128
- ...state.branches.map((b, i) => ({
129
- id: String.fromCharCode(67 + i),
130
- // C, D, E…
131
- label: b.label || `Branch ${i + 1}`,
132
- tracks: [{ trackId: MAIN_TRACK_ID, lane: 0, config: b.config }],
133
- at: { pos: b.pos, side: b.side }
134
- }))
135
- ],
136
- state.poseOverrides
150
+ state.poseOverrides
151
+ ),
152
+ state.endplateWidths
137
153
  ),
138
154
  tracks: [
139
155
  state.loop ? (
@@ -259,6 +275,11 @@ function docToState(doc, fallbackLength, moduleTracks = []) {
259
275
  (e) => e.id !== "A" && e.id !== "B" && e.at
260
276
  );
261
277
  const poseOverrides = poseOverridesFromDoc(d);
278
+ const endplateWidths = {};
279
+ for (const e of d.endplates ?? []) {
280
+ if (typeof e.widthInches === "number" && e.widthInches > 0)
281
+ endplateWidths[e.id] = e.widthInches;
282
+ }
262
283
  return {
263
284
  lengthInches: len,
264
285
  loop,
@@ -273,6 +294,7 @@ function docToState(doc, fallbackLength, moduleTracks = []) {
273
294
  config: ep.tracks?.[0]?.config === "double" ? "double" : "single"
274
295
  })),
275
296
  poseOverrides,
297
+ endplateWidths,
276
298
  crossings: (d.crossings ?? []).map((x) => ({
277
299
  id: x.id,
278
300
  name: x.name ?? "",
@@ -730,6 +752,6 @@ function poseOverridesFromDoc(doc) {
730
752
  return out;
731
753
  }
732
754
 
733
- export { MAIN2_TRACK_ID, MAIN_TRACK_ID, N_SCALE_RATIO, asModuleSchematic, buildCrossover, buildPassingSiding, buildTransition, deriveEndplatePoses, divergeSideForHand, docToState, emptyEditorState, geometryTurnDegrees, inchesToScaleFeet, isLoopDoc, isTransitionTurnout, moduleFeatures, nextId, poseNeedsManual, poseOverridesFromDoc, scaleFeetToInches, stateToDoc };
755
+ export { FREEMO_ENDPLATE_WIDTH_MIN_INCHES, FREEMO_ENDPLATE_WIDTH_RECOMMENDED_INCHES, MAIN2_TRACK_ID, MAIN_TRACK_ID, N_SCALE_RATIO, asModuleSchematic, buildCrossover, buildPassingSiding, buildTransition, deriveEndplatePoses, divergeSideForHand, docToState, emptyEditorState, endplateWidthInches, geometryTurnDegrees, inchesToScaleFeet, isLoopDoc, isTransitionTurnout, moduleFeatures, nextId, poseNeedsManual, poseOverridesFromDoc, scaleFeetToInches, stateToDoc };
734
756
  //# sourceMappingURL=index.js.map
735
757
  //# sourceMappingURL=index.js.map