@cadit-app/maker-chips 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/src/main.ts ADDED
@@ -0,0 +1,36 @@
1
+ /**
2
+ * @cadit-app/maker-chips
3
+ *
4
+ * A customizable maker chip generator with patterns, center circles,
5
+ * and optional embedded QR codes.
6
+ */
7
+
8
+ import { defineParams } from '@cadit-app/script-params';
9
+ import { Manifold } from '@cadit-app/manifold-3d/manifoldCAD';
10
+ import { assembleMakerchipShapes, AssemblyType } from './assembly';
11
+ import { threeMfExporter } from './threeMfExport';
12
+ import { makerChipParamsSchema, MakerChipParams } from './params';
13
+
14
+ // Re-export for external use
15
+ export { assembleMakerchipShapes } from './assembly';
16
+ export { makerChipParamsSchema } from './params';
17
+ export type { MakerChipParams } from './params';
18
+
19
+ /**
20
+ * Main entry point using defineParams
21
+ */
22
+ export default defineParams({
23
+ params: makerChipParamsSchema,
24
+ exporters: {
25
+ '3mf': threeMfExporter as any,
26
+ },
27
+ main: async (params): Promise<Manifold> => {
28
+ const assemblyType = params.assemblyType as AssemblyType;
29
+
30
+ // Get all shapes for the assembly
31
+ const allShapes = await assembleMakerchipShapes(params as MakerChipParams, assemblyType);
32
+
33
+ // Compose all shapes into a single manifold
34
+ return Manifold.compose(allShapes);
35
+ },
36
+ });
package/src/params.ts ADDED
@@ -0,0 +1,110 @@
1
+ /**
2
+ * Parameter schema for the Makerchip generator.
3
+ */
4
+
5
+ import { svgDataUrls } from './embeddedSvgs';
6
+ import qrCodeMaker from '@cadit-app/qr-code';
7
+ import imageExtrudeMaker from '@cadit-app/image-extrude';
8
+ import type { EmbeddedParamValue } from '@cadit-app/script-params';
9
+
10
+ // Get the params from the imported makers
11
+ const qrCodeParams = qrCodeMaker.params;
12
+ const imageExtrudeParams = imageExtrudeMaker.params;
13
+
14
+ // Override defaults for embedded use (smaller sizes to fit in chip)
15
+ const qrCodeParamsWithOverrides = {
16
+ ...qrCodeParams,
17
+ size: { ...qrCodeParams.size, default: 18 },
18
+ };
19
+
20
+ const imageExtrudeParamsWithOverrides = {
21
+ ...imageExtrudeParams,
22
+ maxWidth: { ...imageExtrudeParams.maxWidth, default: 18 },
23
+ };
24
+
25
+ export const makerChipParamsSchema = {
26
+ radius: {
27
+ type: 'number',
28
+ label: 'Chip Radius (mm)',
29
+ default: 20,
30
+ min: 10,
31
+ max: 100,
32
+ },
33
+ height: {
34
+ type: 'number',
35
+ label: 'Extrusion Height (mm)',
36
+ default: 3,
37
+ },
38
+ roundingRadius: {
39
+ type: 'number',
40
+ label: "Round the chip's edges (mm)",
41
+ default: 1,
42
+ min: 0,
43
+ },
44
+ centerCircleRadius: {
45
+ type: 'number',
46
+ label: 'Center Circle Radius (mm)',
47
+ default: 14,
48
+ },
49
+ assemblyType: {
50
+ type: 'choice',
51
+ label: 'Assembly Type',
52
+ options: [
53
+ { value: 'flat', label: 'Flat (for preview/export)' },
54
+ { value: 'printable', label: 'Assembled (for 3D printing)' },
55
+ ],
56
+ default: 'flat',
57
+ },
58
+ markings: {
59
+ type: 'buttonGrid',
60
+ label: 'Pattern Style',
61
+ options: [
62
+ { value: 'makerChipV1', image: svgDataUrls.makerChipV1 },
63
+ { value: 'makerChipV2', image: svgDataUrls.makerChipV2 },
64
+ { value: 'makerChipV3', image: svgDataUrls.makerChipV3 },
65
+ { value: 'makerChipV4', image: svgDataUrls.makerChipV4 },
66
+ { value: 'makerChipV5', image: svgDataUrls.makerChipV5 },
67
+ { value: 'makerChipV6', image: svgDataUrls.makerChipV6 },
68
+ { value: 'makerChipV7', image: svgDataUrls.makerChipV7 },
69
+ { value: 'makerChipV8', image: svgDataUrls.makerChipV8 },
70
+ { value: 'makerChipV9', image: svgDataUrls.makerChipV9 },
71
+ { value: 'makerChipV10', image: svgDataUrls.makerChipV10 },
72
+ { value: 'makerChipV11', image: svgDataUrls.makerChipV11 },
73
+ { value: 'makerChipV12', image: svgDataUrls.makerChipV12 },
74
+ { value: 'makerChipV13', image: svgDataUrls.makerChipV13 },
75
+ { value: 'makerChipV14', image: svgDataUrls.makerChipV14 },
76
+ { value: 'makerChipV15', image: svgDataUrls.makerChipV15 },
77
+ { value: 'makerChipV16', image: svgDataUrls.makerChipV16 },
78
+ { value: 'makerChipV17', image: svgDataUrls.makerChipV17 },
79
+ { value: 'makerChipV18', image: svgDataUrls.makerChipV18 },
80
+ { value: 'makerChipV19', image: svgDataUrls.makerChipV19 },
81
+ { value: 'makerChipV20', image: svgDataUrls.makerChipV20 },
82
+ ],
83
+ default: 'makerChipV1',
84
+ },
85
+ qrCodeSettings: {
86
+ type: 'embedded',
87
+ label: 'QR Code (Optional)',
88
+ params: qrCodeParamsWithOverrides,
89
+ enabled: false,
90
+ showSettings: false,
91
+ },
92
+ imageExtrudeSettings: {
93
+ type: 'embedded',
94
+ label: 'Image Extrude (Optional)',
95
+ params: imageExtrudeParamsWithOverrides,
96
+ enabled: false,
97
+ showSettings: false,
98
+ },
99
+ } as const;
100
+
101
+ export type MakerChipParams = {
102
+ radius: number;
103
+ height: number;
104
+ roundingRadius: number;
105
+ centerCircleRadius: number;
106
+ assemblyType: 'flat' | 'printable';
107
+ markings: string;
108
+ qrCodeSettings: EmbeddedParamValue<typeof qrCodeParamsWithOverrides>;
109
+ imageExtrudeSettings: EmbeddedParamValue<typeof imageExtrudeParamsWithOverrides>;
110
+ };
@@ -0,0 +1,123 @@
1
+ /**
2
+ * 3MF Exporter for Makerchip.
3
+ * Exports the chip with separate parts for multi-color printing.
4
+ */
5
+
6
+ // @ts-ignore - No type declarations available
7
+ import type { Exporter, ExportResult } from '@cadit-app/script-params';
8
+ import type { Manifold } from '@cadit-app/manifold-3d';
9
+ // @ts-ignore - No type declarations available
10
+ import { to3dmodel, fileForContentTypes, FileForRelThumbnail } from '@jscadui/3mf-export';
11
+ import { strToU8, Zippable, zipSync } from 'fflate';
12
+ import { assembleMakerchipShapes } from './assembly';
13
+ import type { MakerChipParams } from './params';
14
+
15
+ /**
16
+ * Export the Makerchip as a 3MF file.
17
+ * Always uses the "printable" assembly for proper multi-part export.
18
+ */
19
+ export async function threeMfExport(params: MakerChipParams): Promise<ExportResult> {
20
+ // Always use the "printable" assembly for 3MF export
21
+ const shapes = await assembleMakerchipShapes(params, 'printable');
22
+
23
+ // Export each shape as a separate mesh
24
+ const meshes = shapes.map((shape, i) => {
25
+ const mesh = shape.getMesh();
26
+ return {
27
+ id: (i + 1).toString(),
28
+ vertices: mesh.vertProperties,
29
+ indices: mesh.triVerts,
30
+ name: `Makerchip-Part-${i + 1}`,
31
+ };
32
+ });
33
+
34
+ // Generate a single component, with all meshes as children, in order
35
+ const components = [
36
+ {
37
+ id: meshes.length + 1,
38
+ children: meshes.map((mesh) => ({ objectID: mesh.id })),
39
+ name: 'Makerchip-Assembly',
40
+ },
41
+ ];
42
+
43
+ // The main item should reference the components
44
+ const items = components.map((component) => ({
45
+ objectID: component.id,
46
+ }));
47
+
48
+ const header = {
49
+ unit: 'millimeter',
50
+ title: 'CADit Makerchip',
51
+ description: 'Makerchip 3MF export',
52
+ application: 'CADit',
53
+ };
54
+
55
+ const to3mf = {
56
+ meshes,
57
+ components,
58
+ items,
59
+ precision: 7,
60
+ header,
61
+ };
62
+
63
+ // Generate the 3MF XML model
64
+ const model = to3dmodel(to3mf as any);
65
+
66
+ // Package the 3MF file using fflate
67
+ const fileForRelThumbnail = new FileForRelThumbnail();
68
+ fileForRelThumbnail.add3dModel('3D/3dmodel.model');
69
+
70
+ const files: Zippable = {};
71
+ files['3D/3dmodel.model'] = strToU8(model);
72
+ files[fileForContentTypes.name] = strToU8(fileForContentTypes.content);
73
+ files[fileForRelThumbnail.name] = strToU8(fileForRelThumbnail.content);
74
+
75
+ // Set extruders for multi-color printing
76
+ const modelSettingsXml = generateModelSettingsConfig(meshes.length);
77
+ files['Metadata/model_settings.config'] = strToU8(modelSettingsXml);
78
+
79
+ const zipFile = zipSync(files);
80
+
81
+ return {
82
+ mimeType: 'model/3mf',
83
+ fileName: 'makerchip.3mf',
84
+ data: zipFile.buffer as ArrayBuffer,
85
+ };
86
+ }
87
+
88
+ /**
89
+ * Generate the model_settings.config XML for multi-extruder support.
90
+ */
91
+ function generateModelSettingsConfig(partsCount: number): string {
92
+ // Assign extruder numbers 1-4, repeat 4 for any extra parts
93
+ const extruderForPart = (i: number) => (i < 4 ? i + 1 : 4);
94
+
95
+ let partsXml = '';
96
+ for (let i = 0; i < partsCount; i++) {
97
+ partsXml += `
98
+ <part id="${i + 1}" subtype="normal_part">
99
+ <metadata key="name" value="Makerchip-Assembly_${i + 1}"/>
100
+ <metadata key="extruder" value="${extruderForPart(i)}"/>
101
+ </part>`;
102
+ }
103
+
104
+ return `<?xml version="1.0" encoding="UTF-8"?>
105
+ <config>
106
+ <object id="${partsCount + 1}">
107
+ <metadata key="name" value="Makerchip-Assembly"/>
108
+ <metadata key="extruder" value="1"/>
109
+ ${partsXml}
110
+ </object>
111
+ </config>
112
+ `;
113
+ }
114
+
115
+ /**
116
+ * 3MF Exporter for defineParams.
117
+ */
118
+ export const threeMfExporter: Exporter<MakerChipParams> = {
119
+ name: '3MF',
120
+ label: 'Download 3MF',
121
+ description: 'Export the Makerchip as a 3MF file for multi-color 3D printing.',
122
+ export: threeMfExport,
123
+ };
package/src/utils.ts ADDED
@@ -0,0 +1,32 @@
1
+ /**
2
+ * Utility for parsing SVG content to CrossSection.
3
+ */
4
+
5
+ import { svgToPolygons } from '@cadit-app/svg-sampler';
6
+ import { embeddedSvgs } from './embeddedSvgs';
7
+ import { CrossSection } from '@cadit-app/manifold-3d/manifoldCAD';
8
+
9
+ /**
10
+ * Parse an SVG pattern name to a CrossSection
11
+ */
12
+ export async function parseSvgToCrossSection(
13
+ shapeName: string,
14
+ maxError: number = 0.01
15
+ ): Promise<CrossSection> {
16
+ // Get the SVG content from embedded SVGs
17
+ const svgContent = embeddedSvgs[shapeName];
18
+ if (!svgContent) {
19
+ throw new Error(`Unknown shape: ${shapeName}. Available shapes: ${Object.keys(embeddedSvgs).join(', ')}`);
20
+ }
21
+
22
+ // Sample the SVG into polygons
23
+ const polygons = await svgToPolygons(svgContent, { maxError });
24
+
25
+ // Flip the Y-axis for SVG paths (SVG uses Y-down, but 3D modeling uses Y-up)
26
+ const flippedPolygons = polygons.map((polygon) => {
27
+ return polygon.points.map(([x, y]) => [x, -y]) as [number, number][];
28
+ });
29
+
30
+ // Create and return a cross-section from the sampled paths
31
+ return new CrossSection(flippedPolygons, 'EvenOdd').simplify(maxError);
32
+ }
package/tsconfig.json ADDED
@@ -0,0 +1,19 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2022",
4
+ "module": "ESNext",
5
+ "moduleResolution": "bundler",
6
+ "lib": ["ES2022"],
7
+ "strict": true,
8
+ "esModuleInterop": true,
9
+ "skipLibCheck": true,
10
+ "declaration": true,
11
+ "outDir": "./dist",
12
+ "rootDir": ".",
13
+ "resolveJsonModule": true,
14
+ "allowSyntheticDefaultImports": true,
15
+ "noEmit": true
16
+ },
17
+ "include": ["src/**/*", "cli.ts"],
18
+ "exclude": ["node_modules", "dist"]
19
+ }