bryanmubarak-joint/geometry.html

417 lines
15 KiB
HTML
Raw Normal View History

2026-07-19 22:46:46 +02:00
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Service Geometry Engine | Bryan Mubarak</title>
<meta property="og:type" content="website">
<meta property="og:title" content="Service Geometry Engine | Bryan Mubarak">
<meta property="og:description" content="Service Geometry Engine Input constraints. Output perfection. Dinner Plate Diameter (cm) Course Count Three Courses (Standard) Five Courses (Extended)…">
<meta property="og:url" content="https://bryan-mubarak.4ort.net/geometry.html">
<meta name="twitter:card" content="summary">
<meta name="description" content="Service Geometry Engine Input constraints. Output perfection. Dinner Plate Diameter (cm) Course Count Three Courses (Standard) Five Courses (Extended)…">
<style>
:root {
--bg: #0a0a0a;
--fg: #e8e8e8;
--panel: #111111;
--border: #222222;
--accent: #ff3333;
--success: #00ff66;
--font-main: 'Helvetica Neue', Helvetica, Arial, sans-serif;
--font-mono: 'SF Mono', 'Menlo', monospace;
}
html, body {
margin: 0; padding: 0;
background: var(--bg);
color: var(--fg);
font-family: var(--font-main);
line-height: 1.6;
}
.container {
max-width: 1200px;
margin: 0 auto;
padding: 2rem;
display: grid;
grid-template-columns: 350px 1fr;
gap: 2rem;
min-height: 100vh;
}
header {
grid-column: 1 / -1;
border-bottom: 1px solid var(--border);
padding-bottom: 2rem;
margin-bottom: 2rem;
}
h1 {
font-size: 2.5rem;
margin: 0 0 0.5rem 0;
}
.subtitle {
font-family: var(--font-mono);
color: var(--accent);
font-size: 0.9rem;
}
.controls {
background: var(--panel);
border: 1px solid var(--border);
padding: 2rem;
border-radius: 4px;
}
.control-group {
margin-bottom: 1.5rem;
}
label {
display: block;
font-family: var(--font-mono);
font-size: 0.8rem;
text-transform: uppercase;
margin-bottom: 0.5rem;
color: #888;
}
input[type="number"], select {
width: 100%;
background: #000;
border: 1px solid var(--border);
color: var(--fg);
padding: 0.75rem;
font-family: var(--font-mono);
font-size: 1rem;
border-radius: 2px;
}
input[type="range"] {
width: 100%;
accent-color: var(--accent);
}
button {
width: 100%;
background: var(--accent);
color: #000;
border: none;
padding: 1rem;
font-family: var(--font-mono);
font-weight: bold;
font-size: 1rem;
cursor: pointer;
margin-top: 1rem;
transition: all 0.2s ease;
}
button:hover {
transform: translateY(-2px);
box-shadow: 0 4px 20px rgba(255, 51, 51, 0.4);
}
.viewport {
background: linear-gradient(135deg, #050505 0%, #0a0a0a 100%);
border: 1px solid var(--border);
border-radius: 4px;
padding: 2rem;
position: relative;
min-height: 600px;
display: flex;
flex-direction: column;
align-items: center;
}
.diagram-container {
width: 100%;
height: 500px;
position: relative;
}
svg {
width: 100%;
height: 100%;
}
.measurement {
position: absolute;
font-family: var(--font-mono);
font-size: 0.7rem;
color: var(--accent);
white-space: nowrap;
}
.stats-panel {
margin-top: 2rem;
background: var(--panel);
border: 1px solid var(--border);
padding: 1.5rem;
border-radius: 4px;
width: 100%;
}
.stat-row {
display: flex;
justify-content: space-between;
font-family: var(--font-mono);
font-size: 0.85rem;
padding: 0.5rem 0;
border-bottom: 1px solid var(--border);
}
.stat-row:last-child {
border-bottom: none;
}
.stat-value {
color: var(--success);
}
.error {
color: var(--accent);
font-family: var(--font-mono);
font-size: 0.8rem;
margin-top: 0.5rem;
min-height: 1.2em;
}
.legend {
position: absolute;
top: 1rem;
right: 1rem;
background: rgba(0,0,0,0.8);
border: 1px solid var(--border);
padding: 1rem;
font-family: var(--font-mono);
font-size: 0.7rem;
}
.legend-item {
display: flex;
align-items: center;
gap: 0.5rem;
margin-bottom: 0.5rem;
}
.legend-dot {
width: 8px;
height: 8px;
border-radius: 50%;
}
</style>
<script defer src="https://analytics.4ort.xyz/script.js" data-website-id="d3ed927c-888a-4a6c-ae5f-0b1c613ddf5b"></script>
</head>
<body>
<div class="container">
<header>
<h1>Service Geometry Engine</h1>
<div class="subtitle">Input constraints. Output perfection.</div>
</header>
<aside class="controls">
<div class="control-group">
<label>Dinner Plate Diameter (cm)</label>
<input type="number" id="plateDiameter" value="26.0" step="0.1" min="20" max="35">
<output class="error"></output>
</div>
<div class="control-group">
<label>Course Count</label>
<select id="courseCount">
<option value="3">Three Courses (Standard)</option>
<option value="5">Five Courses (Extended)</option>
<option value="7">Seven Courses (Prix Fixe)</option>
</select>
</div>
<div class="control-group">
<label>Server Reach Radius (cm)</label>
<input type="number" id="serverReach" value="24.0" step="0.1" min="20" max="40">
</div>
<div class="control-group">
<label>Glass Arc Angle (degrees)</label>
<input type="range" id="glassArc" min="5" max="30" value="15">
<output id="arcValue" style="font-family: var(--font-mono); font-size: 0.8rem; color: #888;">15°</output>
</div>
<button onclick="calculateSetting()">COMPUTE SETTING</button>
<div style="margin-top: 2rem; font-family: var(--font-mono); font-size: 0.7rem; color: #666;">
Grounded in: Q81881, Q32489, Q2002583, Q57216<br>
Manifest: /manifest.json
</div>
</aside>
<main class="viewport">
<div class="diagram-container" id="diagram">
<!-- SVG will be injected here -->
</div>
<div class="stats-panel">
<div class="stat-row">
<span>Total Utensil Span</span>
<span class="stat-value" id="utensilSpan">--</span>
</div>
<div class="stat-row">
<span>Fork-Knife Gap</span>
<span class="stat-value" id="forkKnifeGap">--</span>
</div>
<div class="stat-row">
<span>Clearance Margin</span>
<span class="stat-value" id="clearanceMargin">--</span>
</div>
<div class="stat-row">
<span>Tolerance Status</span>
<span class="stat-value" id="toleranceStatus">AWAITING COMPUTE</span>
</div>
</div>
<div class="legend">
<div class="legend-item"><div class="legend-dot" style="background: #ff3333;"></div> Primary Vectors</div>
<div class="legend-item"><div class="legend-dot" style="background: #00ff66;"></div> Tolerance Zones</div>
<div class="legend-item"><div class="legend-dot" style="background: #ffffff;"></div> Physical Objects</div>
</div>
</main>
</div>
<script>
// Load manifest constants
const CONSTANTS = {
dinner_fork_length_cm: 21.5,
dinner_knife_length_cm: 23.0,
soup_spoon_length_cm: 19.0,
teaspoon_length_cm: 16.5,
water_goblet_base_diameter_cm: 7.5,
bread_plate_offset_x_cm: 15.0,
napkin_fold_height_cm: 12.0,
gap_between_utensils_mm: 5.0,
placement_variance_mm: 2.0
};
document.getElementById('glassArc').addEventListener('input', (e) => {
document.getElementById('arcValue').textContent = e.target.value + '°';
});
function calculateSetting() {
const plateDia = parseFloat(document.getElementById('plateDiameter').value);
const courses = parseInt(document.getElementById('courseCount').value);
const reach = parseFloat(document.getElementById('serverReach').value);
const arcAngle = parseInt(document.getElementById('glassArc').value);
if (!plateDia || plateDia < 20 || plateDia > 35) {
alert("Plate diameter must be between 20 and 35 cm.");
return;
}
const plateRadius = plateDia / 2;
const utensilOffset = plateRadius + 2; // 2cm clearance from rim
// Calculate utensil positions based on course count
const numUtensilsPerSide = Math.ceil(courses / 2);
const totalWidth = (numUtensilsPerSide * (CONSTANTS.dinner_fork_length_cm + CONSTANTS.gap_between_utensils_mm / 10));
// Generate SVG
const svgNS = "http://www.w3.org/2000/svg";
const svg = document.createElementNS(svgNS, "svg");
svg.setAttribute("viewBox", "-200 -200 400 400");
// Grid
for(let i=-180; i<=180; i+=20) {
const hLine = document.createElementNS(svgNS, "line");
hLine.setAttribute("x1", i); hLine.setAttribute("y1", -180);
hLine.setAttribute("x2", i); hLine.setAttribute("y2", 180);
hLine.setAttribute("stroke", "#1a1a1a"); hLine.setAttribute("stroke-width", "0.5");
svg.appendChild(hLine);
const vLine = document.createElementNS(svgNS, "line");
vLine.setAttribute("x1", -180); vLine.setAttribute("y1", i);
vLine.setAttribute("x2", 180); vLine.setAttribute("y2", i);
vLine.setAttribute("stroke", "#1a1a1a"); vLine.setAttribute("stroke-width", "0.5");
svg.appendChild(vLine);
}
// Origin marker
const origin = document.createElementNS(svgNS, "circle");
origin.setAttribute("cx", 0); origin.setAttribute("cy", 0);
origin.setAttribute("r", 3); origin.setAttribute("fill", "#ff3333");
svg.appendChild(origin);
// Plate
const plate = document.createElementNS(svgNS, "circle");
plate.setAttribute("cx", 0); plate.setAttribute("cy", 0);
plate.setAttribute("r", plateRadius);
plate.setAttribute("fill", "none"); plate.setAttribute("stroke", "#fff");
plate.setAttribute("stroke-width", "2");
svg.appendChild(plate);
// Forks (left side)
for(let i=0; i<numUtensilsPerSide; i++) {
const x = -utensilOffset - (i * (CONSTANTS.dinner_fork_length_cm + CONSTANTS.gap_between_utensils_mm / 10));
const fork = document.createElementNS(svgNS, "rect");
fork.setAttribute("x", x - CONSTANTS.dinner_fork_length_cm);
fork.setAttribute("y", -2); fork.setAttribute("width", CONSTANTS.dinner_fork_length_cm);
fork.setAttribute("height", 4); fork.setAttribute("fill", "#fff");
svg.appendChild(fork);
// Vector line
const vec = document.createElementNS(svgNS, "line");
vec.setAttribute("x1", 0); vec.setAttribute("y1", 0);
vec.setAttribute("x2", x); vec.setAttribute("y2", 0);
vec.setAttribute("stroke", "#ff3333"); vec.setAttribute("stroke-width", "1");
vec.setAttribute("stroke-dasharray", "4");
svg.appendChild(vec);
}
// Knives (right side)
for(let i=0; i<numUtensilsPerSide; i++) {
const x = utensilOffset + (i * (CONSTANTS.dinner_knife_length_cm + CONSTANTS.gap_between_utensils_mm / 10));
const knife = document.createElementNS(svgNS, "rect");
knife.setAttribute("x", x); knife.setAttribute("y", -2);
knife.setAttribute("width", CONSTANTS.dinner_knife_length_cm);
knife.setAttribute("height", 4); knife.setAttribute("fill", "#fff");
svg.appendChild(knife);
// Vector line
const vec = document.createElementNS(svgNS, "line");
vec.setAttribute("x1", 0); vec.setAttribute("y1", 0);
vec.setAttribute("x2", x); vec.setAttribute("y2", 0);
vec.setAttribute("stroke", "#ff3333"); vec.setAttribute("stroke-width", "1");
vec.setAttribute("stroke-dasharray", "4");
svg.appendChild(vec);
}
// Spoons (far right)
for(let i=0; i<numUtensilsPerSide; i++) {
const x = utensilOffset + (numUtensilsPerSide * (CONSTANTS.dinner_knife_length_cm + CONSTANTS.gap_between_utensils_mm / 10)) + (i * (CONSTANTS.soup_spoon_length_cm + CONSTANTS.gap_between_utensils_mm / 10));
const spoon = document.createElementNS(svgNS, "rect");
spoon.setAttribute("x", x); spoon.setAttribute("y", -2);
spoon.setAttribute("width", CONSTANTS.soup_spoon_length_cm);
spoon.setAttribute("height", 4); spoon.setAttribute("fill", "#00ff66");
svg.appendChild(spoon);
}
// Glass arc
const glassX = plateRadius * 1.5;
const glassY = -plateRadius * 1.2;
const arcPath = document.createElementNS(svgNS, "path");
const arcLen = (arcAngle / 360) * 2 * Math.PI * (plateRadius * 1.5);
arcPath.setAttribute("d", `M ${glassX} ${glassY} Q ${glassX + 20} ${glassY - 30} ${glassX + 40} ${glassY - 60}`);
arcPath.setAttribute("stroke", "#ff3333"); arcPath.setAttribute("stroke-width", "1");
arcPath.setAttribute("fill", "none"); arcPath.setAttribute("stroke-dasharray", "4");
svg.appendChild(arcPath);
// Glass base
const goblet = document.createElementNS(svgNS, "circle");
goblet.setAttribute("cx", glassX); goblet.setAttribute("cy", glassY);
goblet.setAttribute("r", CONSTANTS.water_goblet_base_diameter_cm / 2);
goblet.setAttribute("fill", "none"); goblet.setAttribute("stroke", "#00ff66");
goblet.setAttribute("stroke-width", "2");
svg.appendChild(goblet);
// Inject SVG
const container = document.getElementById('diagram');
container.innerHTML = '';
container.appendChild(svg);
// Update stats
const totalSpan = (totalWidth * 2) + (CONSTANTS.soup_spoon_length_cm * numUtensilsPerSide);
document.getElementById('utensilSpan').textContent = totalSpan.toFixed(1) + ' cm';
document.getElementById('forkKnifeGap').textContent = (plateDia + 4).toFixed(1) + ' cm';
const clearance = reach - (totalWidth + 5);
document.getElementById('clearanceMargin').textContent = clearance.toFixed(1) + ' cm';
if (clearance >= 0) {
document.getElementById('toleranceStatus').textContent = 'WITHIN SPEC';
document.getElementById('toleranceStatus').style.color = '#00ff66';
} else {
document.getElementById('toleranceStatus').textContent = 'VIOLATION DETECTED';
document.getElementById('toleranceStatus').style.color = '#ff3333';
}
}
// Auto-calculate on load
window.onload = calculateSetting;
</script>
</body>
</html>