cyclecad 3.11.0 → 3.13.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.
@@ -0,0 +1,1102 @@
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>ExplodeView — 3D viewer, AR, AI render · cycleCAD Suite</title>
7
+ <meta name="description" content="ExplodeView: browser-based 3D viewer with AR mode, AI render (Gemini Nano Banana v2 preservation-first), AI part identifier with McMaster-Carr matches. MIT. Part of the cycleCAD Suite." />
8
+ <meta name="keywords" content="ExplodeView, 3D viewer, STEP viewer, AR CAD, WebXR, AI render, Gemini Nano Banana, McMaster-Carr, exploded view, cycleCAD Suite" />
9
+ <meta name="author" content="Sachin Kumar" />
10
+ <link rel="canonical" href="https://cyclecad.com/explodeview.html" />
11
+ <meta property="og:type" content="website" />
12
+ <meta property="og:site_name" content="cycleCAD Suite" />
13
+ <meta property="og:title" content="ExplodeView — 3D viewer, AR, AI render" />
14
+ <meta property="og:description" content="Any STEP file. A marketing-ready 3D experience. In seconds. Exploded views, AI renders, AR walkthroughs, McMaster-matched part identifiers — all in one browser tab." />
15
+ <meta property="og:url" content="https://cyclecad.com/explodeview.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="ExplodeView — 3D viewer, AR, AI render" />
19
+ <meta name="twitter:description" content="Exploded views, AI renders, AR walkthroughs, McMaster-matched part identifiers — 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
+ --teal-2: #5ACCC5;
44
+ --teal-3: rgba(58,175,169,0.14);
45
+ --emerald: #10B981;
46
+ --emerald-2: #34D399;
47
+ --emerald-3: rgba(16,185,129,0.12);
48
+ --purple: #8B6FC0;
49
+ --amber: #F59E0B;
50
+ --red: #EF4444;
51
+ --t-fast: 0.18s;
52
+ --t-med: 0.35s;
53
+ --t-slow: 0.8s;
54
+ --ease: cubic-bezier(0.22, 0.61, 0.36, 1);
55
+ }
56
+
57
+ * { margin: 0; padding: 0; box-sizing: border-box; }
58
+ html { scroll-behavior: smooth; }
59
+ body {
60
+ font-family: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif;
61
+ font-weight: 400;
62
+ background: var(--bg);
63
+ color: var(--text);
64
+ line-height: 1.65;
65
+ overflow-x: hidden;
66
+ -webkit-font-smoothing: antialiased;
67
+ }
68
+ h1, h2, h3, h4 { font-family: 'Fraunces', Georgia, serif; font-weight: 700; line-height: 1.15; letter-spacing: -0.015em; color: var(--text); }
69
+ em { font-style: italic; color: var(--teal-2); font-weight: 700; }
70
+ code, pre { font-family: 'JetBrains Mono', ui-monospace, monospace; }
71
+
72
+ .wrap { max-width: 1280px; margin: 0 auto; padding: 0 32px; }
73
+
74
+ /* ─────────────────────────────────────────────
75
+ NAV — matches suite landing
76
+ ───────────────────────────────────────────── */
77
+ nav {
78
+ position: sticky; top: 0; z-index: 50;
79
+ background: rgba(10, 22, 40, 0.72);
80
+ backdrop-filter: blur(20px) saturate(1.5);
81
+ border-bottom: 1px solid var(--border);
82
+ padding: 16px 0;
83
+ }
84
+ nav .wrap { display: flex; align-items: center; justify-content: space-between; gap: 24px; }
85
+ .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; }
86
+ .brand .logo { display: inline-grid; place-items: center; width: 30px; height: 30px; border-radius: 8px; background: linear-gradient(135deg, var(--gold), var(--teal)); color: var(--bg); font-size: 0.9rem; }
87
+ .brand em { color: var(--gold); font-style: italic; }
88
+ nav .links { display: flex; align-items: center; gap: 24px; font-size: 0.95rem; }
89
+ nav .links a { color: var(--text-2); text-decoration: none; transition: color var(--t-fast); }
90
+ nav .links a:hover { color: var(--text); }
91
+ nav .links a.cta {
92
+ background: linear-gradient(135deg, var(--teal), var(--blue));
93
+ color: var(--bg); padding: 8px 16px; border-radius: 24px;
94
+ font-weight: 600; transition: transform var(--t-fast), box-shadow var(--t-fast);
95
+ }
96
+ nav .links a.cta:hover { transform: translateY(-1px); box-shadow: 0 6px 18px rgba(58,175,169,0.32); }
97
+ @media (max-width: 720px) { nav .links a:not(.cta) { display: none; } }
98
+
99
+ /* ─────────────────────────────────────────────
100
+ HERO
101
+ ───────────────────────────────────────────── */
102
+ .hero {
103
+ position: relative;
104
+ padding: 120px 0 100px;
105
+ background:
106
+ radial-gradient(ellipse 1000px 450px at 20% 0%, rgba(58,175,169,0.16), transparent 60%),
107
+ radial-gradient(ellipse 800px 350px at 80% 30%, rgba(46,134,222,0.12), transparent 60%),
108
+ var(--bg);
109
+ overflow: hidden;
110
+ }
111
+ .hero::before {
112
+ content: ''; position: absolute; inset: 0;
113
+ 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>");
114
+ opacity: 0.35; pointer-events: none;
115
+ }
116
+ .hero .wrap { position: relative; z-index: 1; display: grid; grid-template-columns: 1.1fr 1fr; gap: 72px; align-items: center; }
117
+ .hero .kicker {
118
+ display: inline-flex; align-items: center; gap: 8px;
119
+ padding: 6px 14px; border-radius: 24px; font-size: 0.78rem; font-weight: 600;
120
+ color: var(--teal-2); background: var(--teal-3); border: 1px solid rgba(58,175,169,0.38);
121
+ letter-spacing: 0.6px; text-transform: uppercase; margin-bottom: 24px;
122
+ }
123
+ .hero .kicker .dot { width: 8px; height: 8px; border-radius: 50%; background: var(--teal); animation: dotPulse 1.8s ease-in-out infinite; box-shadow: 0 0 12px var(--teal); }
124
+ @keyframes dotPulse { 0%, 100% { opacity: 1; } 50% { opacity: 0.35; } }
125
+ .hero h1 { font-size: clamp(2.6rem, 5vw, 4.2rem); max-width: 680px; margin-bottom: 24px; font-weight: 900; }
126
+ .hero p.lead { font-size: 1.2rem; color: var(--text-2); max-width: 620px; margin-bottom: 36px; }
127
+ .hero .ctas { display: flex; gap: 14px; flex-wrap: wrap; }
128
+ .btn {
129
+ display: inline-flex; align-items: center; gap: 10px;
130
+ padding: 14px 26px; border-radius: 30px; font-weight: 600; font-size: 0.98rem;
131
+ text-decoration: none; transition: transform var(--t-fast), box-shadow var(--t-fast), background var(--t-fast);
132
+ }
133
+ .btn-primary { background: linear-gradient(135deg, var(--teal), var(--blue)); color: var(--bg); }
134
+ .btn-primary:hover { transform: translateY(-2px); box-shadow: 0 10px 30px rgba(58,175,169,0.38); }
135
+ .btn-secondary { background: transparent; color: var(--text); border: 1px solid var(--border-hi); }
136
+ .btn-secondary:hover { background: rgba(255,255,255,0.04); border-color: var(--teal); color: var(--teal-2); }
137
+ .btn .arrow { transition: transform var(--t-fast); }
138
+ .btn:hover .arrow { transform: translateX(4px); }
139
+
140
+ /* Hero visual — exploded assembly */
141
+ .hero-visual {
142
+ position: relative; aspect-ratio: 1 / 1; max-width: 460px; justify-self: end;
143
+ background: radial-gradient(circle at 50% 50%, rgba(58,175,169,0.1), transparent 70%);
144
+ border-radius: 50%;
145
+ }
146
+ .hero-visual svg { width: 100%; height: 100%; }
147
+ .hero-visual .p1 { animation: pop1 5s ease-in-out infinite; transform-origin: 150px 150px; }
148
+ .hero-visual .p2 { animation: pop2 5s ease-in-out infinite; transform-origin: 150px 150px; }
149
+ .hero-visual .p3 { animation: pop3 5s ease-in-out infinite; transform-origin: 150px 150px; }
150
+ .hero-visual .p4 { animation: pop4 5s ease-in-out infinite; transform-origin: 150px 150px; }
151
+ .hero-visual .p5 { animation: pop5 5s ease-in-out infinite; transform-origin: 150px 150px; }
152
+ .hero-visual .p6 { animation: pop6 5s ease-in-out infinite; transform-origin: 150px 150px; }
153
+ @keyframes pop1 { 0%, 100% { transform: translate(0, 0); } 50% { transform: translate(-36px, -32px); } }
154
+ @keyframes pop2 { 0%, 100% { transform: translate(0, 0); } 50% { transform: translate(38px, -28px); } }
155
+ @keyframes pop3 { 0%, 100% { transform: translate(0, 0); } 50% { transform: translate(-40px, 30px); } }
156
+ @keyframes pop4 { 0%, 100% { transform: translate(0, 0); } 50% { transform: translate(42px, 34px); } }
157
+ @keyframes pop5 { 0%, 100% { transform: translate(0, 0); } 50% { transform: translate(0, -52px); } }
158
+ @keyframes pop6 { 0%, 100% { transform: translate(0, 0); } 50% { transform: translate(0, 48px); } }
159
+ .hero-visual .trail { stroke-dasharray: 4 4; animation: dashMove 12s linear infinite; }
160
+ @keyframes dashMove { to { stroke-dashoffset: -160; } }
161
+
162
+ @media (max-width: 920px) {
163
+ .hero { padding: 80px 0 60px; }
164
+ .hero .wrap { grid-template-columns: 1fr; gap: 40px; }
165
+ .hero-visual { max-width: 360px; justify-self: center; }
166
+ }
167
+
168
+ /* ─────────────────────────────────────────────
169
+ PROBLEM STRIP
170
+ ───────────────────────────────────────────── */
171
+ .problem {
172
+ padding: 70px 0;
173
+ background: var(--bg-alt);
174
+ border-top: 1px solid var(--border);
175
+ border-bottom: 1px solid var(--border);
176
+ }
177
+ .problem h2 { font-size: clamp(1.6rem, 3vw, 2.2rem); max-width: 740px; margin: 0 auto 14px; text-align: center; }
178
+ .problem .sub { color: var(--text-2); text-align: center; max-width: 760px; margin: 0 auto 40px; }
179
+ .problem-grid { display: grid; grid-template-columns: repeat(5, 1fr); gap: 14px; }
180
+ .problem-card {
181
+ padding: 18px 16px; border-radius: 12px;
182
+ background: var(--bg); border: 1px solid var(--border);
183
+ text-align: center;
184
+ }
185
+ .problem-card .icon {
186
+ width: 38px; height: 38px; display: grid; place-items: center; margin: 0 auto 10px;
187
+ border-radius: 10px; background: rgba(239,68,68,0.12); color: var(--red); font-size: 1.2rem;
188
+ }
189
+ .problem-card .ttl { font-weight: 600; font-size: 0.95rem; margin-bottom: 4px; color: var(--text); }
190
+ .problem-card .sub { font-size: 0.78rem; color: var(--text-3); margin-bottom: 0; }
191
+ @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; } }
192
+ @media (max-width: 560px) { .problem-grid { grid-template-columns: repeat(2, 1fr); } }
193
+
194
+ .vs-line {
195
+ position: relative; margin: 40px 0 0; text-align: center;
196
+ font-family: 'Fraunces', serif; font-style: italic; font-size: 1.15rem; color: var(--text-2);
197
+ }
198
+ .vs-line::before, .vs-line::after {
199
+ content: ''; display: inline-block; width: 64px; height: 1px;
200
+ background: linear-gradient(to right, transparent, var(--border-hi));
201
+ vertical-align: middle; margin: 0 12px;
202
+ }
203
+ .vs-line::after { background: linear-gradient(to left, transparent, var(--border-hi)); }
204
+
205
+ /* ─────────────────────────────────────────────
206
+ SOLUTION — five modules
207
+ ───────────────────────────────────────────── */
208
+ .solution { padding: 100px 0; }
209
+ .solution .header-block { text-align: center; max-width: 760px; margin: 0 auto 60px; }
210
+ .section-kicker {
211
+ display: inline-block; font-size: 0.72rem; letter-spacing: 2.5px; text-transform: uppercase;
212
+ color: var(--teal-2); font-weight: 700; margin-bottom: 16px;
213
+ }
214
+ .solution h2 { font-size: clamp(2rem, 4vw, 3rem); margin-bottom: 16px; }
215
+ .solution p.sub { color: var(--text-2); font-size: 1.08rem; }
216
+
217
+ .five-modules { display: grid; grid-template-columns: repeat(5, 1fr); gap: 20px; }
218
+ .mod-card {
219
+ position: relative;
220
+ padding: 28px 22px; border-radius: 16px;
221
+ background: var(--bg-alt); border: 1px solid var(--border);
222
+ transition: transform var(--t-med), border-color var(--t-med), box-shadow var(--t-med);
223
+ }
224
+ .mod-card:hover {
225
+ transform: translateY(-4px);
226
+ border-color: rgba(58,175,169,0.45);
227
+ box-shadow: 0 12px 32px rgba(58,175,169,0.16);
228
+ }
229
+ .mod-num {
230
+ display: grid; place-items: center;
231
+ width: 28px; height: 28px; border-radius: 8px;
232
+ background: var(--teal-3); color: var(--teal-2);
233
+ font: 700 0.82rem 'JetBrains Mono'; margin-bottom: 14px;
234
+ }
235
+ .mod-card h3 { font-size: 1.05rem; font-family: 'Inter', sans-serif; font-weight: 700; margin-bottom: 8px; }
236
+ .mod-card p { font-size: 0.88rem; color: var(--text-2); line-height: 1.55; }
237
+ @media (max-width: 920px) { .five-modules { grid-template-columns: repeat(2, 1fr); } }
238
+ @media (max-width: 520px) { .five-modules { grid-template-columns: 1fr; } }
239
+
240
+ /* ─────────────────────────────────────────────
241
+ FEATURES GRID
242
+ ───────────────────────────────────────────── */
243
+ .strategies { padding: 100px 0; background: var(--bg-alt); }
244
+ .strategies .header-block { text-align: center; max-width: 720px; margin: 0 auto 50px; }
245
+ .strategies h2 { font-size: clamp(2rem, 4vw, 2.8rem); margin-bottom: 14px; }
246
+ .strategies p.sub { color: var(--text-2); }
247
+ .strat-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 16px; }
248
+ .strat-card {
249
+ padding: 22px 20px; border-radius: 14px;
250
+ background: var(--bg); border: 1px solid var(--border);
251
+ transition: all var(--t-med);
252
+ }
253
+ .strat-card:hover { border-color: var(--teal); transform: translateY(-3px); }
254
+ .strat-card .icon {
255
+ width: 40px; height: 40px; border-radius: 10px;
256
+ background: var(--teal-3); margin-bottom: 14px;
257
+ display: grid; place-items: center;
258
+ }
259
+ .strat-card .icon svg { width: 20px; height: 20px; stroke: var(--teal-2); stroke-width: 2; fill: none; }
260
+ .strat-card h4 { font-size: 1rem; font-family: 'Inter', sans-serif; font-weight: 700; margin-bottom: 4px; }
261
+ .strat-card .kind { font-size: 0.72rem; font-family: 'JetBrains Mono'; color: var(--text-3); text-transform: uppercase; letter-spacing: 1px; margin-bottom: 8px; }
262
+ .strat-card p { font-size: 0.84rem; color: var(--text-2); line-height: 1.5; }
263
+ @media (max-width: 920px) { .strat-grid { grid-template-columns: repeat(2, 1fr); } }
264
+ @media (max-width: 520px) { .strat-grid { grid-template-columns: 1fr; } }
265
+
266
+ /* ─────────────────────────────────────────────
267
+ AI RENDER — side-by-side with prompt sample
268
+ ───────────────────────────────────────────── */
269
+ .post-section { padding: 100px 0; }
270
+ .post-layout { display: grid; grid-template-columns: 1fr 1fr; gap: 60px; align-items: center; }
271
+ .post-body h2 { font-size: clamp(1.9rem, 3.5vw, 2.6rem); margin-bottom: 16px; }
272
+ .post-body p { color: var(--text-2); margin-bottom: 14px; font-size: 1.02rem; }
273
+ .post-body .feature-list { list-style: none; margin-top: 26px; }
274
+ .post-body .feature-list li {
275
+ position: relative; padding-left: 24px; margin-bottom: 10px;
276
+ color: var(--text); font-size: 0.95rem;
277
+ }
278
+ .post-body .feature-list li::before {
279
+ content: '✓'; position: absolute; left: 0; top: 0;
280
+ width: 16px; height: 16px; background: var(--teal-3); color: var(--teal-2);
281
+ border-radius: 4px; display: grid; place-items: center;
282
+ font-size: 0.78rem; font-weight: 700;
283
+ }
284
+ .post-body code.inline {
285
+ background: var(--bg-card); color: var(--teal-2); padding: 2px 7px; border-radius: 4px;
286
+ font-size: 0.88em;
287
+ }
288
+
289
+ .ngc-block {
290
+ position: relative;
291
+ background: var(--bg-alt);
292
+ border: 1px solid var(--border); border-radius: 14px;
293
+ overflow: hidden;
294
+ font-family: 'JetBrains Mono', ui-monospace, monospace;
295
+ font-size: 0.82rem;
296
+ }
297
+ .ngc-block .hd {
298
+ padding: 10px 16px; background: var(--bg-card);
299
+ border-bottom: 1px solid var(--border);
300
+ display: flex; align-items: center; justify-content: space-between;
301
+ color: var(--text-2); font-size: 0.78rem; letter-spacing: 1px; text-transform: uppercase;
302
+ }
303
+ .ngc-block .hd .dots { display: inline-flex; gap: 5px; }
304
+ .ngc-block .hd .dots span { width: 9px; height: 9px; border-radius: 50%; background: var(--border-hi); }
305
+ .ngc-block pre {
306
+ padding: 18px 18px 22px;
307
+ color: var(--text); line-height: 1.65;
308
+ overflow-x: auto; white-space: pre-wrap;
309
+ }
310
+ .ngc-block .kw { color: var(--teal-2); font-weight: 700; }
311
+ .ngc-block .val { color: var(--gold-2); }
312
+ .ngc-block .cm { color: var(--text-3); font-style: italic; }
313
+ .ngc-block .ax { color: var(--blue); }
314
+ @media (max-width: 900px) { .post-layout { grid-template-columns: 1fr; gap: 40px; } }
315
+
316
+ /* ─────────────────────────────────────────────
317
+ AR SECTION
318
+ ───────────────────────────────────────────── */
319
+ .sim-section { padding: 100px 0; background: var(--bg-alt); }
320
+ .sim-layout { display: grid; grid-template-columns: 1fr 1fr; gap: 60px; align-items: center; }
321
+ .sim-layout.rev > :first-child { order: 2; }
322
+ .sim-visual {
323
+ aspect-ratio: 1.1 / 1;
324
+ background: radial-gradient(circle at 50% 50%, rgba(58,175,169,0.1), transparent 70%);
325
+ border-radius: 20px; border: 1px solid var(--border);
326
+ position: relative; overflow: hidden;
327
+ }
328
+ .sim-visual svg { width: 100%; height: 100%; }
329
+ .sim-visual .ar-float { animation: arFloat 4.2s ease-in-out infinite; transform-origin: 150px 110px; }
330
+ @keyframes arFloat {
331
+ 0%, 100% { transform: translateY(0); }
332
+ 50% { transform: translateY(-8px); }
333
+ }
334
+ .sim-visual .ar-parts { animation: arPartsSpread 6s ease-in-out infinite; }
335
+ @keyframes arPartsSpread {
336
+ 0%, 100% { transform: scale(1); }
337
+ 50% { transform: scale(1.08); }
338
+ }
339
+ .sim-visual .floor-grid { stroke-dasharray: 6 4; animation: floorScroll 14s linear infinite; }
340
+ @keyframes floorScroll { to { stroke-dashoffset: -120; } }
341
+ .sim-body h2 { font-size: clamp(1.9rem, 3.5vw, 2.6rem); margin-bottom: 16px; }
342
+ .sim-body p { color: var(--text-2); margin-bottom: 14px; font-size: 1.02rem; }
343
+ .sim-body .feature-list { list-style: none; margin-top: 22px; }
344
+ .sim-body .feature-list li { position: relative; padding-left: 24px; margin-bottom: 10px; font-size: 0.95rem; }
345
+ .sim-body .feature-list li::before {
346
+ content: '✓'; position: absolute; left: 0; top: 0;
347
+ width: 16px; height: 16px; background: var(--teal-3); color: var(--teal-2);
348
+ border-radius: 4px; display: grid; place-items: center;
349
+ font-size: 0.78rem; font-weight: 700;
350
+ }
351
+ @media (max-width: 900px) {
352
+ .sim-layout { grid-template-columns: 1fr; gap: 40px; }
353
+ .sim-layout.rev > :first-child { order: 0; }
354
+ }
355
+
356
+ /* ─────────────────────────────────────────────
357
+ McMASTER BRIDGE SECTION
358
+ ───────────────────────────────────────────── */
359
+ .bridge { padding: 100px 0; }
360
+ .bridge .header-block { text-align: center; max-width: 780px; margin: 0 auto 60px; }
361
+ .bridge h2 { font-size: clamp(1.9rem, 3.8vw, 2.7rem); margin-bottom: 16px; }
362
+ .bridge p.sub { color: var(--text-2); font-size: 1.05rem; }
363
+ .bridge-diagram {
364
+ position: relative;
365
+ padding: 60px 40px;
366
+ border-radius: 20px;
367
+ background: var(--bg-alt); border: 1px solid var(--border);
368
+ }
369
+ .bridge-row { display: grid; grid-template-columns: 1fr 90px 1fr 90px 1fr 90px 1fr; align-items: center; gap: 12px; }
370
+ .bridge-node {
371
+ padding: 22px 14px; border-radius: 14px;
372
+ background: var(--bg); border: 1px solid var(--border);
373
+ text-align: center;
374
+ }
375
+ .bridge-node .icn { font-size: 1.6rem; margin-bottom: 8px; }
376
+ .bridge-node h4 { font-size: 0.96rem; font-family: 'Inter', sans-serif; font-weight: 700; margin-bottom: 4px; }
377
+ .bridge-node .ttag { display: inline-block; font-size: 0.7rem; font-family: 'JetBrains Mono'; color: var(--text-3); }
378
+ .bridge-arrow { position: relative; height: 2px; background: linear-gradient(to right, var(--border-hi), var(--teal), var(--border-hi)); border-radius: 2px; }
379
+ .bridge-arrow::after {
380
+ content: ''; position: absolute; right: -2px; top: 50%; transform: translateY(-50%);
381
+ border-left: 8px solid var(--teal); border-top: 5px solid transparent; border-bottom: 5px solid transparent;
382
+ }
383
+ .bridge-arrow .packet {
384
+ position: absolute; top: 50%; left: 0; transform: translateY(-50%);
385
+ width: 10px; height: 10px; border-radius: 50%; background: var(--teal);
386
+ box-shadow: 0 0 14px var(--teal);
387
+ animation: packetFly 2.6s ease-in-out infinite;
388
+ }
389
+ .bridge-arrow .packet.p2 { animation-delay: 1s; }
390
+ @keyframes packetFly { 0% { left: 0; opacity: 0; } 10% { opacity: 1; } 80% { opacity: 1; } 100% { left: calc(100% - 10px); opacity: 0; } }
391
+ .bridge-caption { text-align: center; margin-top: 30px; color: var(--text-2); font-size: 0.92rem; }
392
+ .bridge-caption code { background: var(--bg-card); color: var(--teal-2); padding: 2px 7px; border-radius: 4px; font-size: 0.88em; }
393
+
394
+ .bridge-events {
395
+ margin-top: 36px;
396
+ display: grid; grid-template-columns: repeat(3, 1fr); gap: 12px;
397
+ }
398
+ .bridge-event {
399
+ padding: 14px 16px; border-radius: 10px;
400
+ background: var(--bg-card); border: 1px solid var(--border);
401
+ font-family: 'JetBrains Mono', monospace; font-size: 0.82rem;
402
+ }
403
+ .bridge-event .evt-name { color: var(--teal-2); }
404
+ .bridge-event .evt-sub { color: var(--text-3); font-size: 0.76rem; margin-top: 2px; }
405
+ @media (max-width: 1040px) {
406
+ .bridge-row { grid-template-columns: 1fr; gap: 8px; }
407
+ .bridge-arrow { height: 36px; width: 2px; margin: 0 auto; background: linear-gradient(to bottom, var(--border-hi), var(--teal), var(--border-hi)); }
408
+ .bridge-arrow::after { right: 50%; top: auto; bottom: -2px; transform: translateX(50%); border: 0; border-top: 8px solid var(--teal); border-left: 5px solid transparent; border-right: 5px solid transparent; }
409
+ .bridge-arrow .packet { animation: packetFlyV 2.6s ease-in-out infinite; }
410
+ .bridge-events { grid-template-columns: 1fr; }
411
+ }
412
+ @keyframes packetFlyV { 0% { top: 0; opacity: 0; } 10% { opacity: 1; } 80% { opacity: 1; } 100% { top: calc(100% - 10px); opacity: 0; } }
413
+
414
+ /* ─────────────────────────────────────────────
415
+ ROADMAP
416
+ ───────────────────────────────────────────── */
417
+ .roadmap { padding: 100px 0; background: var(--bg-alt); }
418
+ .roadmap .header-block { text-align: center; max-width: 720px; margin: 0 auto 60px; }
419
+ .roadmap h2 { font-size: clamp(1.9rem, 3.5vw, 2.6rem); margin-bottom: 14px; }
420
+ .roadmap p.sub { color: var(--text-2); }
421
+
422
+ .phases { display: grid; grid-template-columns: repeat(4, 1fr); gap: 16px; position: relative; }
423
+ .phases::before {
424
+ content: ''; position: absolute; top: 45px; left: 8%; right: 8%; height: 2px;
425
+ background: linear-gradient(to right, var(--teal), var(--amber), var(--border-hi), var(--border-hi));
426
+ z-index: 0;
427
+ }
428
+ .phase {
429
+ position: relative; z-index: 1;
430
+ padding: 24px 20px; border-radius: 14px;
431
+ background: var(--bg); border: 1px solid var(--border);
432
+ }
433
+ .phase-dot {
434
+ width: 18px; height: 18px; border-radius: 50%;
435
+ margin: 0 auto 12px; border: 3px solid var(--bg);
436
+ box-shadow: 0 0 0 2px var(--border-hi);
437
+ }
438
+ .phase.done .phase-dot { background: var(--teal); box-shadow: 0 0 0 2px var(--teal); }
439
+ .phase.active .phase-dot { background: var(--amber); box-shadow: 0 0 0 2px var(--amber); animation: pulseDot 1.8s ease-in-out infinite; }
440
+ .phase.next .phase-dot { background: var(--bg-card); box-shadow: 0 0 0 2px var(--border-hi); }
441
+ @keyframes pulseDot { 0%, 100% { transform: scale(1); } 50% { transform: scale(1.22); } }
442
+ .phase-num {
443
+ display: block; font-family: 'JetBrains Mono'; font-size: 0.78rem;
444
+ color: var(--text-3); letter-spacing: 1.5px; text-align: center; margin-bottom: 4px; text-transform: uppercase;
445
+ }
446
+ .phase h4 { text-align: center; font-size: 1rem; font-family: 'Inter', sans-serif; font-weight: 700; margin-bottom: 10px; }
447
+ .phase ul { list-style: none; }
448
+ .phase li { font-size: 0.82rem; color: var(--text-2); padding: 4px 0; border-bottom: 1px dashed var(--border); }
449
+ .phase li:last-child { border-bottom: 0; }
450
+ .phase.done { border-color: rgba(58,175,169,0.4); }
451
+ .phase.active { border-color: rgba(245,158,11,0.4); }
452
+ @media (max-width: 920px) { .phases { grid-template-columns: repeat(2, 1fr); } .phases::before { display: none; } }
453
+ @media (max-width: 520px) { .phases { grid-template-columns: 1fr; } }
454
+
455
+ /* ─────────────────────────────────────────────
456
+ FINAL CTA
457
+ ───────────────────────────────────────────── */
458
+ .cta-final {
459
+ padding: 110px 0;
460
+ background:
461
+ radial-gradient(ellipse 800px 400px at 50% 50%, rgba(58,175,169,0.16), transparent 60%),
462
+ var(--bg);
463
+ text-align: center;
464
+ }
465
+ .cta-final h2 { font-size: clamp(2rem, 4vw, 3rem); max-width: 780px; margin: 0 auto 16px; }
466
+ .cta-final p { color: var(--text-2); max-width: 680px; margin: 0 auto 36px; font-size: 1.05rem; }
467
+ .cta-final .ctas { display: flex; gap: 14px; justify-content: center; flex-wrap: wrap; }
468
+ .cta-final .tiny {
469
+ margin-top: 26px;
470
+ color: var(--text-3); font-size: 0.82rem;
471
+ }
472
+ .cta-final .tiny a { color: var(--text-2); text-decoration: underline; text-decoration-color: var(--border-hi); }
473
+ .cta-final .tiny a:hover { color: var(--teal-2); }
474
+
475
+ /* ─────────────────────────────────────────────
476
+ FOOTER — same as suite landing
477
+ ───────────────────────────────────────────── */
478
+ footer {
479
+ padding: 70px 0 40px;
480
+ background: var(--bg-alt);
481
+ border-top: 1px solid var(--border);
482
+ font-size: 0.9rem;
483
+ }
484
+ footer .row {
485
+ display: grid; grid-template-columns: 1.8fr 1fr 1fr 1fr 1fr; gap: 40px;
486
+ padding-bottom: 40px; border-bottom: 1px solid var(--border);
487
+ }
488
+ footer .brand-col p { color: var(--text-2); font-size: 0.92rem; margin-top: 14px; max-width: 320px; }
489
+ footer .col h4 {
490
+ font-size: 0.78rem; font-family: 'Inter', sans-serif; font-weight: 700;
491
+ text-transform: uppercase; letter-spacing: 1.5px; color: var(--text-3); margin-bottom: 14px;
492
+ }
493
+ footer .col a { display: block; color: var(--text-2); text-decoration: none; padding: 4px 0; transition: color var(--t-fast); }
494
+ footer .col a:hover { color: var(--teal-2); }
495
+ footer .legal {
496
+ margin-top: 30px; display: flex; justify-content: space-between; gap: 16px;
497
+ color: var(--text-3); font-size: 0.82rem; flex-wrap: wrap;
498
+ }
499
+ @media (max-width: 900px) { footer .row { grid-template-columns: 1fr 1fr; } }
500
+
501
+ /* ─────────────────────────────────────────────
502
+ SCROLL-TRIGGERED ANIMATION
503
+ ───────────────────────────────────────────── */
504
+ [data-animate] { opacity: 0; transform: translateY(24px); transition: opacity var(--t-slow) var(--ease), transform var(--t-slow) var(--ease); }
505
+ [data-animate].in-view { opacity: 1; transform: translateY(0); }
506
+ </style>
507
+ </head>
508
+ <body>
509
+
510
+ <nav>
511
+ <div class="wrap">
512
+ <a href="/" class="brand">
513
+ <span class="logo">⚙</span>
514
+ cycle<em>CAD</em> suite
515
+ </a>
516
+ <div class="links">
517
+ <a href="/">Suite</a>
518
+ <a href="/cyclecad.html">cycleCAD</a>
519
+ <a href="/pentacad.html">Pentacad</a>
520
+ <a href="#features">Features</a>
521
+ <a href="https://explodeview.com/" class="cta">Open ExplodeView →</a>
522
+ </div>
523
+ </div>
524
+ </nav>
525
+
526
+ <!-- HERO -->
527
+ <header class="hero">
528
+ <div class="wrap">
529
+ <div>
530
+ <div class="kicker">
531
+ <span class="dot"></span>
532
+ Live · v1.0.22 · MIT
533
+ </div>
534
+ <h1>
535
+ Any STEP file.<br/>
536
+ A <em>marketing-ready</em> 3D experience.<br/>
537
+ In seconds.
538
+ </h1>
539
+ <p class="lead">
540
+ ExplodeView is the presentation stage of the Suite. Drop a STEP or IAM in —
541
+ get an interactive exploded view, AI-rendered hero shots, AR walkthroughs,
542
+ and McMaster-matched part identifiers. All shareable via URL.
543
+ </p>
544
+ <div class="ctas">
545
+ <a href="https://explodeview.com/" class="btn btn-primary">Open ExplodeView <span class="arrow">→</span></a>
546
+ <a href="#features" class="btn btn-secondary">See features</a>
547
+ </div>
548
+ </div>
549
+
550
+ <div class="hero-visual" aria-hidden="true">
551
+ <svg viewBox="0 0 300 300" xmlns="http://www.w3.org/2000/svg">
552
+ <defs>
553
+ <radialGradient id="hero-core-ev" cx="50%" cy="50%">
554
+ <stop offset="0%" stop-color="#3AAFA9" stop-opacity="0.55"/>
555
+ <stop offset="70%" stop-color="#3AAFA9" stop-opacity="0.06"/>
556
+ <stop offset="100%" stop-color="#3AAFA9" stop-opacity="0"/>
557
+ </radialGradient>
558
+ <linearGradient id="part-teal" x1="0" x2="0" y1="0" y2="1">
559
+ <stop offset="0%" stop-color="#5ACCC5"/>
560
+ <stop offset="100%" stop-color="#3AAFA9"/>
561
+ </linearGradient>
562
+ <linearGradient id="part-gold" x1="0" x2="0" y1="0" y2="1">
563
+ <stop offset="0%" stop-color="#E8C065"/>
564
+ <stop offset="100%" stop-color="#D4A843"/>
565
+ </linearGradient>
566
+ <linearGradient id="part-blue" x1="0" x2="0" y1="0" y2="1">
567
+ <stop offset="0%" stop-color="#5BA0E6"/>
568
+ <stop offset="100%" stop-color="#2E86DE"/>
569
+ </linearGradient>
570
+ </defs>
571
+ <!-- Center glow -->
572
+ <circle cx="150" cy="150" r="110" fill="url(#hero-core-ev)"/>
573
+ <!-- Dashed trail rings connecting exploded parts -->
574
+ <g opacity="0.25" stroke="#3AAFA9" fill="none" stroke-width="1" class="trail">
575
+ <circle cx="150" cy="150" r="60"/>
576
+ <circle cx="150" cy="150" r="98"/>
577
+ </g>
578
+ <!-- Central hub -->
579
+ <g>
580
+ <rect x="130" y="130" width="40" height="40" rx="4" fill="url(#part-teal)" stroke="#2D8580" stroke-width="0.8"/>
581
+ <circle cx="150" cy="150" r="6" fill="#0A1628" opacity="0.5"/>
582
+ </g>
583
+ <!-- Exploded part 1 — top-left cylinder -->
584
+ <g class="p1">
585
+ <ellipse cx="100" cy="100" rx="16" ry="5" fill="url(#part-blue)" stroke="#1F5A9E" stroke-width="0.6"/>
586
+ <rect x="84" y="100" width="32" height="18" fill="url(#part-blue)" stroke="#1F5A9E" stroke-width="0.6"/>
587
+ <ellipse cx="100" cy="118" rx="16" ry="5" fill="#1F5A9E"/>
588
+ </g>
589
+ <!-- Exploded part 2 — top-right bolt -->
590
+ <g class="p2">
591
+ <polygon points="190,96 210,96 214,106 210,116 190,116 186,106" fill="url(#part-gold)" stroke="#8F7229" stroke-width="0.6"/>
592
+ <rect x="197" y="116" width="6" height="26" fill="#B89238"/>
593
+ </g>
594
+ <!-- Exploded part 3 — bottom-left washer -->
595
+ <g class="p3">
596
+ <ellipse cx="95" cy="205" rx="18" ry="6" fill="url(#part-teal)" stroke="#2D8580" stroke-width="0.6"/>
597
+ <ellipse cx="95" cy="205" rx="8" ry="3" fill="#0A1628"/>
598
+ </g>
599
+ <!-- Exploded part 4 — bottom-right bracket -->
600
+ <g class="p4">
601
+ <path d="M 180 200 L 215 200 L 215 220 L 195 220 L 195 214 L 180 214 Z" fill="url(#part-teal)" stroke="#2D8580" stroke-width="0.6"/>
602
+ </g>
603
+ <!-- Exploded part 5 — top plate -->
604
+ <g class="p5">
605
+ <rect x="130" y="65" width="40" height="14" rx="2" fill="url(#part-gold)" stroke="#8F7229" stroke-width="0.6"/>
606
+ <circle cx="138" cy="72" r="1.5" fill="#0A1628"/>
607
+ <circle cx="162" cy="72" r="1.5" fill="#0A1628"/>
608
+ </g>
609
+ <!-- Exploded part 6 — bottom plate -->
610
+ <g class="p6">
611
+ <rect x="128" y="225" width="44" height="14" rx="2" fill="url(#part-blue)" stroke="#1F5A9E" stroke-width="0.6"/>
612
+ <circle cx="136" cy="232" r="1.5" fill="#0A1628"/>
613
+ <circle cx="164" cy="232" r="1.5" fill="#0A1628"/>
614
+ </g>
615
+ <!-- Corner labels -->
616
+ <text x="16" y="24" font-family="JetBrains Mono" font-size="9" fill="#5A6B85">01</text>
617
+ <text x="270" y="24" font-family="JetBrains Mono" font-size="9" fill="#5A6B85">02</text>
618
+ <text x="16" y="288" font-family="JetBrains Mono" font-size="9" fill="#5A6B85">03</text>
619
+ <text x="272" y="288" font-family="JetBrains Mono" font-size="9" fill="#5A6B85">04</text>
620
+ </svg>
621
+ </div>
622
+ </div>
623
+ </header>
624
+
625
+ <!-- PROBLEM STRIP -->
626
+ <section class="problem" data-animate>
627
+ <div class="wrap">
628
+ <h2>Every CAD marketing asset used to take a <em>week</em>.</h2>
629
+ <p class="sub">STEP → SolidWorks Visualize → Photoshop retouch → PowerPoint for the exploded view → Adobe Dimension for the AR try-on. Five tools. Five handoffs. Five license fees.</p>
630
+ <div class="problem-grid">
631
+ <div class="problem-card"><div class="icon">$$</div><div class="ttl">KeyShot</div><div class="sub">~$995/yr</div></div>
632
+ <div class="problem-card"><div class="icon">$$</div><div class="ttl">SW Visualize</div><div class="sub">~$1,995/yr</div></div>
633
+ <div class="problem-card"><div class="icon">$$</div><div class="ttl">Autodesk VRED</div><div class="sub">~$4,495/yr</div></div>
634
+ <div class="problem-card"><div class="icon">$$</div><div class="ttl">Adobe Dimension</div><div class="sub">~$240/yr</div></div>
635
+ <div class="problem-card"><div class="icon">!!</div><div class="ttl">PowerPoint gymnastics</div><div class="sub">priceless frustration</div></div>
636
+ </div>
637
+ <div class="vs-line">ExplodeView does all of it in one browser tab.</div>
638
+ </div>
639
+ </section>
640
+
641
+ <!-- SOLUTION — 5 MODULES -->
642
+ <section class="solution" data-animate>
643
+ <div class="wrap">
644
+ <div class="header-block">
645
+ <span class="section-kicker">The Viewer Surface</span>
646
+ <h2>Five modules. <em>One</em> shareable URL.</h2>
647
+ <p class="sub">ExplodeView is the presentation stage of the cycleCAD Suite. It picks up a STEP, GLB, or IAM and turns it into something a product team, a marketing lead, or a field tech can actually use.</p>
648
+ </div>
649
+
650
+ <div class="five-modules">
651
+ <div class="mod-card">
652
+ <div class="mod-num">01</div>
653
+ <h3>Loader</h3>
654
+ <p>STEP / GLB / IAM import via server-side converter or browser WASM. Cached in IndexedDB. Survives tab refresh and 138MB assemblies.</p>
655
+ </div>
656
+ <div class="mod-card">
657
+ <div class="mod-num">02</div>
658
+ <h3>Interactive Viewer</h3>
659
+ <p>Assembly tree with AI drawings, 399-part performance, section cut X/Y/Z, annotations, 2-3 point measurements. Built on Three.js r170.</p>
660
+ </div>
661
+ <div class="mod-card">
662
+ <div class="mod-num">03</div>
663
+ <h3>AI Render</h3>
664
+ <p>Gemini Nano Banana v2 with preservation-first prompts. Photoreal any scene — forest, studio, factory — without the model redesigning your CAD.</p>
665
+ </div>
666
+ <div class="mod-card">
667
+ <div class="mod-num">04</div>
668
+ <h3>AR Mode</h3>
669
+ <p>WebXR hit-test + pinch-to-scale. iOS Safari 17+ and Chrome Android. Drop your assembly on the floor, walk around it, explode in place.</p>
670
+ </div>
671
+ <div class="mod-card">
672
+ <div class="mod-num">05</div>
673
+ <h3>AI Part Identifier</h3>
674
+ <p>Geometry-based classification with McMaster-Carr deep links + CSV BOM export. Click a mystery bolt, get a purchase link.</p>
675
+ </div>
676
+ </div>
677
+ </div>
678
+ </section>
679
+
680
+ <!-- FEATURES GRID -->
681
+ <section class="strategies" id="features" data-animate>
682
+ <div class="wrap">
683
+ <div class="header-block">
684
+ <span class="section-kicker">Viewer features</span>
685
+ <h2>Every tool a product team <em>needs</em>.</h2>
686
+ <p class="sub">45+ features shipped, all reachable from a tabbed toolbar. These are the 12 that matter most when you're presenting a physical product.</p>
687
+ </div>
688
+
689
+ <div class="strat-grid">
690
+
691
+ <div class="strat-card">
692
+ <div class="icon"><svg viewBox="0 0 24 24"><path d="M12 3v18 M4 7l8-4 8 4 M4 17l8 4 8-4 M4 7v10 M20 7v10"/></svg></div>
693
+ <h4>Exploded view</h4>
694
+ <div class="kind">Viewer · Core</div>
695
+ <p>Explosion slider + presets. Drag parts independently. Animate assembly ↔ disassembly. Save and load sequences.</p>
696
+ </div>
697
+
698
+ <div class="strat-card">
699
+ <div class="icon"><svg viewBox="0 0 24 24"><path d="M3 12h18 M12 3v18" stroke-dasharray="2 2"/><rect x="7" y="7" width="10" height="10"/></svg></div>
700
+ <h4>Section cut</h4>
701
+ <div class="kind">Viewer · Inspect</div>
702
+ <p>Per-axis X/Y/Z with flip, plus global clipping. DoubleSide material mode — no hollow artifacts when slicing.</p>
703
+ </div>
704
+
705
+ <div class="strat-card">
706
+ <div class="icon"><svg viewBox="0 0 24 24"><path d="M4 5h16 M4 12h10 M4 19h16 M18 9l3 3-3 3"/></svg></div>
707
+ <h4>Assembly tree</h4>
708
+ <div class="kind">Viewer · Navigate</div>
709
+ <p>Tree-style numbering (1.4.21), hide/show/isolate per branch, AI-generated drawings per sub-assembly. 6 sub-assembly rollups.</p>
710
+ </div>
711
+
712
+ <div class="strat-card">
713
+ <div class="icon"><svg viewBox="0 0 24 24"><circle cx="12" cy="9" r="4"/><path d="M12 13v8 M8 21h8"/></svg></div>
714
+ <h4>Annotations</h4>
715
+ <div class="kind">Viewer · Collaborate</div>
716
+ <p>Click-to-place 3D notes. Draggable pins, click-to-edit. Stored per session. User-specific colors for team review.</p>
717
+ </div>
718
+
719
+ <div class="strat-card">
720
+ <div class="icon"><svg viewBox="0 0 24 24"><path d="M3 17 L21 17 M6 14 L6 17 M12 12 L12 17 M18 9 L18 17 M9 17 L15 11"/></svg></div>
721
+ <h4>Measurements</h4>
722
+ <div class="kind">Viewer · Inspect</div>
723
+ <p>2-point distance, 3-point angle, radial, edge-to-edge. Tooltips track pointer. Snap to vertex / edge / face centers.</p>
724
+ </div>
725
+
726
+ <div class="strat-card">
727
+ <div class="icon"><svg viewBox="0 0 24 24"><path d="M12 3 L20 9 L20 17 L12 21 L4 17 L4 9 Z"/><path d="M8 12 L16 12 M12 8 L12 16"/></svg></div>
728
+ <h4>AI Render</h4>
729
+ <div class="kind">Create · Marketing</div>
730
+ <p>Preservation-first Gemini 2.0 Flash Image. 6 scene presets, 5 style presets + None. Multi-turn conversation for refinement.</p>
731
+ </div>
732
+
733
+ <div class="strat-card">
734
+ <div class="icon"><svg viewBox="0 0 24 24"><path d="M9 4h6l1 3H8z M7 7h10l-1 14H8z M11 11v6 M13 11v6"/></svg></div>
735
+ <h4>AI Part Identifier</h4>
736
+ <div class="kind">Analyze · AI</div>
737
+ <p>Geometry-based classifier plus Gemini Vision fallback. McMaster-Carr search queries auto-built from classification.</p>
738
+ </div>
739
+
740
+ <div class="strat-card">
741
+ <div class="icon"><svg viewBox="0 0 24 24"><rect x="6" y="3" width="12" height="18" rx="2"/><path d="M10 18h4" stroke-linecap="round"/><circle cx="12" cy="7" r="1.5"/></svg></div>
742
+ <h4>AR Mode</h4>
743
+ <div class="kind">Viewer · Field</div>
744
+ <p>WebXR hit-test. iOS Safari 17+ and Chrome Android. Pinch-scale, tap to place, rotate around, explode in-place.</p>
745
+ </div>
746
+
747
+ <div class="strat-card">
748
+ <div class="icon"><svg viewBox="0 0 24 24"><circle cx="12" cy="12" r="9"/><path d="M3 12h18 M12 3a14 14 0 0 1 0 18 M12 3a14 14 0 0 0 0 18"/></svg></div>
749
+ <h4>Multi-language</h4>
750
+ <div class="kind">UI · Localization</div>
751
+ <p>EN · DE · FR · ES · IT · NL with dropdown selector. All panel text, tooltips, and toasts fully translated.</p>
752
+ </div>
753
+
754
+ <div class="strat-card">
755
+ <div class="icon"><svg viewBox="0 0 24 24"><path d="M12 3v12 M6 10l6 6 6-6 M4 19h16"/></svg></div>
756
+ <h4>STL export</h4>
757
+ <div class="kind">Export · Per-part</div>
758
+ <p>Right-click any part → Export STL (ASCII or binary). Works on selected mesh or whole assembly. Drop straight into Kiri:Moto.</p>
759
+ </div>
760
+
761
+ <div class="strat-card">
762
+ <div class="icon"><svg viewBox="0 0 24 24"><rect x="3" y="5" width="18" height="14" rx="1"/><path d="M3 9h18 M8 5v14"/></svg></div>
763
+ <h4>Embed widget</h4>
764
+ <div class="kind">Share · Distribute</div>
765
+ <p>Single <code>&lt;iframe&gt;</code> snippet with URL params for starting angle, explosion state, and hidden parts.</p>
766
+ </div>
767
+
768
+ <div class="strat-card">
769
+ <div class="icon"><svg viewBox="0 0 24 24"><rect x="4" y="4" width="7" height="7"/><rect x="13" y="4" width="7" height="7"/><rect x="4" y="13" width="7" height="7"/><rect x="14" y="14" width="3" height="3"/><rect x="19" y="14" width="1" height="1"/><rect x="14" y="19" width="1" height="1"/></svg></div>
770
+ <h4>QR codes</h4>
771
+ <div class="kind">Share · Physical</div>
772
+ <p>One QR per part. Scans deep-link to <code>#part={idx}</code> — lands on the viewer pre-selected. Print on service labels.</p>
773
+ </div>
774
+
775
+ </div>
776
+ </div>
777
+ </section>
778
+
779
+ <!-- AI RENDER -->
780
+ <section class="post-section" data-animate>
781
+ <div class="wrap post-layout">
782
+ <div class="post-body">
783
+ <span class="section-kicker">AI Render · v304</span>
784
+ <h2>Gemini + CAD geometry, <em>finally</em> co-operating.</h2>
785
+ <p>Most generative image models redesign your CAD the moment they see a better-looking shape. The wing-shaped side panel becomes a smooth curve. The stainless frame becomes matte black. The whole thing drifts 15% off spec.</p>
786
+ <p>ExplodeView v304 shipped a <strong>preservation-first prompt pattern</strong> that leads with reference-image anchoring. The model renders your exact geometry into any scene, instead of reinterpreting it.</p>
787
+ <ul class="feature-list">
788
+ <li>Gemini 2.0 Flash Image (aka Nano Banana 2) via <code class="inline">generativelanguage.googleapis.com</code></li>
789
+ <li>Preservation-first prompt wrapper with explicit reference anchors</li>
790
+ <li>6 scene presets: forest trail, golden hour, studio, factory floor, urban loft, beach</li>
791
+ <li>5 style presets + <code class="inline">None</code> for raw scene fidelity</li>
792
+ <li>Multi-turn refinement conversation with context carry-over</li>
793
+ <li>1024×1024 offscreen capture before prompting — no viewport artifacts</li>
794
+ </ul>
795
+ </div>
796
+
797
+ <div class="ngc-block">
798
+ <div class="hd">
799
+ <span class="dots"><span></span><span></span><span></span></span>
800
+ <span>prompt.pattern.v304</span>
801
+ </div>
802
+ <pre><span class="cm">[PRESERVE]</span>
803
+ <span class="kw">Silver/grey</span> bike washing station from the
804
+ reference image. <span class="kw">Same</span> shape, <span class="kw">same</span>
805
+ wing-shaped side panels, <span class="kw">same</span> white top,
806
+ <span class="kw">same</span> stainless frame, <span class="kw">same</span> adjustable feet.
807
+ <span class="val">Do not redesign it.</span>
808
+
809
+ <span class="cm">[SCENE]</span>
810
+ Three mountain bikers on a forest trail at
811
+ golden hour. Station in the left third,
812
+ bikers <span class="ax">mid-shot</span>.
813
+
814
+ <span class="cm">[CAMERA]</span>
815
+ DSLR, <span class="val">35mm f/2.8</span>, natural light,
816
+ shallow <span class="ax">DoF</span>.
817
+
818
+ <span class="cm">[STYLE]</span>
819
+ <span class="val">None</span> <span class="cm">(let the scene breathe)</span></pre>
820
+ </div>
821
+ </div>
822
+ </section>
823
+
824
+ <!-- AR MODE -->
825
+ <section class="sim-section" data-animate>
826
+ <div class="wrap sim-layout">
827
+ <div class="sim-visual" aria-hidden="true">
828
+ <svg viewBox="0 0 300 270" xmlns="http://www.w3.org/2000/svg">
829
+ <defs>
830
+ <linearGradient id="phone-body" x1="0" x2="0" y1="0" y2="1">
831
+ <stop offset="0%" stop-color="#1A2D50"/>
832
+ <stop offset="100%" stop-color="#0A1628"/>
833
+ </linearGradient>
834
+ <linearGradient id="ar-part" x1="0" x2="0" y1="0" y2="1">
835
+ <stop offset="0%" stop-color="#5ACCC5"/>
836
+ <stop offset="100%" stop-color="#3AAFA9"/>
837
+ </linearGradient>
838
+ </defs>
839
+ <!-- Phone silhouette -->
840
+ <rect x="80" y="10" width="140" height="250" rx="20" fill="url(#phone-body)" stroke="#2A4F80" stroke-width="1.5"/>
841
+ <!-- Screen area -->
842
+ <rect x="90" y="24" width="120" height="220" rx="6" fill="#122240"/>
843
+ <!-- Camera notch -->
844
+ <rect x="140" y="16" width="20" height="4" rx="2" fill="#0A1628"/>
845
+
846
+ <!-- AR Scene inside screen -->
847
+ <!-- Floor grid (perspective) -->
848
+ <g opacity="0.45">
849
+ <line x1="92" y1="180" x2="208" y2="180" stroke="#3AAFA9" stroke-width="0.5" class="floor-grid"/>
850
+ <line x1="92" y1="195" x2="208" y2="195" stroke="#3AAFA9" stroke-width="0.5" class="floor-grid"/>
851
+ <line x1="92" y1="215" x2="208" y2="215" stroke="#3AAFA9" stroke-width="0.5" class="floor-grid"/>
852
+ <line x1="92" y1="240" x2="208" y2="240" stroke="#3AAFA9" stroke-width="0.5" class="floor-grid"/>
853
+ <line x1="120" y1="180" x2="100" y2="240" stroke="#3AAFA9" stroke-width="0.5" opacity="0.3"/>
854
+ <line x1="150" y1="180" x2="150" y2="240" stroke="#3AAFA9" stroke-width="0.5" opacity="0.3"/>
855
+ <line x1="180" y1="180" x2="200" y2="240" stroke="#3AAFA9" stroke-width="0.5" opacity="0.3"/>
856
+ </g>
857
+
858
+ <!-- Plane-detection reticle -->
859
+ <ellipse cx="150" cy="215" rx="40" ry="10" fill="none" stroke="#5ACCC5" stroke-width="0.8" stroke-dasharray="3 2" opacity="0.6"/>
860
+ <circle cx="150" cy="215" r="3" fill="#5ACCC5" opacity="0.8"/>
861
+
862
+ <!-- Exploded assembly floating above plane -->
863
+ <g class="ar-float">
864
+ <g class="ar-parts">
865
+ <!-- Top floating part -->
866
+ <rect x="135" y="60" width="30" height="10" rx="2" fill="url(#ar-part)" stroke="#2D8580" stroke-width="0.6"/>
867
+ <!-- Left floating part -->
868
+ <rect x="105" y="95" width="18" height="14" rx="2" fill="url(#ar-part)" stroke="#2D8580" stroke-width="0.6"/>
869
+ <!-- Right floating part -->
870
+ <rect x="180" y="95" width="18" height="14" rx="2" fill="url(#ar-part)" stroke="#2D8580" stroke-width="0.6"/>
871
+ <!-- Central body -->
872
+ <rect x="128" y="120" width="44" height="28" rx="3" fill="url(#ar-part)" stroke="#2D8580" stroke-width="0.8"/>
873
+ <circle cx="150" cy="134" r="4" fill="#0A1628" opacity="0.4"/>
874
+ <!-- Bottom base -->
875
+ <rect x="118" y="160" width="64" height="12" rx="2" fill="#D4A843" stroke="#8F7229" stroke-width="0.6"/>
876
+ </g>
877
+ <!-- Connection lines -->
878
+ <g stroke="#3AAFA9" stroke-width="0.4" stroke-dasharray="1 2" opacity="0.5" fill="none">
879
+ <line x1="150" y1="70" x2="150" y2="120"/>
880
+ <line x1="114" y1="109" x2="128" y2="134"/>
881
+ <line x1="189" y1="109" x2="172" y2="134"/>
882
+ <line x1="150" y1="148" x2="150" y2="160"/>
883
+ </g>
884
+ </g>
885
+
886
+ <!-- AR UI overlay - top -->
887
+ <rect x="98" y="32" width="28" height="8" rx="3" fill="#3AAFA9" opacity="0.35"/>
888
+ <text x="112" y="38" font-family="JetBrains Mono" font-size="5" fill="#5ACCC5" text-anchor="middle">AR</text>
889
+ <circle cx="198" cy="36" r="3" fill="#3AAFA9" opacity="0.6"/>
890
+
891
+ <!-- Bottom tap hint -->
892
+ <circle cx="150" cy="255" r="5" fill="none" stroke="#8B9AB5" stroke-width="0.8"/>
893
+ <circle cx="150" cy="255" r="2" fill="#8B9AB5" opacity="0.7"/>
894
+ </svg>
895
+ </div>
896
+
897
+ <div class="sim-body">
898
+ <span class="section-kicker">AR Mode</span>
899
+ <h2>Walk around the assembly. <em>Before</em> it exists.</h2>
900
+ <p>ExplodeView runs WebXR natively in iOS Safari 17+ and Chrome Android. Tap AR, point at the floor, drop the assembly in place. Pinch to scale. Rotate around it.</p>
901
+ <p>Hit the Explode button and the physical world hosts your exploded view — parts floating in your living room, at scale, with the tree panel in your hand.</p>
902
+ <ul class="feature-list">
903
+ <li>WebXR hit-test + plane detection (iOS Safari 17+ · Chrome Android)</li>
904
+ <li>Pinch-to-scale gesture with clamped min/max</li>
905
+ <li>Object-anchored exploded view — explosion persists as you walk</li>
906
+ <li>Works offline once the page is loaded</li>
907
+ <li>Shares via URL back to the normal in-browser viewer</li>
908
+ </ul>
909
+ </div>
910
+ </div>
911
+ </section>
912
+
913
+ <!-- McMASTER BRIDGE -->
914
+ <section class="bridge" data-animate>
915
+ <div class="wrap">
916
+ <div class="header-block">
917
+ <span class="section-kicker">AI Part Identifier</span>
918
+ <h2>From mystery part to <em>purchase link</em> in 3 clicks.</h2>
919
+ <p class="sub">Click a part. ExplodeView analyses geometry (bbox, volume, feature hints), classifies it (bolt / nut / washer / bearing / profile / bracket / …), generates a McMaster-Carr search query, and surfaces matching parts with prices.</p>
920
+ </div>
921
+
922
+ <div class="bridge-diagram">
923
+ <div class="bridge-row">
924
+ <div class="bridge-node">
925
+ <div class="icn">🖱️</div>
926
+ <h4>Click a part</h4>
927
+ <div class="ttag">3D selection</div>
928
+ </div>
929
+ <div class="bridge-arrow"><div class="packet"></div><div class="packet p2"></div></div>
930
+ <div class="bridge-node">
931
+ <div class="icn">🧠</div>
932
+ <h4>AI classify</h4>
933
+ <div class="ttag">geometry + vision</div>
934
+ </div>
935
+ <div class="bridge-arrow"><div class="packet"></div><div class="packet p2"></div></div>
936
+ <div class="bridge-node">
937
+ <div class="icn">🔍</div>
938
+ <h4>McMaster search</h4>
939
+ <div class="ttag">built query URL</div>
940
+ </div>
941
+ <div class="bridge-arrow"><div class="packet"></div><div class="packet p2"></div></div>
942
+ <div class="bridge-node">
943
+ <div class="icn">🛒</div>
944
+ <h4>Matches + prices</h4>
945
+ <div class="ttag">ranked list</div>
946
+ </div>
947
+ </div>
948
+
949
+ <div class="bridge-caption">
950
+ Persisted in <code>window._aiIdentifiedParts</code> and reused across session tools — BOM, report, shopping list.
951
+ </div>
952
+
953
+ <div class="bridge-events">
954
+ <div class="bridge-event"><span class="evt-name">explodeview:classify</span><div class="evt-sub">geometry heuristics · Gemini Vision fallback · returns type + confidence</div></div>
955
+ <div class="bridge-event"><span class="evt-name">explodeview:search</span><div class="evt-sub">McMaster-Carr URL with exact query params</div></div>
956
+ <div class="bridge-event"><span class="evt-name">explodeview:match</span><div class="evt-sub">ranked candidate list with prices · alternative sizes</div></div>
957
+ <div class="bridge-event"><span class="evt-name">explodeview:csv</span><div class="evt-sub">BOM export with McMaster part numbers in column</div></div>
958
+ <div class="bridge-event"><span class="evt-name">explodeview:order</span><div class="evt-sub">deep-link to McMaster cart with qty pre-filled</div></div>
959
+ <div class="bridge-event"><span class="evt-name">explodeview:database</span><div class="evt-sub">persists identifications across session for report export</div></div>
960
+ </div>
961
+ </div>
962
+ </div>
963
+ </section>
964
+
965
+ <!-- ROADMAP -->
966
+ <section class="roadmap" data-animate>
967
+ <div class="wrap">
968
+ <div class="header-block">
969
+ <span class="section-kicker">Roadmap</span>
970
+ <h2>Shipped. <em>Shipping</em>. And what's next.</h2>
971
+ <p class="sub">ExplodeView is live — v1.0.22 on npm, 400+ weekly downloads. The roadmap is honest about what works today and what comes next.</p>
972
+ </div>
973
+
974
+ <div class="phases">
975
+ <div class="phase done">
976
+ <div class="phase-dot"></div>
977
+ <span class="phase-num">Done</span>
978
+ <h4>Phase 0 · Shipped</h4>
979
+ <ul>
980
+ <li>Three.js r170 viewer</li>
981
+ <li>STEP / GLB / IAM import</li>
982
+ <li>45+ features in tabbed toolbar</li>
983
+ <li>AI Render v304 preservation-first</li>
984
+ <li>AR Mode (WebXR)</li>
985
+ <li>Multi-language · McMaster integration</li>
986
+ </ul>
987
+ </div>
988
+
989
+ <div class="phase active">
990
+ <div class="phase-dot"></div>
991
+ <span class="phase-num">In progress</span>
992
+ <h4>Phase 1 · Compositing</h4>
993
+ <ul>
994
+ <li>Transparent-background 3D render</li>
995
+ <li>Background-only inpainting prompt</li>
996
+ <li>Canvas compositing of foreground over gen background</li>
997
+ <li>Guaranteed pixel-level CAD preservation</li>
998
+ <li>Ship as v305 / v1.0.23</li>
999
+ </ul>
1000
+ </div>
1001
+
1002
+ <div class="phase next">
1003
+ <div class="phase-dot"></div>
1004
+ <span class="phase-num">Next</span>
1005
+ <h4>Phase 2 · Collaboration</h4>
1006
+ <ul>
1007
+ <li>Real-time collab cursors</li>
1008
+ <li>Cloud-backed shared sessions</li>
1009
+ <li>Comment threads per part</li>
1010
+ <li>Multi-user AR walk-around</li>
1011
+ <li>Review-mode history</li>
1012
+ </ul>
1013
+ </div>
1014
+
1015
+ <div class="phase next">
1016
+ <div class="phase-dot"></div>
1017
+ <span class="phase-num">Later</span>
1018
+ <h4>Phase 3 · Distribute</h4>
1019
+ <ul>
1020
+ <li>Video walkthrough export</li>
1021
+ <li>Embed widget analytics</li>
1022
+ <li>White-label embed</li>
1023
+ <li>VR mode (Quest / Vision Pro)</li>
1024
+ <li>Offline desktop build (Tauri)</li>
1025
+ </ul>
1026
+ </div>
1027
+ </div>
1028
+ </div>
1029
+ </section>
1030
+
1031
+ <!-- FINAL CTA -->
1032
+ <section class="cta-final">
1033
+ <div class="wrap">
1034
+ <h2>Your next 3D asset shouldn't take a <em>week</em>.</h2>
1035
+ <p>Open ExplodeView in the browser. Drop in your STEP file. Explode it, render it, walk around it in AR, match the hardware to McMaster. Share a URL.</p>
1036
+ <div class="ctas">
1037
+ <a href="https://explodeview.com/" class="btn btn-primary">Open ExplodeView <span class="arrow">→</span></a>
1038
+ <a href="https://github.com/vvlars-cmd/explodeview" class="btn btn-secondary">View on GitHub</a>
1039
+ <a href="https://www.npmjs.com/package/explodeview" class="btn btn-secondary">View on npm</a>
1040
+ </div>
1041
+ <div class="tiny">
1042
+ ExplodeView is <strong>MIT-licensed</strong>. Part of the <a href="/">cycleCAD Suite</a>.
1043
+ </div>
1044
+ </div>
1045
+ </section>
1046
+
1047
+ <!-- FOOTER -->
1048
+ <footer>
1049
+ <div class="wrap">
1050
+ <div class="row">
1051
+ <div class="col brand-col">
1052
+ <span class="brand">cycle<em>CAD</em> suite</span>
1053
+ <p>From idea to finished part, in one browser tab. Open-source CAD for designers, makers, and CNC shops.</p>
1054
+ </div>
1055
+ <div class="col">
1056
+ <h4>Products</h4>
1057
+ <a href="/app/">cycleCAD</a>
1058
+ <a href="https://explodeview.com/">ExplodeView</a>
1059
+ <a href="/pentacad.html">Pentacad</a>
1060
+ </div>
1061
+ <div class="col">
1062
+ <h4>Resources</h4>
1063
+ <a href="https://github.com/vvlars-cmd/cyclecad#readme">Documentation</a>
1064
+ <a href="https://github.com/vvlars-cmd/cyclecad/blob/main/cycleCAD-Architecture.pptx">Architecture</a>
1065
+ <a href="https://github.com/vvlars-cmd/cyclecad/blob/main/docs/API-REFERENCE.md">API reference</a>
1066
+ </div>
1067
+ <div class="col">
1068
+ <h4>Developers</h4>
1069
+ <a href="https://github.com/vvlars-cmd/explodeview">GitHub</a>
1070
+ <a href="https://www.npmjs.com/package/explodeview">npm</a>
1071
+ <a href="https://github.com/vvlars-cmd/cyclecad/blob/main/server/mcp-server.js">MCP server</a>
1072
+ </div>
1073
+ <div class="col">
1074
+ <h4>Contact</h4>
1075
+ <a href="mailto:sachin.kumar@cyclewash.com">Email</a>
1076
+ <a href="https://cyclewash.de/en">cycleWASH</a>
1077
+ </div>
1078
+ </div>
1079
+ <div class="legal">
1080
+ <span>© 2026 cycleCAD Suite · Sachin Kumar</span>
1081
+ <span>cycleCAD MIT · ExplodeView MIT · Pentacad AGPL-3.0</span>
1082
+ </div>
1083
+ </div>
1084
+ </footer>
1085
+
1086
+ <script>
1087
+ (() => {
1088
+ const els = document.querySelectorAll('[data-animate]');
1089
+ const obs = new IntersectionObserver((entries) => {
1090
+ entries.forEach((e) => {
1091
+ if (e.isIntersecting) {
1092
+ e.target.classList.add('in-view');
1093
+ obs.unobserve(e.target);
1094
+ }
1095
+ });
1096
+ }, { threshold: 0.12 });
1097
+ els.forEach((el) => obs.observe(el));
1098
+ })();
1099
+ </script>
1100
+
1101
+ </body>
1102
+ </html>