Skip to content

KCL causes app to become unresponsive #11147

@iterion

Description

@iterion

Describe the bug

When I run some specific KCL, the app becomes almost entirely frozen. For me, the code editor is still interactive, but the app is completely frozen. Also, the model does render fine when executed via the CLI or on our backend.

Steps to Reproduce

Internal link: https://admin-dashboard-dev.hawk-dinosaur.ts.net/app/projects/714e8fb1-a124-491a-a589-3db7e76f7185
Run this KCL:

// Parametric Utensil Drawer Organizer
// 3D-printable tray with five configurable cutlery compartments for two fork sizes, two spoon sizes, and butter knives.
@settings(defaultLengthUnit = mm)

drawerLength = 463
drawerWidth = 264
sideClearance = 2

trayLength = drawerLength - (2 * sideClearance)
trayWidth = drawerWidth - (2 * sideClearance)
trayHeight = 55
floorThickness = 2.4
outerWallThickness = 2.4
dividerThickness = 2.2

forkLargeUnits = 1.2
forkSmallUnits = 1.0
spoonLargeUnits = 1.35
spoonSmallUnits = 1.05
knifeUnits = 0.95

totalUnits = forkLargeUnits + forkSmallUnits + spoonLargeUnits + spoonSmallUnits + knifeUnits

innerLength = trayLength - (2 * outerWallThickness)
innerWidth = trayWidth - (2 * outerWallThickness)
usableCompartmentWidth = innerWidth - (4 * dividerThickness)

forkLargeWidth = usableCompartmentWidth * forkLargeUnits / totalUnits
forkSmallWidth = usableCompartmentWidth * forkSmallUnits / totalUnits
spoonLargeWidth = usableCompartmentWidth * spoonLargeUnits / totalUnits
spoonSmallWidth = usableCompartmentWidth * spoonSmallUnits / totalUnits
knifeWidth = usableCompartmentWidth * knifeUnits / totalUnits

forkLargeUtensilLength = 205
forkLargeHandleMaxWidth = 22
forkLargeHandleMinWidth = 6
forkLargeHeadMaxWidth = 25
forkLargeHeadEndWidth = 18
forkLargeHandleToNeckLength = 125
forkLargeFitClearance = 1.5
forkLargeLengthClearance = 4
forkLargeShoulderRadius = 30
forkLargePocketStartX = outerWallThickness + 8
forkLargePocketCenterY = outerWallThickness + forkLargeWidth / 2
forkLargePocketLength = forkLargeUtensilLength + forkLargeLengthClearance
forkLargeHeadShoulderLength = (forkLargePocketLength - forkLargeHandleToNeckLength) * 0.25
forkLargeHeadTipLength = forkLargePocketLength - forkLargeHandleToNeckLength - forkLargeHeadShoulderLength
forkLargeHandleHalfWidth = (forkLargeHandleMaxWidth + 2 * forkLargeFitClearance) / 2
forkLargeNeckHalfWidth = (forkLargeHandleMinWidth + 2 * forkLargeFitClearance) / 2
forkLargeHeadHalfWidth = (forkLargeHeadMaxWidth + 2 * forkLargeFitClearance) / 2
forkLargeTipHalfWidth = (forkLargeHeadEndWidth + 2 * forkLargeFitClearance) / 2
forkLargeShoulderChordRise = forkLargeHeadHalfWidth - forkLargeNeckHalfWidth
forkLargeShoulderChordLength = sqrt((forkLargeHeadShoulderLength ^ 2) + (forkLargeShoulderChordRise ^ 2))
forkLargeShoulderBisectorOffset = sqrt((forkLargeShoulderRadius ^ 2) - ((forkLargeShoulderChordLength / 2) ^ 2))
forkLargeShoulderMidX = forkLargePocketStartX + forkLargeHeadTipLength + forkLargeHeadShoulderLength / 2
forkLargeShoulderUpperMidY = forkLargePocketCenterY + (forkLargeHeadHalfWidth + forkLargeNeckHalfWidth) / 2
forkLargeShoulderLowerMidY = forkLargePocketCenterY - (forkLargeHeadHalfWidth + forkLargeNeckHalfWidth) / 2
forkLargeShoulderCenterOffsetX = forkLargeShoulderBisectorOffset * forkLargeShoulderChordRise / forkLargeShoulderChordLength
forkLargeShoulderCenterOffsetY = forkLargeShoulderBisectorOffset * forkLargeHeadShoulderLength / forkLargeShoulderChordLength
forkLargeUpperShoulderCenterX = forkLargeShoulderMidX - forkLargeShoulderCenterOffsetX
forkLargeUpperShoulderCenterY = forkLargeShoulderUpperMidY - forkLargeShoulderCenterOffsetY
forkLargeLowerShoulderCenterX = forkLargeShoulderMidX - forkLargeShoulderCenterOffsetX
forkLargeLowerShoulderCenterY = forkLargeShoulderLowerMidY + forkLargeShoulderCenterOffsetY

forkSmallUtensilLength = 188
forkSmallHandleMaxWidth = 20
forkSmallHandleMinWidth = 5
forkSmallHeadMaxWidth = 27.0
forkSmallHeadEndWidth = 19.0
forkSmallHandleToNeckLength = 115
forkSmallFitClearance = 1.5
forkSmallLengthClearance = 4
forkSmallShoulderRadius = 30
forkSmallPocketStartX = outerWallThickness + 8
forkSmallPocketCenterY = outerWallThickness + forkLargeWidth + dividerThickness + forkSmallWidth / 2
forkSmallPocketLength = forkSmallUtensilLength + forkSmallLengthClearance
forkSmallHeadShoulderLength = (forkSmallPocketLength - forkSmallHandleToNeckLength) * 0.25
forkSmallHeadTipLength = forkSmallPocketLength - forkSmallHandleToNeckLength - forkSmallHeadShoulderLength
forkSmallHandleHalfWidth = (forkSmallHandleMaxWidth + 2 * forkSmallFitClearance) / 2
forkSmallNeckHalfWidth = (forkSmallHandleMinWidth + 2 * forkSmallFitClearance) / 2
forkSmallHeadHalfWidth = (forkSmallHeadMaxWidth + 2 * forkSmallFitClearance) / 2
forkSmallTipHalfWidth = (forkSmallHeadEndWidth + 2 * forkSmallFitClearance) / 2
forkSmallShoulderChordRise = forkSmallHeadHalfWidth - forkSmallNeckHalfWidth
forkSmallShoulderChordLength = sqrt((forkSmallHeadShoulderLength ^ 2) + (forkSmallShoulderChordRise ^ 2))
forkSmallShoulderBisectorOffset = sqrt((forkSmallShoulderRadius ^ 2) - ((forkSmallShoulderChordLength / 2) ^ 2))
forkSmallShoulderMidX = forkSmallPocketStartX + forkSmallHeadTipLength + forkSmallHeadShoulderLength / 2
forkSmallShoulderUpperMidY = forkSmallPocketCenterY + (forkSmallHeadHalfWidth + forkSmallNeckHalfWidth) / 2
forkSmallShoulderLowerMidY = forkSmallPocketCenterY - (forkSmallHeadHalfWidth + forkSmallNeckHalfWidth) / 2
forkSmallShoulderCenterOffsetX = forkSmallShoulderBisectorOffset * forkSmallShoulderChordRise / forkSmallShoulderChordLength
forkSmallShoulderCenterOffsetY = forkSmallShoulderBisectorOffset * forkSmallHeadShoulderLength / forkSmallShoulderChordLength
forkSmallUpperShoulderCenterX = forkSmallShoulderMidX - forkSmallShoulderCenterOffsetX
forkSmallUpperShoulderCenterY = forkSmallShoulderUpperMidY - forkSmallShoulderCenterOffsetY
forkSmallLowerShoulderCenterX = forkSmallShoulderMidX - forkSmallShoulderCenterOffsetX
forkSmallLowerShoulderCenterY = forkSmallShoulderLowerMidY + forkSmallShoulderCenterOffsetY

innerXMin = outerWallThickness
innerYMin = outerWallThickness

forkLargeYMin = innerYMin
forkLargeYMax = forkLargeYMin + forkLargeWidth

forkSmallYMin = forkLargeYMax + dividerThickness
forkSmallYMax = forkSmallYMin + forkSmallWidth

spoonLargeYMin = forkSmallYMax + dividerThickness
spoonLargeYMax = spoonLargeYMin + spoonLargeWidth

spoonSmallYMin = spoonLargeYMax + dividerThickness
spoonSmallYMax = spoonSmallYMin + spoonSmallWidth

knifeYMin = spoonSmallYMax + dividerThickness
knifeYMax = knifeYMin + knifeWidth

spoonLargePocketCenterY = spoonLargeYMin + spoonLargeWidth / 2
spoonLargeShoulderUpperMidY = spoonLargePocketCenterY + (forkLargeHeadHalfWidth + forkLargeNeckHalfWidth) / 2
spoonLargeShoulderLowerMidY = spoonLargePocketCenterY - (forkLargeHeadHalfWidth + forkLargeNeckHalfWidth) / 2
spoonLargeUpperShoulderCenterX = forkLargeShoulderMidX - forkLargeShoulderCenterOffsetX
spoonLargeUpperShoulderCenterY = spoonLargeShoulderUpperMidY - forkLargeShoulderCenterOffsetY
spoonLargeLowerShoulderCenterX = forkLargeShoulderMidX - forkLargeShoulderCenterOffsetX
spoonLargeLowerShoulderCenterY = spoonLargeShoulderLowerMidY + forkLargeShoulderCenterOffsetY

spoonSmallPocketCenterY = spoonSmallYMin + spoonSmallWidth / 2
spoonSmallShoulderUpperMidY = spoonSmallPocketCenterY + (forkSmallHeadHalfWidth + forkSmallNeckHalfWidth) / 2
spoonSmallShoulderLowerMidY = spoonSmallPocketCenterY - (forkSmallHeadHalfWidth + forkSmallNeckHalfWidth) / 2
spoonSmallUpperShoulderCenterX = forkSmallShoulderMidX - forkSmallShoulderCenterOffsetX
spoonSmallUpperShoulderCenterY = spoonSmallShoulderUpperMidY - forkSmallShoulderCenterOffsetY
spoonSmallLowerShoulderCenterX = forkSmallShoulderMidX - forkSmallShoulderCenterOffsetX
spoonSmallLowerShoulderCenterY = spoonSmallShoulderLowerMidY + forkSmallShoulderCenterOffsetY

pocketPlane = offsetPlane(XY, offset = floorThickness)
pocketDepth = trayHeight - floorThickness
pocketCutHeight = trayHeight

outerSketch = sketch(on = XY) {
  bottom = line(start = [var 0mm, var 0mm], end = [var 300mm, var 0mm])
  right = line(start = [var 300mm, var 0mm], end = [var 300mm, var 180mm])
  top = line(start = [var 300mm, var 180mm], end = [var 0mm, var 180mm])
  left = line(start = [var 0mm, var 180mm], end = [var 0mm, var 0mm])

  coincident([bottom.end, right.start])
  coincident([right.end, top.start])
  coincident([top.end, left.start])
  coincident([left.end, bottom.start])

  horizontal(bottom)
  vertical(right)
  horizontal(top)
  vertical(left)

  horizontalDistance([ORIGIN, bottom.start]) == 0mm
  verticalDistance([ORIGIN, bottom.start]) == 0mm
  horizontalDistance([bottom.start, bottom.end]) == trayLength
  verticalDistance([bottom.start, left.start]) == trayWidth
}

outerRegion = region(segments = [outerSketch.bottom])
outerBlock = extrude(outerRegion, length = trayHeight, tagEnd = $trayTop)
hide(outerSketch)

forkSmallPocketSketch = sketch(on = faceOf(outerBlock, face = trayTop)) {
  centerline = line(start = [var 15mm, var 80mm], end = [var 210mm, var 80mm], construction = true)
  shoulderCenter = point(at = [var 70mm, var 80mm])
  neckCenter = point(at = [var 130mm, var 80mm])

  butt = arc(start = [var 210mm, var 70mm], end = [var 210mm, var 90mm], center = [var 210mm, var 80mm])
  upperHandle = line(start = [var 210mm, var 90mm], end = [var 130mm, var 82mm])
  upperShoulder = arc(start = [var 130mm, var 82mm], end = [var 70mm, var 90mm], center = [var 64mm, var 65mm])
  upperHead = line(start = [var 70mm, var 90mm], end = [var 15mm, var 85mm])
  tip = line(start = [var 15mm, var 85mm], end = [var 15mm, var 75mm])
  lowerHead = line(start = [var 15mm, var 75mm], end = [var 70mm, var 70mm])
  lowerShoulder = arc(start = [var 70mm, var 70mm], end = [var 130mm, var 78mm], center = [var 64mm, var 95mm])
  lowerHandle = line(start = [var 130mm, var 78mm], end = [var 210mm, var 70mm])

  coincident([butt.end, upperHandle.start])
  coincident([upperHandle.end, upperShoulder.start])
  coincident([upperShoulder.end, upperHead.start])
  coincident([upperHead.end, tip.start])
  coincident([tip.end, lowerHead.start])
  coincident([lowerHead.end, lowerShoulder.start])
  coincident([lowerShoulder.end, lowerHandle.start])
  coincident([lowerHandle.end, butt.start])

  coincident([shoulderCenter, centerline])
  coincident([neckCenter, centerline])
  coincident([butt.center, centerline.end])

  horizontal(centerline)
  vertical(tip)

  horizontalDistance([ORIGIN, centerline.start]) == forkSmallPocketStartX
  verticalDistance([ORIGIN, centerline.start]) == forkSmallPocketCenterY
  horizontalDistance([centerline.start, shoulderCenter]) == forkSmallHeadTipLength
  horizontalDistance([shoulderCenter, neckCenter]) == forkSmallHeadShoulderLength
  horizontalDistance([neckCenter, centerline.end]) == forkSmallHandleToNeckLength

  horizontalDistance([ORIGIN, upperShoulder.center]) == forkSmallUpperShoulderCenterX
  verticalDistance([ORIGIN, upperShoulder.center]) == forkSmallUpperShoulderCenterY
  horizontalDistance([ORIGIN, lowerShoulder.center]) == forkSmallLowerShoulderCenterX
  verticalDistance([ORIGIN, lowerShoulder.center]) == forkSmallLowerShoulderCenterY

  horizontalDistance([upperHead.end, centerline.start]) == 0mm
  horizontalDistance([lowerHead.start, centerline.start]) == 0mm
  horizontalDistance([upperHead.start, shoulderCenter]) == 0mm
  horizontalDistance([lowerHead.end, shoulderCenter]) == 0mm
  horizontalDistance([upperShoulder.start, neckCenter]) == 0mm
  horizontalDistance([lowerShoulder.end, neckCenter]) == 0mm
  horizontalDistance([centerline.end, upperHandle.start]) == 0mm
  horizontalDistance([centerline.end, lowerHandle.end]) == 0mm

  verticalDistance([tip.end, centerline.start]) == forkSmallTipHalfWidth
  verticalDistance([centerline.start, tip.start]) == forkSmallTipHalfWidth
  verticalDistance([lowerHead.end, shoulderCenter]) == forkSmallHeadHalfWidth
  verticalDistance([shoulderCenter, upperHead.start]) == forkSmallHeadHalfWidth
  verticalDistance([lowerShoulder.end, neckCenter]) == forkSmallNeckHalfWidth
  verticalDistance([neckCenter, upperShoulder.start]) == forkSmallNeckHalfWidth
  verticalDistance([butt.start, centerline.end]) == forkSmallHandleHalfWidth
  verticalDistance([centerline.end, butt.end]) == forkSmallHandleHalfWidth
}

forkSmallPocketRegion = region(segments = [forkSmallPocketSketch.butt])
trayWithForkSmallCut = extrude(forkSmallPocketRegion, length = -pocketDepth)
hide(forkSmallPocketSketch)

forkLargePocketSketch = sketch(on = faceOf(trayWithForkSmallCut, face = trayTop)) {
  centerline = line(start = [var 10mm, var 30mm], end = [var 220mm, var 30mm], construction = true)
  shoulderCenter = point(at = [var 73mm, var 30mm])
  neckCenter = point(at = [var 94mm, var 30mm])

  butt = arc(start = [var 220mm, var 18mm], end = [var 220mm, var 42mm], center = [var 220mm, var 30mm])
  upperHandle = line(start = [var 220mm, var 42mm], end = [var 94mm, var 34mm])
  upperShoulder = arc(start = [var 94mm, var 34mm], end = [var 73mm, var 43mm], center = [var 64mm, var 15mm])
  upperHead = line(start = [var 73mm, var 43mm], end = [var 10mm, var 40mm])
  tip = line(start = [var 10mm, var 40mm], end = [var 10mm, var 18mm])
  lowerHead = line(start = [var 10mm, var 18mm], end = [var 73mm, var 15mm])
  lowerShoulder = arc(start = [var 73mm, var 15mm], end = [var 94mm, var 25mm], center = [var 64mm, var 45mm])
  lowerHandle = line(start = [var 94mm, var 25mm], end = [var 220mm, var 18mm])

  coincident([butt.end, upperHandle.start])
  coincident([upperHandle.end, upperShoulder.start])
  coincident([upperShoulder.end, upperHead.start])
  coincident([upperHead.end, tip.start])
  coincident([tip.end, lowerHead.start])
  coincident([lowerHead.end, lowerShoulder.start])
  coincident([lowerShoulder.end, lowerHandle.start])
  coincident([lowerHandle.end, butt.start])

  coincident([shoulderCenter, centerline])
  coincident([neckCenter, centerline])
  coincident([butt.center, centerline.end])

  horizontal(centerline)
  vertical(tip)

  horizontalDistance([ORIGIN, centerline.start]) == forkLargePocketStartX
  verticalDistance([ORIGIN, centerline.start]) == forkLargePocketCenterY
  horizontalDistance([centerline.start, shoulderCenter]) == forkLargeHeadTipLength
  horizontalDistance([shoulderCenter, neckCenter]) == forkLargeHeadShoulderLength
  horizontalDistance([neckCenter, centerline.end]) == forkLargeHandleToNeckLength

  horizontalDistance([ORIGIN, upperShoulder.center]) == forkLargeUpperShoulderCenterX
  verticalDistance([ORIGIN, upperShoulder.center]) == forkLargeUpperShoulderCenterY
  horizontalDistance([ORIGIN, lowerShoulder.center]) == forkLargeLowerShoulderCenterX
  verticalDistance([ORIGIN, lowerShoulder.center]) == forkLargeLowerShoulderCenterY

  horizontalDistance([upperHead.end, centerline.start]) == 0mm
  horizontalDistance([lowerHead.start, centerline.start]) == 0mm
  horizontalDistance([upperHead.start, shoulderCenter]) == 0mm
  horizontalDistance([lowerHead.end, shoulderCenter]) == 0mm
  horizontalDistance([upperShoulder.start, neckCenter]) == 0mm
  horizontalDistance([lowerShoulder.end, neckCenter]) == 0mm
  horizontalDistance([centerline.end, upperHandle.start]) == 0mm
  horizontalDistance([centerline.end, lowerHandle.end]) == 0mm

  verticalDistance([tip.end, centerline.start]) == forkLargeTipHalfWidth
  verticalDistance([centerline.start, tip.start]) == forkLargeTipHalfWidth
  verticalDistance([lowerHead.end, shoulderCenter]) == forkLargeHeadHalfWidth
  verticalDistance([shoulderCenter, upperHead.start]) == forkLargeHeadHalfWidth
  verticalDistance([lowerShoulder.end, neckCenter]) == forkLargeNeckHalfWidth
  verticalDistance([neckCenter, upperShoulder.start]) == forkLargeNeckHalfWidth
  verticalDistance([butt.start, centerline.end]) == forkLargeHandleHalfWidth
  verticalDistance([centerline.end, butt.end]) == forkLargeHandleHalfWidth
}

forkLargePocketRegion = region(segments = [forkLargePocketSketch.butt])
trayWithForkCutouts = extrude(forkLargePocketRegion, length = -pocketDepth)
hide(forkLargePocketSketch)

spoonLargePocketSketch = sketch(on = faceOf(trayWithForkCutouts, face = trayTop)) {
  centerline = line(start = [var 10mm, var 150mm], end = [var 220mm, var 150mm], construction = true)
  shoulderCenter = point(at = [var 73mm, var 150mm])
  neckCenter = point(at = [var 94mm, var 150mm])
  bowlCenter = point(at = [var 21mm, var 150mm])

  butt = arc(start = [var 220mm, var 140mm], end = [var 220mm, var 160mm], center = [var 220mm, var 150mm])
  upperHandle = line(start = [var 220mm, var 160mm], end = [var 94mm, var 154mm])
  upperShoulder = arc(start = [var 94mm, var 154mm], end = [var 73mm, var 163mm], center = [var 64mm, var 135mm])
  upperHead = line(start = [var 73mm, var 163mm], end = [var 21mm, var 160mm])
  bowl = arc(start = [var 21mm, var 160mm], end = [var 21mm, var 140mm], center = [var 21mm, var 150mm])
  lowerHead = line(start = [var 21mm, var 140mm], end = [var 73mm, var 137mm])
  lowerShoulder = arc(start = [var 73mm, var 137mm], end = [var 94mm, var 146mm], center = [var 64mm, var 165mm])
  lowerHandle = line(start = [var 94mm, var 146mm], end = [var 220mm, var 140mm])

  coincident([butt.end, upperHandle.start])
  coincident([upperHandle.end, upperShoulder.start])
  coincident([upperShoulder.end, upperHead.start])
  coincident([upperHead.end, bowl.start])
  coincident([bowl.end, lowerHead.start])
  coincident([lowerHead.end, lowerShoulder.start])
  coincident([lowerShoulder.end, lowerHandle.start])
  coincident([lowerHandle.end, butt.start])

  coincident([shoulderCenter, centerline])
  coincident([neckCenter, centerline])
  coincident([bowlCenter, centerline])
  coincident([butt.center, centerline.end])
  coincident([bowl.center, bowlCenter])

  horizontal(centerline)

  horizontalDistance([ORIGIN, centerline.start]) == forkLargePocketStartX
  verticalDistance([ORIGIN, centerline.start]) == spoonLargePocketCenterY
  horizontalDistance([centerline.start, shoulderCenter]) == forkLargeHeadTipLength
  horizontalDistance([shoulderCenter, neckCenter]) == forkLargeHeadShoulderLength
  horizontalDistance([neckCenter, centerline.end]) == forkLargeHandleToNeckLength
  horizontalDistance([centerline.start, bowlCenter]) == forkLargeTipHalfWidth

  horizontalDistance([ORIGIN, upperShoulder.center]) == spoonLargeUpperShoulderCenterX
  verticalDistance([ORIGIN, upperShoulder.center]) == spoonLargeUpperShoulderCenterY
  horizontalDistance([ORIGIN, lowerShoulder.center]) == spoonLargeLowerShoulderCenterX
  verticalDistance([ORIGIN, lowerShoulder.center]) == spoonLargeLowerShoulderCenterY

  horizontalDistance([upperHead.start, shoulderCenter]) == 0mm
  horizontalDistance([lowerHead.end, shoulderCenter]) == 0mm
  horizontalDistance([upperShoulder.start, neckCenter]) == 0mm
  horizontalDistance([lowerShoulder.end, neckCenter]) == 0mm
  horizontalDistance([upperHead.end, bowlCenter]) == 0mm
  horizontalDistance([lowerHead.start, bowlCenter]) == 0mm
  horizontalDistance([centerline.end, upperHandle.start]) == 0mm
  horizontalDistance([centerline.end, lowerHandle.end]) == 0mm

  verticalDistance([centerline.start, upperHead.end]) == forkLargeTipHalfWidth
  verticalDistance([lowerHead.start, centerline.start]) == forkLargeTipHalfWidth
  verticalDistance([lowerHead.end, shoulderCenter]) == forkLargeHeadHalfWidth
  verticalDistance([shoulderCenter, upperHead.start]) == forkLargeHeadHalfWidth
  verticalDistance([lowerShoulder.end, neckCenter]) == forkLargeNeckHalfWidth
  verticalDistance([neckCenter, upperShoulder.start]) == forkLargeNeckHalfWidth
  verticalDistance([butt.start, centerline.end]) == forkLargeHandleHalfWidth
  verticalDistance([centerline.end, butt.end]) == forkLargeHandleHalfWidth
}

spoonLargePocketRegion = region(segments = [spoonLargePocketSketch.butt])
trayWithSpoonLargeCut = extrude(spoonLargePocketRegion, length = -pocketDepth)
hide(spoonLargePocketSketch)

spoonSmallPocketSketch = sketch(on = faceOf(trayWithSpoonLargeCut, face = trayTop)) {
  centerline = line(start = [var 15mm, var 205mm], end = [var 210mm, var 205mm], construction = true)
  shoulderCenter = point(at = [var 70mm, var 205mm])
  neckCenter = point(at = [var 130mm, var 205mm])
  bowlCenter = point(at = [var 21mm, var 205mm])

  butt = arc(start = [var 210mm, var 195mm], end = [var 210mm, var 215mm], center = [var 210mm, var 205mm])
  upperHandle = line(start = [var 210mm, var 215mm], end = [var 130mm, var 208mm])
  upperShoulder = arc(start = [var 130mm, var 208mm], end = [var 70mm, var 216mm], center = [var 64mm, var 190mm])
  upperHead = line(start = [var 70mm, var 216mm], end = [var 21mm, var 214mm])
  bowl = arc(start = [var 21mm, var 214mm], end = [var 21mm, var 196mm], center = [var 21mm, var 205mm])
  lowerHead = line(start = [var 21mm, var 196mm], end = [var 70mm, var 194mm])
  lowerShoulder = arc(start = [var 70mm, var 194mm], end = [var 130mm, var 202mm], center = [var 64mm, var 220mm])
  lowerHandle = line(start = [var 130mm, var 202mm], end = [var 210mm, var 195mm])

  coincident([butt.end, upperHandle.start])
  coincident([upperHandle.end, upperShoulder.start])
  coincident([upperShoulder.end, upperHead.start])
  coincident([upperHead.end, bowl.start])
  coincident([bowl.end, lowerHead.start])
  coincident([lowerHead.end, lowerShoulder.start])
  coincident([lowerShoulder.end, lowerHandle.start])
  coincident([lowerHandle.end, butt.start])

  coincident([shoulderCenter, centerline])
  coincident([neckCenter, centerline])
  coincident([bowlCenter, centerline])
  coincident([butt.center, centerline.end])
  coincident([bowl.center, bowlCenter])

  horizontal(centerline)

  horizontalDistance([ORIGIN, centerline.start]) == forkSmallPocketStartX
  verticalDistance([ORIGIN, centerline.start]) == spoonSmallPocketCenterY
  horizontalDistance([centerline.start, shoulderCenter]) == forkSmallHeadTipLength
  horizontalDistance([shoulderCenter, neckCenter]) == forkSmallHeadShoulderLength
  horizontalDistance([neckCenter, centerline.end]) == forkSmallHandleToNeckLength
  horizontalDistance([centerline.start, bowlCenter]) == forkSmallTipHalfWidth

  horizontalDistance([ORIGIN, upperShoulder.center]) == spoonSmallUpperShoulderCenterX
  verticalDistance([ORIGIN, upperShoulder.center]) == spoonSmallUpperShoulderCenterY
  horizontalDistance([ORIGIN, lowerShoulder.center]) == spoonSmallLowerShoulderCenterX
  verticalDistance([ORIGIN, lowerShoulder.center]) == spoonSmallLowerShoulderCenterY

  horizontalDistance([upperHead.start, shoulderCenter]) == 0mm
  horizontalDistance([lowerHead.end, shoulderCenter]) == 0mm
  horizontalDistance([upperShoulder.start, neckCenter]) == 0mm
  horizontalDistance([lowerShoulder.end, neckCenter]) == 0mm
  horizontalDistance([upperHead.end, bowlCenter]) == 0mm
  horizontalDistance([lowerHead.start, bowlCenter]) == 0mm
  horizontalDistance([centerline.end, upperHandle.start]) == 0mm
  horizontalDistance([centerline.end, lowerHandle.end]) == 0mm

  verticalDistance([centerline.start, upperHead.end]) == forkSmallTipHalfWidth
  verticalDistance([lowerHead.start, centerline.start]) == forkSmallTipHalfWidth
  verticalDistance([lowerHead.end, shoulderCenter]) == forkSmallHeadHalfWidth
  verticalDistance([shoulderCenter, upperHead.start]) == forkSmallHeadHalfWidth
  verticalDistance([lowerShoulder.end, neckCenter]) == forkSmallNeckHalfWidth
  verticalDistance([neckCenter, upperShoulder.start]) == forkSmallNeckHalfWidth
  verticalDistance([butt.start, centerline.end]) == forkSmallHandleHalfWidth
  verticalDistance([centerline.end, butt.end]) == forkSmallHandleHalfWidth
}

spoonSmallPocketRegion = region(segments = [spoonSmallPocketSketch.butt])
trayWithSpoonCutouts = extrude(spoonSmallPocketRegion, length = -pocketDepth)
hide(spoonSmallPocketSketch)

knifePocketSketch = sketch(on = pocketPlane) {
  bottom = line(start = [var 5mm, var 240mm], end = [var 295mm, var 240mm])
  right = line(start = [var 295mm, var 240mm], end = [var 295mm, var 285mm])
  top = line(start = [var 295mm, var 285mm], end = [var 5mm, var 285mm])
  left = line(start = [var 5mm, var 285mm], end = [var 5mm, var 240mm])

  coincident([bottom.end, right.start])
  coincident([right.end, top.start])
  coincident([top.end, left.start])
  coincident([left.end, bottom.start])

  horizontal(bottom)
  vertical(right)
  horizontal(top)
  vertical(left)

  horizontalDistance([ORIGIN, bottom.start]) == innerXMin
  verticalDistance([ORIGIN, bottom.start]) == knifeYMin
  horizontalDistance([bottom.start, bottom.end]) == innerLength
  verticalDistance([bottom.start, left.start]) == knifeWidth
}

knifePocketRegion = region(segments = [knifePocketSketch.bottom])
knifeCutter = extrude(knifePocketRegion, length = pocketCutHeight)
hide(knifePocketSketch)

organizer = subtract(
  trayWithSpoonCutouts,
  tools = [knifeCutter],
)

Expected Behavior

The app doesn't freeze.

Screenshots and Recordings

No response

Desktop OS

MacOS

Browser

No response

Version

1.2.2

Additional Context

No response

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions