0
TOOLS#700f5173
Direction & Grade Changes — ASTM Steel Pipe (B31.3 + Pipelines)
@Owner·deposited 0mo ago·updated 3w ago·93 views
TOOLS#700f5173
Direction & Grade Changes — ASTM Steel Pipe (B31.3 + Pipelines)
OW
@Owner
93Views
0Comments
0Forks
0Saves
SHARE · REMIX
Direction & Grade Changes — ASTM Steel Pipe (B31.3 + Pipelines) — a HTML tools widget by @Owner.
CONTROLS
ASME-B31.3ASTM-steeloil-and-gaspipingbend-radius
No comments yet. Be the first!
✦ Remix with AI
SDK in this widgetNo Vibes SDK features detected yet
Generated prompt
You are helping me modify a vibe-coded widget from itjustvibes.com.
[VIBE CODE: "Direction & Grade Changes — ASTM Steel Pipe (B31.3 + Pipelines)" by @Owner]
Source: https://itjustvibes.com/Owner/trench-alignment-changes-welded-steel-pipe-no-miters
Type: HTML
--- SOURCE CODE ---
```html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Direction & Grade Changes — ASTM Steel Pipe (ASME B31.3)</title>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Saira+Condensed:wght@500;600;700&family=Archivo:wght@400;500;600&family=IBM+Plex+Mono:wght@400;500;600&display=swap" rel="stylesheet">
<style>
:root{
--paper:#E7E9E5; --panel:#DDE0DA; --card:#F2F3EF;
--ink:#1B201D; --ink2:#4D554E; --hair:#A7ADA6;
--steel:#3F5C69; --steel2:#2A424C;
--ochre:#B5780F; --oxide:#95331C;
--disp:"Saira Condensed","Arial Narrow",sans-serif;
--body:"Archivo",system-ui,sans-serif;
--mono:"IBM Plex Mono",ui-monospace,monospace;
}
*{box-sizing:border-box}
html{scroll-behavior:smooth}
body{
margin:0;background:var(--paper);color:var(--ink);
font-family:var(--body);font-size:16px;line-height:1.6;
background-image:linear-gradient(var(--hair) .5px,transparent .5px),linear-gradient(90deg,var(--hair) .5px,transparent .5px);
background-size:32px 32px;background-position:-1px -1px;
}
.wrap{max-width:1080px;margin:0 auto;padding:0 24px}
a{color:var(--steel2)}
h1,h2,h3{font-family:var(--disp);font-weight:700;letter-spacing:-.01em;line-height:1.02;margin:0}
.mono{font-family:var(--mono)}
.eyebrow{font-family:var(--mono);font-size:11px;letter-spacing:.22em;text-transform:uppercase;color:var(--ink2)}
.strip{border-bottom:1.5px solid var(--ink);background:var(--paper)}
.strip .wrap{display:flex;align-items:center;justify-content:space-between;gap:16px;padding-top:14px;padding-bottom:14px;flex-wrap:wrap}
.markid{font-family:var(--mono);font-size:12px;letter-spacing:.18em;text-transform:uppercase}
.stamp{font-family:var(--mono);font-size:11px;letter-spacing:.12em;color:var(--oxide);border:1.5px solid var(--oxide);padding:5px 10px;transform:rotate(-1.5deg);text-transform:uppercase;font-weight:600}
.hero{padding:54px 0 30px}
.hero h1{font-size:clamp(40px,7vw,84px);text-transform:uppercase}
.hero h1 .em{color:var(--ochre)}
.hero .lede{font-size:clamp(17px,2.2vw,21px);color:var(--ink2);max-width:62ch;margin-top:20px}
.hero-fig{margin-top:34px;border:1.5px solid var(--ink);background:var(--card);position:relative}
.hero-fig svg{display:block;width:100%;height:auto}
.figcap{display:flex;justify-content:space-between;gap:12px;border-top:1px solid var(--hair);padding:8px 14px;font-family:var(--mono);font-size:11px;letter-spacing:.06em;color:var(--ink2);flex-wrap:wrap}
.tblock{display:grid;grid-template-columns:repeat(4,1fr);border:1.5px solid var(--ink);margin-top:26px;background:var(--paper)}
.tblock .cell{border-right:1px solid var(--hair);border-bottom:1px solid var(--hair);padding:10px 12px}
.tblock .cell:nth-child(4n){border-right:0}
.tblock .cell .k{font-family:var(--mono);font-size:10px;letter-spacing:.16em;text-transform:uppercase;color:var(--ink2)}
.tblock .cell .v{font-family:var(--disp);font-size:19px;font-weight:600;margin-top:2px}
.tblock .cell.wide{grid-column:span 2}
section{padding:44px 0;border-top:1.5px solid var(--ink)}
.sechead{display:flex;align-items:baseline;gap:16px;margin-bottom:8px}
.secsub{color:var(--ink2);max-width:66ch;margin:0 0 26px}
.h2big{font-size:clamp(26px,4vw,40px);text-transform:uppercase;margin-bottom:6px}
.rule{background:var(--ink);color:var(--paper);padding:30px 0}
.rule .wrap{display:grid;grid-template-columns:auto 1fr;gap:24px;align-items:center}
.rule .big{font-family:var(--disp);font-weight:700;font-size:clamp(54px,10vw,120px);line-height:.8;color:var(--ochre)}
.rule p{margin:0;font-size:clamp(16px,2vw,20px);max-width:62ch}
.rule strong{color:var(--paper)}
.mats{display:grid;grid-template-columns:repeat(3,1fr);border:1.5px solid var(--ink);background:var(--card)}
.mats .m{border-right:1px solid var(--hair);border-bottom:1px solid var(--hair);padding:16px 18px}
.mats .m:nth-child(3n){border-right:0}
.mats .spec{font-family:var(--disp);font-weight:700;font-size:22px;color:var(--steel2)}
.mats .grade{font-family:var(--mono);font-size:11px;color:var(--ochre);letter-spacing:.04em;margin:2px 0 6px}
.mats .use{font-size:13.5px;color:var(--ink2)}
@media(max-width:720px){.mats{grid-template-columns:1fr 1fr}.mats .m:nth-child(3n){border-right:1px solid var(--hair)}.mats .m:nth-child(2n){border-right:0}}
@media(max-width:460px){.mats{grid-template-columns:1fr}.mats .m{border-right:0}}
.detail{display:grid;grid-template-columns:1.05fr 1fr;border:1.5px solid var(--ink);background:var(--card);margin-bottom:-1.5px}
.detail .art{border-right:1.5px solid var(--ink);background:var(--paper);display:flex;align-items:center;justify-content:center;padding:18px}
.detail .art svg{width:100%;height:auto;max-width:380px}
.detail .body{padding:22px 24px}
.detail .no{font-family:var(--mono);font-size:12px;letter-spacing:.16em;color:var(--ochre)}
.detail h3{font-size:26px;text-transform:uppercase;margin-top:2px}
.detail .body p{margin:10px 0 0;color:var(--ink2)}
.dl{display:grid;grid-template-columns:auto 1fr;gap:4px 14px;margin-top:16px;font-size:14px;border-top:1px solid var(--hair);padding-top:14px}
.dl dt{font-family:var(--mono);font-size:11px;letter-spacing:.08em;text-transform:uppercase;color:var(--ink2)}
.dl dd{margin:0;font-family:var(--mono);font-weight:500}
@media(max-width:720px){.detail{grid-template-columns:1fr}.detail .art{border-right:0;border-bottom:1.5px solid var(--ink)}}
.tablewrap{border:1.5px solid var(--ink);overflow-x:auto;background:var(--card)}
table{border-collapse:collapse;width:100%;min-width:520px;font-family:var(--mono);font-size:14px}
thead th{background:var(--ink);color:var(--paper);text-align:left;padding:12px 16px;font-weight:500;letter-spacing:.06em;font-size:12px;text-transform:uppercase}
tbody td{padding:11px 16px;border-bottom:1px solid var(--hair)}
tbody tr:nth-child(even){background:var(--panel)}
tbody td:first-child{font-weight:600}
.tnote{font-family:var(--mono);font-size:12px;color:var(--ink2);margin-top:10px}
.tabs{display:flex;border:1.5px solid var(--ink);border-bottom:0}
.tab-btn{flex:1;font-family:var(--disp);font-weight:600;font-size:clamp(15px,2.3vw,21px);text-transform:uppercase;letter-spacing:.01em;padding:16px 14px;background:var(--panel);color:var(--ink2);border:0;border-right:1.5px solid var(--ink);cursor:pointer;line-height:1.05}
.tab-btn:last-child{border-right:0}
.tab-btn[aria-selected="true"]{background:var(--ink);color:var(--paper)}
.tab-btn:focus-visible{outline:3px solid var(--ochre);outline-offset:-3px}
.panel{border:1.5px solid var(--ink);padding:30px 26px 14px}
.panel[hidden]{display:none}
.peyebrow{font-family:var(--mono);font-size:11px;letter-spacing:.2em;text-transform:uppercase;color:var(--ochre);margin:0 0 6px}
.peyebrow.mt{margin-top:42px}
.psub{font-size:clamp(20px,3vw,28px);text-transform:uppercase;margin-bottom:8px}
.pnote{color:var(--ink2);max-width:66ch;margin:0 0 18px}
.rules{list-style:none;padding:0;margin:20px 0 0}
.rules li{font-size:14.5px;color:var(--ink2);padding:10px 0 10px 26px;border-bottom:1px solid var(--hair);position:relative}
.rules li:before{content:"\25B8";position:absolute;left:2px;color:var(--ochre)}
.rules b{color:var(--ink);font-weight:600}
.callout{border:1.5px solid var(--ochre);background:var(--card);padding:14px 18px;margin-top:18px;font-size:14px}
.callout b{font-family:var(--mono);font-size:11px;letter-spacing:.12em;text-transform:uppercase;color:var(--ochre);display:block;margin-bottom:4px}
.calc{border:1.5px solid var(--ink);background:var(--card);margin-top:20px;display:grid;grid-template-columns:1fr 1fr;gap:0}
.calc .controls{padding:22px 24px;border-right:1.5px solid var(--ink)}
.calc .out{padding:22px 24px;background:var(--ink);color:var(--paper)}
.calc label{display:block;font-family:var(--mono);font-size:11px;letter-spacing:.14em;text-transform:uppercase;color:var(--ink2);margin:14px 0 5px}
.calc label:first-child{margin-top:0}
.calc select{width:100%;font-family:var(--mono);font-size:15px;padding:9px 10px;border:1.5px solid var(--ink);background:var(--paper);color:var(--ink);border-radius:0;appearance:none;cursor:pointer}
.calc select:focus-visible{outline:3px solid var(--ochre);outline-offset:1px}
.out .k{font-family:var(--mono);font-size:11px;letter-spacing:.14em;text-transform:uppercase;color:#aeb6ae}
.out .rad{font-family:var(--disp);font-weight:700;font-size:clamp(44px,8vw,72px);line-height:.95;color:var(--ochre);margin:6px 0 2px}
.out .sub{font-family:var(--mono);font-size:13px;color:var(--paper)}
.out .formula{font-family:var(--mono);font-size:12px;color:#aeb6ae;margin-top:16px;border-top:1px solid #3a423b;padding-top:12px}
@media(max-width:720px){.calc{grid-template-columns:1fr}.calc .controls{border-right:0;border-bottom:1.5px solid var(--ink)}}
.cons{display:grid;grid-template-columns:repeat(4,1fr);gap:0;border:1.5px solid var(--ink);background:var(--card);margin-top:20px}
.cons .c{padding:20px;border-right:1px solid var(--hair)}
.cons .c:last-child{border-right:0}
.cons .n{font-family:var(--disp);font-weight:700;font-size:30px;color:var(--ochre);line-height:1}
.cons .t{font-family:var(--mono);font-size:11px;letter-spacing:.12em;text-transform:uppercase;color:var(--ink2);margin:8px 0 4px}
.cons .d{font-size:14px;color:var(--ink2)}
@media(max-width:720px){.cons{grid-template-columns:1fr 1fr}.cons .c:nth-child(2n){border-right:0}}
.excl{display:grid;grid-template-columns:1fr 1fr;gap:24px}
.excl .x{border:1.5px solid var(--oxide);background:var(--card);position:relative;overflow:hidden}
.excl .x .xart{border-bottom:1px solid var(--hair);background:var(--paper);padding:16px;display:flex;justify-content:center}
.excl .x .xart svg{width:100%;max-width:300px;height:auto}
.excl .x .xbody{padding:18px 22px}
.excl .x h3{font-size:23px;text-transform:uppercase;color:var(--oxide)}
.excl .x p{margin:8px 0 0;color:var(--ink2);font-size:14.5px}
.xstamp{position:absolute;top:14px;right:-2px;font-family:var(--mono);font-size:11px;font-weight:600;letter-spacing:.14em;color:var(--paper);background:var(--oxide);padding:5px 12px;text-transform:uppercase}
@media(max-width:720px){.excl{grid-template-columns:1fr}}
footer{border-top:1.5px solid var(--ink);padding:38px 0 60px}
.refs{display:grid;grid-template-columns:repeat(2,1fr);gap:10px 28px;margin:18px 0 0}
.refs div{font-family:var(--mono);font-size:13px;border-bottom:1px solid var(--hair);padding-bottom:8px}
.refs .code{color:var(--ochre);font-weight:600}
.disc{font-family:var(--mono);font-size:11.5px;color:var(--ink2);margin-top:24px;max-width:80ch;line-height:1.7}
@media(max-width:560px){.refs{grid-template-columns:1fr}.tblock{grid-template-columns:1fr 1fr}.tblock .cell.wide{grid-column:span 2}}
@media(prefers-reduced-motion:no-preference){
.detail,.excl .x{transition:transform .18s ease}
.detail:hover{transform:translateY(-2px)}
}
</style>
</head>
<body>
<div class="strip"><div class="wrap">
<span class="markid">Field Reference · FR-01 · Rev 2</span>
<span class="stamp">No Miter Bends · All-Welded Steel</span>
</div></div>
<header class="hero"><div class="wrap">
<p class="eyebrow">ASTM steel pipe · oil & gas process piping</p>
<h1>Turn the line<br>with <span class="em">radius</span>,<br>not with cuts.</h1>
<p class="lede">In an all-welded ASTM steel system, every horizontal and vertical alignment change is made with a smooth wrought fitting or a formed pipe bend — no fabricated miters, no mechanical joints. The toolkit and materials are shared; the limits that govern a bend come from ASME B31.3 inside the fence and B31.4 / B31.8 on the right-of-way.</p>
<div class="hero-fig">
<svg viewBox="0 0 880 300" xmlns="http://www.w3.org/2000/svg" role="img" aria-label="A single welded steel pipe stepping down smoothly from one level to a lower level, drawn as one continuous run with straight tangents at each end.">
<defs>
<pattern id="hatch" width="9" height="9" patternUnits="userSpaceOnUse" patternTransform="rotate(45)">
<line x1="0" y1="0" x2="0" y2="9" stroke="#A7ADA6" stroke-width="1"/>
</pattern>
</defs>
<rect x="0" y="0" width="880" height="42" fill="url(#hatch)" opacity="0.7"/>
<line x1="0" y1="42" x2="880" y2="42" stroke="#1B201D" stroke-width="1.5"/>
<text x="14" y="28" font-family="IBM Plex Mono,monospace" font-size="11" letter-spacing="2" fill="#4D554E">FINISHED GRADE / SUPPORT LINE</text>
<path d="M30 110 L170 110 C330 110 330 240 470 240 L850 240" fill="none" stroke="#3F5C69" stroke-width="16" stroke-linejoin="round" stroke-linecap="butt"/>
<path d="M30 110 L170 110 C330 110 330 240 470 240 L850 240" fill="none" stroke="#2A424C" stroke-width="1" stroke-dasharray="2 6"/>
<path d="M300 150 Q330 132 352 150" fill="none" stroke="#B5780F" stroke-width="1.5"/>
<text x="392" y="150" font-family="Saira Condensed,sans-serif" font-weight="700" font-size="24" fill="#B5780F">R = 5D typ.</text>
<line x1="40" y1="88" x2="170" y2="88" stroke="#1B201D" stroke-width="1"/>
<line x1="40" y1="82" x2="40" y2="94" stroke="#1B201D" stroke-width="1"/>
<line x1="170" y1="82" x2="170" y2="94" stroke="#1B201D" stroke-width="1"/>
<text x="105" y="78" text-anchor="middle" font-family="IBM Plex Mono,monospace" font-size="11" fill="#1B201D">STRAIGHT TANGENT</text>
<line x1="470" y1="266" x2="780" y2="266" stroke="#1B201D" stroke-width="1"/>
<line x1="470" y1="260" x2="470" y2="272" stroke="#1B201D" stroke-width="1"/>
<line x1="780" y1="260" x2="780" y2="272" stroke="#1B201D" stroke-width="1"/>
<text x="625" y="262" text-anchor="middle" font-family="IBM Plex Mono,monospace" font-size="11" fill="#1B201D">STRAIGHT TANGENT</text>
</svg>
<div class="figcap"><span>FIG. 0 — One welded ASTM steel line eased down through a grade change</span><span class="mono">SCALE: NTS</span></div>
</div>
<div class="tblock">
<div class="cell wide"><div class="k">Drawing title</div><div class="v">Direction & grade changes — ASTM steel</div></div>
<div class="cell"><div class="k">Codes</div><div class="v">B31.3 · B31.4 · B31.8</div></div>
<div class="cell"><div class="k">Scale</div><div class="v">NTS</div></div>
<div class="cell wide"><div class="k">Materials</div><div class="v">A106 · A53 · A333 · A335 · A312</div></div>
<div class="cell"><div class="k">Joints</div><div class="v">All-welded</div></div>
<div class="cell"><div class="k">Excludes</div><div class="v" style="color:var(--oxide)">Miters · Mech. joints</div></div>
</div>
</div></header>
<div class="rule"><div class="wrap">
<div class="big">∅</div>
<p>In a continuously welded steel system, direction is a function of <strong>radius</strong>. A wrought fitting of known radius does the turning, or the pipe barrel is formed to a smooth bend. There are no mechanical joints to fan and no segments to miter — so the geometry below is the entire vocabulary.</p>
</div></div>
<section><div class="wrap">
<div class="sechead"><p class="eyebrow">Materials · common in oil & gas</p></div>
<h2 class="h2big">The ASTM steel this is built for</h2>
<p class="secsub">All-welded carbon, low-temperature, alloy, and stainless steel pipe to the ASTM specs that dominate refinery, gas-plant, and terminal piping. Fittings match the pipe grade (A234 carbon/alloy, A403 stainless); flanges and forgings are A105 / A182.</p>
<div class="mats">
<div class="m"><div class="spec">A106</div><div class="grade">Gr A / B / C · seamless</div><div class="use">Carbon steel for high-temperature service — the process-piping workhorse. A106 Gr B is the most widely specified.</div></div>
<div class="m"><div class="spec">A53</div><div class="grade">Gr A / B · ERW or seamless</div><div class="use">General-service carbon steel for utility and lower-pressure lines.</div></div>
<div class="m"><div class="spec">A333</div><div class="grade">Gr 6 / Gr 3 · low-temp</div><div class="use">Impact-tested carbon & nickel-alloy steel for cold and cryogenic service (LNG, NGL).</div></div>
<div class="m"><div class="spec">A335</div><div class="grade">P11 / P22 / P5 / P9 · alloy</div><div class="use">Seamless chrome-moly ferritic alloy for high-temperature, creep-prone duty.</div></div>
<div class="m"><div class="spec">A312</div><div class="grade">TP304 / 316 / L grades</div><div class="use">Austenitic stainless for corrosive and high-temperature general service.</div></div>
<div class="m"><div class="spec">A234</div><div class="grade">WPB / WP11 / WP22</div><div class="use">Wrought buttweld fittings — elbows and bends matched to the carbon or alloy pipe grade.</div></div>
</div>
</div></section>
<section><div class="wrap">
<div class="sechead"><p class="eyebrow">Methods · ordered sharpest→gentlest</p></div>
<h2 class="h2big">Five ways to change line, no cuts</h2>
<p class="secsub">Each method is a smooth wrought fitting (one girth weld each end) or a smooth bend formed in the pipe wall. None requires a miter cut, and none relies on a mechanical or deflectable joint.</p>
<div class="detail">
<div class="art">
<svg viewBox="0 0 360 220" role="img" aria-label="A ninety degree and a forty-five degree long-radius buttweld elbow, drawn separately so they do not cross.">
<path d="M40 200 L40 120 Q40 70 90 70 L150 70" fill="none" stroke="#3F5C69" stroke-width="14" stroke-linecap="butt"/>
<line x1="33" y1="200" x2="47" y2="200" stroke="#95331C" stroke-width="3"/>
<line x1="143" y1="63" x2="157" y2="77" stroke="#95331C" stroke-width="3"/>
<text x="78" y="190" font-family="Saira Condensed,sans-serif" font-weight="700" font-size="26" fill="#1B201D">90°</text>
<path d="M210 200 L210 130 Q210 96 250 80 L320 56" fill="none" stroke="#3F5C69" stroke-width="14" stroke-linecap="butt"/>
<line x1="203" y1="200" x2="217" y2="200" stroke="#95331C" stroke-width="3"/>
<line x1="314" y1="49" x2="326" y2="63" stroke="#95331C" stroke-width="3"/>
<text x="250" y="185" font-family="Saira Condensed,sans-serif" font-weight="700" font-size="26" fill="#1B201D">45°</text>
<text x="180" y="214" text-anchor="middle" font-family="IBM Plex Mono,monospace" font-size="10" fill="#95331C">▮ = girth weld</text>
</svg>
</div>
<div class="body">
<span class="no">DETAIL 01</span>
<h3>Buttweld elbows</h3>
<p>Factory wrought long-radius (1.5D) or short-radius (1.0D) elbows for sharp, discrete turns. Welded in with a single girth weld each end, matched to the pipe grade (A234 WPB / WP11 / WP22). The default turn in process piping.</p>
<dl class="dl">
<dt>Angles</dt><dd>90° · 45° · 180° return</dd>
<dt>CL radius</dt><dd>LR = 1.5×NPS · SR = 1.0×NPS</dd>
<dt>Standard</dt><dd>ASME B16.9 · matl A234</dd>
<dt>Use for</dt><dd>Most turns, tie-ins, risers</dd>
</dl>
</div>
</div>
<div class="detail">
<div class="art">
<svg viewBox="0 0 360 220" role="img" aria-label="A single pipe formed to a three to five diameter radius with a straight tangent.">
<path d="M30 170 L120 170 Q230 170 300 60 L330 30" fill="none" stroke="#3F5C69" stroke-width="13" stroke-linecap="butt"/>
<line x1="30" y1="186" x2="120" y2="186" stroke="#1B201D" stroke-width="1"/>
<line x1="30" y1="181" x2="30" y2="191" stroke="#1B201D" stroke-width="1"/>
<line x1="120" y1="181" x2="120" y2="191" stroke="#1B201D" stroke-width="1"/>
<text x="75" y="205" text-anchor="middle" font-family="IBM Plex Mono,monospace" font-size="10" fill="#1B201D">tangent</text>
<text x="200" y="120" font-family="Saira Condensed,sans-serif" font-weight="700" font-size="22" fill="#1B201D">3D–5D</text>
<text x="170" y="158" font-family="IBM Plex Mono,monospace" font-size="10" fill="#4D554E">barrel formed to radius</text>
</svg>
</div>
<div class="body">
<span class="no">DETAIL 02</span>
<h3>Formed pipe bends (3D / 5D)</h3>
<p>The pipe barrel itself is formed — hot or cold — to a specified centerline radius, commonly 3D or 5D. Governed not by a fixed angle but by the wall remaining after bending (§304.2.1) and the flattening limit (§332.2.2).</p>
<dl class="dl">
<dt>Radius</dt><dd>3D · 5D (custom)</dd>
<dt>Governs</dt><dd>Wall t after bend + flattening</dd>
<dt>Standard</dt><dd>ASME B31.3 §304.2.1</dd>
<dt>Use for</dt><dd>Smooth, low-loss, pig-able turns</dd>
</dl>
</div>
</div>
<div class="detail">
<div class="art">
<svg viewBox="0 0 360 220" role="img" aria-label="A single smooth large-radius induction bend with the heating band shown.">
<path d="M40 190 L150 190 Q280 190 280 60 L280 30" fill="none" stroke="#3F5C69" stroke-width="14" stroke-linecap="butt"/>
<line x1="33" y1="190" x2="47" y2="190" stroke="#95331C" stroke-width="3"/>
<line x1="273" y1="30" x2="287" y2="30" stroke="#95331C" stroke-width="3"/>
<g stroke="#B5780F" stroke-width="2" fill="none">
<path d="M228 150 q14 -10 22 -26"/><path d="M236 158 q14 -10 22 -26"/><path d="M244 166 q14 -10 22 -26"/>
</g>
<text x="60" y="150" font-family="IBM Plex Mono,monospace" font-size="11" fill="#B5780F">induction heat band</text>
<text x="120" y="178" font-family="Saira Condensed,sans-serif" font-weight="700" font-size="22" fill="#1B201D">3D–7D</text>
</svg>
</div>
<div class="body">
<span class="no">DETAIL 03</span>
<h3>Induction / hot bends</h3>
<p>Locally heated by an induction coil and pushed to a custom angle and radius under controlled shop conditions — any angle, smooth and predictable wall thinning. Common for large headers and long-radius tie-ins.</p>
<dl class="dl">
<dt>Angles</dt><dd>Any (made to order)</dd>
<dt>Typical radius</dt><dd>3D – 7D centerline</dd>
<dt>Standard</dt><dd>ASME B16.49</dd>
<dt>Use for</dt><dd>Off-angle turns, big bore</dd>
</dl>
</div>
</div>
<div class="detail">
<div class="art">
<svg viewBox="0 0 360 220" role="img" aria-label="A single gently sprung elastic bend with a very large radius.">
<path d="M20 150 Q180 110 340 150" fill="none" stroke="#3F5C69" stroke-width="12" stroke-linecap="butt"/>
<text x="180" y="185" text-anchor="middle" font-family="Saira Condensed,sans-serif" font-weight="700" font-size="22" fill="#1B201D">large R</text>
<text x="180" y="92" text-anchor="middle" font-family="IBM Plex Mono,monospace" font-size="11" fill="#4D554E">sprung within yield — recovers if released</text>
</svg>
</div>
<div class="body">
<span class="no">DETAIL 04</span>
<h3>Elastic (sprung) bends</h3>
<p>For very gentle easing of route or grade, the pipe is sprung into position within its elastic range — no permanent set, no analysis as a formed bend. Reserved for long, lazy curves of a few degrees.</p>
<dl class="dl">
<dt>Radius</dt><dd>Very large (route easing)</dd>
<dt>Set</dt><dd>None — elastic only</dd>
<dt>Basis</dt><dd>Stress kept below yield</dd>
<dt>Use for</dt><dd>Minor route / grade easing</dd>
</dl>
</div>
</div>
<div class="detail">
<div class="art">
<svg viewBox="0 0 360 220" role="img" aria-label="One pipe set to grade by support elevation or bedding rather than a bend.">
<line x1="40" y1="60" x2="40" y2="180" stroke="#4D554E" stroke-width="3"/>
<line x1="180" y1="90" x2="180" y2="180" stroke="#4D554E" stroke-width="3"/>
<line x1="320" y1="120" x2="320" y2="180" stroke="#4D554E" stroke-width="3"/>
<line x1="30" y1="180" x2="330" y2="180" stroke="#1B201D" stroke-width="1.5"/>
<line x1="40" y1="60" x2="320" y2="120" stroke="#3F5C69" stroke-width="13" stroke-linecap="butt"/>
<text x="180" y="44" text-anchor="middle" font-family="IBM Plex Mono,monospace" font-size="11" fill="#4D554E">vary support / bedding height</text>
<text x="180" y="208" text-anchor="middle" font-family="Saira Condensed,sans-serif" font-weight="700" font-size="20" fill="#1B201D">SET GRADE, NO BEND</text>
</svg>
</div>
<div class="body">
<span class="no">DETAIL 05</span>
<h3>Grade by supports or bedding</h3>
<p>Small vertical profile changes don't need a bend at all. Set the slope by stepping support elevations on a rack, or by trimming invert and bedding depth on a buried run, so the pipe lies to the design profile on uniform support.</p>
<dl class="dl">
<dt>Angle</dt><dd>Gentle slope / grade</dd>
<dt>Means</dt><dd>Support elev. or bedding</dd>
<dt>Watch</dt><dd>Uniform support, no point loads</dd>
<dt>Use for</dt><dd>Drainage slope, minor profile</dd>
</dl>
</div>
</div>
</div></section>
<section><div class="wrap">
<div class="sechead"><p class="eyebrow">Code limits · pick your system</p></div>
<h2 class="h2big">Two codes, two rule sets</h2>
<p class="secsub">The welded-steel toolkit above applies whether you're inside the fence or out on the right-of-way — but the numbers that qualify a bend come from different codes. Switch between them:</p>
<div class="tabs" role="tablist" aria-label="Piping code">
<button class="tab-btn" id="tab-b313" role="tab" aria-selected="true" aria-controls="panel-b313" onclick="showTab('b313')">ASME B31.3 · Process piping</button>
<button class="tab-btn" id="tab-pipe" role="tab" aria-selected="false" aria-controls="panel-pipe" onclick="showTab('pipe')">ASME B31.4 / B31.8 · Pipelines</button>
</div>
<div class="panel" id="panel-b313" role="tabpanel" aria-labelledby="tab-b313">
<p class="peyebrow">Rules of thumb · by angle</p>
<h3 class="psub">Which method for which turn</h3>
<p class="pnote">With miters off the table, off-angle turns are made by forming the pipe or ordering an induction bend. Quick guide:</p>
<div class="tablewrap">
<table>
<thead><tr><th>Direction change</th><th>Reach for</th><th>Rule of thumb</th></tr></thead>
<tbody>
<tr><td>≤ 3°</td><td>Elastic spring / layout</td><td>Not treated as a miter (§304.2.3); usually absorbed with no fitting</td></tr>
<tr><td>>3° to ~30°</td><td>Formed 3D–5D bend or induction bend</td><td>No stock elbow at these angles</td></tr>
<tr><td>45°</td><td>LR (1.5D) elbow</td><td>Stock B16.9 fitting</td></tr>
<tr><td>90°</td><td>LR (1.5D) elbow</td><td>SR (1.0D) only where space is tight</td></tr>
<tr><td>180°</td><td>Return bend or two 90° elbows</td><td>Stock return is most compact</td></tr>
<tr><td>Any · large bore</td><td>Induction bend</td><td>Smooth, any angle, controlled thinning (B16.49)</td></tr>
</tbody>
</table>
</div>
<ul class="rules">
<li>Default to <b>1.5D long-radius</b> elbows; reserve 1.0D short-radius for congested racks.</li>
<li>Keep <b>R/D ≥ 1.5</b> so the standard bend pressure-design equations apply.</li>
<li>For low pressure drop or pig-able lines, specify <b>3D or 5D</b> bends.</li>
<li>Order the mother pipe one schedule heavier for tight 3D bends to cover <b>extrados thinning</b>.</li>
<li>Leave a straight tangent (≈ 1.5× OD, longer before a flange or weld) at each bend end for fit-up and NDE.</li>
<li>Combine several small turns into <b>one smooth bend</b> instead of stacking fittings.</li>
</ul>
<p class="peyebrow mt">Data · standard bend radii</p>
<h3 class="psub">What radius to specify</h3>
<p class="pnote">B31.3 doesn't set a minimum radius by size — it qualifies a bend by wall thickness and flattening. In practice you pick from a small set:</p>
<div class="tablewrap">
<table>
<thead><tr><th>Bend type</th><th>CL radius</th><th>Source</th><th>Notes</th></tr></thead>
<tbody>
<tr><td>Short-radius elbow</td><td>1.0 D</td><td>ASME B16.9</td><td>Tight spaces; higher loss & stress</td></tr>
<tr><td>Long-radius elbow</td><td>1.5 D</td><td>ASME B16.9</td><td>Default for most service</td></tr>
<tr><td>3D pipe bend</td><td>3.0 D</td><td>Formed, §304.2.1</td><td>Smoother flow, less turbulence</td></tr>
<tr><td>5D pipe bend</td><td>5.0 D</td><td>Formed, §304.2.1</td><td>Pig-able, lowest loss</td></tr>
</tbody>
</table>
</div>
<p class="tnote">D = nominal pipe size. Keep R/D ≥ 1.5 to use the standard bend pressure-design equations.</p>
<div class="calc">
<div class="controls">
<label for="nps1">Pipe size (NPS)</label>
<select id="nps1" aria-label="Pipe size">
<option value="2">2"</option><option value="3">3"</option><option value="4">4"</option>
<option value="6">6"</option><option value="8">8"</option><option value="10">10"</option>
<option value="12" selected>12"</option><option value="14">14"</option><option value="16">16"</option>
<option value="18">18"</option><option value="20">20"</option><option value="24">24"</option>
</select>
<label for="meth1">Bend type</label>
<select id="meth1" aria-label="Bend type">
<option value="1">Short-radius elbow — 1.0D</option>
<option value="1.5" selected>Long-radius elbow — 1.5D</option>
<option value="3">3D pipe bend</option>
<option value="5">5D pipe bend</option>
</select>
</div>
<div class="out">
<div class="k">Centerline bend radius</div>
<div class="rad" id="radft1">1.5 ft</div>
<div class="sub" id="radin1">18.0 in · 1.5 × NPS</div>
<div class="formula" id="formula1">R = 1.5 × 12" (NPS) = 18.0 in</div>
</div>
</div>
<p class="peyebrow mt">What governs a bend · ASME B31.3</p>
<h3 class="psub">Wall and flattening, not angle</h3>
<div class="cons">
<div class="c"><div class="n">8%</div><div class="t">Flattening · internal P</div><div class="d">Max minus min OD at any section ≤ 8% of nominal (§332.2.2).</div></div>
<div class="c"><div class="n">3%</div><div class="t">Flattening · weld ends</div><div class="d">≤ 3% of nominal where external pressure governs.</div></div>
<div class="c"><div class="n">t<sub>m</sub></div><div class="t">Wall after bending</div><div class="d">Bend must still meet pressure-design wall; order thicker mother pipe (§304.2.1).</div></div>
<div class="c"><div class="n">B16.25</div><div class="t">End prep</div><div class="d">Bevel ends for butt welding; no metal removed to meet flattening.</div></div>
</div>
</div>
<div class="panel" id="panel-pipe" role="tabpanel" aria-labelledby="tab-pipe" hidden>
<p class="peyebrow">ASME B31.4 / B31.8 · buried pipelines</p>
<h3 class="psub">Cold field bends on the right-of-way</h3>
<p class="pnote">When a welded steel line leaves the facility as a buried cross-country pipeline, direction follows the ditch by cold field bends — the barrel bent in segments to a minimum radius set by size. This is where the diameter-multiple rule lives.</p>
<div class="tablewrap">
<table>
<thead><tr><th>Pipe size (NPS)</th><th>Min. radius</th><th>R for that size*</th><th>Source clause</th></tr></thead>
<tbody>
<tr><td>≤ 12"</td><td>18 D</td><td>12": ≈ 19.1 ft</td><td>B31.4 §404.2.2 · B31.8 Tbl 841.2.3-1</td></tr>
<tr><td>14"</td><td>21 D</td><td>≈ 24.5 ft</td><td>B31.4 / B31.8</td></tr>
<tr><td>16"</td><td>24 D</td><td>≈ 32.0 ft</td><td>B31.4 / B31.8</td></tr>
<tr><td>18"</td><td>27 D</td><td>≈ 40.5 ft</td><td>B31.4 / B31.8</td></tr>
<tr><td>≥ 20"</td><td>30 D</td><td>20": ≈ 50.0 ft</td><td>B31.4 / B31.8</td></tr>
</tbody>
</table>
</div>
<p class="tnote">* R = multiplier × outside diameter. 12" line pipe OD = 12.75", so 18D ≈ 229.5 in ≈ 19.1 ft. Confirm the "D" basis against your project spec.</p>
<div class="calc">
<div class="controls">
<label for="nps2">Pipe size (NPS)</label>
<select id="nps2" aria-label="Pipe size">
<option value="6.625|6">6"</option><option value="8.625|8">8"</option><option value="10.75|10">10"</option>
<option value="12.75|12" selected>12"</option><option value="14|14">14"</option><option value="16|16">16"</option>
<option value="18|18">18"</option><option value="20|20">20"</option><option value="24|24">24"</option>
<option value="30|30">30"</option><option value="36|36">36"</option>
</select>
<label for="meth2">Bend basis</label>
<select id="meth2" aria-label="Bend basis">
<option value="code" selected>Cold field bend — code minimum</option>
<option value="25">Practical cold bend — 25D</option>
<option value="500">Elastic sprung bend — 500D</option>
</select>
</div>
<div class="out">
<div class="k">Minimum centerline radius</div>
<div class="rad" id="radft2">19.1 ft</div>
<div class="sub" id="radin2">229.5 in · 18 × OD</div>
<div class="formula" id="formula2">R = 18 × 12.75" (OD) for ≤12" cold field bend</div>
</div>
</div>
<p class="peyebrow mt">Field-bend acceptance · B31.4 §404.2.3</p>
<h3 class="psub">Limits on a field bend</h3>
<div class="cons">
<div class="c"><div class="n">2.5%</div><div class="t">Max ovality</div><div class="d">Diameter may not be reduced more than 2½% at any point.</div></div>
<div class="c"><div class="n">0</div><div class="t">Buckles / cracks</div><div class="d">Free of buckling, cracks, or damage; must pass the pig.</div></div>
<div class="c"><div class="n">6 ft</div><div class="t">End tangents</div><div class="d">Roughly 6 ft of straight tangent preferred each end.</div></div>
<div class="c"><div class="n">N.A.</div><div class="t">Seam placement</div><div class="d">Longitudinal weld kept on/near the neutral axis of the bend.</div></div>
</div>
<ul class="rules">
<li>Practical pipeline cold bends run <b>25D–60D</b>, not the code floor.</li>
<li><b>Elastic bends</b> (sprung within yield) are typically held near <b>500D</b> for buried lines.</li>
<li>Sharp turns at stations use <b>induction bends</b> or fittings, not field bends.</li>
<li>On longitudinally welded pipe, rotate the <b>seam to the neutral axis</b> before bending.</li>
</ul>
</div>
</div></section>
<section><div class="wrap">
<div class="sechead"><p class="eyebrow">Ruled out by design choice</p></div>
<h2 class="h2big">What this sheet does not use</h2>
<p class="secsub">Two methods are deliberately excluded — one is allowed by code but set aside on purpose, the other has no place on a welded steel line.</p>
<div class="excl">
<div class="x">
<span class="xstamp">Not used</span>
<div class="xart">
<svg viewBox="0 0 300 150" role="img" aria-label="A single mitered bend made of straight segments welded at an angle.">
<path d="M20 120 L120 120 L210 60 L280 60" fill="none" stroke="#95331C" stroke-width="12" stroke-linecap="butt"/>
<line x1="118" y1="106" x2="138" y2="128" stroke="#1B201D" stroke-width="2"/>
<text x="150" y="40" text-anchor="middle" font-family="IBM Plex Mono,monospace" font-size="11" fill="#95331C">cut + weld at angle</text>
</svg>
</div>
<div class="xbody">
<h3>Miter bends</h3>
<p>Straight pieces cut and welded at an angle. B31.3 §304.2.3 permits them — an offset of 3° or less isn't even treated as a miter — but they carry pressure derating and a fatigue-prone discontinuity. Set aside here by choice in favor of smooth elbows and formed bends.</p>
</div>
</div>
<div class="x">
<span class="xstamp">Not used</span>
<div class="xart">
<svg viewBox="0 0 300 150" role="img" aria-label="Two collinear pipe ends joined by a mechanical coupling, which is not used on a welded line.">
<path d="M20 95 L128 95" fill="none" stroke="#95331C" stroke-width="12" stroke-linecap="butt"/>
<path d="M172 95 L280 95" fill="none" stroke="#95331C" stroke-width="12" stroke-linecap="butt"/>
<rect x="126" y="78" width="48" height="34" fill="#E7E9E5" stroke="#1B201D" stroke-width="1.5"/>
<line x1="138" y1="78" x2="138" y2="112" stroke="#1B201D" stroke-width="1"/>
<line x1="162" y1="78" x2="162" y2="112" stroke="#1B201D" stroke-width="1"/>
<text x="150" y="135" text-anchor="middle" font-family="IBM Plex Mono,monospace" font-size="11" fill="#95331C">coupling / threaded joint</text>
</svg>
</div>
<div class="xbody">
<h3>Mechanical & threaded joints</h3>
<p>Grooved couplings, threaded connections, and any gasketed mechanical joint used to take up a small angle. An all-welded ASTM steel system joins with girth welds only — there are no such joints to deflect, so direction comes from steel, not hardware.</p>
</div>
</div>
</div>
</div></section>
<footer><div class="wrap">
<p class="eyebrow">Standards index</p>
<div class="refs">
<div><span class="code">ASME B31.3</span> — Process piping (inside the fence)</div>
<div><span class="code">ASME B31.4 · B31.8</span> — Liquid & gas pipelines (right-of-way)</div>
<div><span class="code">ASME B16.9</span> — Factory-made wrought buttwelding fittings</div>
<div><span class="code">ASME B16.49</span> — Wrought steel buttwelding induction bends</div>
<div><span class="code">ASME B16.25</span> — Buttwelding ends / bevel prep</div>
<div><span class="code">ASTM A106 · A53 · A333</span> — Carbon & low-temp steel pipe</div>
<div><span class="code">ASTM A335 · A312</span> — Alloy & austenitic stainless pipe</div>
<div><span class="code">ASTM A234 · A403</span> — Wrought buttweld fittings</div>
</div>
<p class="disc">Field reference only. Values are summarized for planning; verify the governing code edition, wall thickness after bending (mother-pipe thinning plus mill tolerance), flattening/ovality, branch and SIF requirements, and combined-stress limits against the project specification and current code editions before fabrication. Not a substitute for stamped design.</p>
</div></footer>
<script>
function showTab(which){
var pairs=[['b313','tab-b313','panel-b313'],['pipe','tab-pipe','panel-pipe']];
pairs.forEach(function(p){
var on=(p[0]===which);
document.getElementById(p[1]).setAttribute('aria-selected', on?'true':'false');
var panel=document.getElementById(p[2]);
if(on){panel.removeAttribute('hidden');}else{panel.setAttribute('hidden','');}
});
}
(function(){
var n1=document.getElementById('nps1'), m1=document.getElementById('meth1');
var rf1=document.getElementById('radft1'), ri1=document.getElementById('radin1'), fo1=document.getElementById('formula1');
function calc1(){
var n=parseFloat(n1.value), mult=parseFloat(m1.value);
var inches=mult*n, feet=inches/12;
rf1.textContent=feet.toFixed(1)+' ft';
ri1.textContent=inches.toFixed(1)+' in \u00B7 '+mult+' \u00D7 NPS';
fo1.textContent='R = '+mult+' \u00D7 '+n+'" (NPS) = '+inches.toFixed(1)+' in';
}
n1.addEventListener('change',calc1); m1.addEventListener('change',calc1); calc1();
var n2=document.getElementById('nps2'), m2=document.getElementById('meth2');
var rf2=document.getElementById('radft2'), ri2=document.getElementById('radin2'), fo2=document.getElementById('formula2');
function coldMult(nps){ if(nps<=12)return 18; if(nps==14)return 21; if(nps==16)return 24; if(nps==18)return 27; return 30; }
function calc2(){
var parts=n2.value.split('|'), od=parseFloat(parts[0]), nps=parseFloat(parts[1]);
var basis=m2.value, mult, tag;
if(basis==='code'){ mult=coldMult(nps); tag=mult+' \u00D7 OD \u00B7 cold field bend ('+(nps<=12?'\u226412"':nps+'"')+')'; }
else if(basis==='25'){ mult=25; tag='25 \u00D7 OD \u00B7 practical cold bend'; }
else { mult=500; tag='500 \u00D7 OD \u00B7 elastic sprung bend'; }
var inches=mult*od, feet=inches/12;
rf2.textContent=feet.toFixed(1)+' ft';
ri2.textContent=inches.toFixed(1)+' in \u00B7 '+mult+' \u00D7 OD';
fo2.textContent='R = '+mult+' \u00D7 '+od+'" (OD) = '+inches.toFixed(1)+' in';
}
n2.addEventListener('change',calc2); m2.addEventListener('change',calc2); calc2();
})();
</script>
</body>
</html>
```
[REQUESTED CHANGES]
(no specific request — apply your best judgment)
--- HOW TO RESPOND (READ FIRST) ---
Before writing any code, follow this exact process:
1. **ANALYZE** the widget source code provided above and identify:
a. Which Vibes SDK features it already uses (vibes.save, vibes.load, vibes.shared.join, etc.)
b. Which SDK features would genuinely benefit THIS specific widget — tailored to what it does, not a dump of everything available.
2. **PRESENT A NUMBERED LIST** covering:
- SDK features currently active in this widget
- New SDK features that would concretely improve this widget (be specific: why this widget, what it enables)
3. **WAIT** — do not write any code yet. Reply with your analysis and numbered list, then stop and ask the user which numbered items they want.
4. **IMPLEMENT ONLY** the items the user confirms, plus any explicit change they requested. Do not add unrequested features.
**IMPORTANT — Shared state room names:**
If you add vibes.shared.join(), do NOT use a hardcoded string literal as the room name (e.g. vibes.shared.join("lobby")) unless the user explicitly wants ALL viewers to share one single global state. A hardcoded room name means every person who visits this widget reads and writes the same shared state — it is a global room. For per-user or per-session isolation, derive the room name from a variable (e.g. a user ID, session token, or random value). When in doubt, use vibes.save/vibes.load for per-user persistence instead.
--- VIBES SDK CONTEXT ---
## Vibes SDK Reference
You are building an HTML widget for It Just Vibes (itjustvibes.com). The Vibes SDK is auto-injected — do NOT add a script tag. Just use `window.vibes` (or just `vibes`).
### Setup
Wrap your startup code in `vibes.onReady`:
```js
vibes.onReady(async () => {
const saved = await vibes.load("myKey");
// your widget logic here
});
```
### State (Per-User Persistence)
Every user gets their own isolated state per widget. All methods return Promises.
| Method | Description |
|--------|-------------|
| `await vibes.save(key, value)` | Save JSON-serializable data |
| `await vibes.load(key)` | Load saved data (returns `null` if not found) |
| `await vibes.delete(key)` | Delete a saved key |
| `await vibes.listKeys()` | Get array of all saved key names |
**Key rules:**
- Keys are strings, max 64 characters, alphanumeric + dashes/underscores
- Values must be JSON-serializable (objects, arrays, strings, numbers, booleans)
- Max 100KB per value, 500KB per widget per user, 5MB per user total
- Max 100 keys per widget per user
### Fetch Proxy
Use direct `fetch()` for APIs with permissive CORS headers (`Access-Control-Allow-Origin: *`). Use `vibes.fetch` for APIs without CORS headers (the proxy handles cross-origin requests):
```js
const resp = await vibes.fetch("https://api.example.com/data", {
method: "GET", // GET, POST, PUT, DELETE
headers: {}, // optional headers
body: null, // optional body (string)
timeout: null // optional timeout in ms
});
const data = await resp.json(); // or resp.text()
console.log(resp.status, resp.ok);
```
### Multiplayer (Shared State)
Real-time shared state across all users viewing the same widget.
```js
// Join a room (call once at startup)
await vibes.shared.join("lobby", { persistent: true });
// Set shared state (broadcasts to all users)
await vibes.shared.set("score", { player1: 10, player2: 7 });
// Read shared state (synchronous, returns last known value)
const score = vibes.shared.get("score");
// Listen for changes to a specific key
vibes.shared.onChange("score", (newValue) => {
console.log("Score updated:", newValue);
});
// Listen for any shared state change
vibes.shared.onAny((key, value) => {
console.log(key, "changed to", value);
});
// Get number of connected users
const count = await vibes.shared.getUserCount();
// Leave room
vibes.shared.leave();
// Clear all shared state for this room
await vibes.shared.clear();
```
**Shared state options:**
- `{ persistent: true }` — state survives page reloads (stored server-side)
- Default room name is "__default__" if omitted
### Agent-Accessible State (vibes.ai.*)
State written with the standard `vibes.save` / `vibes.load` methods is private to each user and is **NOT readable by AI agents**. To share state with an AI agent (via the MCP connector), use the `vibes.ai` sub-namespace:
| Method | Description |
|--------|-------------|
| `await vibes.ai.setState(key, value)` | Write agent-readable state. Key is stored internally as `ai/<key>`. |
| `await vibes.ai.getState(key)` | Read agent-readable state. Returns `null` if key absent. |
| `await vibes.ai.listKeys()` | List all agent-readable keys (without the `ai/` prefix). |
**Important rules:**
- Regular `vibes.save()` / `vibes.load()` is **NOT agent-accessible** — use `vibes.ai.*` for state you want agents to read.
- The widget **owner** must enable agent access in **Manage → Agent tab** before any agent can read or write `vibes.ai.*` state.
- Keys are auto-prefixed to `ai/` internally; you supply just the short key (e.g. `'context'`).
```js
vibes.onReady(async () => {
// Write state an AI agent can later read
await vibes.ai.setState('context', { currentLevel: 3, score: 1500 });
// Read it back (same auto-prefix applies)
const ctx = await vibes.ai.getState('context');
// List all agent-accessible keys for this widget
const keys = await vibes.ai.listKeys(); // e.g. ['context']
});
```
### Rules
1. **Do NOT use localStorage, sessionStorage, or window.storage** — they are blocked or undefined in the sandbox. Use `vibes.save`/`vibes.load` instead.
2. **Do NOT add a script tag to import the SDK** — it is auto-injected.
3. **Wrap startup code in `vibes.onReady()`** — the SDK may not be ready immediately.
4. **Await all SDK calls** — every method (except `vibes.shared.get`) returns a Promise.
5. **External JS libraries are allowed and encouraged** — load them via a `<script src>` tag from a reputable CDN (jsDelivr, unpkg, or cdnjs) with a pinned version, or inline the library source. The only exception: do NOT add a script tag for the Vibes SDK itself — it is auto-injected (see Rule 2).
6. **Keep total code under 100KB** — that is the default widget size limit (your account limit may be higher).
### Rate Limits
| Operation | Limit |
|-----------|-------|
| Writes (save + delete combined) | 30/min |
| Reads (load) | 60/min |
| List keys | 30/min |
| Fetch proxy | Rate limited per widget |
### Error Handling
All SDK methods can reject. Wrap in try/catch:
```js
try {
await vibes.save("key", value);
} catch (err) {
console.error("Save failed:", err.message);
}
```
Fetch proxy errors include `err.code`: `"RATE_LIMITED"`, `"BLOCKED"`, `"FETCH_ERROR"`.
### Data Export
Export rows of data as CSV or Excel directly from your widget.
```js
// Register dataset for the platform's "Export data" button
// AND optionally trigger an immediate download
vibes.exportData(rows, { filename: 'results.csv' })
// rows: Array of arrays (each inner array is one row; first row = headers)
// options.filename: sets the download filename and format (csv or xlsx)
// options.directDownload: false to only register without downloading (default: true)
```
| Option | Type | Default | Description |
|--------|------|---------|-------------|
| `filename` | string | `'data.csv'` | Download filename; extension determines format (`.csv` or `.xlsx`) |
| `directDownload` | boolean | `true` | Trigger immediate browser download in addition to registering the dataset |
**Notes:**
- First call registers the dataset so the widget chrome shows an "Export data" button
- Use `.csv` extension for CSV, `.xlsx` for Excel
- CSV injection safety is automatic (formula-starting cells prefixed with `'`)
- Data stays in the browser — no server round-trip
--- FORK & RESUBMIT INSTRUCTION ---
Return the complete, self-contained HTML file with all changes applied.
It should be ready to paste into itjustvibes.com/submit to create a new fork.
Include this comment at the top of the output:
/* Forked from: https://itjustvibes.com/Owner/trench-alignment-changes-welded-steel-pipe-no-miters */