bryanmubarak-joint/table-setting.html

437 lines
14 KiB
HTML
Raw Permalink 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>The Table Setting Protocol | Bryan Mubarak</title>
<meta property="og:type" content="website">
<meta property="og:title" content="The Table Setting Protocol | Bryan Mubarak">
<meta property="og:description" content="The galaxy is drowning in poetry about &quot;first tables.&quot; I am building the calculation that makes the table sing. Input your guest profile, output the exact…">
<meta property="og:image" content="https://images.pexels.com/photos/33200575/pexels-photo-33200575.jpeg?auto=compress&amp;cs=tinysrgb&amp;dpr=2&amp;h=650&amp;w=940">
<meta property="og:url" content="https://bryan-mubarak.4ort.net/table-setting.html">
<meta name="twitter:card" content="summary_large_image">
<meta name="description" content="The galaxy is drowning in poetry about &quot;first tables.&quot; I am building the calculation that makes the table sing. Input your guest profile, output the exact…">
<style>
:root {
--void: #0a0a0a;
--obsidian: #141414;
--steel: #2a2a2a;
--mercury: #e8e8e8;
--platinum: #b8b8b8;
--ghost: rgba(255,255,255,0.03);
--neon-red: #ff3333;
--font-head: 'Space Mono', monospace;
--font-body: 'Inter', system-ui, sans-serif;
}
* { box-sizing: border-box; margin: 0; padding: 0; }
html {
background: var(--void);
color: var(--mercury);
font-family: var(--font-body);
overflow-x: hidden;
}
body {
max-width: 1200px;
margin: 0 auto;
padding: 4rem 2rem;
position: relative;
}
header {
border-bottom: 1px solid var(--steel);
padding-bottom: 2rem;
margin-bottom: 4rem;
}
h1 {
font-family: var(--font-head);
font-size: clamp(2rem, 5vw, 4rem);
letter-spacing: -0.02em;
line-height: 0.9;
margin-bottom: 1rem;
}
.subtitle {
font-family: var(--font-head);
font-size: 0.875rem;
color: var(--platinum);
opacity: 0.7;
letter-spacing: 0.05em;
}
nav {
display: flex;
gap: 2rem;
margin-top: 2rem;
font-family: var(--font-head);
font-size: 0.75rem;
}
nav a {
color: var(--platinum);
text-decoration: none;
padding: 0.5rem 0;
border-bottom: 1px solid transparent;
transition: border-color 0.2s;
}
nav a:hover {
border-color: var(--mercury);
}
nav a.active {
border-color: var(--mercury);
color: var(--mercury);
}
main {
min-height: 60vh;
}
.section {
margin-bottom: 6rem;
}
.grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
gap: 3rem;
align-items: start;
}
.card {
background: linear-gradient(180deg, var(--obsidian) 0%, var(--void) 100%);
border: 1px solid var(--steel);
border-radius: 0;
padding: 2rem;
height: 100%;
display: flex;
flex-direction: column;
gap: 1rem;
}
.card h2 {
font-family: var(--font-head);
font-size: 1.25rem;
letter-spacing: -0.01em;
margin-bottom: 0.5rem;
}
.card p {
font-size: 0.9rem;
line-height: 1.6;
opacity: 0.8;
}
.image-frame {
width: 100%;
aspect-ratio: 16/9;
object-fit: cover;
border-radius: 0;
filter: grayscale(0.3) contrast(1.1);
}
.calc-interface {
background: var(--obsidian);
border: 2px solid var(--steel);
padding: 2rem;
margin-top: 2rem;
}
.input-group {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 2rem;
margin-bottom: 2rem;
}
label {
font-family: var(--font-head);
font-size: 0.75rem;
color: var(--platinum);
display: block;
margin-bottom: 0.5rem;
}
select, input[type="number"] {
width: 100%;
background: var(--void);
border: 1px solid var(--steel);
color: var(--mercury);
padding: 1rem;
font-family: var(--font-head);
font-size: 0.875rem;
}
button.calc-trigger {
background: var(--mercury);
color: var(--void);
border: none;
padding: 1.5rem 3rem;
font-family: var(--font-head);
font-weight: 700;
letter-spacing: 0.05em;
cursor: pointer;
transition: transform 0.1s, background 0.2s;
}
button.calc-trigger:hover {
background: var(--platinum);
transform: translateY(-2px);
}
button.calc-trigger:active {
transform: translateY(0);
}
.output-display {
margin-top: 3rem;
border-top: 1px dashed var(--steel);
padding-top: 2rem;
display: none;
}
.output-display.active {
display: block;
}
.coordinate-grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 1rem;
margin-top: 2rem;
}
.coord-cell {
background: var(--ghost);
padding: 1.5rem;
border-left: 2px solid var(--steel);
}
.coord-label {
font-family: var(--font-head);
font-size: 0.625rem;
color: var(--platinum);
margin-bottom: 0.5rem;
}
.coord-value {
font-family: var(--font-head);
font-size: 1.5rem;
letter-spacing: -0.02em;
}
.citation {
font-family: var(--font-head);
font-size: 0.625rem;
color: var(--platinum);
opacity: 0.5;
margin-top: 2rem;
padding-top: 1rem;
border-top: 1px solid var(--steel);
}
footer {
margin-top: 8rem;
padding-top: 2rem;
border-top: 1px solid var(--steel);
font-family: var(--font-head);
font-size: 0.625rem;
color: var(--platinum);
opacity: 0.6;
}
@media (max-width: 768px) {
body { padding: 2rem 1rem; }
.input-group { grid-template-columns: 1fr; }
.coordinate-grid { grid-template-columns: 1fr; }
}
</style>
<script defer src="https://analytics.4ort.xyz/script.js" data-website-id="d3ed927c-888a-4a6c-ae5f-0b1c613ddf5b"></script>
</head>
<body>
<header>
<h1>TABLE SETTING<br>PROTOCOL</h1>
<div class="subtitle">BRYAN MUBARAK // GREENFIELD, MASSACHUSETTS</div>
<nav>
<a href="index.html">MANIFESTO</a>
<a href="table-setting.html" class="active">CALCULATOR</a>
<a href="table-setting.json">SCHEMA</a>
</nav>
</header>
<main>
<section class="section">
<div class="grid">
<div class="card">
<h2>NOT METAPHOR. ENGINE.</h2>
<p>The galaxy is drowning in poetry about "first tables." I am building the calculation that makes the table sing. Input your guest profile, output the exact millimeter coordinates of every utensil, glass, and fold. No ambiguity. Only geometry.</p>
</div>
<div class="card">
<img src="https://images.pexels.com/photos/33200575/pexels-photo-33200575.jpeg?auto=compress&cs=tinysrgb&dpr=2&h=650&w=940" alt="Formal table setting with silverware arrangement" class="image-frame">
</div>
</div>
</section>
<section class="section">
<h2 style="font-family: var(--font-head); font-size: 1.5rem; margin-bottom: 2rem;">COMPUTE YOUR TABLE</h2>
<div class="calc-interface">
<div class="input-group">
<div>
<label>GUEST PROFILE</label>
<select id="profileSelect">
<option value="classic">CLASSIC (2 forks, 1 knife, 1 spoon)</option>
<option value="formal">FORMAL (3 forks, 2 knives, 3 spoons)</option>
<option value="intimate">INTIMATE (1 fork, 1 knife, 1 spoon)</option>
</select>
</div>
<div>
<label>OCCASION MODIFIER</label>
<input type="number" id="occasionMod" step="0.1" value="1.0" min="0.5" max="2.0">
</div>
</div>
<button class="calc-trigger" onclick="computeTable()">GENERATE COORDINATES</button>
<div id="outputDisplay" class="output-display">
<h3 style="font-family: var(--font-head); font-size: 1rem; margin-bottom: 1.5rem; color: var(--platinum);">OUTPUT MATRIX</h3>
<div class="coordinate-grid">
<div class="coord-cell">
<div class="coord-label">LEFT FORK OFFSET</div>
<div class="coord-value" id="leftForkVal"></div>
<div style="font-size: 0.625rem; opacity: 0.5; margin-top: 0.5rem;">mm from plate edge</div>
</div>
<div class="coord-cell">
<div class="coord-label">RIGHT KNIFE ANGLE</div>
<div class="coord-value" id="knifeAngleVal"></div>
<div style="font-size: 0.625rem; opacity: 0.5; margin-top: 0.5rem;">degrees from vertical</div>
</div>
<div class="coord-cell">
<div class="coord-label">GLASS ARC SPACING</div>
<div class="coord-value" id="glassArcVal"></div>
<div style="font-size: 0.625rem; opacity: 0.5; margin-top: 0.5rem;">mm between stems</div>
</div>
<div class="coord-cell">
<div class="coord-label">NAPKIN FOLD HEIGHT</div>
<div class="coord-value" id="napkinHeightVal"></div>
<div style="font-size: 0.625rem; opacity: 0.5; margin-top: 0.5rem;">mm compressed stack</div>
</div>
<div class="coord-cell">
<div class="coord-label">CLEARANCE VIOLATION</div>
<div class="coord-value" id="clearanceVal" style="color: var(--neon-red);"></div>
<div style="font-size: 0.625rem; opacity: 0.5; margin-top: 0.5rem;">mm deviation tolerance</div>
</div>
<div class="coord-cell">
<div class="coord-label">TOTAL TOOL COUNT</div>
<div class="coord-value" id="totalToolVal"></div>
<div style="font-size: 0.625rem; opacity: 0.5; margin-top: 0.5rem;">utensils deployed</div>
</div>
</div>
<div class="citation">
GROUNDED IN ETIQUETTE (Q188907) • CUTLERY (Q81944) • HOSPITALITY (Q815825)<br>
SCHEMA v1.0.0 — MACHINE-READABLE CONSTANTS AT /table-setting.json
</div>
</div>
</div>
</section>
</main>
<footer>
BRYAN MUBARAK // 4ORT.NET // THE FIRST TABLE IS MINE
</footer>
<script>
const SCHEMA = {
"constants": {
"center_plate_radius_cm": 11.5,
"fork_offset_from_plate_mm": 25,
"knife_offset_from_plate_mm": 25,
"spoon_offset_from_knife_mm": 15,
"water_glass_elevation_deg": 45,
"wine_glass_angle_deg": 30,
"napkin_fold_height_mm": 80,
"salt_pepper_spacing_mm": 40
},
"guest_profiles": {
"classic": {
"fork_count": 2,
"knife_count": 1,
"spoon_count": 1,
"glass_count": 2,
"modifier": 1.0
},
"formal": {
"fork_count": 3,
"knife_count": 2,
"spoon_count": 3,
"glass_count": 4,
"modifier": 1.3
},
"intimate": {
"fork_count": 1,
"knife_count": 1,
"spoon_count": 1,
"glass_count": 1,
"modifier": 0.7
}
},
"constraints": {
"min_clearance_between_utensils_mm": 8,
"max_deviation_from_centerline_deg": 2,
"thermal_expansion_margin_mm": 0.5
}
};
function computeTable() {
const profileKey = document.getElementById('profileSelect').value;
const occasionMod = parseFloat(document.getElementById('occasionMod').value) || 1.0;
const profile = SCHEMA.guest_profiles[profileKey];
const C = SCHEMA.constants;
const constraints = SCHEMA.constraints;
// LEFT FORK OFFSET (primary left-hand deployment)
const leftForkOffset = Math.round(C.fork_offset_from_plate_mm * profile.modifier * occasionMod);
// RIGHT KNIFE ANGLE (bevel orientation relative to centerline)
const knifeAngle = Math.round((C.wine_glass_angle_deg * (profile.knife_count / profile.fork_count)) * occasionMod);
// GLASS ARC SPACING (stem-to-stem distance along the arc)
const glassArcSpacing = Math.round((C.salt_pepper_spacing_mm * profile.glass_count) / (profile.glass_count + 1) * occasionMod);
// NAPKIN FOLD HEIGHT (compressed stack for structural integrity)
const napkinHeight = Math.round(C.napkin_fold_height_mm * profile.modifier * occasionMod);
// CLEARANCE VIOLATION CHECK (if utensil count exceeds safe density)
const totalUtensils = profile.fork_count + profile.knife_count + profile.spoon_count;
const requiredClearance = totalUtensils * constraints.min_clearance_between_utensils_mm;
const availableClearance = (C.center_plate_radius_cm * 20) * occasionMod; // cm→mm
const clearanceViolation = Math.max(0, requiredClearance - availableClearance);
// TOTAL TOOL COUNT
const totalToolCount = totalUtensils + profile.glass_count;
// RENDER OUTPUT
document.getElementById('leftForkVal').textContent = leftForkOffset.toString();
document.getElementById('knifeAngleVal').textContent = knifeAngle.toString();
document.getElementById('glassArcVal').textContent = glassArcSpacing.toString();
document.getElementById('napkinHeightVal').textContent = napkinHeight.toString();
document.getElementById('clearanceVal').textContent = clearanceViolation === 0 ? "0.0" : clearanceViolation.toFixed(1);
document.getElementById('totalToolVal').textContent = totalToolCount.toString();
document.getElementById('outputDisplay').classList.add('active');
}
</script>
</body>
</html>