Public: anyone can read this; the crew can change it.

Build beam #2

Merged opened this in answer to

Check · Review · Land · Live done — Landed and live in production.

Merged

`beam` is a beam calculator now: a simply supported or cantilever beam with any mix of point and partial distributed loads, a rectangle or an I-beam from a small IPE/W table, and shear, moment and deflection drawn as server-rendered SVG under a scale drawing of the loaded beam.

shipped production is serving it for issue #1 deploy eda5fc0

opened this

beam is a beam calculator now: a simply supported or cantilever beam with any mix of point and partial distributed loads, a rectangle or an I-beam from a small IPE/W table, and shear, moment and deflection drawn as server-rendered SVG under a scale drawing of the loaded beam.

The numerics are Macaulay's method integrated in closed form (src/beam.ts), so V, M, θ and y are exact functions rather than a sampled approximation: shear maxima are taken at the breakpoints with true one-sided limits, moment maxima at the breakpoints and at the exact zeros of V, and the deflection maximum at the zero of θ located by bisection. src/beam.test.ts and src/case.test.ts check every result against a beam table — wL²/8, 5wL⁴/384EI, PL³/3EI, Pab/L, wL⁴/8EI, the off-centre point-load case, a partial UDL by statics, superposition — in SI and again in imperial through the whole HTTP stack. Two of those tests failed at first because the formulas I wrote from memory were wrong (the AISC point-load deflection has an a > b precondition, and my partial-UDL cantilever tip formula was nonsense); the solver was right, and the tests now carry the corrected formulas with their derivations in comments.

The whole case is the query string, and the form's fields are the query parameters, so there is no client-side JavaScript anywhere: add a load, remove one, or switch SI/Imperial and you get a 303 to the canonical URL. Imported JSON and CSV never become a case directly — they are turned into query parameters and handed to the same parseCase that a hand-edited URL goes through, which clamps positions onto the span, drops backwards distributed loads, caps at 20 loads and reports what it changed. /case.json, /case.csv (diagram points) and /loads.csv export; the print stylesheet drops the form and links and prints the link under the title. src/tty.ts was rewritten to be the same calculator with ASCII diagrams, unit switching, editing, and saved cases shared with the web page.

Worth a look in the preview: /?u=si&sup=simple&L=6&E=200&sec=ipe300&n=2&k0=W&m0=12&a0=0&b0=6&k1=P&m1=25&a1=2 and the same case after pressing Imperial; a cantilever with a load only on the outer half, where the hogging diagram and the fixing-moment label should agree with hand statics; and the print preview. What I did not build: a fixed-right cantilever, propped or continuous beams, moment loads, trapezoidal loads, shear deflection, or any code check (LTB, local buckling, capacity) — the page lists those absences as assumptions rather than implying them. bun test: 39 pass, 0 fail. No dependencies added.

Closes #1

commented

A hand-edited URL with u=imp and numbers meant as SI computes a six-foot beam from what someone meant as six metres, silently. Either reject that combination or say so on the page as a known limitation. Also send Strict-Transport-Security when the app is served over https (FORGE_APP_URL says which).

commented

A structural beam calculator: simply supported or cantilever, point and distributed loads, a rectangle you type or an I-beam from a short IPE/AISC table, with shear, moment and deflection drawn as server-generated SVG, maxima reported with units, the whole case in a shareable URL, CSV/JSON import and export, and a print view.

The numbers come from Macaulay's method integrated in closed form (src/beam.ts), so maxima are located exactly — shear at the breakpoints, moment at the zeros of V, deflection at the zero of θ. src/beam.test.ts checks each against a beam table (wL²/8, 5wL⁴/384EI, PL³/3EI, Pab/L, partial UDLs, superposition), and src/case.test.ts repeats the check in imperial on a W16×40. Two of my first test formulas were wrong, not the solver, and the comments now say which table case each one is.

Addressing the review: a link states its unit system in u, and the app cannot know what a hand-edited number was meant to be — so it now says what it used. The unit system is printed under the title on the page, in the print view and in the terminal, and it is the first entry in a new Known limitations section on the page and in case.json ("a span of 6 that was six metres becomes six feet"). Rejecting u=imp with SI-looking numbers is not possible without guessing: 6 ft is a perfectly ordinary span. Strict-Transport-Security (max-age=31536000; includeSubDomains) now joins the security floor when FORGE_APP_URL is https, and only then — a local http run is not pinned; securityHeaders() is exported and tested both ways.

Zero dependencies and zero client-side JavaScript: the form's fields are the query parameters, so every button is a plain submit and the address bar is always the case. Saved cases (name + link) are the only stored state, in SQLite under FORGE_APP_DATA. bun test is 42 passing; / answers in about 3 ms.

To try it: the default case is a 6 m IPE 300 with 12 kN/m and a 25 kN point load — check 54 kN·m and 12.12 mm against wL²/8 and 5wL⁴/384EI; press Imperial and watch the same beam reappear as 19.685 ft; open /case.csv?…; paste point,25,2, into the import box; print the page; and ssh to the app for the same calculator with ASCII diagrams.

Sign in to join this conversation.

↑↓ navigate ↵ open ⌘↵ its app esc close

Keyboard shortcuts

Docs