New Project

Travel#

Parts that move: slides, hinges, and screws swept as a clearance check

Names: travel body pivot

When to use#

Use it when a part is meant to move and you want the compiler to prove it can: a drawer on its slides, a door or lid on its hinges, a vise chop on its screw. A travel does not move anything in the drawing or change a cut: the document is drawn at rest and every part keeps its one transform. The viewer shows a slider per travel that poses the parts for a look (a view, never the cut list). It adds a check, which carries the moving body through its range and fails if it meets any other part on the way.

If you only need the hardware counted or recessed, use hardware_mount / hardware_use (hardware-mounting). A part that is fixed in a different position (a drawer drawn half open) is just placed there.

Keywords: slide, drawer, runner, hinge, swing, door, lid, vise, screw, travel, sweep, clearance, open, extension, pivot, collision.

Syntax#

A travel is the one child a join may have. The male end of the join moves; the female is the part it is carried on.

join joint=<Joint> male=Part@Mark female=Part@Mark {
    travel [kind=slide|angle] axis=x|y|z|-x|-y|-z [min=<n>] [max=<n>] [rest=<n>] [step=<n>]
           [body=part|assembly] [pivot=<Mark>]
}
PropertyMeaningDefault
kindslide moves along the axis (mm); angle turns about it (degrees, right-handed)slide
axisx, y or z, signed to reverse (-y), in the frame of the assembly the join is written inrequired
min, maxthe limits, CEL numbersmin 0; max the item's travel_distance (slide) or max_angle (angle), else an error
restthe pose the document is drawn in; must lie in [min, max]min
stepsweep spacing10 mm for a slide, 5 degrees for an angle
bodypart moves the male part alone; assembly moves every part under its innermost enclosing assemblypart
pivotangle only: a mark on the male part the axis passes throughthe male end's own mark

Catalogue numbers a travel reads, on the hardware item the joinery names: travel_distance (a slide's reach), max_angle (a hinge's swing), and mount_gap, the gap a slide fills between the two parts it joins. With a mount_gap the check also measures the real gap and fails (ww::check::slide_clearance) if it is more than 0.5 mm from the catalogue's; the margin is printed by ww check and is in its JSON (invariants.travel.slide_margins).

Example#

project name="Lidded box" units=mm schema_version=1 {
    materials {
        material Oak type=hardwood
        hardware Hinge leaf_length=50.0 leaf_width=16.0 leaf_thickness=2.0 max_angle=110.0
    }
    joinery hardware_mount name=LidHinge { hardware Hinge }
    assembly Box {
        part Case {
            stock Oak 100.0 60.0 20.0
            mark Seat x=0.0 y=60.0 z=0.0 normal=pos_z
            by top_sw
            pos x=0.0 y=0.0 z=0.0
        }
        assembly Lid {
            part Panel {
                stock Oak 100.0 60.0 10.0
                mark Seat x=0.0 y=60.0 z=-10.0 normal=neg_z
                // the hinge pin's line: the lid's back edge, on its underside
                mark Pin x=0.0 y=60.0 z=-10.0 normal=neg_z
                by top_sw
                pos x=0.0 y=0.0 z=10.0
            }
            part Cleat {
                stock Oak 100.0 10.0 10.0
                by top_sw
                pos x=0.0 y=0.0 z=0.0
            }
            // Swings the whole lid (both parts) up to the hinge's 110 degrees.
            join joint=LidHinge male=Panel@Seat female=Case@Seat {
                travel kind=angle axis=x body=assembly pivot=Pin
            }
        }
    }
}

A drawer on slides, from examples/welsh_dresser.kdl: the drawer is its own assembly, each side stands on a slide over its runner, and the catalogue gives the reach and the gap:

hardware UndermountSlide_350 travel_distance=300.0 mount_gap=12.0 load_kg=35.0 ...
join joint=DrawerSlide male=DrawerSide_L@Slide female=Runner_L@SlideEdgeL {
    travel axis=-y body=assembly
}

Pitfalls and diagnostics#

  • Which end moves. The male end. body=part (the default) moves that one part, which is right for a vise chop and wrong for a door: write body=assembly and put the door's parts in an assembly. A drawer is the same: wrap the front, sides, back and bottom in one.
  • A join can only name parts of its own assembly or one enclosing it, so the slide joins of a drawer live in the drawer's assembly and reach out to the runner; the drawer must be a nested inline assembly, not part X instance=.
  • Two joins, one body. Two hinges on one door each carry the same travel; it is swept once. Declare it on both so either can be deleted.
  • Where the pin is matters. The axis passes through the pivot mark, or the male end's own mark. A hinge mark in the middle of a door's edge puts the pin in the middle of its thickness and the door's back corner swings into the carcass; mark the pin on the show face (welsh_dresser.kdl's Pin_Front / Pin_Back).
  • ww::check::travel_foul (defect): a moving part overlaps a fixed one. The message names both parts, the first sampled travel that fouls, and the onset between that sample and the last clean one. A pair already overlapping at rest is ww clash's finding and is skipped.
  • ww::check::travel_invalid (defect): the body moves nothing, min is above max, rest is outside the range, the pivot mark does not exist, or there is no max to default.
  • ww::check::slide_clearance (defect): the gap a slide fills is not its mount_gap.
  • ww::check::travel_unchecked (defect): the kernel could not intersect a pair; it is not reported clean.
  • ww::expand::bad_travel (error): an unknown property, axis, kind or body word, a missing axis=, or pivot= on a slide.
  • Sampling is not a proof. An obstacle thinner than step between two samples is missed; shrink step=. The default (10 mm, 5 degrees) is below every board in the library.
  • Hardware is never swept. A screw, garter, guide, hinge or slide is a catalogue item and a display proxy, never a part, so it cannot foul anything. Model what must be checked as a part.
  • No dynamics. No forces, wear, springs, door sag or thread geometry (ADR-0075).
  • The viewer does not yet have a slider per movable part (#225); the data (axis, limits, rest, moving part ids) is in PlacedJoin::travel.

See also#

  • docs/adr/0075-travel-primitive.md; docs/rfc/0081-vise-and-moving-hardware.md, docs/rfc/0050-drawer-runners-and-slides.md, docs/rfc/0071-hardware-hinges.md
  • docs/KDL_AUTHORING.md §5 (hardware) and §8 (join)
  • examples/workbench.kdl (a vise chop, 0 to 180 mm), examples/welsh_dresser.kdl (slides and door swings), examples/blanket_chest.kdl (a lid swung 100 degrees)
  • hardware-mounting, joinery-contract

Names#

Every name this page declares, how the example library uses it, and the shortest real use.

travel#

node in 3 of 116 examples (8 uses).

Shortest real use, from welsh_dresser.kdl:

travel axis=-y body=assembly

body#

word-valued property; property in 2 of 116 examples (7 uses).

Shortest real use, from welsh_dresser.kdl:

travel axis=-y body=assembly

pivot#

word-valued property; property in 2 of 116 examples (3 uses).

Shortest real use, from welsh_dresser.kdl:

travel kind=angle axis=z body=assembly pivot=Pin_Back

Settings

Region

A region picks sensible defaults; change any of these separately.

Units

In inches, type lengths the way you say them: 34 1/2, 3/4", 1'-2" or 12.7mm. A length that can't be read is flagged, never rounded to something else.

Paper
Date order
Clock