@classcad/mcp 0.1.5 → 0.2.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.
Files changed (38) hide show
  1. package/README.md +20 -2
  2. package/dist/auth.d.ts +7 -0
  3. package/dist/auth.js +2 -2
  4. package/dist/auth.js.map +1 -1
  5. package/dist/mcp-server.d.ts +1 -1
  6. package/dist/mcp-server.js +9 -3
  7. package/dist/mcp-server.js.map +1 -1
  8. package/dist/queue.d.ts +7 -0
  9. package/dist/queue.js +22 -9
  10. package/dist/queue.js.map +1 -1
  11. package/dist/tools/auth.js +1 -1
  12. package/dist/tools/auth.js.map +1 -1
  13. package/dist/tools/lifecycle.js +40 -18
  14. package/dist/tools/lifecycle.js.map +1 -1
  15. package/dist/tools/viewer.d.ts +6 -0
  16. package/dist/tools/viewer.js +110 -0
  17. package/dist/tools/viewer.js.map +1 -0
  18. package/dist/viewer/scene.d.ts +60 -0
  19. package/dist/viewer/scene.js +271 -0
  20. package/dist/viewer/scene.js.map +1 -0
  21. package/dist/viewer/server.d.ts +27 -0
  22. package/dist/viewer/server.js +229 -0
  23. package/dist/viewer/server.js.map +1 -0
  24. package/dist/viewer-page/cube.svg +15 -0
  25. package/dist/viewer-page/fonts/LICENSE.txt +3 -0
  26. package/dist/viewer-page/fonts/jetbrains-mono-latin.woff2 +0 -0
  27. package/dist/viewer-page/index.html +135 -0
  28. package/dist/viewer-page/vendor/LICENSE.txt +21 -0
  29. package/dist/viewer-page/vendor/VERSION.txt +1 -0
  30. package/dist/viewer-page/vendor/addons/controls/OrbitControls.js +1963 -0
  31. package/dist/viewer-page/vendor/addons/lines/LineMaterial.js +726 -0
  32. package/dist/viewer-page/vendor/addons/lines/LineSegments2.js +434 -0
  33. package/dist/viewer-page/vendor/addons/lines/LineSegmentsGeometry.js +298 -0
  34. package/dist/viewer-page/vendor/three.core.min.js +6 -0
  35. package/dist/viewer-page/vendor/three.module.min.js +6 -0
  36. package/dist/viewer-page/viewer.css +717 -0
  37. package/dist/viewer-page/viewer.js +530 -0
  38. package/package.json +3 -2
@@ -0,0 +1,60 @@
1
+ type Tree = Record<string, any>;
2
+ export type SceneFace = {
3
+ /** positions, flat xyz */
4
+ p: number[];
5
+ /** normals, flat xyz (same length as p), or null: the viewer computes them */
6
+ n: number[] | null;
7
+ /** triangle indices */
8
+ i: number[];
9
+ /** a planar face has no silhouette */
10
+ flat: boolean;
11
+ /** the face's own colour, when it differs from its body's */
12
+ c?: [number, number, number];
13
+ };
14
+ export type SceneBody = {
15
+ /** the solid's id in the structure tree */
16
+ id: number;
17
+ name: string;
18
+ /** the colour the model gave the body, or null: it takes the paper's */
19
+ color: [number, number, number] | null;
20
+ opacity: number;
21
+ faces: SceneFace[];
22
+ /** B-rep edges as polylines, flat xyz */
23
+ edges: number[][];
24
+ };
25
+ export type Scene = {
26
+ kind: 'PART' | 'ASSEMBLY' | 'EMPTY';
27
+ name: string;
28
+ bodies: SceneBody[];
29
+ /** where each body is drawn: a row-major 4×4 per placement (identity in a part) */
30
+ placements: {
31
+ body: number;
32
+ m: number[];
33
+ }[];
34
+ features: {
35
+ no: number;
36
+ name: string;
37
+ kind: string;
38
+ }[];
39
+ stats: {
40
+ bodies: number;
41
+ faces: number;
42
+ triangles: number;
43
+ edges: number;
44
+ };
45
+ /** world bounds of everything placed, or null when empty */
46
+ bounds: {
47
+ min: [number, number, number];
48
+ max: [number, number, number];
49
+ } | null;
50
+ };
51
+ export declare function buildScene(tree: Tree | null | undefined, graphic: {
52
+ containers?: any[];
53
+ } | null | undefined): Scene;
54
+ /**
55
+ * The scene as binary glTF 2.0: one mesh per body, one node per placement,
56
+ * Z up turned to glTF's Y up at the root. Bodies without a colour of their
57
+ * own are white. Edges are not part of it (glTF viewers draw faces).
58
+ */
59
+ export declare function sceneToGlb(scene: Scene): Buffer;
60
+ export {};
@@ -0,0 +1,271 @@
1
+ // viewer/scene.ts — what the 3D viewer draws, built from a session's
2
+ // structure tree and graphic exactly as the PNG renderer reads them: live
3
+ // solids only (a consumed body's container is stale), and in an assembly one
4
+ // placement per part instance.
5
+ import { extractAssemblyInstances, graphicWithEdges, isConsumedSolid } from '@classcad/renderer';
6
+ const IDENTITY = [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1];
7
+ /** The engine's colour for a body nobody coloured: such a body is drawn as paper. */
8
+ const ENGINE_DEFAULT = [[128, 128, 128]];
9
+ const rgb = (c) => {
10
+ if (!Array.isArray(c) || c.length < 3)
11
+ return null;
12
+ // the engine sends 0–255; tolerate 0–1
13
+ const scale = c.every(v => typeof v === 'number' && v <= 1) ? 255 : 1;
14
+ return [Math.round(c[0] * scale), Math.round(c[1] * scale), Math.round(c[2] * scale)];
15
+ };
16
+ const ownColor = (c) => {
17
+ const v = rgb(c);
18
+ if (!v)
19
+ return null;
20
+ return ENGINE_DEFAULT.some(d => d[0] === v[0] && d[1] === v[1] && d[2] === v[2]) ? null : v;
21
+ };
22
+ const same = (a, b) => (a && b ? a[0] === b[0] && a[1] === b[1] && a[2] === b[2] : a === b);
23
+ /** 4 decimals: a tenth of a micron, and a third less JSON. */
24
+ const round = (a) => {
25
+ const out = new Array(a.length);
26
+ for (let i = 0; i < a.length; i++)
27
+ out[i] = Math.round(a[i] * 1e4) / 1e4;
28
+ return out;
29
+ };
30
+ /**
31
+ * Features in build order. The operation sequence holds references
32
+ * (`refObj` → the feature); the datums' references and the rollback bar are
33
+ * not features.
34
+ */
35
+ function features(tree) {
36
+ const out = [];
37
+ const seq = Object.values(tree).find(n => n?.class === 'CC_OperationSequence');
38
+ for (const id of seq?.children ?? []) {
39
+ const ref = tree[String(id)];
40
+ const target = tree[String(ref?.members?.refObj?.value)];
41
+ if (!target || /^CC_(Work|RollbackBar)/.test(String(target.class ?? '')))
42
+ continue;
43
+ out.push({ no: out.length + 1, name: String(target.name ?? ''), kind: String(target.class ?? '').replace(/^CC_/, '') });
44
+ }
45
+ return out;
46
+ }
47
+ export function buildScene(tree, graphic) {
48
+ const t = tree ?? {};
49
+ // Analytic edges arrive as lines and arcs; as the renderer does, draw them as edges too.
50
+ const containers = (graphicWithEdges(graphic)?.containers ?? []).filter((c) => (c?.meshes?.length ?? 0) > 0 && !isConsumedSolid(t, c.owner));
51
+ const root = Object.values(t).find(n => n?.class === 'CC_AssemblyRoot') ?? Object.values(t).find(n => n?.class === 'CC_Part');
52
+ const kind = !root ? 'EMPTY' : root.class === 'CC_AssemblyRoot' ? 'ASSEMBLY' : 'PART';
53
+ const bodies = [];
54
+ const bodyOfOwner = new Map();
55
+ let faces = 0;
56
+ let triangles = 0;
57
+ let edges = 0;
58
+ for (const c of containers) {
59
+ const color = ownColor(c.properties?.material?.color);
60
+ const body = {
61
+ id: Number(c.owner ?? c.id),
62
+ name: String(t[String(c.owner)]?.name ?? t[String(c.id)]?.name ?? 'Body'),
63
+ color,
64
+ opacity: typeof c.properties?.material?.opacity === 'number' ? c.properties.material.opacity : 1,
65
+ faces: [],
66
+ edges: [],
67
+ };
68
+ for (const m of c.meshes) {
69
+ if (!m?.vertices?.length || !m?.indices?.length)
70
+ continue;
71
+ const fc = ownColor(m.properties?.material?.color);
72
+ body.faces.push({
73
+ p: round(m.vertices),
74
+ n: m.normals?.length === m.vertices.length ? round(m.normals) : null,
75
+ i: Array.from(m.indices),
76
+ flat: m.properties?.surface?.type === 'plane',
77
+ ...(fc && !same(fc, color) ? { c: fc } : {}),
78
+ });
79
+ faces++;
80
+ triangles += m.indices.length / 3;
81
+ }
82
+ // A seam is not a line of the part: it is where one curved face closes on
83
+ // itself. An edge of a solid lies between two faces; a seam borders one.
84
+ const borders = new Map();
85
+ for (const m of c.meshes) {
86
+ for (const loop of m.loops ?? []) {
87
+ for (const id of loop) {
88
+ const faces = borders.get(id) ?? new Set();
89
+ faces.add(m.id);
90
+ borders.set(id, faces);
91
+ }
92
+ }
93
+ }
94
+ const isSeam = (id) => borders.size > 0 && (borders.get(id)?.size ?? 0) < 2;
95
+ for (const e of c.edges ?? []) {
96
+ if (e?.points?.length >= 6 && !isSeam(e.id)) {
97
+ body.edges.push(round(e.points));
98
+ edges++;
99
+ }
100
+ }
101
+ if (!body.faces.length)
102
+ continue;
103
+ bodyOfOwner.set(body.id, bodies.length);
104
+ bodies.push(body);
105
+ }
106
+ // An assembly draws each part's bodies once per instance; a part draws them where they are.
107
+ const instances = kind === 'ASSEMBLY' ? extractAssemblyInstances(t) : null;
108
+ const placements = [];
109
+ if (instances?.length) {
110
+ for (const inst of instances) {
111
+ const body = bodyOfOwner.get(Number(inst.ownerSolidId));
112
+ if (body != null)
113
+ placements.push({ body, m: inst.transform.map(Number) });
114
+ }
115
+ }
116
+ else {
117
+ bodies.forEach((_, body) => placements.push({ body, m: IDENTITY }));
118
+ }
119
+ // world bounds
120
+ let bounds = null;
121
+ const min = [Infinity, Infinity, Infinity];
122
+ const max = [-Infinity, -Infinity, -Infinity];
123
+ for (const pl of placements) {
124
+ const m = pl.m;
125
+ for (const f of bodies[pl.body].faces) {
126
+ for (let k = 0; k < f.p.length; k += 3) {
127
+ const x = f.p[k], y = f.p[k + 1], z = f.p[k + 2];
128
+ const w = [m[0] * x + m[1] * y + m[2] * z + m[3], m[4] * x + m[5] * y + m[6] * z + m[7], m[8] * x + m[9] * y + m[10] * z + m[11]];
129
+ for (let a = 0; a < 3; a++) {
130
+ if (w[a] < min[a])
131
+ min[a] = w[a];
132
+ if (w[a] > max[a])
133
+ max[a] = w[a];
134
+ }
135
+ }
136
+ }
137
+ }
138
+ if (placements.length && Number.isFinite(min[0]))
139
+ bounds = { min, max };
140
+ return {
141
+ kind: bodies.length || kind !== 'EMPTY' ? kind : 'EMPTY',
142
+ name: String(root?.name ?? ''),
143
+ bodies,
144
+ placements,
145
+ features: kind === 'PART' ? features(t) : [],
146
+ stats: { bodies: placements.length, faces, triangles, edges },
147
+ bounds,
148
+ };
149
+ }
150
+ // ─── GLB ───────────────────────────────────────────────────────────────────
151
+ /**
152
+ * The scene as binary glTF 2.0: one mesh per body, one node per placement,
153
+ * Z up turned to glTF's Y up at the root. Bodies without a colour of their
154
+ * own are white. Edges are not part of it (glTF viewers draw faces).
155
+ */
156
+ export function sceneToGlb(scene) {
157
+ const chunks = [];
158
+ let offset = 0;
159
+ const bufferViews = [];
160
+ const accessors = [];
161
+ const push = (buf, target) => {
162
+ const pad = (4 - (buf.length % 4)) % 4;
163
+ bufferViews.push({ buffer: 0, byteOffset: offset, byteLength: buf.length, target });
164
+ chunks.push(buf, Buffer.alloc(pad));
165
+ offset += buf.length + pad;
166
+ return bufferViews.length - 1;
167
+ };
168
+ const materials = [];
169
+ const materialOf = (c, opacity) => {
170
+ const col = c ?? [255, 255, 255];
171
+ const key = `${col.join(',')}|${opacity}`;
172
+ let i = materials.findIndex(m => m.extras.key === key);
173
+ if (i < 0) {
174
+ const lin = (v) => Math.pow(v / 255, 2.2);
175
+ materials.push({
176
+ pbrMetallicRoughness: { baseColorFactor: [lin(col[0]), lin(col[1]), lin(col[2]), opacity], metallicFactor: 0, roughnessFactor: 0.8 },
177
+ doubleSided: true,
178
+ ...(opacity < 1 ? { alphaMode: 'BLEND' } : {}),
179
+ extras: { key },
180
+ });
181
+ i = materials.length - 1;
182
+ }
183
+ return i;
184
+ };
185
+ const meshes = scene.bodies.map(body => {
186
+ // one primitive per colour
187
+ const groups = new Map();
188
+ for (const f of body.faces) {
189
+ const color = f.c ?? body.color;
190
+ const key = color ? color.join(',') : '-';
191
+ const g = groups.get(key) ?? { color, faces: [] };
192
+ g.faces.push(f);
193
+ groups.set(key, g);
194
+ }
195
+ const primitives = [...groups.values()].map(g => {
196
+ let nv = 0;
197
+ let ni = 0;
198
+ for (const f of g.faces) {
199
+ nv += f.p.length / 3;
200
+ ni += f.i.length;
201
+ }
202
+ const pos = new Float32Array(nv * 3);
203
+ const nor = new Float32Array(nv * 3);
204
+ const idx = new Uint32Array(ni);
205
+ const lo = [Infinity, Infinity, Infinity];
206
+ const hi = [-Infinity, -Infinity, -Infinity];
207
+ let vo = 0;
208
+ let io = 0;
209
+ let normals = true;
210
+ for (const f of g.faces) {
211
+ pos.set(f.p, vo * 3);
212
+ if (f.n)
213
+ nor.set(f.n, vo * 3);
214
+ else
215
+ normals = false;
216
+ for (let k = 0; k < f.i.length; k++)
217
+ idx[io + k] = f.i[k] + vo;
218
+ for (let k = 0; k < f.p.length; k += 3) {
219
+ for (let a = 0; a < 3; a++) {
220
+ if (f.p[k + a] < lo[a])
221
+ lo[a] = f.p[k + a];
222
+ if (f.p[k + a] > hi[a])
223
+ hi[a] = f.p[k + a];
224
+ }
225
+ }
226
+ vo += f.p.length / 3;
227
+ io += f.i.length;
228
+ }
229
+ const attributes = {};
230
+ accessors.push({ bufferView: push(Buffer.from(pos.buffer), 34962), componentType: 5126, count: nv, type: 'VEC3', min: lo, max: hi });
231
+ attributes.POSITION = accessors.length - 1;
232
+ if (normals) {
233
+ accessors.push({ bufferView: push(Buffer.from(nor.buffer), 34962), componentType: 5126, count: nv, type: 'VEC3' });
234
+ attributes.NORMAL = accessors.length - 1;
235
+ }
236
+ accessors.push({ bufferView: push(Buffer.from(idx.buffer), 34963), componentType: 5125, count: ni, type: 'SCALAR' });
237
+ return { attributes, indices: accessors.length - 1, material: materialOf(g.color, body.opacity), mode: 4 };
238
+ });
239
+ return { name: body.name, primitives };
240
+ });
241
+ // glTF matrices are column-major; ours are row-major. The root turns Z up into Y up, in metres.
242
+ const columnMajor = (m) => [m[0], m[4], m[8], m[12], m[1], m[5], m[9], m[13], m[2], m[6], m[10], m[14], m[3], m[7], m[11], m[15]];
243
+ const nodes = scene.placements.map(pl => ({ name: scene.bodies[pl.body].name, mesh: pl.body, matrix: columnMajor(pl.m) }));
244
+ nodes.push({ name: scene.name || 'ClassCAD', children: nodes.map((_, i) => i), matrix: [0.001, 0, 0, 0, 0, 0, -0.001, 0, 0, 0.001, 0, 0, 0, 0, 0, 1] });
245
+ const bin = Buffer.concat(chunks);
246
+ const json = {
247
+ asset: { version: '2.0', generator: 'ClassCAD MCP' },
248
+ scene: 0,
249
+ scenes: [{ nodes: [nodes.length - 1] }],
250
+ nodes,
251
+ meshes,
252
+ materials: materials.map(({ extras, ...m }) => m),
253
+ accessors,
254
+ bufferViews,
255
+ buffers: [{ byteLength: bin.length }],
256
+ };
257
+ let jsonBuf = Buffer.from(JSON.stringify(json), 'utf8');
258
+ jsonBuf = Buffer.concat([jsonBuf, Buffer.alloc((4 - (jsonBuf.length % 4)) % 4, 0x20)]);
259
+ const header = Buffer.alloc(12);
260
+ header.writeUInt32LE(0x46546c67, 0);
261
+ header.writeUInt32LE(2, 4);
262
+ header.writeUInt32LE(12 + 8 + jsonBuf.length + 8 + bin.length, 8);
263
+ const jsonHead = Buffer.alloc(8);
264
+ jsonHead.writeUInt32LE(jsonBuf.length, 0);
265
+ jsonHead.writeUInt32LE(0x4e4f534a, 4);
266
+ const binHead = Buffer.alloc(8);
267
+ binHead.writeUInt32LE(bin.length, 0);
268
+ binHead.writeUInt32LE(0x004e4942, 4);
269
+ return Buffer.concat([header, jsonHead, jsonBuf, binHead, bin]);
270
+ }
271
+ //# sourceMappingURL=scene.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scene.js","sourceRoot":"","sources":["../../src/viewer/scene.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,27 @@
1
+ export type ViewerSource = {
2
+ /** Structure tree and graphic of the session, read in its tool queue. null: the engine was never used. */
3
+ load: () => Promise<{
4
+ tree: Record<string, any>;
5
+ graphic: {
6
+ containers?: any[];
7
+ } | null;
8
+ } | null>;
9
+ /** The model in an engine format, read in the session's tool queue. */
10
+ exportModel: (format: 'STP' | 'STL') => Promise<Buffer>;
11
+ /** The host as people know it ("Claude Code"), and where the engine runs. */
12
+ host: () => string | undefined;
13
+ engine: () => string;
14
+ log?: (msg: string) => void;
15
+ };
16
+ export type ViewerSession = {
17
+ /** The link of this session's view. */
18
+ readonly url: string;
19
+ /** The model may have changed: watchers are told, and the first model opens the view. */
20
+ touch: () => void;
21
+ /** Opens the view in the user's browser now. False where there is no browser to open. */
22
+ open: () => boolean;
23
+ /** The session is over: its watchers are told and the link stops working. */
24
+ close: () => void;
25
+ };
26
+ /** A session's view. The listener starts with the first one. */
27
+ export declare function openViewerSession(source: ViewerSource): Promise<ViewerSession>;
@@ -0,0 +1,229 @@
1
+ // viewer/server.ts — the live 3D view of a session, served to the user's
2
+ // browser from this machine.
3
+ //
4
+ // http://127.0.0.1:<port>/v/<token> the page (viewer-page/)
5
+ // …/v/<token>/scene what to draw, as JSON
6
+ // …/v/<token>/events server-sent events: "scene" whenever the model changed
7
+ // …/v/<token>/export/<name>.{stp,stl,glb} the model as a file
8
+ // …/assets/… the page's own files (three.js, the font)
9
+ //
10
+ // One listener per MCP process (the daemon, or a shim serving in-process),
11
+ // shared by all of its sessions. Each session has its own unguessable token:
12
+ // a page shows the model of exactly one session, and two sessions never see
13
+ // each other's. The listener binds 127.0.0.1 and answers only requests that
14
+ // name it as their host.
15
+ //
16
+ // The engine is read in the session's own tool queue (`load`, `exportModel`
17
+ // are queued by the caller), never in the middle of a script.
18
+ import { createServer } from 'node:http';
19
+ import { randomBytes } from 'node:crypto';
20
+ import { existsSync, readFileSync, readdirSync, statSync } from 'node:fs';
21
+ import { dirname, extname, join, relative, sep } from 'node:path';
22
+ import { fileURLToPath } from 'node:url';
23
+ import { gzipSync } from 'node:zlib';
24
+ import { openBrowser } from '../auth.js';
25
+ import { buildScene, sceneToGlb } from './scene.js';
26
+ const PAGE_DIR = join(dirname(fileURLToPath(import.meta.url)), '..', 'viewer-page');
27
+ const DEFAULT_PORT = 9098;
28
+ const sessions = new Map();
29
+ let listener = null;
30
+ const MIME = {
31
+ '.html': 'text/html; charset=utf-8',
32
+ '.js': 'text/javascript; charset=utf-8',
33
+ '.css': 'text/css; charset=utf-8',
34
+ '.woff2': 'font/woff2',
35
+ '.svg': 'image/svg+xml',
36
+ '.txt': 'text/plain; charset=utf-8',
37
+ };
38
+ /** The page's files, read once: path under /assets/ → bytes. */
39
+ let assets = null;
40
+ function loadAssets() {
41
+ if (assets)
42
+ return assets;
43
+ assets = new Map();
44
+ const walk = (dir) => {
45
+ for (const name of readdirSync(dir)) {
46
+ const file = join(dir, name);
47
+ if (statSync(file).isDirectory())
48
+ walk(file);
49
+ else
50
+ assets.set(relative(PAGE_DIR, file).split(sep).join('/'), { body: readFileSync(file), type: MIME[extname(name)] ?? 'application/octet-stream' });
51
+ }
52
+ };
53
+ if (existsSync(PAGE_DIR))
54
+ walk(PAGE_DIR);
55
+ return assets;
56
+ }
57
+ function listen() {
58
+ listener ??= new Promise((resolve, reject) => {
59
+ const server = createServer((req, res) => {
60
+ handle(req, res).catch(err => {
61
+ if (!res.headersSent)
62
+ res.writeHead(500, { 'content-type': 'text/plain; charset=utf-8' });
63
+ res.end(String(err?.message ?? err));
64
+ });
65
+ });
66
+ const wanted = Number(process.env.CLASSCAD_VIEWER_PORT ?? DEFAULT_PORT);
67
+ const bound = () => {
68
+ server.unref();
69
+ resolve({ server, port: server.address().port });
70
+ };
71
+ server.once('error', (err) => {
72
+ // Another MCP process of this machine has the port: any free one will do.
73
+ if (err.code === 'EADDRINUSE' && wanted !== 0) {
74
+ server.once('error', reject);
75
+ server.listen(0, '127.0.0.1', bound);
76
+ }
77
+ else
78
+ reject(err);
79
+ });
80
+ server.listen(wanted, '127.0.0.1', bound);
81
+ });
82
+ return listener;
83
+ }
84
+ /** A session's view. The listener starts with the first one. */
85
+ export async function openViewerSession(source) {
86
+ const { port } = await listen();
87
+ const entry = { token: randomBytes(18).toString('base64url'), source, scene: null, body: null, version: 0, dirty: true, building: null, streams: new Set(), opened: false };
88
+ sessions.set(entry.token, entry);
89
+ const url = `http://127.0.0.1:${port}/v/${entry.token}`;
90
+ const open = () => {
91
+ entry.opened = true;
92
+ return process.env.CLASSCAD_VIEWER_NO_BROWSER === '1' ? false : openBrowser(url);
93
+ };
94
+ return {
95
+ url,
96
+ open,
97
+ touch: () => {
98
+ entry.dirty = true;
99
+ // Nobody watching and the view already offered: the next page load rebuilds.
100
+ if (!entry.streams.size && entry.opened)
101
+ return;
102
+ void rebuild(entry).then(() => {
103
+ broadcast(entry, 'scene', { version: entry.version });
104
+ // The first model of a session brings its view up, once.
105
+ if (!entry.opened && entry.scene?.bodies.length) {
106
+ entry.opened = true;
107
+ if (process.env.CLASSCAD_VIEWER_OPEN !== '0' && process.env.CLASSCAD_VIEWER_NO_BROWSER !== '1' && !entry.streams.size)
108
+ openBrowser(url);
109
+ }
110
+ }, err => source.log?.(`viewer: ${err?.message ?? err}`));
111
+ },
112
+ close: () => {
113
+ broadcast(entry, 'closed', {});
114
+ for (const res of entry.streams)
115
+ res.end();
116
+ entry.streams.clear();
117
+ sessions.delete(entry.token);
118
+ },
119
+ };
120
+ }
121
+ /** Reads the session and packs what the page draws. One build at a time per session. */
122
+ function rebuild(entry) {
123
+ entry.building ??= (async () => {
124
+ entry.dirty = false;
125
+ const state = await entry.source.load();
126
+ const scene = buildScene(state?.tree, state?.graphic);
127
+ entry.scene = scene;
128
+ entry.version++;
129
+ entry.body = gzipSync(JSON.stringify({ version: entry.version, host: entry.source.host() ?? null, engine: entry.source.engine(), scene }));
130
+ })().finally(() => {
131
+ entry.building = null;
132
+ });
133
+ return entry.building;
134
+ }
135
+ function broadcast(entry, event, data) {
136
+ const frame = `event: ${event}\ndata: ${JSON.stringify(data)}\n\n`;
137
+ for (const res of entry.streams)
138
+ res.write(frame);
139
+ }
140
+ const SAFE_HEADERS = { 'cache-control': 'no-store', 'x-content-type-options': 'nosniff', 'referrer-policy': 'no-referrer' };
141
+ async function handle(req, res) {
142
+ const port = (req.socket.localPort ?? 0);
143
+ // Only this listener's own address: no DNS rebinding, no other sites' pages.
144
+ if (req.headers.host !== `127.0.0.1:${port}` && req.headers.host !== `localhost:${port}`)
145
+ return text(res, 403, 'forbidden');
146
+ if (req.method !== 'GET' && req.method !== 'HEAD')
147
+ return text(res, 405, 'method not allowed');
148
+ const path = decodeURIComponent(new URL(req.url ?? '/', `http://127.0.0.1:${port}`).pathname);
149
+ if (path.startsWith('/assets/')) {
150
+ const asset = loadAssets().get(path.slice('/assets/'.length));
151
+ if (!asset || path.endsWith('index.html'))
152
+ return text(res, 404, 'not found');
153
+ res.writeHead(200, { ...SAFE_HEADERS, 'content-type': asset.type, 'cache-control': 'no-cache' });
154
+ return void res.end(asset.body);
155
+ }
156
+ const m = /^\/v\/([A-Za-z0-9_-]{16,64})(\/.*)?$/.exec(path);
157
+ if (!m)
158
+ return text(res, 404, 'not found');
159
+ const entry = sessions.get(m[1]);
160
+ const rest = m[2] ?? '';
161
+ if (rest === '' || rest === '/') {
162
+ // The page is served for an ended session too: it says so itself.
163
+ const page = loadAssets().get('index.html');
164
+ if (!page)
165
+ return text(res, 500, 'the viewer page is missing from this build');
166
+ const nonce = randomBytes(12).toString('base64');
167
+ res.writeHead(200, {
168
+ ...SAFE_HEADERS,
169
+ 'content-type': page.type,
170
+ 'content-security-policy': `default-src 'self'; script-src 'self' 'nonce-${nonce}'; style-src 'self'; img-src 'self' data: blob:; connect-src 'self'; font-src 'self'; frame-ancestors 'none'; base-uri 'none'`,
171
+ });
172
+ return void res.end(page.body.toString('utf8').replaceAll('__NONCE__', nonce));
173
+ }
174
+ if (!entry)
175
+ return json(res, 404, { error: 'This view has ended: its session is over.' });
176
+ if (rest === '/scene') {
177
+ // A build in flight may have read the model before the last change: wait for it, then look again.
178
+ if (entry.building)
179
+ await entry.building;
180
+ if (entry.dirty || !entry.body)
181
+ await rebuild(entry);
182
+ res.writeHead(200, { ...SAFE_HEADERS, 'content-type': 'application/json; charset=utf-8', 'content-encoding': 'gzip' });
183
+ return void res.end(entry.body);
184
+ }
185
+ if (rest === '/events') {
186
+ res.writeHead(200, { ...SAFE_HEADERS, 'content-type': 'text/event-stream; charset=utf-8', connection: 'keep-alive' });
187
+ res.write(`retry: 2000\nevent: hello\ndata: ${JSON.stringify({ version: entry.version })}\n\n`);
188
+ entry.streams.add(res);
189
+ entry.opened = true;
190
+ const beat = setInterval(() => res.write(': still here\n\n'), 20_000);
191
+ beat.unref();
192
+ req.on('close', () => {
193
+ clearInterval(beat);
194
+ entry.streams.delete(res);
195
+ });
196
+ return;
197
+ }
198
+ const file = /^\/export\/([^/]{1,80})\.(stp|step|stl|glb)$/i.exec(rest);
199
+ if (file) {
200
+ const ext = file[2].toLowerCase();
201
+ let body;
202
+ let type;
203
+ if (ext === 'glb') {
204
+ if (entry.building)
205
+ await entry.building;
206
+ if (entry.dirty || !entry.scene)
207
+ await rebuild(entry);
208
+ body = sceneToGlb(entry.scene);
209
+ type = 'model/gltf-binary';
210
+ }
211
+ else {
212
+ body = await entry.source.exportModel(ext === 'stl' ? 'STL' : 'STP');
213
+ type = ext === 'stl' ? 'model/stl' : 'model/step';
214
+ }
215
+ const name = file[1].replace(/[^A-Za-z0-9._ -]/g, '_');
216
+ res.writeHead(200, { ...SAFE_HEADERS, 'content-type': type, 'content-length': String(body.length), 'content-disposition': `attachment; filename="${name}.${ext}"` });
217
+ return void res.end(body);
218
+ }
219
+ return text(res, 404, 'not found');
220
+ }
221
+ function text(res, status, body) {
222
+ res.writeHead(status, { ...SAFE_HEADERS, 'content-type': 'text/plain; charset=utf-8' });
223
+ res.end(body);
224
+ }
225
+ function json(res, status, body) {
226
+ res.writeHead(status, { ...SAFE_HEADERS, 'content-type': 'application/json; charset=utf-8' });
227
+ res.end(JSON.stringify(body));
228
+ }
229
+ //# sourceMappingURL=server.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.js","sourceRoot":"","sources":["../../src/viewer/server.ts"],"names":[],"mappings":"AAAA,yEAAyE;AACzE,6BAA6B;AAC7B,EAAE;AACF,yEAAyE;AACzE,uEAAuE;AACvE,wGAAwG;AACxG,qEAAqE;AACrE,2FAA2F;AAC3F,EAAE;AACF,2EAA2E;AAC3E,6EAA6E;AAC7E,4EAA4E;AAC5E,4EAA4E;AAC5E,yBAAyB;AACzB,EAAE;AACF,4EAA4E;AAC5E,8DAA8D;AAC9D,OAAO,EAAE,YAAY,EAA0D,MAAM,WAAW,CAAA;AAChG,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAA;AACzC,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAA;AACzE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,GAAG,EAAE,MAAM,WAAW,CAAA;AACjE,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAA;AACxC,OAAO,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAA;AACpC,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAA;AACxC,OAAO,EAAE,UAAU,EAAE,UAAU,EAAc,MAAM,YAAY,CAAA;AAE/D,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,EAAE,aAAa,CAAC,CAAA;AACnF,MAAM,YAAY,GAAG,IAAI,CAAA;AAoCzB,MAAM,QAAQ,GAAG,IAAI,GAAG,EAAiB,CAAA;AACzC,IAAI,QAAQ,GAAqD,IAAI,CAAA;AAErE,MAAM,IAAI,GAA2B;IACnC,OAAO,EAAE,0BAA0B;IACnC,KAAK,EAAE,gCAAgC;IACvC,MAAM,EAAE,yBAAyB;IACjC,QAAQ,EAAE,YAAY;IACtB,MAAM,EAAE,eAAe;IACvB,MAAM,EAAE,2BAA2B;CACpC,CAAA;AAED,gEAAgE;AAChE,IAAI,MAAM,GAAuD,IAAI,CAAA;AACrE,SAAS,UAAU;IACjB,IAAI,MAAM;QAAE,OAAO,MAAM,CAAA;IACzB,MAAM,GAAG,IAAI,GAAG,EAAE,CAAA;IAClB,MAAM,IAAI,GAAG,CAAC,GAAW,EAAE,EAAE;QAC3B,KAAK,MAAM,IAAI,IAAI,WAAW,CAAC,GAAG,CAAC,EAAE,CAAC;YACpC,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,EAAE,IAAI,CAAC,CAAA;YAC5B,IAAI,QAAQ,CAAC,IAAI,CAAC,CAAC,WAAW,EAAE;gBAAE,IAAI,CAAC,IAAI,CAAC,CAAA;;gBACvC,MAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,IAAI,EAAE,YAAY,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,IAAI,0BAA0B,EAAE,CAAC,CAAA;QACxJ,CAAC;IACH,CAAC,CAAA;IACD,IAAI,UAAU,CAAC,QAAQ,CAAC;QAAE,IAAI,CAAC,QAAQ,CAAC,CAAA;IACxC,OAAO,MAAM,CAAA;AACf,CAAC;AAED,SAAS,MAAM;IACb,QAAQ,KAAK,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QAC3C,MAAM,MAAM,GAAG,YAAY,CAAC,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE;YACvC,MAAM,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE;gBAC3B,IAAI,CAAC,GAAG,CAAC,WAAW;oBAAE,GAAG,CAAC,SAAS,CAAC,GAAG,EAAE,EAAE,cAAc,EAAE,2BAA2B,EAAE,CAAC,CAAA;gBACzF,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,GAAG,EAAE,OAAO,IAAI,GAAG,CAAC,CAAC,CAAA;YACtC,CAAC,CAAC,CAAA;QACJ,CAAC,CAAC,CAAA;QACF,MAAM,MAAM,GAAG,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,oBAAoB,IAAI,YAAY,CAAC,CAAA;QACvE,MAAM,KAAK,GAAG,GAAG,EAAE;YACjB,MAAM,CAAC,KAAK,EAAE,CAAA;YACd,OAAO,CAAC,EAAE,MAAM,EAAE,IAAI,EAAG,MAAM,CAAC,OAAO,EAAuB,CAAC,IAAI,EAAE,CAAC,CAAA;QACxE,CAAC,CAAA;QACD,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC,GAA0B,EAAE,EAAE;YAClD,0EAA0E;YAC1E,IAAI,GAAG,CAAC,IAAI,KAAK,YAAY,IAAI,MAAM,KAAK,CAAC,EAAE,CAAC;gBAC9C,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,MAAM,CAAC,CAAA;gBAC5B,MAAM,CAAC,MAAM,CAAC,CAAC,EAAE,WAAW,EAAE,KAAK,CAAC,CAAA;YACtC,CAAC;;gBAAM,MAAM,CAAC,GAAG,CAAC,CAAA;QACpB,CAAC,CAAC,CAAA;QACF,MAAM,CAAC,MAAM,CAAC,MAAM,EAAE,WAAW,EAAE,KAAK,CAAC,CAAA;IAC3C,CAAC,CAAC,CAAA;IACF,OAAO,QAAQ,CAAA;AACjB,CAAC;AAED,gEAAgE;AAChE,MAAM,CAAC,KAAK,UAAU,iBAAiB,CAAC,MAAoB;IAC1D,MAAM,EAAE,IAAI,EAAE,GAAG,MAAM,MAAM,EAAE,CAAA;IAC/B,MAAM,KAAK,GAAU,EAAE,KAAK,EAAE,WAAW,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,GAAG,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,CAAA;IAClL,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,EAAE,KAAK,CAAC,CAAA;IAChC,MAAM,GAAG,GAAG,oBAAoB,IAAI,MAAM,KAAK,CAAC,KAAK,EAAE,CAAA;IACvD,MAAM,IAAI,GAAG,GAAG,EAAE;QAChB,KAAK,CAAC,MAAM,GAAG,IAAI,CAAA;QACnB,OAAO,OAAO,CAAC,GAAG,CAAC,0BAA0B,KAAK,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,WAAW,CAAC,GAAG,CAAC,CAAA;IAClF,CAAC,CAAA;IACD,OAAO;QACL,GAAG;QACH,IAAI;QACJ,KAAK,EAAE,GAAG,EAAE;YACV,KAAK,CAAC,KAAK,GAAG,IAAI,CAAA;YAClB,6EAA6E;YAC7E,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,IAAI,KAAK,CAAC,MAAM;gBAAE,OAAM;YAC/C,KAAK,OAAO,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,GAAG,EAAE;gBAC5B,SAAS,CAAC,KAAK,EAAE,OAAO,EAAE,EAAE,OAAO,EAAE,KAAK,CAAC,OAAO,EAAE,CAAC,CAAA;gBACrD,yDAAyD;gBACzD,IAAI,CAAC,KAAK,CAAC,MAAM,IAAI,KAAK,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC;oBAChD,KAAK,CAAC,MAAM,GAAG,IAAI,CAAA;oBACnB,IAAI,OAAO,CAAC,GAAG,CAAC,oBAAoB,KAAK,GAAG,IAAI,OAAO,CAAC,GAAG,CAAC,0BAA0B,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI;wBAAE,WAAW,CAAC,GAAG,CAAC,CAAA;gBACzI,CAAC;YACH,CAAC,EAAE,GAAG,CAAC,EAAE,CAAC,MAAM,CAAC,GAAG,EAAE,CAAC,WAAW,GAAG,EAAE,OAAO,IAAI,GAAG,EAAE,CAAC,CAAC,CAAA;QAC3D,CAAC;QACD,KAAK,EAAE,GAAG,EAAE;YACV,SAAS,CAAC,KAAK,EAAE,QAAQ,EAAE,EAAE,CAAC,CAAA;YAC9B,KAAK,MAAM,GAAG,IAAI,KAAK,CAAC,OAAO;gBAAE,GAAG,CAAC,GAAG,EAAE,CAAA;YAC1C,KAAK,CAAC,OAAO,CAAC,KAAK,EAAE,CAAA;YACrB,QAAQ,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,CAAA;QAC9B,CAAC;KACF,CAAA;AACH,CAAC;AAED,wFAAwF;AACxF,SAAS,OAAO,CAAC,KAAY;IAC3B,KAAK,CAAC,QAAQ,KAAK,CAAC,KAAK,IAAI,EAAE;QAC7B,KAAK,CAAC,KAAK,GAAG,KAAK,CAAA;QACnB,MAAM,KAAK,GAAG,MAAM,KAAK,CAAC,MAAM,CAAC,IAAI,EAAE,CAAA;QACvC,MAAM,KAAK,GAAG,UAAU,CAAC,KAAK,EAAE,IAAI,EAAE,KAAK,EAAE,OAAO,CAAC,CAAA;QACrD,KAAK,CAAC,KAAK,GAAG,KAAK,CAAA;QACnB,KAAK,CAAC,OAAO,EAAE,CAAA;QACf,KAAK,CAAC,IAAI,GAAG,QAAQ,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,OAAO,EAAE,KAAK,CAAC,OAAO,EAAE,IAAI,EAAE,KAAK,CAAC,MAAM,CAAC,IAAI,EAAE,IAAI,IAAI,EAAE,MAAM,EAAE,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,EAAE,KAAK,EAAE,CAAC,CAAC,CAAA;IAC5I,CAAC,CAAC,EAAE,CAAC,OAAO,CAAC,GAAG,EAAE;QAChB,KAAK,CAAC,QAAQ,GAAG,IAAI,CAAA;IACvB,CAAC,CAAC,CAAA;IACF,OAAO,KAAK,CAAC,QAAQ,CAAA;AACvB,CAAC;AAED,SAAS,SAAS,CAAC,KAAY,EAAE,KAAa,EAAE,IAAa;IAC3D,MAAM,KAAK,GAAG,UAAU,KAAK,WAAW,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,MAAM,CAAA;IAClE,KAAK,MAAM,GAAG,IAAI,KAAK,CAAC,OAAO;QAAE,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,CAAA;AACnD,CAAC;AAED,MAAM,YAAY,GAAG,EAAE,eAAe,EAAE,UAAU,EAAE,wBAAwB,EAAE,SAAS,EAAE,iBAAiB,EAAE,aAAa,EAAE,CAAA;AAE3H,KAAK,UAAU,MAAM,CAAC,GAAoB,EAAE,GAAmB;IAC7D,MAAM,IAAI,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,SAAS,IAAI,CAAC,CAAW,CAAA;IAClD,6EAA6E;IAC7E,IAAI,GAAG,CAAC,OAAO,CAAC,IAAI,KAAK,aAAa,IAAI,EAAE,IAAI,GAAG,CAAC,OAAO,CAAC,IAAI,KAAK,aAAa,IAAI,EAAE;QAAE,OAAO,IAAI,CAAC,GAAG,EAAE,GAAG,EAAE,WAAW,CAAC,CAAA;IAC5H,IAAI,GAAG,CAAC,MAAM,KAAK,KAAK,IAAI,GAAG,CAAC,MAAM,KAAK,MAAM;QAAE,OAAO,IAAI,CAAC,GAAG,EAAE,GAAG,EAAE,oBAAoB,CAAC,CAAA;IAC9F,MAAM,IAAI,GAAG,kBAAkB,CAAC,IAAI,GAAG,CAAC,GAAG,CAAC,GAAG,IAAI,GAAG,EAAE,oBAAoB,IAAI,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAA;IAE7F,IAAI,IAAI,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;QAChC,MAAM,KAAK,GAAG,UAAU,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,CAAA;QAC7D,IAAI,CAAC,KAAK,IAAI,IAAI,CAAC,QAAQ,CAAC,YAAY,CAAC;YAAE,OAAO,IAAI,CAAC,GAAG,EAAE,GAAG,EAAE,WAAW,CAAC,CAAA;QAC7E,GAAG,CAAC,SAAS,CAAC,GAAG,EAAE,EAAE,GAAG,YAAY,EAAE,cAAc,EAAE,KAAK,CAAC,IAAI,EAAE,eAAe,EAAE,UAAU,EAAE,CAAC,CAAA;QAChG,OAAO,KAAK,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,CAAA;IACjC,CAAC;IAED,MAAM,CAAC,GAAG,sCAAsC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;IAC3D,IAAI,CAAC,CAAC;QAAE,OAAO,IAAI,CAAC,GAAG,EAAE,GAAG,EAAE,WAAW,CAAC,CAAA;IAC1C,MAAM,KAAK,GAAG,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAA;IAChC,MAAM,IAAI,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAA;IAEvB,IAAI,IAAI,KAAK,EAAE,IAAI,IAAI,KAAK,GAAG,EAAE,CAAC;QAChC,kEAAkE;QAClE,MAAM,IAAI,GAAG,UAAU,EAAE,CAAC,GAAG,CAAC,YAAY,CAAC,CAAA;QAC3C,IAAI,CAAC,IAAI;YAAE,OAAO,IAAI,CAAC,GAAG,EAAE,GAAG,EAAE,4CAA4C,CAAC,CAAA;QAC9E,MAAM,KAAK,GAAG,WAAW,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAA;QAChD,GAAG,CAAC,SAAS,CAAC,GAAG,EAAE;YACjB,GAAG,YAAY;YACf,cAAc,EAAE,IAAI,CAAC,IAAI;YACzB,yBAAyB,EAAE,gDAAgD,KAAK,+HAA+H;SAChN,CAAC,CAAA;QACF,OAAO,KAAK,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,UAAU,CAAC,WAAW,EAAE,KAAK,CAAC,CAAC,CAAA;IAChF,CAAC;IACD,IAAI,CAAC,KAAK;QAAE,OAAO,IAAI,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE,KAAK,EAAE,2CAA2C,EAAE,CAAC,CAAA;IAEzF,IAAI,IAAI,KAAK,QAAQ,EAAE,CAAC;QACtB,kGAAkG;QAClG,IAAI,KAAK,CAAC,QAAQ;YAAE,MAAM,KAAK,CAAC,QAAQ,CAAA;QACxC,IAAI,KAAK,CAAC,KAAK,IAAI,CAAC,KAAK,CAAC,IAAI;YAAE,MAAM,OAAO,CAAC,KAAK,CAAC,CAAA;QACpD,GAAG,CAAC,SAAS,CAAC,GAAG,EAAE,EAAE,GAAG,YAAY,EAAE,cAAc,EAAE,iCAAiC,EAAE,kBAAkB,EAAE,MAAM,EAAE,CAAC,CAAA;QACtH,OAAO,KAAK,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,CAAA;IACjC,CAAC;IAED,IAAI,IAAI,KAAK,SAAS,EAAE,CAAC;QACvB,GAAG,CAAC,SAAS,CAAC,GAAG,EAAE,EAAE,GAAG,YAAY,EAAE,cAAc,EAAE,kCAAkC,EAAE,UAAU,EAAE,YAAY,EAAE,CAAC,CAAA;QACrH,GAAG,CAAC,KAAK,CAAC,oCAAoC,IAAI,CAAC,SAAS,CAAC,EAAE,OAAO,EAAE,KAAK,CAAC,OAAO,EAAE,CAAC,MAAM,CAAC,CAAA;QAC/F,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,CAAA;QACtB,KAAK,CAAC,MAAM,GAAG,IAAI,CAAA;QACnB,MAAM,IAAI,GAAG,WAAW,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,kBAAkB,CAAC,EAAE,MAAM,CAAC,CAAA;QACrE,IAAI,CAAC,KAAK,EAAE,CAAA;QACZ,GAAG,CAAC,EAAE,CAAC,OAAO,EAAE,GAAG,EAAE;YACnB,aAAa,CAAC,IAAI,CAAC,CAAA;YACnB,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,CAAA;QAC3B,CAAC,CAAC,CAAA;QACF,OAAM;IACR,CAAC;IAED,MAAM,IAAI,GAAG,+CAA+C,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;IACvE,IAAI,IAAI,EAAE,CAAC;QACT,MAAM,GAAG,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,CAAA;QACjC,IAAI,IAAY,CAAA;QAChB,IAAI,IAAY,CAAA;QAChB,IAAI,GAAG,KAAK,KAAK,EAAE,CAAC;YAClB,IAAI,KAAK,CAAC,QAAQ;gBAAE,MAAM,KAAK,CAAC,QAAQ,CAAA;YACxC,IAAI,KAAK,CAAC,KAAK,IAAI,CAAC,KAAK,CAAC,KAAK;gBAAE,MAAM,OAAO,CAAC,KAAK,CAAC,CAAA;YACrD,IAAI,GAAG,UAAU,CAAC,KAAK,CAAC,KAAM,CAAC,CAAA;YAC/B,IAAI,GAAG,mBAAmB,CAAA;QAC5B,CAAC;aAAM,CAAC;YACN,IAAI,GAAG,MAAM,KAAK,CAAC,MAAM,CAAC,WAAW,CAAC,GAAG,KAAK,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAA;YACpE,IAAI,GAAG,GAAG,KAAK,KAAK,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,YAAY,CAAA;QACnD,CAAC;QACD,MAAM,IAAI,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,mBAAmB,EAAE,GAAG,CAAC,CAAA;QACtD,GAAG,CAAC,SAAS,CAAC,GAAG,EAAE,EAAE,GAAG,YAAY,EAAE,cAAc,EAAE,IAAI,EAAE,gBAAgB,EAAE,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,qBAAqB,EAAE,yBAAyB,IAAI,IAAI,GAAG,GAAG,EAAE,CAAC,CAAA;QACpK,OAAO,KAAK,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,CAAA;IAC3B,CAAC;IAED,OAAO,IAAI,CAAC,GAAG,EAAE,GAAG,EAAE,WAAW,CAAC,CAAA;AACpC,CAAC;AAED,SAAS,IAAI,CAAC,GAAmB,EAAE,MAAc,EAAE,IAAY;IAC7D,GAAG,CAAC,SAAS,CAAC,MAAM,EAAE,EAAE,GAAG,YAAY,EAAE,cAAc,EAAE,2BAA2B,EAAE,CAAC,CAAA;IACvF,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,CAAA;AACf,CAAC;AAED,SAAS,IAAI,CAAC,GAAmB,EAAE,MAAc,EAAE,IAAa;IAC9D,GAAG,CAAC,SAAS,CAAC,MAAM,EAAE,EAAE,GAAG,YAAY,EAAE,cAAc,EAAE,iCAAiC,EAAE,CAAC,CAAA;IAC7F,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAA;AAC/B,CAAC"}
@@ -0,0 +1,15 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="256" height="256" viewBox="0 0 200 200">
2
+ <title>ClassCAD</title>
3
+ <defs>
4
+ <mask id="cube">
5
+ <rect width="200" height="200" fill="#fff"/>
6
+ <path d="M100 -4V204M100 100L4 44.5M100 100L196 44.5" stroke="#000" stroke-width="10"/>
7
+ </mask>
8
+ </defs>
9
+ <g mask="url(#cube)">
10
+ <path d="M100 0L13 50L100 100Z" fill="#8f0d10"/>
11
+ <path d="M100 0L187 50L100 100Z" fill="#e8232a"/>
12
+ <path d="M13 50L100 100V200L13 150Z" fill="#e8232a"/>
13
+ <path d="M187 50L100 100V200L187 150Z" fill="#8f0d10"/>
14
+ </g>
15
+ </svg>