Files
battery-builder/index.html
2026-05-08 22:55:25 +02:00

252 lines
17 KiB
HTML

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=5.0, user-scalable=yes">
<meta name="theme-color" content="#0a0f1e">
<title>Cell Holder Generator - waak.me</title>
<link rel="stylesheet" href="styles/main.css">
</head>
<body>
<div class="loading-overlay active" id="loadingOverlay" style="display: flex !important;">
<div class="loading-content">
<div class="spinner"></div>
<div class="loading-text" id="loadingText">Initializing 3D Engine</div>
<div class="loading-subtext" id="loadingSubtext">Loading OpenCascade...</div>
</div>
</div>
<div class="container">
<div class="header-row">
<div class="header-title">
<h1>Cell Holder Generator</h1>
<p class="waak-credit">Huge thanks to <a href="https://t.me/waak86" target="_blank" rel="noopener noreferrer">waak</a> for the original project.</p>
</div>
<div class="header-right">
<a class="gitea-link" href="https://gitea.overkill.cc/morss12/battery-builder" target="_blank" rel="noopener noreferrer" title="View source on Gitea">
<svg class="gitea-icon" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true" xmlns="http://www.w3.org/2000/svg"><path d="M11.9999 1C6.0589 1 1.1999 5.859 1.1999 11.8C1.1999 16.554 4.2629 20.579 8.5569 22.053C9.1069 22.155 9.3089 21.818 9.3089 21.531C9.3089 21.272 9.2989 20.483 9.2949 19.641C6.3169 20.298 5.6699 18.261 5.6699 18.261C5.1699 16.976 4.4469 16.64 4.4469 16.64C3.4549 15.964 4.5219 15.978 4.5219 15.978C5.6209 16.053 6.1999 17.104 6.1999 17.104C7.1749 18.791 8.7029 18.306 9.3289 18.029C9.4289 17.322 9.7099 16.838 10.0199 16.563C7.6459 16.285 5.1489 15.366 5.1489 11.274C5.1489 10.056 5.5769 9.061 6.2199 8.282C6.1069 8.004 5.7309 6.868 6.3279 5.336C6.3279 5.336 7.2449 5.041 9.2829 6.487C10.1369 6.244 11.0709 6.122 11.9999 6.118C12.9289 6.122 13.8629 6.244 14.7179 6.487C16.7549 5.041 17.6709 5.336 17.6709 5.336C18.2689 6.868 17.8929 8.004 17.7799 8.282C18.4239 9.061 18.8499 10.056 18.8499 11.274C18.8499 15.376 16.3489 16.283 13.9679 16.554C14.3559 16.892 14.7019 17.558 14.7019 18.576C14.7019 20.038 14.6889 21.222 14.6889 21.531C14.6889 21.82 14.8879 22.159 15.4459 22.052C19.7369 20.576 22.7999 16.553 22.7999 11.8C22.7999 5.859 17.9409 1 11.9999 1Z"/></svg>
Source
</a>
<a class="gitea-link" href="https://github.com/waak86/battery-builder" target="_blank" rel="noopener noreferrer" title="View original project on GitHub">
<svg class="gitea-icon" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true" xmlns="http://www.w3.org/2000/svg"><path d="M12 2C6.477 2 2 6.477 2 12c0 4.418 2.865 8.166 6.839 9.489.5.092.682-.217.682-.482 0-.237-.009-.868-.013-1.703-2.782.604-3.369-1.341-3.369-1.341-.454-1.154-1.11-1.462-1.11-1.462-.908-.62.069-.608.069-.608 1.003.07 1.531 1.03 1.531 1.03.892 1.529 2.341 1.087 2.91.832.092-.647.35-1.088.636-1.338-2.22-.253-4.555-1.11-4.555-4.943 0-1.091.39-1.984 1.029-2.683-.103-.253-.446-1.27.098-2.647 0 0 .84-.269 2.75 1.025A9.578 9.578 0 0 1 12 6.836a9.59 9.59 0 0 1 2.504.337c1.909-1.294 2.747-1.025 2.747-1.025.546 1.377.202 2.394.1 2.647.64.699 1.028 1.592 1.028 2.683 0 3.842-2.339 4.687-4.566 4.935.359.309.678.919.678 1.852 0 1.336-.012 2.415-.012 2.743 0 .267.18.578.688.48C19.138 20.163 22 16.418 22 12c0-5.523-4.477-10-10-10z"/></svg>
Original Source
</a>
</div>
</div>
<p class="subtitle">Generate custom 3D printable cell holders with STEP export</p>
<div class="main-layout">
<div class="config-sidebar">
<nav class="sidebar-tabs" role="tablist" data-tabs>
<button type="button" role="tab" class="tab active" data-panel="pack" aria-selected="true">
<svg class="tab-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
<rect x="3" y="6.5" width="15" height="11" rx="1.5"/>
<line x1="18" y1="10" x2="21" y2="10"/>
<line x1="18" y1="14" x2="21" y2="14"/>
</svg>
<span class="tab-label">Pack</span>
</button>
<button type="button" role="tab" class="tab" data-panel="cells" aria-selected="false">
<svg class="tab-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
<circle cx="7.5" cy="12" r="3.2"/>
<circle cx="15.5" cy="8" r="3.2"/>
<circle cx="15.5" cy="16" r="3.2"/>
</svg>
<span class="tab-label">Cells</span>
</button>
<button type="button" role="tab" class="tab" data-panel="bms" aria-selected="false">
<svg class="tab-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
<path d="M13 3l-8 11h6l-1 7 8-11h-6l1-7z"/>
</svg>
<span class="tab-label">BMS</span>
</button>
<button type="button" role="tab" class="tab" data-panel="busbars" aria-selected="false">
<svg class="tab-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
<circle cx="6" cy="12" r="2"/>
<circle cx="18" cy="12" r="2"/>
<line x1="8" y1="12" x2="16" y2="12"/>
<line x1="6" y1="5" x2="18" y2="5"/>
<line x1="6" y1="19" x2="18" y2="19"/>
</svg>
<span class="tab-label">Busbars</span>
</button>
<span class="tab-indicator" aria-hidden="true"></span>
</nav>
<div class="tab-panels">
<section class="tab-panel active" role="tabpanel" data-panel="pack">
<div class="seg-toggle" data-pack-mode data-mode="sp">
<button type="button" class="seg active" data-mode="sp">Series &times; Parallel</button>
<button type="button" class="seg" data-mode="mm">Size (mm)</button>
<span class="seg-indicator" aria-hidden="true"></span>
</div>
<div class="pack-fields pack-sp-fields">
<div class="form-group">
<label>Series (S)</label>
<input type="number" id="series" value="7" min="1" step="1">
<span class="field-hint">Cells stacked in series. Sets voltage.</span>
</div>
<div class="form-group">
<label>Parallel (P)</label>
<input type="number" id="parallel" value="5" min="1" step="1">
<span class="field-hint">Cells bundled in parallel. Sets capacity.</span>
</div>
</div>
<div class="pack-fields pack-mm-fields" hidden>
<div class="row">
<div class="form-group">
<label>Width (mm)</label>
<input type="number" id="xDim" value="150">
</div>
<div class="form-group">
<label>Depth (mm)</label>
<input type="number" id="yDim" value="100">
</div>
</div>
<span class="field-hint">Cells are fit automatically inside the footprint.</span>
</div>
<div class="form-group">
<label>Holder Thickness (mm)</label>
<input type="number" id="height" value="10">
</div>
<div class="pack-summary" id="packSummary" aria-live="polite"></div>
</section>
<section class="tab-panel" role="tabpanel" data-panel="cells">
<div class="form-group">
<label>Cell Diameter (mm)</label>
<input type="number" id="cellSize" value="21.35">
</div>
<div class="form-group">
<label>Layout Type</label>
<select id="layoutType">
<option value="grid">Grid Layout</option>
<option value="honeycomb" selected>Honeycomb Layout</option>
<option value="vertical">Vertical Honeycomb</option>
</select>
</div>
<div class="form-group">
<label>Cell Spacing (mm)</label>
<input type="number" id="spacing" value="0.6">
</div>
<div class="panel-divider" aria-hidden="true"></div>
<div class="row">
<div class="form-group">
<label>Ledge Thickness (mm)</label>
<input type="number" id="coverThickness" value="0.4">
</div>
<div class="form-group">
<label>Ledge Width (mm)</label>
<input type="number" id="ledgeWidth" value="2.75">
</div>
</div>
<div class="checkbox-group">
<input type="checkbox" id="roundedCorners" checked>
<label for="roundedCorners">Rounded Corners</label>
</div>
</section>
<section class="tab-panel" role="tabpanel" data-panel="bms">
<div class="form-group">
<label>Opening Type</label>
<select id="bmsHolesType">
<option value="off">Off</option>
<option value="halfcircles">Half Circles</option>
<option value="fullcircles" selected>Full Circles</option>
<option value="tabs">Edge Tabs</option>
</select>
</div>
<div class="form-group" id="bmsHoleDiameterGroup">
<label>Hole Diameter (mm)</label>
<input type="number" id="bmsHoleDiameter" value="4.0" min="1" max="10">
</div>
<div class="row" id="tabDimensionsGroup" style="display:none;">
<div class="form-group">
<label>Tab Length (mm)</label>
<input type="number" id="tabLength" value="10.0" min="1" step="0.5">
</div>
<div class="form-group">
<label>Edge Cut Width (mm)</label>
<input type="number" id="tabWidth" value="4.0" min="1" step="0.5">
</div>
</div>
<div class="form-group" id="tabOverlapSideGroup" style="display:none;">
<label>Tab Overlap Side</label>
<select id="tabOverlapSide">
<option value="off" selected>Off</option>
<option value="top">Top</option>
<option value="bottom">Bottom</option>
</select>
<span class="field-hint">Adds one continuous outside lip across the selected edge tabs.</span>
</div>
</section>
<section class="tab-panel" role="tabpanel" data-panel="busbars">
<div class="form-group">
<label>Export Format</label>
<select id="busbarFormat">
<option value="step" selected>STEP (3D stencil)</option>
<option value="dxf">DXF (laser cutting)</option>
</select>
<span class="field-hint">STEP exports a 3D solid for CAD or 3D printing. DXF exports a flat 2D outline for laser or plasma cutters.</span>
</div>
<div class="checkbox-group">
<input type="checkbox" id="busbarCellCutoutEnabled">
<label for="busbarCellCutoutEnabled">Cell center cutout (5x2 mm) for all busbars</label>
</div>
<div class="busbar-controls-row">
<div class="busbar-face-filter" role="group" aria-label="Face filter">
<button type="button" class="face-filter-btn active" data-filter="both">Top &amp; Bottom</button>
<button type="button" class="face-filter-btn" data-filter="top">Top only</button>
</div>
<div class="busbar-controls-right">
<button type="button" class="btn-ghost btn-dl-all" id="downloadAllBusbarsBtn" title="Download all busbars as a ZIP file">
<svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M12 3v13M7 11l5 5 5-5"/><path d="M4 20h16"/></svg>
ZIP all
</button>
<button type="button" class="btn-ghost btn-clear-markings" id="clearMarkingsBtn" title="Remove all cell assignments without deleting busbars">Clear</button>
</div>
</div>
<div id="busbarList"></div>
<div class="busbar-add-row">
<button class="btn-secondary" id="addTopBusbarBtn">+ Top Busbar</button>
<button class="btn-secondary" id="addBottomBusbarBtn">+ Bottom Busbar</button>
</div>
<div class="panel-divider" aria-hidden="true"></div>
<div class="order-header">Copper Sheet Calculator</div>
<div id="orderContent">
<p class="order-placeholder">Generate a preview first to see sheet requirements.</p>
</div>
</section>
</div>
<button class="btn" id="generateBtn">Generate 3D Model</button>
<button class="btn-secondary" id="copyShareUrlBtn" type="button">Copy Share URL</button>
</div>
<div class="preview-container">
<h2>Preview</h2>
<div class="previews-row">
<div class="preview-face-wrap">
<div class="face-label" id="topFaceLabel">Top</div>
<canvas id="preview"></canvas>
</div>
<div class="preview-face-wrap" id="bottomFaceWrap">
<div class="face-label" id="bottomFaceLabel">Bottom</div>
<canvas id="preview-bottom"></canvas>
</div>
</div>
<div id="previewStats">Configure settings and click Generate to see preview</div>
</div>
</div>
</div>
<script src="vendor/opencascade.wasm.js"></script>
<script type="module" src="src/main.js"></script>
</body>
</html>