@willcgage/module-schematic 0.25.0 → 0.26.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
@@ -201,6 +201,10 @@ interface ModuleSchematicDoc {
201
201
  * tracks unrolled as a ladder past the throat — the default when inLoop
202
202
  * tracks exist), "geometric" (drawn balloon, AL&E-style). */
203
203
  loopRender?: "bulb" | "fan" | "geometric";
204
+ /** The two mains' positions are swapped: Main 1 draws above (lane 1), Main 2
205
+ * on the centre line (lane 0). Absent/false = the default (Main 1 below).
206
+ * Identities are unchanged — only which lane each is drawn in (#FMN-0043). */
207
+ mainsSwapped?: boolean;
204
208
  endplates: SchematicEndplate[];
205
209
  tracks: SchematicTrack[];
206
210
  turnouts?: SchematicTurnout[];
@@ -429,6 +433,11 @@ interface EditorState {
429
433
  loopReturn: "same" | "main2";
430
434
  configA: TrackConfig;
431
435
  configB: EndplateBConfig;
436
+ /** Swap the two mains' POSITIONS: Main 1 draws above (lane 1) and Main 2 on
437
+ * the centre line (lane 0). The module decides which physical track is which
438
+ * main — on some modules the upper track is the through/primary main
439
+ * (#FMN-0043). Identities and references are unchanged; only the lanes swap. */
440
+ mainsSwapped: boolean;
432
441
  extraTracks: EditorTrack[];
433
442
  turnouts: EditorTurnout[];
434
443
  /** Grade crossings / diamonds (#170). */
package/dist/index.d.ts CHANGED
@@ -201,6 +201,10 @@ interface ModuleSchematicDoc {
201
201
  * tracks unrolled as a ladder past the throat — the default when inLoop
202
202
  * tracks exist), "geometric" (drawn balloon, AL&E-style). */
203
203
  loopRender?: "bulb" | "fan" | "geometric";
204
+ /** The two mains' positions are swapped: Main 1 draws above (lane 1), Main 2
205
+ * on the centre line (lane 0). Absent/false = the default (Main 1 below).
206
+ * Identities are unchanged — only which lane each is drawn in (#FMN-0043). */
207
+ mainsSwapped?: boolean;
204
208
  endplates: SchematicEndplate[];
205
209
  tracks: SchematicTrack[];
206
210
  turnouts?: SchematicTurnout[];
@@ -429,6 +433,11 @@ interface EditorState {
429
433
  loopReturn: "same" | "main2";
430
434
  configA: TrackConfig;
431
435
  configB: EndplateBConfig;
436
+ /** Swap the two mains' POSITIONS: Main 1 draws above (lane 1) and Main 2 on
437
+ * the centre line (lane 0). The module decides which physical track is which
438
+ * main — on some modules the upper track is the through/primary main
439
+ * (#FMN-0043). Identities and references are unchanged; only the lanes swap. */
440
+ mainsSwapped: boolean;
432
441
  extraTracks: EditorTrack[];
433
442
  turnouts: EditorTurnout[];
434
443
  /** Grade crossings / diamonds (#170). */
package/dist/index.js CHANGED
@@ -208,6 +208,7 @@ function emptyEditorState(lengthInches) {
208
208
  loopReturn: "same",
209
209
  configA: "single",
210
210
  configB: "single",
211
+ mainsSwapped: false,
211
212
  extraTracks: [],
212
213
  turnouts: [],
213
214
  crossings: [],
@@ -228,29 +229,31 @@ function main1Track(state) {
228
229
  const bothDouble = state.configA === "double" && state.configB === "double";
229
230
  const isDouble = state.configA === "double" || state.configB === "double";
230
231
  const sw = state.turnouts.find(isTransitionTurnout);
232
+ const lane = state.mainsSwapped && isDouble ? 1 : 0;
231
233
  if (!isDouble || bothDouble || !sw || sw.onTrack !== MAIN2_TRACK_ID) {
232
- return { id: MAIN_TRACK_ID, role: "main", lane: 0, from: "A", to: "B" };
234
+ return { id: MAIN_TRACK_ID, role: "main", lane, from: "A", to: "B" };
233
235
  }
234
236
  return state.configA === "double" ? (
235
237
  // Double at A: Main 1 runs from A and ends at the turnout.
236
- { id: MAIN_TRACK_ID, role: "main", lane: 0, fromPos: 0, toPos: sw.pos }
238
+ { id: MAIN_TRACK_ID, role: "main", lane, fromPos: 0, toPos: sw.pos }
237
239
  ) : (
238
240
  // Double at B: Main 1 begins at the turnout and runs to B.
239
- { id: MAIN_TRACK_ID, role: "main", lane: 0, fromPos: sw.pos, toPos: state.lengthInches }
241
+ { id: MAIN_TRACK_ID, role: "main", lane, fromPos: sw.pos, toPos: state.lengthInches }
240
242
  );
241
243
  }
242
244
  function main2Track(state) {
243
245
  const bothDouble = state.configA === "double" && state.configB === "double";
244
246
  const sw = state.turnouts.find(isTransitionTurnout);
247
+ const lane = state.mainsSwapped ? 0 : 1;
245
248
  if (bothDouble || !sw || sw.divergeTrack !== MAIN2_TRACK_ID) {
246
- return { id: MAIN2_TRACK_ID, role: "main", lane: 1, from: "A", to: "B" };
249
+ return { id: MAIN2_TRACK_ID, role: "main", lane, from: "A", to: "B" };
247
250
  }
248
251
  return state.configA === "double" ? (
249
252
  // Double at A: Main 2 runs from A and ends at the turnout.
250
- { id: MAIN2_TRACK_ID, role: "main", lane: 1, fromPos: 0, toPos: sw.pos }
253
+ { id: MAIN2_TRACK_ID, role: "main", lane, fromPos: 0, toPos: sw.pos }
251
254
  ) : (
252
255
  // Double at B: Main 2 begins at the turnout and runs to B.
253
- { id: MAIN2_TRACK_ID, role: "main", lane: 1, fromPos: sw.pos, toPos: state.lengthInches }
256
+ { id: MAIN2_TRACK_ID, role: "main", lane, fromPos: sw.pos, toPos: state.lengthInches }
254
257
  );
255
258
  }
256
259
  function buildTransition(state) {
@@ -307,6 +310,7 @@ function stateToDoc(state, recordNumber) {
307
310
  lengthInches: state.lengthInches,
308
311
  ...state.loop ? { loop: true } : {},
309
312
  ...state.loop && state.loopReturn === "main2" ? { loopReturn: "main2" } : {},
313
+ ...state.mainsSwapped ? { mainsSwapped: true } : {},
310
314
  endplates: withWidths(
311
315
  withPoses(
312
316
  [
@@ -518,6 +522,7 @@ function docToState(doc, fallbackLength, moduleTracks = []) {
518
522
  lengthInches: len,
519
523
  loop,
520
524
  loopReturn: loop && d.loopReturn === "main2" ? "main2" : "same",
525
+ mainsSwapped: d.mainsSwapped === true,
521
526
  configA: configOf("A"),
522
527
  // On a loop, a missing B means pure turnback; present = interchange loop.
523
528
  configB: loop && !hasB ? "none" : configOf("B"),