ডেস্কটপে সর্বোত্তম

সিমুলেটরটির জন্য একটি কীবোর্ড, একটি মাউস এবং একটি প্রশস্ত স্ক্রিন প্রয়োজন। এটি ফোনগুলির জন্য ডিজাইন করা হয়নি।

আপনি এখনও শেপ লাইব্রেরি ব্রাউজ করতে, গল্পটি পড়তে বা হার্ডওয়্যার নির্মাণ পরীক্ষা করতে পারেন।

🗂 আকৃতি লাইব্রেরি সম্পর্কে ও ইতিহাস হার্ডওয়্যার প্রশ্ন ও উত্তর
টিপ: cncfoam.com বুকমার্ক করুন এবং ল্যাপটপে খুলুন।

CNCFOAM.COM

🗂 আকৃতি লাইব্রেরি উইকি
সাইন ইন সাইন আপ
স্কেল
%
%
%
%
ঘোরান
°
0,0 থেকে অফসেট
মিমি
মিমি
মিমি
মিমি
ড্রপ .gcode / .nc / .txt / .cnc / .tap / .ngc / .svg
👥 · আজকের দিন
হট ওয়্যার
ওয়্যার (দ্রুত/বন্ধ)
কাট পাথ
উৎস রেখা (X)0 Y0)

অবস্থা

৪-অক্ষ
0

ঘোরান অংশ

X অক্ষ Y অক্ষ Z অক্ষ
STL/OBJ আমদানি করুন (+ অংশ লোড করুন) পুনঃ-অভিমুখীকরণ করতে।

কাট সেটিংস

উপাদান ব্লক

0-লাইন থেকে। এই ডিভাইসে সংরক্ষিত।
জি-কোড ⋮⋮ কপি ×
X/Y · সমতল ⋮⋮ সমতলব্লক ×
চাকা / ± জুম করতে
U/V সমতল ⋮⋮ সমতলব্লক ×
চাকা / ± জুম করতে

নিয়ন্ত্রণ

কক্ষপথটেনে আনুন / তীরচিহ্ন
প্যানshift-টেনে-আনা / right-টেনে-আনা
জুমচাকা / + −
চালু / বিরতিস্থান
পিছনে যানR
রিসেট ভিউহোম / এফ
সেটিংস টেনে আনুন ⋮⋮
মেশিন সেটিংস

মেশিনের ধরন

2-অক্ষের আয়না ইউ/ভি থেকে এক্স/ওয়াই স্বয়ংক্রিয়ভাবে। দুই-অংশের রূপান্তর নিষ্ক্রিয়। 3/5-অক্ষ যুক্ত করে সূচিবদ্ধ বহু-পার্শ্ব কাটার জন্য একটি ঘূর্ণন অক্ষ।

ঘূর্ণন অক্ষ (A)

Vertical ব্যবহার করে Offset X + Z। Horizontal ব্যবহার করে Offset Y + Z। Free positioning সমর্থিত — নিজের পছন্দ অনুযায়ী অফসেট সেট করুন।
G92 শুধুমাত্র বর্তমান অবস্থানকে শূন্য হিসাবে ঘোষণা করে — এটি আসলে মেশিনকে শারীরিকভাবে সরায় না। এই অপশনটি টিক চিহ্নিত করলে সেই লাইনটি সম্পূর্ণভাবে বাদ দেওয়া হয়; এটি কার্যকর যখন আপনার নিয়ন্ত্রকের কর্মপ্রবাহ নিজেই কাজ-শূন্য নির্ধারণ করে (যেমন $H বা একটি কাস্টম বাটনের মাধ্যমে)।

কাটার সাইজ (মেশিন এনভেলপ)

অক্ষ অভিমুখ

X উল্টোভাবে ডিফল্ট হিসেবে সেট করা যাতে 0-লাইন সামনে থাকে?
উপাদান ব্লক বাম-পার্শ্ব প্যানেলে থাকে।

উৎস মার্কার (X=0, Y=0)

টুল ইন্টারফেস

দৃশ্যমান

চেহারা

ইউএসবি-এর মাধ্যমে স্ট্রিমিং

লাইন 0 / 0 · খালি

Wi-Fi · FluidNC মেশিন

প্রকল্পসমূহ

উপাদান

জিএন — আকৃতি জেনারেটর

ফেনা উৎপন্ন করুন আরসি উইং প্যানেল থেকে NACA 4-সংখ্যা এরোফয়েল। ৪টি সংখ্যা সর্বাধিক ক্যাম্বার %, ক্যাম্বার অবস্থান এবং (×১০%) পুরুত্ব % — e.g. 2412 = 2% camber at 40% chord, 12% thick; 0009 = symmetric, 9% thick. Set a smaller টিপ কর্ড টেপারের জন্য, আলাদা টিপ এরোফয়েল যুক্ত করুন ঘুরানো এবং ধোয়াকাটুন ৪-তারের রুট থেকে টিপ পর্যন্ত মর্ফ হিসেবে

উল্লম্ব ডানা: প্রান্তিক জ্যা = মূল জ্যা, সুইপ 0 ধোয়া ঘুমিয়ে পড়ার মতো কয়েক ডিগ্রি নিচু করুন উইংস ও NACA ব্যাখ্যা

 

শেয়ার করুন আপনার সৃষ্টি

📤 লাইব্রেরিতে প্রকাশ করুন

আপনার একটি বিনামূল্যের অ্যাকাউন্ট প্রয়োজন সর্বজনীন Shape লাইব্রেরিতে প্রকাশ করার জন্য। নতুন আকারগুলি প্রকাশিত হওয়ার আগে পর্যালোচনা করা হয়।

এখনও কোন ব্যক্তিগত লাইব্রেরি নেই — আপনি যা প্রকাশ করেন তা সর্বজনীন।

মাল্টি-অ্যাক্সিস সিএনসি ফোম কাটিং সহজ করা হয়েছে এবং বিনামূল্যে ব্যবহারযোগ্য )
⚠ বিটা টেস্ট — অনুগ্রহ করে আমাকে সাহায্য করুন
oves(r.moves, { lengthZ }); document.getElementById('morphStatus').textContent = `Generated ${r.moves.length} moves over ${lengthZ} mm.`; closeModal('parts'); }; // More dropdown const moreMenu = document.getElementById('moreMenu'); document.getElementById('moreBtn').onclick = e => { e.stopPropagation(); if (typeof renderRecentFiles === 'function') renderRecentFiles(); moreMenu.classList.toggle('open'); }; document.addEventListener('click', e => { if (!document.getElementById('moreWrap').contains(e.target)) moreMenu.classList.remove('open'); }); // ---- Download / stream fold-out menu (combines G-code / 3D / USB / Wi-Fi) ---- { const dlWrap = document.getElementById('dlWrap'); const dlBtn = document.getElementById('dlMenuBtn'); if (dlWrap && dlBtn){ dlBtn.onclick = e => { e.stopPropagation(); dlWrap.classList.toggle('open'); }; document.addEventListener('click', e => { if (!dlWrap.contains(e.target)) dlWrap.classList.remove('open'); }); dlWrap.querySelectorAll('#dlMenu button').forEach(b => b.addEventListener('click', () => dlWrap.classList.remove('open'))); } } // ---- Recent files (last 5 loaded shapes / demos / G-code drops) ---- // Each entry: { name, kind: 'gcode'|'svg'|'dxf'|'demo'|'library', payload, ts } // payload is the file text for local loads, or a shape-library id for // library loads. Stored in localStorage so the list survives page reloads. const RECENT_KEY = 'cncfoam-recent'; const RECENT_MAX = 5; function recentList(){ try { return JSON.parse(localStorage.getItem(RECENT_KEY) || '[]'); } catch(e){ return []; } } function recentRecord(entry){ let list = recentList().filter(e => !(e.name === entry.name && e.kind === entry.kind)); list.unshift({ ...entry, ts: Date.now() }); list = list.slice(0, RECENT_MAX); // localStorage has a ~5MB cap; drop the largest payload if the JSON grows // beyond 1.5MB (a couple of huge G-code files would otherwise fill the bucket). while (list.length){ try { const j = JSON.stringify(list); if (j.length < 1500000){ localStorage.setItem(RECENT_KEY, j); return; } } catch(e){} // Strip the payload of the oldest entry first. for (let i = list.length - 1; i >= ০; i--){ if (list[i].payload){ list[i] = { ...list[i], payload: null }; break; } if (i === 0) list.pop(); } } } function renderRecentFiles(){ const list = recentList(); const section = document.getElementById('mmRecentSection'); const container = document.getElementById('mmRecentList'); if (!section || !container) return; if (!list.length){ section.style.display = 'none'; return; } section.style.display = 'block'; container.innerHTML = ''; for (const e of list){ const row = document.createElement('div'); row.className = 'mm-recent'; const ageMs = Date.now() - (e.ts || 0); const age < 60000 ? 'just now' : ageMs < 3600000 ? Math.round(ageMs/60000) + 'm ago' : ageMs < 86400000 ? Math.round(ageMs/3600000) + 'h ago' : Math.round(ageMs/86400000) + 'd ago'; const icon = e.kind === 'library' ? '🗂' : e.kind === 'demo' ? '🎬' : e.kind === 'gcode' ? '⚙️' : e.kind === 'dxf' ? '◇' : e.kind === 'svg' ? '✎' : '·'; row.innerHTML = 'ফাইল নির্বাচন করুন<>Settings<':'<','>উত্তর অনুপস্থিত।' + age + ''; row.onclick = async () => { moreMenu.classList.remove('open'); try { if (e.kind === 'library' && e.payload){ window.location.href = '/?shape=' + encodeURIComponent(e.payload); return; } if (!e.payload){ document.getElementById('status').textContent = '"' + e.name + '" is too old to reload — pick the file again.'; return; } if (e.kind === 'gcode' || e.kind === 'demo'){ loadMoves(parseGcode(e.payload)); } else { const blob = new Blob([e.payload], { type: 'text/plain' }); const file = new File([blob], e.name, { type: 'text/plain' }); await pickProfile(file, 'A'); setTimeout(() => { const b = document.getElementById('morphGo'); if (b && !b.disabled) b.click(); }, 250); } } catch(err){ document.getElementById('status').textContent = 'Recent reload failed: ' + err.message; } }; container.appendChild(row); } } // ---------- OBJECT toolbar ---------- function readScale(src){ const linkEl = document.getElementById('scaleAll'); // Direct edits to Y/U/V were being clobbered by X on every keystroke when // link-all was on. Auto-uncheck the link so manual Y/U/V edits stick. if (linkEl.checked && src && (src === 'scaleY' || src === 'scaleU' || src === 'scaleV')) { linkEl.checked = false; } const link = linkEl.checked; const rot = parseFloat(document.getElementById('rotUV').value) || 0; const mx = parseFloat(document.getElementById('movX').value) || 0; const my = parseFloat(document.getElementById('movY').value) || 0; const mu = parseFloat(document.getElementById('movU').value) || 0; const mv = parseFloat(document.getElementById('movV').value) || 0; if (link){ const v = (parseFloat(document.getElementById('scaleX').value) || 100) / 100; SCALE = { x:v, y:v, u:v, v:v, rotUV:rot, movX:mx, movY:my, movU:mu, movV:mv }; ['scaleY','scaleU','scaleV'].forEach(id => document.getElementById(id).value = Math.round(v*100)); } else { SCALE = { x: (parseFloat(document.getElementById('scaleX').value) || 100) / 100, y: (parseFloat(document.getElementById('scaleY').value) || 100) / 100, u: (parseFloat(document.getElementById('scaleU').value) || 100) / 100, v: (parseFloat(document.getElementById('scaleV').value) || 100) / 100, rotUV: rot, movX: mx, movY: my, movU: mu, movV: mv, }; } applyScaleToMoves(); } ['scaleX','scaleY','scaleU','scaleV','scaleAll','rotUV','movX','movY','movU','movV'].forEach(id => { document.getElementById(id).addEventListener('input', () => readScale(id)); document.getElementById(id).addEventListener('change', () => readScale(id)); }); document.getElementById('scaleReset').onclick = () => { ['scaleX','scaleY','scaleU','scaleV'].forEach(id => document.getElementById(id).value = 100); document.getElementById('scaleAll').checked = true; document.getElementById('rotUV').value = 0; document.getElementById('movX').value = 0; document.getElementById('movY').value = 0; document.getElementById('movU').value = 0; document.getElementById('movV').value = 0; readScale(); }; // ---------- Settings draggable + accordion ---------- (function() { const card = document.getElementById('settingsCard'); const handle = document.getElementById('settingsDrag'); let dx=0, dy=0, dragging=false; handle.addEventListener('mousedown', e => { dragging=true; const r=card.getBoundingClientRect(); dx=e.clientX-r.left; dy=e.clientY-r.top; e.preventDefault(); }); window.addEventListener('mousemove', e => { if (!dragging) return; card.style.right='auto'; card.style.left=Math.max(0,Math.min(window.innerWidth-card.offsetWidth,e.clientX-dx))+'px'; card.style.top=Math.max(0,Math.min(window.innerHeight-60,e.clientY-dy))+'px'; }); window.addEventListener('mouseup', () => dragging=false); document.querySelectorAll('#settings details.acc').forEach(d => { d.addEventListener('toggle', () => { if (d.open) document.querySelectorAll('#settings details.acc').forEach(o => { if (o!==d) o.open=false; }); }); }); })(); // ---------- UI visibility toggles ---------- function applyUiToggles(){ document.getElementById('objectBar').classList.toggle('hidden', !CFG.showObjBar); document.getElementById('controls') .classList.toggle('hidden', !CFG.showControls); // Status section now lives inside #leftPanel — toggle its visibility there. const lp = document.getElementById('leftPanel'); if (lp) lp.classList.toggle('hud-hidden', !CFG.showHud); document.getElementById('legend') .classList.toggle('hidden', !CFG.showLegend); } // Top-centre reminder when the user has disabled the auto-zero line. Dismissable // for 6 hours via the × (reappears after that, or on a fresh trigger/reload). function applyNoHomingBanner(){ const b = document.getElementById('noHomingBanner'); if (!b) return; let until = 0; try { until = parseInt(localStorage.getItem('cncfoam-nohoming-dismiss') || '0', 10) || 0; } catch(e){} b.style.display = (CFG && CFG.noHoming && Date.now() > until) ? 'block' : 'none'; } { const nx = document.getElementById('noHomingX'); if (nx) nx.onclick = () => { try { localStorage.setItem('cncfoam-nohoming-dismiss', String(Date.now() + 6 * 3600 * 1000)); } catch(e){} applyNoHomingBanner(); }; } bindCheckbox('cfgShowObjBar', 'showObjBar', applyUiToggles); bindCheckbox('cfgShowControls', 'showControls', applyUiToggles); bindCheckbox('cfgShowHud', 'showHud', applyUiToggles); bindCheckbox('cfgShowLegend', 'showLegend', applyUiToggles); // ---------- Mini preview window ---------- const previewBox = document.getElementById('preview'); const previewBody = document.getElementById('previewBody'); const previewRenderer = new THREE.WebGLRenderer({ antialias:true, alpha:true }); previewRenderer.setPixelRatio(Math.min(devicePixelRatio||1, 2)); previewRenderer.setSize(240, 220); previewRenderer.setClearColor(0x0e1116, 0); previewBody.appendChild(previewRenderer.domElement); const previewScene = new THREE.Scene(); const previewCamera = new THREE.PerspectiveCamera(35, 240/220, 0.1, 8000); previewScene.add(new THREE.AmbientLight(0xffffff, 0.55)); const pvLight = new THREE.DirectionalLight(0xffffff, 0.9); pvLight.position.set(300, 500, 400); previewScene.add(pvLight); const pvLight2 = new THREE.DirectionalLight(0xffffff, 0.25); pvLight2.position.set(-200, -100, 200); previewScene.add(pvLight2); // Share the cut geometry + material so the preview tracks the main scene live. const previewCut = new THREE.Mesh(cutGeo, cutMat); previewScene.add(previewCut); // Faint wireframe block in the preview for spatial context. const previewBlockGroup = new THREE.Group(); previewScene.add(previewBlockGroup); function rebuildPreviewBlock(){ while (previewBlockGroup.children.length){ const c=previewBlockGroup.children.pop(); if (c.geometry) c.geometry.dispose(); if (c.material) c.material.dispose(); } const g = new THREE.BoxGeometry(BLOCK.x, BLOCK.y, BLOCK.z); const edges = new THREE.LineSegments(new THREE.EdgesGeometry(g), new THREE.LineBasicMaterial({ color:0x444c56 })); edges.position.set(BLOCK.x/2, BLOCK.y/2, BLOCK.z/2); previewBlockGroup.add(edges); } rebuildPreviewBlock(); let pvYaw = 0; function renderPreview(dt){ if (!previewBox.classList.contains('show')) return; pvYaw += dt * 0.6; const dist = Math.max(BLOCK.x, BLOCK.y, BLOCK.z) * 1.5 || 1000; previewCamera.position.set( BLOCK.x/2 + dist * Math.sin(pvYaw), BLOCK.y/2 + dist * 0.35, BLOCK.z/2 + dist * Math.cos(pvYaw) ); previewCamera.lookAt(BLOCK.x/2, BLOCK.y/2, BLOCK.z/2); previewRenderer.render(previewScene, previewCamera); } // Hook into the main animation loop const _origFrame = frame; let lastPv = null; window._cncPv = () => { /* placeholder so closures see it */ }; function pvLoop(now){ requestAnimationFrame(pvLoop); if (lastPv === null){ lastPv = now; return; } const dt = Math.min(0.1, (now - lastPv) / 1000); lastPv = now; renderPreview(dt); } requestAnimationFrame(pvLoop); // Show / hide preview, drag, close const _origLoadMoves2 = loadMoves; loadMoves = function(parsed, opts){ _origLoadMoves2(parsed, opts); previewBox.classList.add('show'); rebuildPreviewBlock(); }; document.getElementById('previewClose').onclick = () => previewBox.classList.remove('show'); (function() { const handle = previewBox.querySelector('.ph'); let dx=0, dy=0, dragging=false; handle.addEventListener('mousedown', e => { if (e.target.id === 'previewClose') return; dragging=true; const r=previewBox.getBoundingClientRect(); dx=e.clientX-r.left; dy=e.clientY-r.top; e.preventDefault(); }); window.addEventListener('mousemove', e => { if (!dragging) return; previewBox.style.right='auto'; previewBox.style.left=Math.max(0,Math.min(window.innerWidth-previewBox.offsetWidth,e.clientX-dx))+'px'; previewBox.style.top=Math.max(0,Math.min(window.innerHeight-50,e.clientY-dy))+'px'; }); window.addEventListener('mouseup', () => dragging=false); })(); // ---------- Init (no auto-load demo) ---------- syncCfgInputs(); document.getElementById('cfgShowObjBar').checked = !!CFG.showObjBar; document.getElementById('cfgShowControls').checked = !!CFG.showControls; document.getElementById('cfgShowHud').checked = !!CFG.showHud; document.getElementById('cfgShowLegend').checked = !!CFG.showLegend; { const g = document.getElementById('cfgShowGcode'); if (g) g.checked = !!CFG.showGcode; } { const xy = document.getElementById('cfgShowXyView'); if (xy) xy.checked = !!CFG.showXyView; } { const uv = document.getElementById('cfgShowUvView'); if (uv) uv.checked = !!CFG.showUvView; } { const h = document.getElementById('cfgNoHoming'); if (h) h.checked = !!CFG.noHoming; } if (typeof gcViewApplyToggle === 'function') gcViewApplyToggle(); if (window.fvXY) fvXY.applyToggle(); if (window.fvUV) fvUV.applyToggle(); if (typeof applyNoHomingBanner === 'function') applyNoHomingBanner(); applyAppearance(); applyUiToggles(); buildWire(); // Hydrate BLOCK from saved CFG (cutter size persists across reloads). This // calls buildBlock() internally + re-frames the camera + fires the checkFit // warning. Direct buildBlock() here would use stale default 500×500×500. resizeBlockFromCfg(); resize(); resetView(); requestAnimationFrame(frame); updatePartsUI(); document.getElementById('status').textContent = 'No part loaded — click + Load parts to start.';