Files
battery-builder/index.html

222 lines
13 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">
<h1>Cell Holder Generator</h1>
<p class="repo-credit">Forked from <a href="https://github.com/waak86/battery-builder" target="_blank" rel="noopener noreferrer">waak's Battery Builder</a> <br>Huge thanks to <a href="https://t.me/waak86" target="_blank" rel="noopener noreferrer">waak</a> for the original project. </p>
</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 Width (mm)</label>
<input type="number" id="tabWidth" value="4.0" min="0.5" step="0.1">
</div>
<div class="form-group">
<label>Tab Depth (mm)</label>
<input type="number" id="tabDepth" value="1.0" min="0.1" step="0.1">
</div>
</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="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>
</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>