@willcgage/module-schematic 0.80.0 → 0.81.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
@@ -1454,7 +1454,11 @@ interface TrackPart {
1454
1454
  /** `flex` is track sold by the length rather than as a fixed geometry — its
1455
1455
  * {@link overallLength} is the LONGEST piece you can lay from it, not a shape
1456
1456
  * (#193). */
1457
- kind: "turnout" | "wye" | "curved-turnout" | "crossing" | "flex";
1457
+ /** ⚠️ `crossover` is an ASSEMBLY, not a single turnout two turnouts plus the
1458
+ * diagonal between two parallel tracks, sold as one fixture. It therefore
1459
+ * carries {@link trackSpacing}, which no single turnout has, and its
1460
+ * `frogNumber` describes the two turnouts in it. */
1461
+ kind: "turnout" | "wye" | "curved-turnout" | "crossover" | "crossing" | "flex";
1458
1462
  /** Manufacturer part numbers by hand, where the part has a hand. */
1459
1463
  partNumbers?: {
1460
1464
  left?: string;
@@ -1521,6 +1525,20 @@ interface TrackPart {
1521
1525
  innerRadius?: PartDimension;
1522
1526
  /** Crossing angle, degrees. */
1523
1527
  crossingAngleDeg?: number;
1528
+ /** Centre-to-centre distance of the two parallel tracks a {@link kind}
1529
+ * `crossover` joins. A crossover fixture is BUILT for one spacing — it is not
1530
+ * adjustable — so this decides whether the part suits a given standard at all.
1531
+ *
1532
+ * ⚠️ READ {@link FREEMO_TRACK_SPACING_INCHES} ALONGSIDE THIS. Free-moN §2.0
1533
+ * fixes double-track spacing at exactly 1.125″; the Fast Tracks N crossovers
1534
+ * are built to 1.09″. That 0.035″ is small but it is REAL and it is not a
1535
+ * tolerance — the fixture cannot be built to another spacing. Recorded rather
1536
+ * than reconciled: it is a fact about the product, and an owner deciding what
1537
+ * to buy is better served by the true number than by a convenient one. */
1538
+ trackSpacing?: PartDimension;
1539
+ /** The SECOND frog angle on a part that has two — the diamond where the
1540
+ * diagonals of a scissors crossover cross. Published in degrees. */
1541
+ secondaryFrogAngle?: PartAngle;
1524
1542
  /** The part's drawn geometry in its own frame, when it came from a library
1525
1543
  * file. This is the payload worth importing — real outlines we can draw
1526
1544
  * instead of deriving a turnout's shape from a frog number. */
@@ -1663,6 +1681,45 @@ declare const FLEX_TRACK_PARTS: TrackPart[];
1663
1681
  * here — the public product pages say the same thing and can be cited.
1664
1682
  */
1665
1683
  declare const FAST_TRACKS_N_ME55: TrackPart[];
1684
+ /**
1685
+ * Fast Tracks N-scale CROSSOVER fixtures, ME Code 55.
1686
+ *
1687
+ * crossover angle 2nd frog default minimum track spacing
1688
+ * #6 9.46° 19° 10.07″ 9.31″ 1.09″
1689
+ * #8 7.13° 14.3° 13.61″ 13.07″ 1.09″
1690
+ *
1691
+ * ⚠️⚠️ **THE TRACK SPACING IS 1.09″, AND FREE-moN §2.0 REQUIRES 1.125″.**
1692
+ * A crossover fixture is machined for ONE spacing; it is not adjustable. So a
1693
+ * crossover hand-built on either of these puts the parallel track 0.035″ closer
1694
+ * than the standard, and that difference has to go somewhere — the tracks pinch
1695
+ * through the crossover and open back out to meet the endplates, which is fixed
1696
+ * at both ends by {@link FREEMO_TRACK_SPACING_INCHES}.
1697
+ *
1698
+ * Recorded, NOT reconciled. It is 0.9 mm and most builders will absorb it, but
1699
+ * it is a property of the product rather than a tolerance, and someone choosing
1700
+ * what to buy for a double-track Free-moN module is better served by the true
1701
+ * number than a convenient one. Nothing here warns or blocks — that would be a
1702
+ * decision for the app, not for a data table.
1703
+ *
1704
+ * ⭐ THE SECOND FROG IS EXACTLY TWICE THE FIRST — 19° against 2 × 9.46 = 18.92,
1705
+ * and 14.3° against 2 × 7.13 = 14.26, both inside the published rounding. That
1706
+ * is the diamond in a scissors crossover, where two diagonals each leaving at
1707
+ * the frog angle meet each other. It is a free cross-check on the pair, and it
1708
+ * passes.
1709
+ *
1710
+ * ⚠️ A CROSSOVER IS AN ASSEMBLY, so `partExtent` means nothing for it and the
1711
+ * turnout size lookups must never see it: `kind` is `"crossover"`, and every
1712
+ * one of them filters `kind === "turnout"`.
1713
+ *
1714
+ * Atlas make crossover parts too — Will has no figures for them as of
1715
+ * 2026-07-26, so there are deliberately no Atlas entries here rather than
1716
+ * guessed ones.
1717
+ *
1718
+ * Source: handlaidtrack.com product pages, read 2026-07-26. Their tables also
1719
+ * carry tie size and tie spacing; those describe the QuickSticks tie strip's
1720
+ * appearance rather than the track's geometry, so they are not carried here.
1721
+ */
1722
+ declare const FAST_TRACKS_N_ME55_CROSSOVERS: TrackPart[];
1666
1723
  /** What a track is laid with when nobody has said — the commonest N-scale flex. */
1667
1724
  declare const DEFAULT_FLEX_PART_ID = "atlas-c55-n-flex";
1668
1725
  /** Every built-in part, across manufacturers. */
@@ -1984,6 +2041,10 @@ interface StoredTrackPart {
1984
2041
  minimumLengthSource?: string | null;
1985
2042
  substitutionRadiusInches?: number | null;
1986
2043
  substitutionRadiusSource?: string | null;
2044
+ trackSpacingInches?: number | null;
2045
+ trackSpacingSource?: string | null;
2046
+ secondaryFrogAngleDeg?: number | null;
2047
+ secondaryFrogAngleSource?: string | null;
1987
2048
  buildable?: boolean | null;
1988
2049
  leadInches?: number | null;
1989
2050
  leadSource?: string | null;
@@ -2327,4 +2388,4 @@ declare function poseOverridesFromDoc(doc: ModuleSchematicDoc): Record<string, {
2327
2388
  heading: number;
2328
2389
  }>;
2329
2390
 
2330
- export { ATLAS_CODE55_N, BUILT_IN_TRACK_PARTS, type BenchworkPoint, type BranchConnector, CLEARANCE_SPACING_INCHES, CODE55_RAIL_HEIGHT_INCHES, DEFAULT_FLEX_PART_ID, type DimensionSource, type DrawCrossing, type DrawCrossover, type DrawIndustry, type DrawSignal, type DrawTrack, type DrawTurnout, ENDPLATE_FASCIA_CLEAR_INCHES, ENDPLATE_LEAD_INCHES, type EditorBranch, type EditorControlPoint, type EditorCpSignal, type EditorCrossing, type EditorIndustry, type EditorState, type EditorTrack, type EditorTurnout, type EndplateBConfig, type EndplatePose, type EndplateTrackIssue, type EndplateWidthIssue, FAST_TRACKS_N_ME55, FLEX_TRACK_PARTS, FREEMO_ENDPLATE_TRACK_FASCIA_CLEARANCE_INCHES, FREEMO_ENDPLATE_WIDTH_MIN_INCHES, FREEMO_ENDPLATE_WIDTH_RECOMMENDED_INCHES, FREEMO_TRACK_SPACING_INCHES, type FlexPiece, type FlexPieceEnd, type FrogCasting, type GeometryType, type ImportedPart, type IndustryLabelMode, type IndustrySpot, 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 OccupiedSpan, type OutlineFace, type PartAngle, type PartDimension, type PartEnd, type PartExtent, type PartSegment, RAIL_GAUGE_INCHES, type ReturnLoopGeometry, type ReturnLoopShape, type SchematicBlock, type SchematicControlPoint, type SchematicCrossing, type SchematicEndplate, type SchematicEndplateTrack, type SchematicIndustry, type SchematicSection, type SchematicSignal, type SchematicTrack, type SchematicTurnout, type SectionAdjacency, type SectionEnd, type SectionEndAssessment, type SectionFootprint, type SectionJointAssessment, type SectionRelativePos, type SignalFacing, type SignalSide, type SpanOverhang, type StoredTrackPart, TIE_HALF_LENGTH_INCHES, TURNOUT_LEAD_INCHES_PER_FROG, type TrackConfig, type TrackPart, type TrackRole, type TurnoutClosure, type TurnoutKind, type UsableCapacity, WHOLE_MODULE_SECTION_ID, asModuleSchematic, assessSectionEnd, assessSectionJoint, benchworkBand, benchworkOutline, buildCrossover, buildPassingSiding, buildTransition, carCapacity, checkEndplateWidth, clearancePointPastFrogInches, deriveEndplatePoses, divergeSideForHand, docToState, emptyEditorState, endplateCentreOffsetInches, endplateFaceSegments, endplateLead, endplateTrackOffsetInches, endplateWidthInches, flexPartFor, flexParts, flexPieces, flexUsage, frogCasting, frogNumberFromName, fromSectionRelative, geometryTurnDegrees, hasNoFarEndplate, importedPartToTrackPart, inchesToScaleFeet, isLoopDoc, isTransitionTurnout, leadInchesForSize, maxFlexPieceInches, mergeImportedParts, mergeStoredParts, moduleCenterline, moduleFeatures, moduleFootprint, moduleLengthFromSections, moduleSections, nextId, parseXtpLibrary, partExtent, partExtentForSize, partOutlineAtFrog, pastFrogInchesForSize, pathLengthInches, poseNeedsManual, poseOverridesFromDoc, remapPos, resizeFlexPiece, returnLoop, sampleBenchworkOutline, samplePartSegments, samplePath, scaleFeetToInches, sectionAdjacency, sectionBand, sectionBreaksFromSections, sectionComponents, sectionFootprints, sectionNeighbours, sectionSpans, sectionSpansOrWhole, sectionedCenterline, sectionedEndPose, sliceCenterline, spanOverhang, stateToDoc, storedPartToTrackPart, toSectionRelative, trackMeetsEndplateIssues, trackPart, trackPath, turnoutClosure, turnoutFacing, turnoutOccupiedSpan, turnoutPartForSize, usableCapacity };
2391
+ export { ATLAS_CODE55_N, BUILT_IN_TRACK_PARTS, type BenchworkPoint, type BranchConnector, CLEARANCE_SPACING_INCHES, CODE55_RAIL_HEIGHT_INCHES, DEFAULT_FLEX_PART_ID, type DimensionSource, type DrawCrossing, type DrawCrossover, type DrawIndustry, type DrawSignal, type DrawTrack, type DrawTurnout, ENDPLATE_FASCIA_CLEAR_INCHES, ENDPLATE_LEAD_INCHES, type EditorBranch, type EditorControlPoint, type EditorCpSignal, type EditorCrossing, type EditorIndustry, type EditorState, type EditorTrack, type EditorTurnout, type EndplateBConfig, type EndplatePose, type EndplateTrackIssue, type EndplateWidthIssue, FAST_TRACKS_N_ME55, FAST_TRACKS_N_ME55_CROSSOVERS, FLEX_TRACK_PARTS, FREEMO_ENDPLATE_TRACK_FASCIA_CLEARANCE_INCHES, FREEMO_ENDPLATE_WIDTH_MIN_INCHES, FREEMO_ENDPLATE_WIDTH_RECOMMENDED_INCHES, FREEMO_TRACK_SPACING_INCHES, type FlexPiece, type FlexPieceEnd, type FrogCasting, type GeometryType, type ImportedPart, type IndustryLabelMode, type IndustrySpot, 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 OccupiedSpan, type OutlineFace, type PartAngle, type PartDimension, type PartEnd, type PartExtent, type PartSegment, RAIL_GAUGE_INCHES, type ReturnLoopGeometry, type ReturnLoopShape, type SchematicBlock, type SchematicControlPoint, type SchematicCrossing, type SchematicEndplate, type SchematicEndplateTrack, type SchematicIndustry, type SchematicSection, type SchematicSignal, type SchematicTrack, type SchematicTurnout, type SectionAdjacency, type SectionEnd, type SectionEndAssessment, type SectionFootprint, type SectionJointAssessment, type SectionRelativePos, type SignalFacing, type SignalSide, type SpanOverhang, type StoredTrackPart, TIE_HALF_LENGTH_INCHES, TURNOUT_LEAD_INCHES_PER_FROG, type TrackConfig, type TrackPart, type TrackRole, type TurnoutClosure, type TurnoutKind, type UsableCapacity, WHOLE_MODULE_SECTION_ID, asModuleSchematic, assessSectionEnd, assessSectionJoint, benchworkBand, benchworkOutline, buildCrossover, buildPassingSiding, buildTransition, carCapacity, checkEndplateWidth, clearancePointPastFrogInches, deriveEndplatePoses, divergeSideForHand, docToState, emptyEditorState, endplateCentreOffsetInches, endplateFaceSegments, endplateLead, endplateTrackOffsetInches, endplateWidthInches, flexPartFor, flexParts, flexPieces, flexUsage, frogCasting, frogNumberFromName, fromSectionRelative, geometryTurnDegrees, hasNoFarEndplate, importedPartToTrackPart, inchesToScaleFeet, isLoopDoc, isTransitionTurnout, leadInchesForSize, maxFlexPieceInches, mergeImportedParts, mergeStoredParts, moduleCenterline, moduleFeatures, moduleFootprint, moduleLengthFromSections, moduleSections, nextId, parseXtpLibrary, partExtent, partExtentForSize, partOutlineAtFrog, pastFrogInchesForSize, pathLengthInches, poseNeedsManual, poseOverridesFromDoc, remapPos, resizeFlexPiece, returnLoop, sampleBenchworkOutline, samplePartSegments, samplePath, scaleFeetToInches, sectionAdjacency, sectionBand, sectionBreaksFromSections, sectionComponents, sectionFootprints, sectionNeighbours, sectionSpans, sectionSpansOrWhole, sectionedCenterline, sectionedEndPose, sliceCenterline, spanOverhang, stateToDoc, storedPartToTrackPart, toSectionRelative, trackMeetsEndplateIssues, trackPart, trackPath, turnoutClosure, turnoutFacing, turnoutOccupiedSpan, turnoutPartForSize, usableCapacity };
package/dist/index.d.ts CHANGED
@@ -1454,7 +1454,11 @@ interface TrackPart {
1454
1454
  /** `flex` is track sold by the length rather than as a fixed geometry — its
1455
1455
  * {@link overallLength} is the LONGEST piece you can lay from it, not a shape
1456
1456
  * (#193). */
1457
- kind: "turnout" | "wye" | "curved-turnout" | "crossing" | "flex";
1457
+ /** ⚠️ `crossover` is an ASSEMBLY, not a single turnout two turnouts plus the
1458
+ * diagonal between two parallel tracks, sold as one fixture. It therefore
1459
+ * carries {@link trackSpacing}, which no single turnout has, and its
1460
+ * `frogNumber` describes the two turnouts in it. */
1461
+ kind: "turnout" | "wye" | "curved-turnout" | "crossover" | "crossing" | "flex";
1458
1462
  /** Manufacturer part numbers by hand, where the part has a hand. */
1459
1463
  partNumbers?: {
1460
1464
  left?: string;
@@ -1521,6 +1525,20 @@ interface TrackPart {
1521
1525
  innerRadius?: PartDimension;
1522
1526
  /** Crossing angle, degrees. */
1523
1527
  crossingAngleDeg?: number;
1528
+ /** Centre-to-centre distance of the two parallel tracks a {@link kind}
1529
+ * `crossover` joins. A crossover fixture is BUILT for one spacing — it is not
1530
+ * adjustable — so this decides whether the part suits a given standard at all.
1531
+ *
1532
+ * ⚠️ READ {@link FREEMO_TRACK_SPACING_INCHES} ALONGSIDE THIS. Free-moN §2.0
1533
+ * fixes double-track spacing at exactly 1.125″; the Fast Tracks N crossovers
1534
+ * are built to 1.09″. That 0.035″ is small but it is REAL and it is not a
1535
+ * tolerance — the fixture cannot be built to another spacing. Recorded rather
1536
+ * than reconciled: it is a fact about the product, and an owner deciding what
1537
+ * to buy is better served by the true number than by a convenient one. */
1538
+ trackSpacing?: PartDimension;
1539
+ /** The SECOND frog angle on a part that has two — the diamond where the
1540
+ * diagonals of a scissors crossover cross. Published in degrees. */
1541
+ secondaryFrogAngle?: PartAngle;
1524
1542
  /** The part's drawn geometry in its own frame, when it came from a library
1525
1543
  * file. This is the payload worth importing — real outlines we can draw
1526
1544
  * instead of deriving a turnout's shape from a frog number. */
@@ -1663,6 +1681,45 @@ declare const FLEX_TRACK_PARTS: TrackPart[];
1663
1681
  * here — the public product pages say the same thing and can be cited.
1664
1682
  */
1665
1683
  declare const FAST_TRACKS_N_ME55: TrackPart[];
1684
+ /**
1685
+ * Fast Tracks N-scale CROSSOVER fixtures, ME Code 55.
1686
+ *
1687
+ * crossover angle 2nd frog default minimum track spacing
1688
+ * #6 9.46° 19° 10.07″ 9.31″ 1.09″
1689
+ * #8 7.13° 14.3° 13.61″ 13.07″ 1.09″
1690
+ *
1691
+ * ⚠️⚠️ **THE TRACK SPACING IS 1.09″, AND FREE-moN §2.0 REQUIRES 1.125″.**
1692
+ * A crossover fixture is machined for ONE spacing; it is not adjustable. So a
1693
+ * crossover hand-built on either of these puts the parallel track 0.035″ closer
1694
+ * than the standard, and that difference has to go somewhere — the tracks pinch
1695
+ * through the crossover and open back out to meet the endplates, which is fixed
1696
+ * at both ends by {@link FREEMO_TRACK_SPACING_INCHES}.
1697
+ *
1698
+ * Recorded, NOT reconciled. It is 0.9 mm and most builders will absorb it, but
1699
+ * it is a property of the product rather than a tolerance, and someone choosing
1700
+ * what to buy for a double-track Free-moN module is better served by the true
1701
+ * number than a convenient one. Nothing here warns or blocks — that would be a
1702
+ * decision for the app, not for a data table.
1703
+ *
1704
+ * ⭐ THE SECOND FROG IS EXACTLY TWICE THE FIRST — 19° against 2 × 9.46 = 18.92,
1705
+ * and 14.3° against 2 × 7.13 = 14.26, both inside the published rounding. That
1706
+ * is the diamond in a scissors crossover, where two diagonals each leaving at
1707
+ * the frog angle meet each other. It is a free cross-check on the pair, and it
1708
+ * passes.
1709
+ *
1710
+ * ⚠️ A CROSSOVER IS AN ASSEMBLY, so `partExtent` means nothing for it and the
1711
+ * turnout size lookups must never see it: `kind` is `"crossover"`, and every
1712
+ * one of them filters `kind === "turnout"`.
1713
+ *
1714
+ * Atlas make crossover parts too — Will has no figures for them as of
1715
+ * 2026-07-26, so there are deliberately no Atlas entries here rather than
1716
+ * guessed ones.
1717
+ *
1718
+ * Source: handlaidtrack.com product pages, read 2026-07-26. Their tables also
1719
+ * carry tie size and tie spacing; those describe the QuickSticks tie strip's
1720
+ * appearance rather than the track's geometry, so they are not carried here.
1721
+ */
1722
+ declare const FAST_TRACKS_N_ME55_CROSSOVERS: TrackPart[];
1666
1723
  /** What a track is laid with when nobody has said — the commonest N-scale flex. */
1667
1724
  declare const DEFAULT_FLEX_PART_ID = "atlas-c55-n-flex";
1668
1725
  /** Every built-in part, across manufacturers. */
@@ -1984,6 +2041,10 @@ interface StoredTrackPart {
1984
2041
  minimumLengthSource?: string | null;
1985
2042
  substitutionRadiusInches?: number | null;
1986
2043
  substitutionRadiusSource?: string | null;
2044
+ trackSpacingInches?: number | null;
2045
+ trackSpacingSource?: string | null;
2046
+ secondaryFrogAngleDeg?: number | null;
2047
+ secondaryFrogAngleSource?: string | null;
1987
2048
  buildable?: boolean | null;
1988
2049
  leadInches?: number | null;
1989
2050
  leadSource?: string | null;
@@ -2327,4 +2388,4 @@ declare function poseOverridesFromDoc(doc: ModuleSchematicDoc): Record<string, {
2327
2388
  heading: number;
2328
2389
  }>;
2329
2390
 
2330
- export { ATLAS_CODE55_N, BUILT_IN_TRACK_PARTS, type BenchworkPoint, type BranchConnector, CLEARANCE_SPACING_INCHES, CODE55_RAIL_HEIGHT_INCHES, DEFAULT_FLEX_PART_ID, type DimensionSource, type DrawCrossing, type DrawCrossover, type DrawIndustry, type DrawSignal, type DrawTrack, type DrawTurnout, ENDPLATE_FASCIA_CLEAR_INCHES, ENDPLATE_LEAD_INCHES, type EditorBranch, type EditorControlPoint, type EditorCpSignal, type EditorCrossing, type EditorIndustry, type EditorState, type EditorTrack, type EditorTurnout, type EndplateBConfig, type EndplatePose, type EndplateTrackIssue, type EndplateWidthIssue, FAST_TRACKS_N_ME55, FLEX_TRACK_PARTS, FREEMO_ENDPLATE_TRACK_FASCIA_CLEARANCE_INCHES, FREEMO_ENDPLATE_WIDTH_MIN_INCHES, FREEMO_ENDPLATE_WIDTH_RECOMMENDED_INCHES, FREEMO_TRACK_SPACING_INCHES, type FlexPiece, type FlexPieceEnd, type FrogCasting, type GeometryType, type ImportedPart, type IndustryLabelMode, type IndustrySpot, 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 OccupiedSpan, type OutlineFace, type PartAngle, type PartDimension, type PartEnd, type PartExtent, type PartSegment, RAIL_GAUGE_INCHES, type ReturnLoopGeometry, type ReturnLoopShape, type SchematicBlock, type SchematicControlPoint, type SchematicCrossing, type SchematicEndplate, type SchematicEndplateTrack, type SchematicIndustry, type SchematicSection, type SchematicSignal, type SchematicTrack, type SchematicTurnout, type SectionAdjacency, type SectionEnd, type SectionEndAssessment, type SectionFootprint, type SectionJointAssessment, type SectionRelativePos, type SignalFacing, type SignalSide, type SpanOverhang, type StoredTrackPart, TIE_HALF_LENGTH_INCHES, TURNOUT_LEAD_INCHES_PER_FROG, type TrackConfig, type TrackPart, type TrackRole, type TurnoutClosure, type TurnoutKind, type UsableCapacity, WHOLE_MODULE_SECTION_ID, asModuleSchematic, assessSectionEnd, assessSectionJoint, benchworkBand, benchworkOutline, buildCrossover, buildPassingSiding, buildTransition, carCapacity, checkEndplateWidth, clearancePointPastFrogInches, deriveEndplatePoses, divergeSideForHand, docToState, emptyEditorState, endplateCentreOffsetInches, endplateFaceSegments, endplateLead, endplateTrackOffsetInches, endplateWidthInches, flexPartFor, flexParts, flexPieces, flexUsage, frogCasting, frogNumberFromName, fromSectionRelative, geometryTurnDegrees, hasNoFarEndplate, importedPartToTrackPart, inchesToScaleFeet, isLoopDoc, isTransitionTurnout, leadInchesForSize, maxFlexPieceInches, mergeImportedParts, mergeStoredParts, moduleCenterline, moduleFeatures, moduleFootprint, moduleLengthFromSections, moduleSections, nextId, parseXtpLibrary, partExtent, partExtentForSize, partOutlineAtFrog, pastFrogInchesForSize, pathLengthInches, poseNeedsManual, poseOverridesFromDoc, remapPos, resizeFlexPiece, returnLoop, sampleBenchworkOutline, samplePartSegments, samplePath, scaleFeetToInches, sectionAdjacency, sectionBand, sectionBreaksFromSections, sectionComponents, sectionFootprints, sectionNeighbours, sectionSpans, sectionSpansOrWhole, sectionedCenterline, sectionedEndPose, sliceCenterline, spanOverhang, stateToDoc, storedPartToTrackPart, toSectionRelative, trackMeetsEndplateIssues, trackPart, trackPath, turnoutClosure, turnoutFacing, turnoutOccupiedSpan, turnoutPartForSize, usableCapacity };
2391
+ export { ATLAS_CODE55_N, BUILT_IN_TRACK_PARTS, type BenchworkPoint, type BranchConnector, CLEARANCE_SPACING_INCHES, CODE55_RAIL_HEIGHT_INCHES, DEFAULT_FLEX_PART_ID, type DimensionSource, type DrawCrossing, type DrawCrossover, type DrawIndustry, type DrawSignal, type DrawTrack, type DrawTurnout, ENDPLATE_FASCIA_CLEAR_INCHES, ENDPLATE_LEAD_INCHES, type EditorBranch, type EditorControlPoint, type EditorCpSignal, type EditorCrossing, type EditorIndustry, type EditorState, type EditorTrack, type EditorTurnout, type EndplateBConfig, type EndplatePose, type EndplateTrackIssue, type EndplateWidthIssue, FAST_TRACKS_N_ME55, FAST_TRACKS_N_ME55_CROSSOVERS, FLEX_TRACK_PARTS, FREEMO_ENDPLATE_TRACK_FASCIA_CLEARANCE_INCHES, FREEMO_ENDPLATE_WIDTH_MIN_INCHES, FREEMO_ENDPLATE_WIDTH_RECOMMENDED_INCHES, FREEMO_TRACK_SPACING_INCHES, type FlexPiece, type FlexPieceEnd, type FrogCasting, type GeometryType, type ImportedPart, type IndustryLabelMode, type IndustrySpot, 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 OccupiedSpan, type OutlineFace, type PartAngle, type PartDimension, type PartEnd, type PartExtent, type PartSegment, RAIL_GAUGE_INCHES, type ReturnLoopGeometry, type ReturnLoopShape, type SchematicBlock, type SchematicControlPoint, type SchematicCrossing, type SchematicEndplate, type SchematicEndplateTrack, type SchematicIndustry, type SchematicSection, type SchematicSignal, type SchematicTrack, type SchematicTurnout, type SectionAdjacency, type SectionEnd, type SectionEndAssessment, type SectionFootprint, type SectionJointAssessment, type SectionRelativePos, type SignalFacing, type SignalSide, type SpanOverhang, type StoredTrackPart, TIE_HALF_LENGTH_INCHES, TURNOUT_LEAD_INCHES_PER_FROG, type TrackConfig, type TrackPart, type TrackRole, type TurnoutClosure, type TurnoutKind, type UsableCapacity, WHOLE_MODULE_SECTION_ID, asModuleSchematic, assessSectionEnd, assessSectionJoint, benchworkBand, benchworkOutline, buildCrossover, buildPassingSiding, buildTransition, carCapacity, checkEndplateWidth, clearancePointPastFrogInches, deriveEndplatePoses, divergeSideForHand, docToState, emptyEditorState, endplateCentreOffsetInches, endplateFaceSegments, endplateLead, endplateTrackOffsetInches, endplateWidthInches, flexPartFor, flexParts, flexPieces, flexUsage, frogCasting, frogNumberFromName, fromSectionRelative, geometryTurnDegrees, hasNoFarEndplate, importedPartToTrackPart, inchesToScaleFeet, isLoopDoc, isTransitionTurnout, leadInchesForSize, maxFlexPieceInches, mergeImportedParts, mergeStoredParts, moduleCenterline, moduleFeatures, moduleFootprint, moduleLengthFromSections, moduleSections, nextId, parseXtpLibrary, partExtent, partExtentForSize, partOutlineAtFrog, pastFrogInchesForSize, pathLengthInches, poseNeedsManual, poseOverridesFromDoc, remapPos, resizeFlexPiece, returnLoop, sampleBenchworkOutline, samplePartSegments, samplePath, scaleFeetToInches, sectionAdjacency, sectionBand, sectionBreaksFromSections, sectionComponents, sectionFootprints, sectionNeighbours, sectionSpans, sectionSpansOrWhole, sectionedCenterline, sectionedEndPose, sliceCenterline, spanOverhang, stateToDoc, storedPartToTrackPart, toSectionRelative, trackMeetsEndplateIssues, trackPart, trackPath, turnoutClosure, turnoutFacing, turnoutOccupiedSpan, turnoutPartForSize, usableCapacity };
package/dist/index.js CHANGED
@@ -1574,10 +1574,47 @@ var FAST_TRACKS_N_ME55 = [
1574
1574
  substitutionRadius: { inches: subR, source: manufacturer, note: spec }
1575
1575
  };
1576
1576
  });
1577
+ var FAST_TRACKS_N_ME55_CROSSOVERS = [
1578
+ // [N, angle°, secondFrog°, defaultLength, minLength, trackSpacing]
1579
+ [6, 9.46, 19, 10.07, 9.31, 1.09],
1580
+ [8, 7.13, 14.3, 13.61, 13.07, 1.09]
1581
+ ].map(([n, deg, second, dflt, min, spacing]) => {
1582
+ const spec = "handlaidtrack.com Detailed Specifications, read 2026-07-26";
1583
+ const manufacturer = "manufacturer";
1584
+ return {
1585
+ id: `fast-tracks-n-me55-c-${n}`,
1586
+ manufacturer: "Fast Tracks",
1587
+ line: "Code 55",
1588
+ scale: "N",
1589
+ name: `#${n} Crossover`,
1590
+ kind: "crossover",
1591
+ partNumbers: { single: `AF-N-C-${n}-ME55` },
1592
+ frogNumber: n,
1593
+ buildable: true,
1594
+ actualAngle: { deg, source: manufacturer, note: `${spec}. atan(1/${n}) exactly.` },
1595
+ secondaryFrogAngle: {
1596
+ deg: second,
1597
+ source: manufacturer,
1598
+ note: `${spec}. The diamond of a scissors crossover \u2014 2 \xD7 ${deg}\xB0 within the published rounding.`
1599
+ },
1600
+ overallLength: {
1601
+ inches: dflt,
1602
+ source: manufacturer,
1603
+ note: `${spec}. The DEFAULT length of the whole assembly \u2014 a fixture, so the builder chooses.`
1604
+ },
1605
+ minimumLength: { inches: min, source: manufacturer, note: spec },
1606
+ trackSpacing: {
1607
+ inches: spacing,
1608
+ source: manufacturer,
1609
+ note: `${spec}. \u26A0\uFE0F Free-moN \xA72.0 requires ${FREEMO_TRACK_SPACING_INCHES}\u2033 \u2014 this fixture is built to ${spacing}\u2033, ${(FREEMO_TRACK_SPACING_INCHES - spacing).toFixed(3)}\u2033 tighter, and cannot be built to another spacing.`
1610
+ }
1611
+ };
1612
+ });
1577
1613
  var DEFAULT_FLEX_PART_ID = "atlas-c55-n-flex";
1578
1614
  var BUILT_IN_TRACK_PARTS = [
1579
1615
  ...ATLAS_CODE55_N,
1580
1616
  ...FAST_TRACKS_N_ME55,
1617
+ ...FAST_TRACKS_N_ME55_CROSSOVERS,
1581
1618
  ...FLEX_TRACK_PARTS
1582
1619
  ];
1583
1620
  function flexParts(library = BUILT_IN_TRACK_PARTS) {
@@ -1905,6 +1942,14 @@ function storedPartToTrackPart(row) {
1905
1942
  if (minimum) part.minimumLength = minimum;
1906
1943
  const substitution = dim(row.substitutionRadiusInches, row.substitutionRadiusSource);
1907
1944
  if (substitution) part.substitutionRadius = substitution;
1945
+ const spacing = dim(row.trackSpacingInches, row.trackSpacingSource);
1946
+ if (spacing) part.trackSpacing = spacing;
1947
+ if (typeof row.secondaryFrogAngleDeg === "number")
1948
+ part.secondaryFrogAngle = {
1949
+ deg: row.secondaryFrogAngleDeg,
1950
+ source: asSource(row.secondaryFrogAngleSource),
1951
+ ...note ? { note } : {}
1952
+ };
1908
1953
  if (row.buildable) part.buildable = true;
1909
1954
  if (lead) part.lead = lead;
1910
1955
  const outer = dim(row.outerRadiusInches, row.radiusSource);
@@ -2600,6 +2645,6 @@ function poseOverridesFromDoc(doc) {
2600
2645
  return out;
2601
2646
  }
2602
2647
 
2603
- export { ATLAS_CODE55_N, BUILT_IN_TRACK_PARTS, CLEARANCE_SPACING_INCHES, CODE55_RAIL_HEIGHT_INCHES, DEFAULT_FLEX_PART_ID, ENDPLATE_FASCIA_CLEAR_INCHES, ENDPLATE_LEAD_INCHES, FAST_TRACKS_N_ME55, FLEX_TRACK_PARTS, FREEMO_ENDPLATE_TRACK_FASCIA_CLEARANCE_INCHES, FREEMO_ENDPLATE_WIDTH_MIN_INCHES, FREEMO_ENDPLATE_WIDTH_RECOMMENDED_INCHES, FREEMO_TRACK_SPACING_INCHES, MAIN2_TRACK_ID, MAIN_TRACK_ID, N_CAR_LENGTH_INCHES, N_SCALE_RATIO, RAIL_GAUGE_INCHES, TIE_HALF_LENGTH_INCHES, TURNOUT_LEAD_INCHES_PER_FROG, WHOLE_MODULE_SECTION_ID, asModuleSchematic, assessSectionEnd, assessSectionJoint, benchworkBand, benchworkOutline, buildCrossover, buildPassingSiding, buildTransition, carCapacity, checkEndplateWidth, clearancePointPastFrogInches, deriveEndplatePoses, divergeSideForHand, docToState, emptyEditorState, endplateCentreOffsetInches, endplateFaceSegments, endplateLead, endplateTrackOffsetInches, endplateWidthInches, flexPartFor, flexParts, flexPieces, flexUsage, frogCasting, frogNumberFromName, fromSectionRelative, geometryTurnDegrees, hasNoFarEndplate, importedPartToTrackPart, inchesToScaleFeet, isLoopDoc, isTransitionTurnout, leadInchesForSize, maxFlexPieceInches, mergeImportedParts, mergeStoredParts, moduleCenterline, moduleFeatures, moduleFootprint, moduleLengthFromSections, moduleSections, nextId, parseXtpLibrary, partExtent, partExtentForSize, partOutlineAtFrog, pastFrogInchesForSize, pathLengthInches, poseNeedsManual, poseOverridesFromDoc, remapPos, resizeFlexPiece, returnLoop, sampleBenchworkOutline, samplePartSegments, samplePath, scaleFeetToInches, sectionAdjacency, sectionBand, sectionBreaksFromSections, sectionComponents, sectionFootprints, sectionNeighbours, sectionSpans, sectionSpansOrWhole, sectionedCenterline, sectionedEndPose, sliceCenterline, spanOverhang, stateToDoc, storedPartToTrackPart, toSectionRelative, trackMeetsEndplateIssues, trackPart, trackPath, turnoutClosure, turnoutFacing, turnoutOccupiedSpan, turnoutPartForSize, usableCapacity };
2648
+ export { ATLAS_CODE55_N, BUILT_IN_TRACK_PARTS, CLEARANCE_SPACING_INCHES, CODE55_RAIL_HEIGHT_INCHES, DEFAULT_FLEX_PART_ID, ENDPLATE_FASCIA_CLEAR_INCHES, ENDPLATE_LEAD_INCHES, FAST_TRACKS_N_ME55, FAST_TRACKS_N_ME55_CROSSOVERS, FLEX_TRACK_PARTS, FREEMO_ENDPLATE_TRACK_FASCIA_CLEARANCE_INCHES, FREEMO_ENDPLATE_WIDTH_MIN_INCHES, FREEMO_ENDPLATE_WIDTH_RECOMMENDED_INCHES, FREEMO_TRACK_SPACING_INCHES, MAIN2_TRACK_ID, MAIN_TRACK_ID, N_CAR_LENGTH_INCHES, N_SCALE_RATIO, RAIL_GAUGE_INCHES, TIE_HALF_LENGTH_INCHES, TURNOUT_LEAD_INCHES_PER_FROG, WHOLE_MODULE_SECTION_ID, asModuleSchematic, assessSectionEnd, assessSectionJoint, benchworkBand, benchworkOutline, buildCrossover, buildPassingSiding, buildTransition, carCapacity, checkEndplateWidth, clearancePointPastFrogInches, deriveEndplatePoses, divergeSideForHand, docToState, emptyEditorState, endplateCentreOffsetInches, endplateFaceSegments, endplateLead, endplateTrackOffsetInches, endplateWidthInches, flexPartFor, flexParts, flexPieces, flexUsage, frogCasting, frogNumberFromName, fromSectionRelative, geometryTurnDegrees, hasNoFarEndplate, importedPartToTrackPart, inchesToScaleFeet, isLoopDoc, isTransitionTurnout, leadInchesForSize, maxFlexPieceInches, mergeImportedParts, mergeStoredParts, moduleCenterline, moduleFeatures, moduleFootprint, moduleLengthFromSections, moduleSections, nextId, parseXtpLibrary, partExtent, partExtentForSize, partOutlineAtFrog, pastFrogInchesForSize, pathLengthInches, poseNeedsManual, poseOverridesFromDoc, remapPos, resizeFlexPiece, returnLoop, sampleBenchworkOutline, samplePartSegments, samplePath, scaleFeetToInches, sectionAdjacency, sectionBand, sectionBreaksFromSections, sectionComponents, sectionFootprints, sectionNeighbours, sectionSpans, sectionSpansOrWhole, sectionedCenterline, sectionedEndPose, sliceCenterline, spanOverhang, stateToDoc, storedPartToTrackPart, toSectionRelative, trackMeetsEndplateIssues, trackPart, trackPath, turnoutClosure, turnoutFacing, turnoutOccupiedSpan, turnoutPartForSize, usableCapacity };
2604
2649
  //# sourceMappingURL=index.js.map
2605
2650
  //# sourceMappingURL=index.js.map