joint-stress-tool/joint-stress-calc.html
2026-07-19 16:45:29 +00:00

262 lines
7.0 KiB
HTML
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Joint Stress Calculator | Albert Karaca</title>
<style>
:root {
--bg: #0c0c0c;
--fg: #e0e0e0;
--accent: #ff3333;
--grid: #333333;
--mono: "JetBrains Mono", "Courier New", monospace;
}
* { box-sizing: border-box; }
body {
background-color: var(--bg);
color: var(--fg);
font-family: var(--mono);
margin: 0;
padding: 2rem;
line-height: 1.4;
}
header {
border-bottom: 2px solid var(--accent);
margin-bottom: 2rem;
padding-bottom: 1rem;
}
h1 {
font-size: 1.5rem;
text-transform: uppercase;
letter-spacing: 0.1em;
margin: 0;
}
.subtitle {
font-size: 0.8rem;
color: #888;
margin-top: 0.5rem;
}
.grid-container {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 2rem;
max-width: 900px;
margin: 0 auto;
}
.panel {
border: 1px solid var(--grid);
padding: 1.5rem;
position: relative;
}
.panel::before {
content: "";
position: absolute;
top: 0; left: 0; right: 0; height: 1px;
background: repeating-linear-gradient(90deg, var(--accent), var(--accent) 2px, transparent 2px, transparent 10px);
}
label {
display: block;
font-size: 0.75rem;
text-transform: uppercase;
margin-bottom: 0.5rem;
color: #aaa;
}
input[type="number"] {
width: 100%;
background: transparent;
border: none;
border-bottom: 1px solid var(--grid);
color: var(--fg);
font-family: var(--mono);
font-size: 1.1rem;
padding: 0.5rem 0;
margin-bottom: 1.5rem;
outline: none;
}
input[type="number"]:focus {
border-bottom-color: var(--accent);
}
.result-row {
display: flex;
justify-content: space-between;
border-bottom: 1px dashed var(--grid);
padding: 0.75rem 0;
font-size: 0.9rem;
}
.result-label { color: #888; }
.result-value { font-weight: bold; }
.status-ok { color: #4caf50; }
.status-warn { color: #ffeb3b; }
.status-fail { color: var(--accent); animation: blink 1s infinite; }
@keyframes blink { 50% { opacity: 0.5; } }
.controls {
margin-top: 2rem;
text-align: center;
}
button {
background: transparent;
border: 1px solid var(--accent);
color: var(--accent);
font-family: var(--mono);
padding: 0.75rem 2rem;
cursor: pointer;
text-transform: uppercase;
transition: all 0.2s;
}
button:hover {
background: var(--accent);
color: var(--bg);
}
.nav-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 2rem;
}
nav a {
color: #888;
text-decoration: none;
font-size: 0.8rem;
margin-left: 1.5rem;
text-transform: uppercase;
}
nav a:hover { color: var(--accent); }
@media (max-width: 600px) {
.grid-container { grid-template-columns: 1fr; }
}
</style>
</head>
<body>
<header>
<div class="nav-header">
<h1>Joint Stress Calculator</h1>
<nav>
<a href="/">Home</a>
<a href="/prevention-protocol.html">Protocol</a>
<a href="/films/prevention-protocol/">Film</a>
</nav>
</div>
<div class="subtitle">NDS Douglas Fir-Larch Select Structural | Real-Time Load Analysis</div>
</header>
<main class="grid-container">
<section class="panel inputs">
<form id="calc-form">
<label>Member Width (w)</label>
<input type="number" id="width" step="0.1" value="3.5" placeholder="inches">
<label>Member Thickness (t)</label>
<input type="number" id="thickness" step="0.1" value="3.5" placeholder="inches">
<label>Span Length (L)</label>
<input type="number" id="span" step="1" value="96" placeholder="inches">
<label>Applied Load (P)</label>
<input type="number" id="load" step="10" value="1200" placeholder="lbs">
<label style="color: var(--accent)">Safety Factor Target</label>
<input type="number" id="sf-target" step="0.1" value="1.5" readonly>
</form>
</section>
<section class="panel outputs">
<div id="results-display">
<div class="result-row">
<span class="result-label">Moment of Inertia (I)</span>
<span class="result-value" id="val-i">0.00 in⁴</span>
</div>
<div class="result-row">
<span class="result-label">Section Modulus (S)</span>
<span class="result-value" id="val-s">0.00 in³</span>
</div>
<div class="result-row">
<span class="result-label">Max Bending Moment (M)</span>
<span class="result-value" id="val-m">0.00 lb-in</span>
</div>
<div class="result-row">
<span class="result-label">Bending Stress (σ)</span>
<span class="result-value" id="val-sigma">0.00 psi</span>
</div>
<div class="result-row">
<span class="result-label">Material Limit (Fb)</span>
<span class="result-value">1,500 psi</span>
</div>
<div class="result-row">
<span class="result-label">Safety Factor (n)</span>
<span class="result-value" id="val-n">0.00</span>
</div>
<div class="result-row" style="border:none; margin-top:1rem;">
<span class="result-label">STRUCTURAL STATUS</span>
<span class="result-value" id="status-text">AWAITING INPUT</span>
</div>
</div>
<div class="controls">
<button onclick="resetDefaults()">Reset Baseline</button>
</div>
</section>
</main>
<script>
// CONSTANTS: NDS Douglas Fir-Larch Select Structural
const F_BENDING = 1500; // psi
const E_MODULUS = 1900000; // psi
const SF_TARGET = 1.5;
function calculate() {
const w = parseFloat(document.getElementById('width').value) || 0;
const t = parseFloat(document.getElementById('thickness').value) || 0;
const L = parseFloat(document.getElementById('span').value) || 0;
const P = parseFloat(document.getElementById('load').value) || 0;
if (w === 0 || t === 0) return;
// Section Properties
const I = (w * Math.pow(t, 3)) / 12;
const S = I / (t / 2);
// Loading (Center Point Load on Simple Span)
const M_max = (P * L) / 4;
// Stresses
const sigma = M_max / S;
const n = F_BENDING / sigma;
// Render
document.getElementById('val-i').textContent = I.toFixed(2) + " in⁴";
document.getElementById('val-s').textContent = S.toFixed(2) + " in³";
document.getElementById('val-m').textContent = M_max.toFixed(0) + " lb-in";
document.getElementById('val-sigma').textContent = sigma.toFixed(1) + " psi";
document.getElementById('val-n').textContent = n.toFixed(2);
const statusEl = document.getElementById('status-text');
if (sigma > F_BENDING) {
statusEl.textContent = "CRITICAL FAILURE";
statusEl.className = "result-value status-fail";
} else if (n < SF_TARGET) {
statusEl.textContent = "UNSAFE";
statusEl.className = "result-value status-warn";
} else {
statusEl.textContent = "COMPLIANT";
statusEl.className = "result-value status-ok";
}
}
function resetDefaults() {
document.getElementById('width').value = 3.5;
document.getElementById('thickness').value = 3.5;
document.getElementById('span').value = 96;
document.getElementById('load').value = 1200;
calculate();
}
document.querySelectorAll('input').forEach(el => {
el.addEventListener('input', calculate);
});
calculate();
</script>
</body>
</html>