cyclecad 3.10.4 → 3.12.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/pentacad.html ADDED
@@ -0,0 +1,1097 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8" />
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
+ <title>Pentacad — Browser-native 5-axis CAM for Pentamachine · cycleCAD Suite</title>
7
+ <meta name="description" content="Pentacad: browser-native 5-axis CAM, G-code simulator, and Kinetic Control bridge — purpose-built for Pentamachine V2 desktop CNC. Part of the cycleCAD Suite." />
8
+ <meta name="keywords" content="Pentacad, Pentamachine, 5-axis CAM, browser CAM, desktop CNC, Kinetic Control, cycleCAD Suite, CAM software, toolpath" />
9
+ <meta name="author" content="Sachin Kumar" />
10
+ <link rel="canonical" href="https://cyclecad.com/pentacad.html" />
11
+ <meta property="og:type" content="website" />
12
+ <meta property="og:site_name" content="cycleCAD Suite" />
13
+ <meta property="og:title" content="Pentacad — Browser-native 5-axis CAM" />
14
+ <meta property="og:description" content="CAM + simulator + post-processor + Kinetic Control bridge, all in one browser tab. Built for Pentamachine V2 desktop CNC." />
15
+ <meta property="og:url" content="https://cyclecad.com/pentacad.html" />
16
+ <meta property="og:image" content="https://cyclecad.com/screenshot.png" />
17
+ <meta name="twitter:card" content="summary_large_image" />
18
+ <meta name="twitter:title" content="Pentacad — Browser-native 5-axis CAM" />
19
+ <meta name="twitter:description" content="CAM + simulator + post-processor + Kinetic Control bridge, all in one browser tab." />
20
+ <meta name="twitter:image" content="https://cyclecad.com/screenshot.png" />
21
+ <link rel="icon" type="image/svg+xml" href="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100'><text y='.9em' font-size='90'>⚙️</text></svg>" />
22
+ <link rel="preconnect" href="https://fonts.googleapis.com" />
23
+ <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
24
+ <link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800;900&family=Fraunces:opsz,wght@9..144,400;9..144,600;9..144,700;9..144,900&family=JetBrains+Mono:wght@400;500;600&display=swap" rel="stylesheet" />
25
+
26
+ <style>
27
+ /* ─────────────────────────────────────────────
28
+ DESIGN TOKENS — shared with suite landing
29
+ ───────────────────────────────────────────── */
30
+ :root {
31
+ --bg: #0A1628;
32
+ --bg-alt: #122240;
33
+ --bg-card: #1A2D50;
34
+ --border: #1E3A5F;
35
+ --border-hi: #2A4F80;
36
+ --text: #F0F0E8;
37
+ --text-2: #8B9AB5;
38
+ --text-3: #5A6B85;
39
+ --gold: #D4A843;
40
+ --gold-2: #E8C065;
41
+ --blue: #2E86DE;
42
+ --teal: #3AAFA9;
43
+ --emerald: #10B981;
44
+ --emerald-2: #34D399;
45
+ --emerald-3: rgba(16,185,129,0.12);
46
+ --purple: #8B6FC0;
47
+ --amber: #F59E0B;
48
+ --red: #EF4444;
49
+ --t-fast: 0.18s;
50
+ --t-med: 0.35s;
51
+ --t-slow: 0.8s;
52
+ --ease: cubic-bezier(0.22, 0.61, 0.36, 1);
53
+ }
54
+
55
+ * { margin: 0; padding: 0; box-sizing: border-box; }
56
+ html { scroll-behavior: smooth; }
57
+ body {
58
+ font-family: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif;
59
+ font-weight: 400;
60
+ background: var(--bg);
61
+ color: var(--text);
62
+ line-height: 1.65;
63
+ overflow-x: hidden;
64
+ -webkit-font-smoothing: antialiased;
65
+ }
66
+ h1, h2, h3, h4 { font-family: 'Fraunces', Georgia, serif; font-weight: 700; line-height: 1.15; letter-spacing: -0.015em; color: var(--text); }
67
+ em { font-style: italic; color: var(--emerald-2); font-weight: 700; }
68
+ code, pre { font-family: 'JetBrains Mono', ui-monospace, monospace; }
69
+
70
+ .wrap { max-width: 1280px; margin: 0 auto; padding: 0 32px; }
71
+
72
+ /* ─────────────────────────────────────────────
73
+ NAV — matches suite landing
74
+ ───────────────────────────────────────────── */
75
+ nav {
76
+ position: sticky; top: 0; z-index: 50;
77
+ background: rgba(10, 22, 40, 0.72);
78
+ backdrop-filter: blur(20px) saturate(1.5);
79
+ border-bottom: 1px solid var(--border);
80
+ padding: 16px 0;
81
+ }
82
+ nav .wrap { display: flex; align-items: center; justify-content: space-between; gap: 24px; }
83
+ .brand { display: inline-flex; align-items: center; gap: 10px; font-family: 'Fraunces', serif; font-weight: 700; font-size: 1.12rem; color: var(--text); text-decoration: none; }
84
+ .brand .logo { display: inline-grid; place-items: center; width: 30px; height: 30px; border-radius: 8px; background: linear-gradient(135deg, var(--gold), var(--emerald)); color: var(--bg); font-size: 0.9rem; }
85
+ .brand em { color: var(--gold); font-style: italic; }
86
+ nav .links { display: flex; align-items: center; gap: 24px; font-size: 0.95rem; }
87
+ nav .links a { color: var(--text-2); text-decoration: none; transition: color var(--t-fast); }
88
+ nav .links a:hover { color: var(--text); }
89
+ nav .links a.cta {
90
+ background: linear-gradient(135deg, var(--emerald), var(--teal));
91
+ color: var(--bg); padding: 8px 16px; border-radius: 24px;
92
+ font-weight: 600; transition: transform var(--t-fast), box-shadow var(--t-fast);
93
+ }
94
+ nav .links a.cta:hover { transform: translateY(-1px); box-shadow: 0 6px 18px rgba(16,185,129,0.32); }
95
+ @media (max-width: 720px) { nav .links a:not(.cta) { display: none; } }
96
+
97
+ /* ─────────────────────────────────────────────
98
+ HERO
99
+ ───────────────────────────────────────────── */
100
+ .hero {
101
+ position: relative;
102
+ padding: 120px 0 100px;
103
+ background:
104
+ radial-gradient(ellipse 1000px 450px at 20% 0%, rgba(16,185,129,0.14), transparent 60%),
105
+ radial-gradient(ellipse 800px 350px at 80% 30%, rgba(58,175,169,0.1), transparent 60%),
106
+ var(--bg);
107
+ overflow: hidden;
108
+ }
109
+ .hero::before {
110
+ content: ''; position: absolute; inset: 0;
111
+ background: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='40' height='40'><circle cx='1' cy='1' r='0.6' fill='%232A4F80'/></svg>");
112
+ opacity: 0.35; pointer-events: none;
113
+ }
114
+ .hero .wrap { position: relative; z-index: 1; display: grid; grid-template-columns: 1.1fr 1fr; gap: 72px; align-items: center; }
115
+ .hero .kicker {
116
+ display: inline-flex; align-items: center; gap: 8px;
117
+ padding: 6px 14px; border-radius: 24px; font-size: 0.78rem; font-weight: 600;
118
+ color: var(--emerald-2); background: var(--emerald-3); border: 1px solid rgba(16,185,129,0.35);
119
+ letter-spacing: 0.6px; text-transform: uppercase; margin-bottom: 24px;
120
+ }
121
+ .hero .kicker .dot { width: 8px; height: 8px; border-radius: 50%; background: var(--emerald-2); animation: dotPulse 1.8s ease-in-out infinite; box-shadow: 0 0 12px var(--emerald); }
122
+ @keyframes dotPulse { 0%, 100% { opacity: 1; } 50% { opacity: 0.35; } }
123
+ .hero h1 { font-size: clamp(2.6rem, 5vw, 4.2rem); max-width: 660px; margin-bottom: 24px; font-weight: 900; }
124
+ .hero p.lead { font-size: 1.2rem; color: var(--text-2); max-width: 620px; margin-bottom: 36px; }
125
+ .hero .ctas { display: flex; gap: 14px; flex-wrap: wrap; }
126
+ .btn {
127
+ display: inline-flex; align-items: center; gap: 10px;
128
+ padding: 14px 26px; border-radius: 30px; font-weight: 600; font-size: 0.98rem;
129
+ text-decoration: none; transition: transform var(--t-fast), box-shadow var(--t-fast), background var(--t-fast);
130
+ }
131
+ .btn-primary { background: linear-gradient(135deg, var(--emerald), var(--teal)); color: var(--bg); }
132
+ .btn-primary:hover { transform: translateY(-2px); box-shadow: 0 10px 30px rgba(16,185,129,0.35); }
133
+ .btn-secondary { background: transparent; color: var(--text); border: 1px solid var(--border-hi); }
134
+ .btn-secondary:hover { background: rgba(255,255,255,0.04); border-color: var(--emerald); color: var(--emerald-2); }
135
+ .btn .arrow { transition: transform var(--t-fast); }
136
+ .btn:hover .arrow { transform: translateX(4px); }
137
+
138
+ /* Hero visual — 5-axis machine schematic */
139
+ .hero-visual {
140
+ position: relative; aspect-ratio: 1 / 1; max-width: 440px; justify-self: end;
141
+ background: radial-gradient(circle at 50% 40%, rgba(16,185,129,0.08), transparent 70%);
142
+ border-radius: 50%;
143
+ }
144
+ .hero-visual svg { width: 100%; height: 100%; }
145
+ .hero-visual .ring { transform-origin: 50% 50%; animation: slowSpin 26s linear infinite; }
146
+ .hero-visual .spindle { animation: drillBob 2.4s ease-in-out infinite; transform-origin: 50% 35%; }
147
+ @keyframes slowSpin { to { transform: rotate(360deg); } }
148
+ @keyframes drillBob { 0%, 100% { transform: translateY(0); } 50% { transform: translateY(4px); } }
149
+ .hero-visual .stock-ring { stroke-dasharray: 8 4; animation: dashMove 18s linear infinite; }
150
+ @keyframes dashMove { to { stroke-dashoffset: -200; } }
151
+
152
+ @media (max-width: 920px) {
153
+ .hero { padding: 80px 0 60px; }
154
+ .hero .wrap { grid-template-columns: 1fr; gap: 40px; }
155
+ .hero-visual { max-width: 360px; justify-self: center; }
156
+ }
157
+
158
+ /* ─────────────────────────────────────────────
159
+ PROBLEM STRIP
160
+ ───────────────────────────────────────────── */
161
+ .problem {
162
+ padding: 70px 0;
163
+ background: var(--bg-alt);
164
+ border-top: 1px solid var(--border);
165
+ border-bottom: 1px solid var(--border);
166
+ }
167
+ .problem h2 { font-size: clamp(1.6rem, 3vw, 2.2rem); max-width: 720px; margin: 0 auto 14px; text-align: center; }
168
+ .problem .sub { color: var(--text-2); text-align: center; max-width: 720px; margin: 0 auto 40px; }
169
+ .problem-grid { display: grid; grid-template-columns: repeat(5, 1fr); gap: 14px; }
170
+ .problem-card {
171
+ padding: 18px 16px; border-radius: 12px;
172
+ background: var(--bg); border: 1px solid var(--border);
173
+ text-align: center;
174
+ }
175
+ .problem-card .icon {
176
+ width: 38px; height: 38px; display: grid; place-items: center; margin: 0 auto 10px;
177
+ border-radius: 10px; background: rgba(239,68,68,0.12); color: var(--red); font-size: 1.2rem;
178
+ }
179
+ .problem-card .ttl { font-weight: 600; font-size: 0.95rem; margin-bottom: 4px; color: var(--text); }
180
+ .problem-card .sub { font-size: 0.78rem; color: var(--text-3); margin-bottom: 0; }
181
+ @media (max-width: 900px) { .problem-grid { grid-template-columns: repeat(3, 1fr); } .problem-card:nth-child(4), .problem-card:nth-child(5) { grid-column: span 1; } }
182
+ @media (max-width: 560px) { .problem-grid { grid-template-columns: repeat(2, 1fr); } }
183
+
184
+ .vs-line {
185
+ position: relative; margin: 40px 0 0; text-align: center;
186
+ font-family: 'Fraunces', serif; font-style: italic; font-size: 1.15rem; color: var(--text-2);
187
+ }
188
+ .vs-line::before, .vs-line::after {
189
+ content: ''; display: inline-block; width: 64px; height: 1px;
190
+ background: linear-gradient(to right, transparent, var(--border-hi));
191
+ vertical-align: middle; margin: 0 12px;
192
+ }
193
+ .vs-line::after { background: linear-gradient(to left, transparent, var(--border-hi)); }
194
+
195
+ /* ─────────────────────────────────────────────
196
+ SOLUTION — pentagon split into 5 modules
197
+ ───────────────────────────────────────────── */
198
+ .solution { padding: 100px 0; }
199
+ .solution .header-block { text-align: center; max-width: 760px; margin: 0 auto 60px; }
200
+ .section-kicker {
201
+ display: inline-block; font-size: 0.72rem; letter-spacing: 2.5px; text-transform: uppercase;
202
+ color: var(--emerald-2); font-weight: 700; margin-bottom: 16px;
203
+ }
204
+ .solution h2 { font-size: clamp(2rem, 4vw, 3rem); margin-bottom: 16px; }
205
+ .solution p.sub { color: var(--text-2); font-size: 1.08rem; }
206
+
207
+ .five-modules { display: grid; grid-template-columns: repeat(5, 1fr); gap: 20px; }
208
+ .mod-card {
209
+ position: relative;
210
+ padding: 28px 22px; border-radius: 16px;
211
+ background: var(--bg-alt); border: 1px solid var(--border);
212
+ transition: transform var(--t-med), border-color var(--t-med), box-shadow var(--t-med);
213
+ }
214
+ .mod-card:hover {
215
+ transform: translateY(-4px);
216
+ border-color: rgba(16,185,129,0.4);
217
+ box-shadow: 0 12px 32px rgba(16,185,129,0.15);
218
+ }
219
+ .mod-num {
220
+ display: inline-block; width: 28px; height: 28px; border-radius: 8px;
221
+ background: var(--emerald-3); color: var(--emerald-2);
222
+ font: 700 0.82rem 'JetBrains Mono'; display: grid; place-items: center; margin-bottom: 14px;
223
+ }
224
+ .mod-card h3 { font-size: 1.05rem; font-family: 'Inter', sans-serif; font-weight: 700; margin-bottom: 8px; }
225
+ .mod-card p { font-size: 0.88rem; color: var(--text-2); line-height: 1.55; }
226
+ @media (max-width: 920px) { .five-modules { grid-template-columns: repeat(2, 1fr); } }
227
+ @media (max-width: 520px) { .five-modules { grid-template-columns: 1fr; } }
228
+
229
+ /* ─────────────────────────────────────────────
230
+ STRATEGIES GRID
231
+ ───────────────────────────────────────────── */
232
+ .strategies { padding: 100px 0; background: var(--bg-alt); }
233
+ .strategies .header-block { text-align: center; max-width: 700px; margin: 0 auto 50px; }
234
+ .strategies h2 { font-size: clamp(2rem, 4vw, 2.8rem); margin-bottom: 14px; }
235
+ .strategies p.sub { color: var(--text-2); }
236
+ .strat-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 16px; }
237
+ .strat-card {
238
+ padding: 22px 20px; border-radius: 14px;
239
+ background: var(--bg); border: 1px solid var(--border);
240
+ transition: all var(--t-med);
241
+ }
242
+ .strat-card:hover { border-color: var(--emerald); transform: translateY(-3px); }
243
+ .strat-card .icon {
244
+ width: 40px; height: 40px; border-radius: 10px;
245
+ background: var(--emerald-3); margin-bottom: 14px;
246
+ display: grid; place-items: center;
247
+ }
248
+ .strat-card .icon svg { width: 20px; height: 20px; stroke: var(--emerald-2); stroke-width: 2; fill: none; }
249
+ .strat-card h4 { font-size: 1rem; font-family: 'Inter', sans-serif; font-weight: 700; margin-bottom: 4px; }
250
+ .strat-card .kind { font-size: 0.72rem; font-family: 'JetBrains Mono'; color: var(--text-3); text-transform: uppercase; letter-spacing: 1px; margin-bottom: 8px; }
251
+ .strat-card p { font-size: 0.84rem; color: var(--text-2); line-height: 1.5; }
252
+ @media (max-width: 920px) { .strat-grid { grid-template-columns: repeat(2, 1fr); } }
253
+ @media (max-width: 520px) { .strat-grid { grid-template-columns: 1fr; } }
254
+
255
+ /* ─────────────────────────────────────────────
256
+ POST-PROCESSOR SECTION — side-by-side with G-code sample
257
+ ───────────────────────────────────────────── */
258
+ .post-section { padding: 100px 0; }
259
+ .post-layout { display: grid; grid-template-columns: 1fr 1fr; gap: 60px; align-items: center; }
260
+ .post-body h2 { font-size: clamp(1.9rem, 3.5vw, 2.6rem); margin-bottom: 16px; }
261
+ .post-body p { color: var(--text-2); margin-bottom: 14px; font-size: 1.02rem; }
262
+ .post-body .feature-list { list-style: none; margin-top: 26px; }
263
+ .post-body .feature-list li {
264
+ position: relative; padding-left: 24px; margin-bottom: 10px;
265
+ color: var(--text); font-size: 0.95rem;
266
+ }
267
+ .post-body .feature-list li::before {
268
+ content: '✓'; position: absolute; left: 0; top: 0;
269
+ width: 16px; height: 16px; background: var(--emerald-3); color: var(--emerald-2);
270
+ border-radius: 4px; display: grid; place-items: center;
271
+ font-size: 0.78rem; font-weight: 700;
272
+ }
273
+ .post-body code.inline {
274
+ background: var(--bg-card); color: var(--emerald-2); padding: 2px 7px; border-radius: 4px;
275
+ font-size: 0.88em;
276
+ }
277
+
278
+ .ngc-block {
279
+ position: relative;
280
+ background: var(--bg-alt);
281
+ border: 1px solid var(--border); border-radius: 14px;
282
+ overflow: hidden;
283
+ font-family: 'JetBrains Mono', ui-monospace, monospace;
284
+ font-size: 0.82rem;
285
+ }
286
+ .ngc-block .hd {
287
+ padding: 10px 16px; background: var(--bg-card);
288
+ border-bottom: 1px solid var(--border);
289
+ display: flex; align-items: center; justify-content: space-between;
290
+ color: var(--text-2); font-size: 0.78rem; letter-spacing: 1px; text-transform: uppercase;
291
+ }
292
+ .ngc-block .hd .dots { display: inline-flex; gap: 5px; }
293
+ .ngc-block .hd .dots span { width: 9px; height: 9px; border-radius: 50%; background: var(--border-hi); }
294
+ .ngc-block pre {
295
+ padding: 18px 18px 22px;
296
+ color: var(--text); line-height: 1.6;
297
+ overflow-x: auto; white-space: pre;
298
+ }
299
+ .ngc-block .kw { color: var(--emerald-2); }
300
+ .ngc-block .val { color: var(--gold-2); }
301
+ .ngc-block .cm { color: var(--text-3); font-style: italic; }
302
+ .ngc-block .ax { color: var(--blue); }
303
+ @media (max-width: 900px) { .post-layout { grid-template-columns: 1fr; gap: 40px; } }
304
+
305
+ /* ─────────────────────────────────────────────
306
+ SIMULATOR SECTION
307
+ ───────────────────────────────────────────── */
308
+ .sim-section { padding: 100px 0; background: var(--bg-alt); }
309
+ .sim-layout { display: grid; grid-template-columns: 1fr 1fr; gap: 60px; align-items: center; }
310
+ .sim-layout.rev > :first-child { order: 2; }
311
+ .sim-visual {
312
+ aspect-ratio: 1.1 / 1;
313
+ background: radial-gradient(circle at 50% 50%, rgba(46,134,222,0.08), transparent 70%);
314
+ border-radius: 20px; border: 1px solid var(--border);
315
+ position: relative; overflow: hidden;
316
+ }
317
+ .sim-visual svg { width: 100%; height: 100%; }
318
+ .sim-visual .a-rot { transform-origin: 50% 50%; animation: aRot 5.4s ease-in-out infinite; }
319
+ .sim-visual .b-rot { transform-origin: 50% 50%; animation: bRot 7s linear infinite; }
320
+ @keyframes aRot { 0%, 100% { transform: rotate(-22deg); } 50% { transform: rotate(22deg); } }
321
+ @keyframes bRot { to { transform: rotate(360deg); } }
322
+ .sim-visual .tp-path {
323
+ stroke: var(--emerald); stroke-width: 1.2; fill: none;
324
+ stroke-dasharray: 600; stroke-dashoffset: 600;
325
+ animation: tpDraw 4.2s ease-in-out infinite;
326
+ }
327
+ @keyframes tpDraw {
328
+ 0% { stroke-dashoffset: 600; }
329
+ 55%, 100% { stroke-dashoffset: 0; }
330
+ }
331
+ .sim-body h2 { font-size: clamp(1.9rem, 3.5vw, 2.6rem); margin-bottom: 16px; }
332
+ .sim-body p { color: var(--text-2); margin-bottom: 14px; font-size: 1.02rem; }
333
+ .sim-body .feature-list { list-style: none; margin-top: 22px; }
334
+ .sim-body .feature-list li { position: relative; padding-left: 24px; margin-bottom: 10px; font-size: 0.95rem; }
335
+ .sim-body .feature-list li::before {
336
+ content: '✓'; position: absolute; left: 0; top: 0;
337
+ width: 16px; height: 16px; background: var(--emerald-3); color: var(--emerald-2);
338
+ border-radius: 4px; display: grid; place-items: center;
339
+ font-size: 0.78rem; font-weight: 700;
340
+ }
341
+ @media (max-width: 900px) {
342
+ .sim-layout { grid-template-columns: 1fr; gap: 40px; }
343
+ .sim-layout.rev > :first-child { order: 0; }
344
+ }
345
+
346
+ /* ─────────────────────────────────────────────
347
+ BRIDGE SECTION — WebSocket flow diagram
348
+ ───────────────────────────────────────────── */
349
+ .bridge { padding: 100px 0; }
350
+ .bridge .header-block { text-align: center; max-width: 760px; margin: 0 auto 60px; }
351
+ .bridge h2 { font-size: clamp(1.9rem, 3.8vw, 2.7rem); margin-bottom: 16px; }
352
+ .bridge p.sub { color: var(--text-2); font-size: 1.05rem; }
353
+ .bridge-diagram {
354
+ position: relative;
355
+ padding: 60px 40px;
356
+ border-radius: 20px;
357
+ background: var(--bg-alt); border: 1px solid var(--border);
358
+ }
359
+ .bridge-row { display: grid; grid-template-columns: 1fr 90px 1fr 90px 1fr; align-items: center; gap: 16px; }
360
+ .bridge-node {
361
+ padding: 22px 18px; border-radius: 14px;
362
+ background: var(--bg); border: 1px solid var(--border);
363
+ text-align: center;
364
+ }
365
+ .bridge-node .icn { font-size: 1.6rem; margin-bottom: 8px; }
366
+ .bridge-node h4 { font-size: 0.98rem; font-family: 'Inter', sans-serif; font-weight: 700; margin-bottom: 4px; }
367
+ .bridge-node .ttag { display: inline-block; font-size: 0.72rem; font-family: 'JetBrains Mono'; color: var(--text-3); }
368
+ .bridge-arrow { position: relative; height: 2px; background: linear-gradient(to right, var(--border-hi), var(--emerald), var(--border-hi)); border-radius: 2px; }
369
+ .bridge-arrow::after {
370
+ content: ''; position: absolute; right: -2px; top: 50%; transform: translateY(-50%);
371
+ border-left: 8px solid var(--emerald); border-top: 5px solid transparent; border-bottom: 5px solid transparent;
372
+ }
373
+ .bridge-arrow .packet {
374
+ position: absolute; top: 50%; left: 0; transform: translateY(-50%);
375
+ width: 10px; height: 10px; border-radius: 50%; background: var(--emerald);
376
+ box-shadow: 0 0 14px var(--emerald);
377
+ animation: packetFly 2.2s ease-in-out infinite;
378
+ }
379
+ .bridge-arrow .packet.p2 { animation-delay: 0.8s; }
380
+ @keyframes packetFly { 0% { left: 0; opacity: 0; } 10% { opacity: 1; } 80% { opacity: 1; } 100% { left: calc(100% - 10px); opacity: 0; } }
381
+ .bridge-caption { text-align: center; margin-top: 30px; color: var(--text-2); font-size: 0.92rem; }
382
+ .bridge-caption code { background: var(--bg-card); color: var(--emerald-2); padding: 2px 7px; border-radius: 4px; font-size: 0.88em; }
383
+
384
+ .bridge-events {
385
+ margin-top: 36px;
386
+ display: grid; grid-template-columns: repeat(3, 1fr); gap: 12px;
387
+ }
388
+ .bridge-event {
389
+ padding: 14px 16px; border-radius: 10px;
390
+ background: var(--bg-card); border: 1px solid var(--border);
391
+ font-family: 'JetBrains Mono', monospace; font-size: 0.82rem;
392
+ }
393
+ .bridge-event .evt-name { color: var(--emerald-2); }
394
+ .bridge-event .evt-sub { color: var(--text-3); font-size: 0.76rem; margin-top: 2px; }
395
+ @media (max-width: 900px) {
396
+ .bridge-row { grid-template-columns: 1fr; gap: 8px; }
397
+ .bridge-arrow { height: 36px; width: 2px; margin: 0 auto; background: linear-gradient(to bottom, var(--border-hi), var(--emerald), var(--border-hi)); }
398
+ .bridge-arrow::after { right: 50%; top: auto; bottom: -2px; transform: translateX(50%); border: 0; border-top: 8px solid var(--emerald); border-left: 5px solid transparent; border-right: 5px solid transparent; }
399
+ .bridge-arrow .packet { animation: packetFlyV 2.2s ease-in-out infinite; }
400
+ .bridge-events { grid-template-columns: 1fr; }
401
+ }
402
+ @keyframes packetFlyV { 0% { top: 0; opacity: 0; } 10% { opacity: 1; } 80% { opacity: 1; } 100% { top: calc(100% - 10px); opacity: 0; } }
403
+
404
+ /* ─────────────────────────────────────────────
405
+ MACHINES SECTION
406
+ ───────────────────────────────────────────── */
407
+ .machines { padding: 100px 0; background: var(--bg-alt); }
408
+ .machines .header-block { text-align: center; max-width: 700px; margin: 0 auto 50px; }
409
+ .machines h2 { font-size: clamp(1.9rem, 3.5vw, 2.6rem); margin-bottom: 14px; }
410
+ .machines p.sub { color: var(--text-2); }
411
+
412
+ .machine-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 20px; }
413
+ .machine-card {
414
+ padding: 26px 22px; border-radius: 16px;
415
+ background: var(--bg); border: 1px solid var(--border);
416
+ position: relative;
417
+ transition: transform var(--t-med), border-color var(--t-med);
418
+ }
419
+ .machine-card:hover { transform: translateY(-4px); border-color: var(--emerald); }
420
+ .machine-card .status-tag {
421
+ position: absolute; top: 14px; right: 14px;
422
+ padding: 3px 10px; border-radius: 12px; font-size: 0.68rem;
423
+ font-weight: 700; letter-spacing: 1.2px; text-transform: uppercase;
424
+ }
425
+ .machine-card .status-tag.phase0 { background: rgba(245,158,11,0.14); color: var(--amber); border: 1px solid rgba(245,158,11,0.3); }
426
+ .machine-card .status-tag.phase1 { background: rgba(46,134,222,0.14); color: #7bafee; border: 1px solid rgba(46,134,222,0.3); }
427
+ .machine-card h4 { font-size: 1.1rem; font-family: 'Inter', sans-serif; font-weight: 700; margin-bottom: 4px; }
428
+ .machine-card .vendor { font-size: 0.82rem; color: var(--text-3); margin-bottom: 14px; font-family: 'JetBrains Mono'; letter-spacing: 0.5px; }
429
+ .machine-card .specs {
430
+ margin-top: 16px; padding-top: 16px; border-top: 1px solid var(--border);
431
+ font-size: 0.85rem; color: var(--text-2);
432
+ }
433
+ .machine-card .specs > div { display: flex; justify-content: space-between; padding: 4px 0; }
434
+ .machine-card .specs > div > span:first-child { color: var(--text-3); }
435
+ .machine-card .specs > div > span:last-child { color: var(--text); font-family: 'JetBrains Mono'; font-size: 0.82rem; }
436
+ @media (max-width: 900px) { .machine-grid { grid-template-columns: 1fr; } }
437
+
438
+ /* ─────────────────────────────────────────────
439
+ ROADMAP — phased timeline
440
+ ───────────────────────────────────────────── */
441
+ .roadmap { padding: 100px 0; }
442
+ .roadmap .header-block { text-align: center; max-width: 720px; margin: 0 auto 60px; }
443
+ .roadmap h2 { font-size: clamp(1.9rem, 3.5vw, 2.6rem); margin-bottom: 14px; }
444
+ .roadmap p.sub { color: var(--text-2); }
445
+
446
+ .phases { display: grid; grid-template-columns: repeat(4, 1fr); gap: 16px; position: relative; }
447
+ .phases::before {
448
+ content: ''; position: absolute; top: 45px; left: 8%; right: 8%; height: 2px;
449
+ background: linear-gradient(to right, var(--emerald), var(--amber), var(--border-hi), var(--border-hi));
450
+ z-index: 0;
451
+ }
452
+ .phase {
453
+ position: relative; z-index: 1;
454
+ padding: 24px 20px; border-radius: 14px;
455
+ background: var(--bg); border: 1px solid var(--border);
456
+ }
457
+ .phase-dot {
458
+ width: 18px; height: 18px; border-radius: 50%;
459
+ margin: 0 auto 12px; border: 3px solid var(--bg);
460
+ box-shadow: 0 0 0 2px var(--border-hi);
461
+ }
462
+ .phase.done .phase-dot { background: var(--emerald); box-shadow: 0 0 0 2px var(--emerald); }
463
+ .phase.active .phase-dot { background: var(--amber); box-shadow: 0 0 0 2px var(--amber); animation: pulseDot 1.8s ease-in-out infinite; }
464
+ .phase.next .phase-dot { background: var(--bg-card); box-shadow: 0 0 0 2px var(--border-hi); }
465
+ @keyframes pulseDot { 0%, 100% { transform: scale(1); } 50% { transform: scale(1.22); } }
466
+ .phase-num {
467
+ display: block; font-family: 'JetBrains Mono'; font-size: 0.78rem;
468
+ color: var(--text-3); letter-spacing: 1.5px; text-align: center; margin-bottom: 4px; text-transform: uppercase;
469
+ }
470
+ .phase h4 { text-align: center; font-size: 1rem; font-family: 'Inter', sans-serif; font-weight: 700; margin-bottom: 10px; }
471
+ .phase ul { list-style: none; }
472
+ .phase li { font-size: 0.82rem; color: var(--text-2); padding: 4px 0; border-bottom: 1px dashed var(--border); }
473
+ .phase li:last-child { border-bottom: 0; }
474
+ .phase.done { border-color: rgba(16,185,129,0.35); }
475
+ .phase.active { border-color: rgba(245,158,11,0.4); }
476
+ @media (max-width: 920px) { .phases { grid-template-columns: repeat(2, 1fr); } .phases::before { display: none; } }
477
+ @media (max-width: 520px) { .phases { grid-template-columns: 1fr; } }
478
+
479
+ /* ─────────────────────────────────────────────
480
+ FINAL CTA
481
+ ───────────────────────────────────────────── */
482
+ .cta-final {
483
+ padding: 110px 0;
484
+ background:
485
+ radial-gradient(ellipse 800px 400px at 50% 50%, rgba(16,185,129,0.14), transparent 60%),
486
+ var(--bg);
487
+ text-align: center;
488
+ }
489
+ .cta-final h2 { font-size: clamp(2rem, 4vw, 3rem); max-width: 780px; margin: 0 auto 16px; }
490
+ .cta-final p { color: var(--text-2); max-width: 680px; margin: 0 auto 36px; font-size: 1.05rem; }
491
+ .cta-final .ctas { display: flex; gap: 14px; justify-content: center; flex-wrap: wrap; }
492
+ .cta-final .tiny {
493
+ margin-top: 26px;
494
+ color: var(--text-3); font-size: 0.82rem;
495
+ }
496
+ .cta-final .tiny a { color: var(--text-2); text-decoration: underline; text-decoration-color: var(--border-hi); }
497
+ .cta-final .tiny a:hover { color: var(--emerald-2); }
498
+
499
+ /* ─────────────────────────────────────────────
500
+ FOOTER — same as suite landing
501
+ ───────────────────────────────────────────── */
502
+ footer {
503
+ padding: 70px 0 40px;
504
+ background: var(--bg-alt);
505
+ border-top: 1px solid var(--border);
506
+ font-size: 0.9rem;
507
+ }
508
+ footer .row {
509
+ display: grid; grid-template-columns: 1.8fr 1fr 1fr 1fr 1fr; gap: 40px;
510
+ padding-bottom: 40px; border-bottom: 1px solid var(--border);
511
+ }
512
+ footer .brand-col p { color: var(--text-2); font-size: 0.92rem; margin-top: 14px; max-width: 320px; }
513
+ footer .col h4 {
514
+ font-size: 0.78rem; font-family: 'Inter', sans-serif; font-weight: 700;
515
+ text-transform: uppercase; letter-spacing: 1.5px; color: var(--text-3); margin-bottom: 14px;
516
+ }
517
+ footer .col a { display: block; color: var(--text-2); text-decoration: none; padding: 4px 0; transition: color var(--t-fast); }
518
+ footer .col a:hover { color: var(--emerald-2); }
519
+ footer .legal {
520
+ margin-top: 30px; display: flex; justify-content: space-between; gap: 16px;
521
+ color: var(--text-3); font-size: 0.82rem; flex-wrap: wrap;
522
+ }
523
+ @media (max-width: 900px) { footer .row { grid-template-columns: 1fr 1fr; } }
524
+
525
+ /* ─────────────────────────────────────────────
526
+ SCROLL-TRIGGERED ANIMATION
527
+ ───────────────────────────────────────────── */
528
+ [data-animate] { opacity: 0; transform: translateY(24px); transition: opacity var(--t-slow) var(--ease), transform var(--t-slow) var(--ease); }
529
+ [data-animate].in-view { opacity: 1; transform: translateY(0); }
530
+ </style>
531
+ </head>
532
+ <body>
533
+
534
+ <nav>
535
+ <div class="wrap">
536
+ <a href="/" class="brand">
537
+ <span class="logo">⚙</span>
538
+ cycle<em>CAD</em> suite
539
+ </a>
540
+ <div class="links">
541
+ <a href="/">Suite</a>
542
+ <a href="/cyclecad.html">cycleCAD</a>
543
+ <a href="/explodeview.html">ExplodeView</a>
544
+ <a href="#strategies">Features</a>
545
+ <a href="/app/pentacad.html" class="cta">Launch Pentacad →</a>
546
+ </div>
547
+ </div>
548
+ </nav>
549
+
550
+ <!-- HERO -->
551
+ <header class="hero">
552
+ <div class="wrap">
553
+ <div>
554
+ <div class="kicker">
555
+ <span class="dot"></span>
556
+ Phase 0 · Built for Pentamachine
557
+ </div>
558
+ <h1>
559
+ 5-axis CAM in the <em>browser</em>.<br/>
560
+ Built for <em>Pentamachine</em>.
561
+ </h1>
562
+ <p class="lead">
563
+ Pentacad is CAM, simulator, post-processor, and machine-control bridge in one browser tab.
564
+ 3+2 strategies tuned to the Pentamachine V2 kinematics, a real-time A/B axis simulator,
565
+ and a live WebSocket bridge to your Kinetic Control box.
566
+ </p>
567
+ <div class="ctas">
568
+ <a href="/app/pentacad.html" class="btn btn-primary">Launch Pentacad <span class="arrow">→</span></a>
569
+ <a href="#strategies" class="btn btn-secondary">See the strategies</a>
570
+ </div>
571
+ </div>
572
+
573
+ <div class="hero-visual" aria-hidden="true">
574
+ <svg viewBox="0 0 300 300" xmlns="http://www.w3.org/2000/svg">
575
+ <defs>
576
+ <radialGradient id="hero-core" cx="50%" cy="45%">
577
+ <stop offset="0%" stop-color="#10B981" stop-opacity="0.7"/>
578
+ <stop offset="70%" stop-color="#10B981" stop-opacity="0.06"/>
579
+ <stop offset="100%" stop-color="#10B981" stop-opacity="0"/>
580
+ </radialGradient>
581
+ </defs>
582
+ <!-- Outer A-axis ring -->
583
+ <g class="ring">
584
+ <circle cx="150" cy="150" r="120" fill="none" stroke="#2E86DE" stroke-width="1" stroke-dasharray="3 4" opacity="0.5"/>
585
+ <circle cx="150" cy="150" r="120" fill="none" stroke="#1E3A5F" stroke-width="0.6"/>
586
+ <text x="270" y="150" font-family="JetBrains Mono" font-size="9" fill="#2E86DE" opacity="0.8">A</text>
587
+ </g>
588
+ <!-- Inner B-axis ring -->
589
+ <circle cx="150" cy="150" r="88" fill="none" stroke="#3AAFA9" stroke-width="0.8" stroke-dasharray="2 3" opacity="0.55"/>
590
+ <text x="150" y="56" font-family="JetBrains Mono" font-size="9" fill="#3AAFA9" text-anchor="middle" opacity="0.8">B</text>
591
+ <!-- Stock (bottle-opener ring) -->
592
+ <circle cx="150" cy="150" r="64" class="stock-ring" fill="none" stroke="#D4A843" stroke-width="2" opacity="0.75"/>
593
+ <circle cx="150" cy="150" r="42" fill="none" stroke="#D4A843" stroke-width="1.2" opacity="0.4"/>
594
+ <!-- Center glow -->
595
+ <circle cx="150" cy="150" r="60" fill="url(#hero-core)"/>
596
+ <!-- Spindle -->
597
+ <g class="spindle">
598
+ <rect x="143" y="85" width="14" height="30" fill="#5A6B85" stroke="#8B9AB5" stroke-width="0.5" rx="2"/>
599
+ <polygon points="146,115 154,115 150,122" fill="#F59E0B"/>
600
+ <circle cx="150" cy="124" r="9" fill="rgba(245,158,11,0.2)"/>
601
+ </g>
602
+ <!-- Axis labels -->
603
+ <text x="18" y="156" font-family="JetBrains Mono" font-size="9" fill="#5A6B85">X</text>
604
+ <text x="148" y="286" font-family="JetBrains Mono" font-size="9" fill="#5A6B85">Y</text>
605
+ <text x="148" y="24" font-family="JetBrains Mono" font-size="9" fill="#5A6B85">Z</text>
606
+ </svg>
607
+ </div>
608
+ </div>
609
+ </header>
610
+
611
+ <!-- PROBLEM STRIP -->
612
+ <section class="problem" data-animate>
613
+ <div class="wrap">
614
+ <h2>Every CNC shop pays for the <em>same five tools</em>. Every day.</h2>
615
+ <p class="sub">SolidWorks or Fusion, Mastercam or HSM, a simulator if you can afford one, a post for your specific machine, and some patchwork control software. Five subscriptions. Four file exchanges. Hours of context switching per part.</p>
616
+ <div class="problem-grid">
617
+ <div class="problem-card"><div class="icon">$$</div><div class="ttt"></div><div class="ttl">CAD tool</div><div class="sub">$1,500 – $4,500/yr</div></div>
618
+ <div class="problem-card"><div class="icon">$$</div><div class="ttl">CAM tool</div><div class="sub">$2,000 – $12,000/yr</div></div>
619
+ <div class="problem-card"><div class="icon">$$</div><div class="ttl">Simulator</div><div class="sub">$1,500 – $8,000/yr</div></div>
620
+ <div class="problem-card"><div class="icon">$$</div><div class="ttl">Post-proc.</div><div class="sub">Custom, per machine</div></div>
621
+ <div class="problem-card"><div class="icon">$$</div><div class="ttl">Controller UI</div><div class="sub">Vendor-locked</div></div>
622
+ </div>
623
+ <div class="vs-line">Pentacad is what happens when you refuse to accept that.</div>
624
+ </div>
625
+ </section>
626
+
627
+ <!-- SOLUTION -->
628
+ <section class="solution" data-animate>
629
+ <div class="wrap">
630
+ <div class="header-block">
631
+ <span class="section-kicker">The solution</span>
632
+ <h2>Five modules. <em>One</em> browser tab.</h2>
633
+ <p class="sub">Pentacad is the CAM stage of the cycleCAD Suite. It picks up where cycleCAD hands off a model and produces verified, posted, streamable G-code — without leaving the browser.</p>
634
+ </div>
635
+
636
+ <div class="five-modules">
637
+ <div class="mod-card">
638
+ <div class="mod-num">01</div>
639
+ <h3>Setup Manager</h3>
640
+ <p>3+2 tilt-plane selection, WCS alignment, stock definition, fixture offsets. Pull parts directly from cycleCAD — no STEP round-trip.</p>
641
+ </div>
642
+ <div class="mod-card">
643
+ <div class="mod-num">02</div>
644
+ <h3>CAM Strategies</h3>
645
+ <p>12 toolpath strategies covering 2D, 3D, drilling, and finishing. Adaptive clear, parallel, scallop, projection, flow — the core you'd expect from a pro CAM.</p>
646
+ </div>
647
+ <div class="mod-card">
648
+ <div class="mod-num">03</div>
649
+ <h3>A/B Simulator</h3>
650
+ <p>Forward-kinematics 5-axis replay. Soft-limit checking, stock removal, collision awareness. See the whole job before a chip flies.</p>
651
+ </div>
652
+ <div class="mod-card">
653
+ <div class="mod-num">04</div>
654
+ <h3>Post-Processor</h3>
655
+ <p>Pentamachine V2 <code>.ngc</code> dialect. G20 imperial, G93 inverse-time feed, A/B rotary, up to 40,000 RPM. Reverse-engineered from real sample files.</p>
656
+ </div>
657
+ <div class="mod-card">
658
+ <div class="mod-num">05</div>
659
+ <h3>Kinetic Bridge</h3>
660
+ <p>WebSocket client with live DRO, jog, stream, pause, abort, probe. Auto-reconnect on dropout. Browser talks to machine — no intermediate app.</p>
661
+ </div>
662
+ </div>
663
+ </div>
664
+ </section>
665
+
666
+ <!-- STRATEGIES -->
667
+ <section class="strategies" id="strategies" data-animate>
668
+ <div class="wrap">
669
+ <div class="header-block">
670
+ <span class="section-kicker">CAM Strategies</span>
671
+ <h2>Twelve strategies. <em>One</em> registry.</h2>
672
+ <p class="sub">Every strategy is a first-class module with its own parameters, parameter UI, and posting behaviour. Add your own — the registry is open.</p>
673
+ </div>
674
+
675
+ <div class="strat-grid">
676
+
677
+ <div class="strat-card">
678
+ <div class="icon"><svg viewBox="0 0 24 24"><path d="M3 12h18 M3 6h18 M3 18h18"/></svg></div>
679
+ <h4>2D Contour</h4>
680
+ <div class="kind">2D · Roughing</div>
681
+ <p>Offset-based contouring with ramp-in, lead-in/out and wear compensation.</p>
682
+ </div>
683
+
684
+ <div class="strat-card">
685
+ <div class="icon"><svg viewBox="0 0 24 24"><path d="M4 4h6v6H4z M14 4h6v6h-6z M4 14h6v6H4z M14 14h6v6h-6z"/></svg></div>
686
+ <h4>Adaptive Clear</h4>
687
+ <div class="kind">2D · Roughing</div>
688
+ <p>Trochoidal material removal with constant chip load. High-feed friendly.</p>
689
+ </div>
690
+
691
+ <div class="strat-card">
692
+ <div class="icon"><svg viewBox="0 0 24 24"><rect x="5" y="5" width="14" height="14" rx="2"/></svg></div>
693
+ <h4>Pocket</h4>
694
+ <div class="kind">2D · Pocketing</div>
695
+ <p>Zig-zag, spiral, or adaptive pocketing with multiple islands.</p>
696
+ </div>
697
+
698
+ <div class="strat-card">
699
+ <div class="icon"><svg viewBox="0 0 24 24"><circle cx="12" cy="12" r="2"/><circle cx="6" cy="6" r="1"/><circle cx="18" cy="6" r="1"/><circle cx="6" cy="18" r="1"/><circle cx="18" cy="18" r="1"/></svg></div>
700
+ <h4>Drill</h4>
701
+ <div class="kind">Drill · Hole ops</div>
702
+ <p>Peck, chip-break, deep-hole, tap, and spot-face canned cycles.</p>
703
+ </div>
704
+
705
+ <div class="strat-card">
706
+ <div class="icon"><svg viewBox="0 0 24 24"><path d="M4 20 L12 4 L20 20 M8 14h8"/></svg></div>
707
+ <h4>Parallel</h4>
708
+ <div class="kind">3D · Finishing</div>
709
+ <p>Axial pass pattern parallel to a chosen axis. Fast preview, clean walls.</p>
710
+ </div>
711
+
712
+ <div class="strat-card">
713
+ <div class="icon"><svg viewBox="0 0 24 24"><circle cx="12" cy="12" r="8"/><path d="M12 4 L12 20 M4 12 L20 12"/></svg></div>
714
+ <h4>Radial</h4>
715
+ <div class="kind">3D · Finishing</div>
716
+ <p>Radially-swept finishing around a spindle point — ideal for bowls, cups, profiles of revolution.</p>
717
+ </div>
718
+
719
+ <div class="strat-card">
720
+ <div class="icon"><svg viewBox="0 0 24 24"><path d="M4 18 Q12 4 20 18"/><path d="M4 14 Q12 2 20 14" opacity="0.4"/></svg></div>
721
+ <h4>Scallop</h4>
722
+ <div class="kind">3D · Finishing</div>
723
+ <p>Constant-scallop-height contour-parallel. Consistent surface finish on complex geometry.</p>
724
+ </div>
725
+
726
+ <div class="strat-card">
727
+ <div class="icon"><svg viewBox="0 0 24 24"><path d="M2 18 Q7 4 12 18 Q17 4 22 18"/></svg></div>
728
+ <h4>Projection</h4>
729
+ <div class="kind">3D · Engraving</div>
730
+ <p>Project a 2D curve onto the 3D model surface. Used for engraving and boundary finishing.</p>
731
+ </div>
732
+
733
+ <div class="strat-card">
734
+ <div class="icon"><svg viewBox="0 0 24 24"><path d="M3 6 C8 6 8 18 13 18 C18 18 18 6 22 6"/></svg></div>
735
+ <h4>Flow</h4>
736
+ <div class="kind">3D · Finishing</div>
737
+ <p>Flow-line / morph finishing between guide curves. Smooth, UV-parallel toolpaths.</p>
738
+ </div>
739
+
740
+ <div class="strat-card">
741
+ <div class="icon"><svg viewBox="0 0 24 24"><circle cx="12" cy="12" r="7"/><circle cx="12" cy="12" r="3"/></svg></div>
742
+ <h4>Bore · Thread</h4>
743
+ <div class="kind">Drill · Precision</div>
744
+ <p>Single-pass bore, helical interpolate bore, and thread-mill canned cycles.</p>
745
+ </div>
746
+
747
+ <div class="strat-card">
748
+ <div class="icon"><svg viewBox="0 0 24 24"><path d="M4 20 L12 8 L20 20"/></svg></div>
749
+ <h4>Chamfer · Deburr</h4>
750
+ <div class="kind">2D · Finishing</div>
751
+ <p>Edge-following chamfer and deburr with V-bit or ball-endmill. Auto-detect sharp edges.</p>
752
+ </div>
753
+
754
+ <div class="strat-card">
755
+ <div class="icon"><svg viewBox="0 0 24 24"><rect x="3" y="9" width="18" height="6" rx="1"/></svg></div>
756
+ <h4>Face</h4>
757
+ <div class="kind">2D · Facing</div>
758
+ <p>Stock-top facing with climb or conventional cut, configurable stepover.</p>
759
+ </div>
760
+
761
+ </div>
762
+ </div>
763
+ </section>
764
+
765
+ <!-- POST PROCESSOR -->
766
+ <section class="post-section" data-animate>
767
+ <div class="wrap post-layout">
768
+ <div class="post-body">
769
+ <span class="section-kicker">Post-processor</span>
770
+ <h2>The <em>exact</em> Pentamachine dialect.</h2>
771
+ <p>Pentacad's post emits G-code in the exact Pentamachine V2 <code class="inline">.ngc</code> dialect — reverse-engineered from Matt's real sample files. No tweaking, no hand-editing, no guessing.</p>
772
+ <p>Generated programs run end-to-end on V2-10, V2-50CHB, and V2-50CHK without modification.</p>
773
+ <ul class="feature-list">
774
+ <li><code class="inline">G20</code> imperial units (and <code class="inline">G21</code> metric via config)</li>
775
+ <li><code class="inline">G17</code> XY workplane · <code class="inline">G90</code> absolute · <code class="inline">G54</code> WCS</li>
776
+ <li><code class="inline">G94</code> feed-per-minute and <code class="inline">G93</code> inverse-time for 5-axis</li>
777
+ <li>5 axes: <code class="inline">X Y Z A B</code> — A tilts, B rotates, up to 40,000 RPM spindle</li>
778
+ <li><code class="inline">M7</code> mist / <code class="inline">M8</code> flood / <code class="inline">M9</code> off · full tool-change with <code class="inline">Tn M6</code></li>
779
+ </ul>
780
+ </div>
781
+
782
+ <div class="ngc-block">
783
+ <div class="hd">
784
+ <span class="dots"><span></span><span></span><span></span></span>
785
+ <span>ring-outer-contour.ngc</span>
786
+ </div>
787
+ <pre>%
788
+ <span class="cm">(AXIS,stop)</span>
789
+ <span class="cm">(PENTACAD GENERATED — Pentamachine V2 dialect)</span>
790
+ <span class="cm">(OP: Adaptive Clear — Setup 1)</span>
791
+ N10 <span class="kw">G20</span> <span class="kw">G17</span> <span class="kw">G90</span> <span class="kw">G40</span> <span class="kw">G54</span>
792
+ N15 <span class="kw">G94</span>
793
+ N20 <span class="kw">T</span><span class="val">1</span> <span class="kw">M6</span> <span class="cm">(T1: 1/4" flat carbide)</span>
794
+ N25 <span class="kw">M3</span> <span class="kw">S</span><span class="val">18000</span> <span class="kw">M7</span>
795
+ N30 <span class="kw">G0</span> <span class="ax">X</span><span class="val">0.0</span> <span class="ax">Y</span><span class="val">0.0</span> <span class="ax">Z</span><span class="val">0.25</span>
796
+ N35 <span class="kw">G0</span> <span class="ax">A</span><span class="val">22.5</span> <span class="ax">B</span><span class="val">0.0</span> <span class="cm">(tilt plane)</span>
797
+ N40 <span class="kw">G93</span> <span class="cm">(inverse-time feed)</span>
798
+ N45 <span class="kw">G1</span> <span class="ax">X</span><span class="val">0.052</span> <span class="ax">Y</span><span class="val">0.310</span> <span class="ax">Z</span><span class="val">0.118</span> <span class="ax">F</span><span class="val">28.3</span>
799
+ N50 <span class="kw">G1</span> <span class="ax">X</span><span class="val">0.104</span> <span class="ax">Y</span><span class="val">0.612</span> <span class="ax">Z</span><span class="val">0.095</span> <span class="ax">F</span><span class="val">31.1</span>
800
+ <span class="cm">... 4,238 lines of toolpath ...</span>
801
+ N4290 <span class="kw">G94</span>
802
+ N4295 <span class="kw">M5</span> <span class="kw">M9</span>
803
+ N4300 <span class="kw">M30</span>
804
+ %</pre>
805
+ </div>
806
+ </div>
807
+ </section>
808
+
809
+ <!-- SIMULATOR -->
810
+ <section class="sim-section" data-animate>
811
+ <div class="wrap sim-layout">
812
+ <div class="sim-visual" aria-hidden="true">
813
+ <svg viewBox="0 0 300 270" xmlns="http://www.w3.org/2000/svg">
814
+ <!-- A-axis arc -->
815
+ <g class="a-rot">
816
+ <path d="M 80 200 A 90 90 0 0 1 220 200" fill="none" stroke="#2E86DE" stroke-width="0.6" stroke-dasharray="2 3" opacity="0.6"/>
817
+ </g>
818
+ <!-- B-axis circle (table) -->
819
+ <g class="b-rot">
820
+ <ellipse cx="150" cy="200" rx="75" ry="22" fill="none" stroke="#3AAFA9" stroke-width="0.8" stroke-dasharray="3 3" opacity="0.6"/>
821
+ <line x1="75" y1="200" x2="225" y2="200" stroke="#3AAFA9" stroke-width="0.4" opacity="0.3"/>
822
+ </g>
823
+ <!-- Table base -->
824
+ <ellipse cx="150" cy="205" rx="85" ry="26" fill="#1A2D50" stroke="#1E3A5F" stroke-width="1"/>
825
+ <!-- Stock (ring shape) -->
826
+ <ellipse cx="150" cy="195" rx="50" ry="16" fill="none" stroke="#D4A843" stroke-width="2" opacity="0.85"/>
827
+ <ellipse cx="150" cy="195" rx="32" ry="10" fill="#122240" stroke="#D4A843" stroke-width="1" opacity="0.7"/>
828
+ <!-- Toolpath -->
829
+ <path class="tp-path" d="M 100 195 C 120 175 180 175 200 195 C 180 215 120 215 100 195 Z"/>
830
+ <!-- Spindle with tool -->
831
+ <g transform="translate(150 90)">
832
+ <rect x="-14" y="-40" width="28" height="55" fill="#5A6B85" stroke="#8B9AB5" stroke-width="0.6" rx="3"/>
833
+ <rect x="-4" y="12" width="8" height="60" fill="#8B9AB5"/>
834
+ <polygon points="-4,72 4,72 0,82" fill="#F59E0B"/>
835
+ <circle cx="0" cy="85" r="10" fill="rgba(245,158,11,0.22)"/>
836
+ </g>
837
+ <!-- Axis labels -->
838
+ <text x="18" y="210" font-family="JetBrains Mono" font-size="10" fill="#8B9AB5">Y</text>
839
+ <text x="275" y="210" font-family="JetBrains Mono" font-size="10" fill="#8B9AB5">X</text>
840
+ <text x="150" y="25" font-family="JetBrains Mono" font-size="10" fill="#8B9AB5" text-anchor="middle">Z</text>
841
+ <text x="240" y="160" font-family="JetBrains Mono" font-size="9" fill="#2E86DE">A</text>
842
+ <text x="230" y="190" font-family="JetBrains Mono" font-size="9" fill="#3AAFA9">B</text>
843
+ </svg>
844
+ </div>
845
+
846
+ <div class="sim-body">
847
+ <span class="section-kicker">A/B Simulator</span>
848
+ <h2>Replay the whole job. <em>Before</em> a chip flies.</h2>
849
+ <p>A forward-kinematics simulator reads the generated G-code and animates the Pentamachine's exact A/B axis geometry. Tool head, A-tilt, B-rotary, and linear moves — all synchronised.</p>
850
+ <p>Soft-limit checking happens in real time, so a move that would crash the table stops the simulation with a line-number flag. Fix the strategy, re-post, re-simulate — no file export needed.</p>
851
+ <ul class="feature-list">
852
+ <li>Full 5-axis forward kinematics — modal G20/G90/G94/G93 tracked</li>
853
+ <li>Soft-limit flagging per axis with exact G-code line reference</li>
854
+ <li>Stock-removal rendering (Phase 2) — see material disappear</li>
855
+ <li>Collision detection against fixtures and table (Phase 2)</li>
856
+ <li>Adjustable playback speed · frame-scrub · bookmark key lines</li>
857
+ </ul>
858
+ </div>
859
+ </div>
860
+ </section>
861
+
862
+ <!-- BRIDGE -->
863
+ <section class="bridge" data-animate>
864
+ <div class="wrap">
865
+ <div class="header-block">
866
+ <span class="section-kicker">Kinetic Control Bridge</span>
867
+ <h2>Your browser is the <em>controller UI</em>.</h2>
868
+ <p class="sub">Pentacad includes a WebSocket client that streams G-code line-by-line to a Kinetic Control box, reading DRO and status back in real time. No vendor app. No middleman.</p>
869
+ </div>
870
+
871
+ <div class="bridge-diagram">
872
+ <div class="bridge-row">
873
+ <div class="bridge-node">
874
+ <div class="icn">🌐</div>
875
+ <h4>Browser (Pentacad)</h4>
876
+ <div class="ttag">WebSocket client</div>
877
+ </div>
878
+ <div class="bridge-arrow"><div class="packet"></div><div class="packet p2"></div></div>
879
+ <div class="bridge-node">
880
+ <div class="icn">🔌</div>
881
+ <h4>Kinetic Bridge</h4>
882
+ <div class="ttag">WS ⇄ LinuxCNC IPC</div>
883
+ </div>
884
+ <div class="bridge-arrow"><div class="packet"></div><div class="packet p2"></div></div>
885
+ <div class="bridge-node">
886
+ <div class="icn">⚙️</div>
887
+ <h4>Pentamachine V2</h4>
888
+ <div class="ttag">A/B kinematics · 40k RPM</div>
889
+ </div>
890
+ </div>
891
+
892
+ <div class="bridge-caption">
893
+ Stream G-code over <code>ws://</code>. Events fire in both directions.
894
+ </div>
895
+
896
+ <div class="bridge-events">
897
+ <div class="bridge-event"><span class="evt-name">pentacad:jog</span><div class="evt-sub">X+ / X- / Y+ / Y- / Z+ / Z- / A+ / B- · rapid or incremental</div></div>
898
+ <div class="bridge-event"><span class="evt-name">pentacad:stream</span><div class="evt-sub">line-by-line with backpressure · resumable on dropout</div></div>
899
+ <div class="bridge-event"><span class="evt-name">pentacad:dro</span><div class="evt-sub">machine position · work offset · feed rate · spindle RPM</div></div>
900
+ <div class="bridge-event"><span class="evt-name">pentacad:probe</span><div class="evt-sub">G38.x probing with result readback</div></div>
901
+ <div class="bridge-event"><span class="evt-name">pentacad:pause</span><div class="evt-sub">feed-hold · resume · optional-stop</div></div>
902
+ <div class="bridge-event"><span class="evt-name">pentacad:abort</span><div class="evt-sub">cycle-stop · safe Z · spindle off · coolant off</div></div>
903
+ </div>
904
+ </div>
905
+ </div>
906
+ </section>
907
+
908
+ <!-- MACHINES -->
909
+ <section class="machines" data-animate>
910
+ <div class="wrap">
911
+ <div class="header-block">
912
+ <span class="section-kicker">Machines</span>
913
+ <h2>The <em>Pentamachine V2</em> family.</h2>
914
+ <p class="sub">Phase 0 supports the three primary V2 variants. Kinematics JSON is versioned and editable — the schema is open for community contributions.</p>
915
+ </div>
916
+
917
+ <div class="machine-grid">
918
+ <div class="machine-card">
919
+ <div class="status-tag phase0">Phase 0</div>
920
+ <h4>V2-10</h4>
921
+ <div class="vendor">Penta Machine Company</div>
922
+ <p>Entry 5-axis with A/B table geometry.</p>
923
+ <div class="specs">
924
+ <div><span>Travel X/Y/Z</span><span>~10 × 7 × 5 in</span></div>
925
+ <div><span>A / B range</span><span>-35° to 135° · ±360°</span></div>
926
+ <div><span>Spindle</span><span>24k RPM · ER11</span></div>
927
+ <div><span>Kinematics JSON</span><span>template</span></div>
928
+ </div>
929
+ </div>
930
+
931
+ <div class="machine-card">
932
+ <div class="status-tag phase0">Phase 0</div>
933
+ <h4>V2-50CHB</h4>
934
+ <div class="vendor">Penta Machine Company · CHB variant</div>
935
+ <p>Larger envelope, bigger collet, higher torque.</p>
936
+ <div class="specs">
937
+ <div><span>Travel X/Y/Z</span><span>~50 × 40 × 30 mm</span></div>
938
+ <div><span>A / B range</span><span>-35° to 135° · ±360°</span></div>
939
+ <div><span>Spindle</span><span>40k RPM · ER20</span></div>
940
+ <div><span>Kinematics JSON</span><span>template</span></div>
941
+ </div>
942
+ </div>
943
+
944
+ <div class="machine-card">
945
+ <div class="status-tag phase0">Phase 0</div>
946
+ <h4>V2-50CHK</h4>
947
+ <div class="vendor">Penta Machine Company · CHK variant</div>
948
+ <p>High-rigidity frame, tool-length probing.</p>
949
+ <div class="specs">
950
+ <div><span>Travel X/Y/Z</span><span>~50 × 40 × 30 mm</span></div>
951
+ <div><span>A / B range</span><span>-35° to 135° · ±360°</span></div>
952
+ <div><span>Spindle</span><span>40k RPM · ER20 + probe</span></div>
953
+ <div><span>Kinematics JSON</span><span>template</span></div>
954
+ </div>
955
+ </div>
956
+ </div>
957
+ </div>
958
+ </section>
959
+
960
+ <!-- ROADMAP -->
961
+ <section class="roadmap" data-animate>
962
+ <div class="wrap">
963
+ <div class="header-block">
964
+ <span class="section-kicker">Roadmap</span>
965
+ <h2>Phased. <em>Honest</em> about where we are.</h2>
966
+ <p class="sub">Pentacad is young. The scaffold is in place. The strategies, post-processor, simulator, and bridge are each phased deliverables with clear exit criteria.</p>
967
+ </div>
968
+
969
+ <div class="phases">
970
+ <div class="phase done">
971
+ <div class="phase-dot"></div>
972
+ <span class="phase-num">Done</span>
973
+ <h4>Phase 0 · Foundations</h4>
974
+ <ul>
975
+ <li>Module scaffold</li>
976
+ <li>Machine JSON schema</li>
977
+ <li>G-code parser (G20/G90/G93/G94/G54)</li>
978
+ <li>Bridge protocol spec</li>
979
+ <li>Strategy registry (12)</li>
980
+ </ul>
981
+ </div>
982
+
983
+ <div class="phase active">
984
+ <div class="phase-dot"></div>
985
+ <span class="phase-num">In progress</span>
986
+ <h4>Phase 1 · CAM core</h4>
987
+ <ul>
988
+ <li>Setup manager UI</li>
989
+ <li>2D Contour + Adaptive + Pocket + Face</li>
990
+ <li>Drill canned cycles</li>
991
+ <li>Post-processor emission</li>
992
+ <li>Real Pentamachine kinematics (awaiting V2 specs)</li>
993
+ </ul>
994
+ </div>
995
+
996
+ <div class="phase next">
997
+ <div class="phase-dot"></div>
998
+ <span class="phase-num">Next</span>
999
+ <h4>Phase 2 · 3D + Sim</h4>
1000
+ <ul>
1001
+ <li>3D finishing strategies (parallel, scallop, projection, flow)</li>
1002
+ <li>Forward-kinematics simulator</li>
1003
+ <li>Soft-limit + stock-removal</li>
1004
+ <li>Collision check</li>
1005
+ <li>WCS probing workflow</li>
1006
+ </ul>
1007
+ </div>
1008
+
1009
+ <div class="phase next">
1010
+ <div class="phase-dot"></div>
1011
+ <span class="phase-num">Later</span>
1012
+ <h4>Phase 3 · Live bridge</h4>
1013
+ <ul>
1014
+ <li>Kinetic Control WS bridge</li>
1015
+ <li>Jog · stream · DRO · pause · abort</li>
1016
+ <li>G38 probing</li>
1017
+ <li>Offline queue with resume</li>
1018
+ <li>Multi-machine dashboard</li>
1019
+ </ul>
1020
+ </div>
1021
+ </div>
1022
+ </div>
1023
+ </section>
1024
+
1025
+ <!-- FINAL CTA -->
1026
+ <section class="cta-final">
1027
+ <div class="wrap">
1028
+ <h2>Ship chips. <em>Not</em> file exchanges.</h2>
1029
+ <p>Open Pentacad in the browser. Import a cycleCAD part. Generate a toolpath. Simulate. Post. Stream.</p>
1030
+ <div class="ctas">
1031
+ <a href="/app/pentacad.html" class="btn btn-primary">Launch Pentacad <span class="arrow">→</span></a>
1032
+ <a href="https://github.com/vvlars-cmd/cyclecad" class="btn btn-secondary">View on GitHub</a>
1033
+ <a href="mailto:sachin.kumar@cyclewash.com?subject=Pentacad%20pilot%20interest" class="btn btn-secondary">Talk about a pilot</a>
1034
+ </div>
1035
+ <div class="tiny">
1036
+ Pentacad is licensed <strong>AGPL-3.0</strong> (commercial dual-license available). Part of the <a href="/">cycleCAD Suite</a>.
1037
+ Built for the <a href="https://pentamachine.com/">Pentamachine V2</a> family of desktop 5-axis CNC.
1038
+ </div>
1039
+ </div>
1040
+ </section>
1041
+
1042
+ <!-- FOOTER -->
1043
+ <footer>
1044
+ <div class="wrap">
1045
+ <div class="row">
1046
+ <div class="col brand-col">
1047
+ <span class="brand">cycle<em>CAD</em> suite</span>
1048
+ <p>From idea to finished part, in one browser tab. Open-source CAD for designers, makers, and CNC shops.</p>
1049
+ </div>
1050
+ <div class="col">
1051
+ <h4>Products</h4>
1052
+ <a href="/app/">cycleCAD</a>
1053
+ <a href="https://explodeview.com/">ExplodeView</a>
1054
+ <a href="/pentacad.html">Pentacad</a>
1055
+ </div>
1056
+ <div class="col">
1057
+ <h4>Resources</h4>
1058
+ <a href="https://github.com/vvlars-cmd/cyclecad#readme">Documentation</a>
1059
+ <a href="https://github.com/vvlars-cmd/cyclecad/blob/main/cycleCAD-Architecture.pptx">Architecture</a>
1060
+ <a href="https://github.com/vvlars-cmd/cyclecad/blob/main/docs/API-REFERENCE.md">API reference</a>
1061
+ </div>
1062
+ <div class="col">
1063
+ <h4>Developers</h4>
1064
+ <a href="https://github.com/vvlars-cmd/cyclecad">GitHub</a>
1065
+ <a href="https://www.npmjs.com/package/cyclecad">npm</a>
1066
+ <a href="https://github.com/vvlars-cmd/cyclecad/blob/main/server/mcp-server.js">MCP server</a>
1067
+ </div>
1068
+ <div class="col">
1069
+ <h4>Contact</h4>
1070
+ <a href="mailto:sachin.kumar@cyclewash.com">Email</a>
1071
+ <a href="https://cyclewash.de/en">cycleWASH</a>
1072
+ </div>
1073
+ </div>
1074
+ <div class="legal">
1075
+ <span>© 2026 cycleCAD Suite · Sachin Kumar</span>
1076
+ <span>cycleCAD MIT · ExplodeView MIT · Pentacad AGPL-3.0</span>
1077
+ </div>
1078
+ </div>
1079
+ </footer>
1080
+
1081
+ <script>
1082
+ (() => {
1083
+ const els = document.querySelectorAll('[data-animate]');
1084
+ const obs = new IntersectionObserver((entries) => {
1085
+ entries.forEach((e) => {
1086
+ if (e.isIntersecting) {
1087
+ e.target.classList.add('in-view');
1088
+ obs.unobserve(e.target);
1089
+ }
1090
+ });
1091
+ }, { threshold: 0.12 });
1092
+ els.forEach((el) => obs.observe(el));
1093
+ })();
1094
+ </script>
1095
+
1096
+ </body>
1097
+ </html>