@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/README.md +107 -0
- package/cadit.json +28 -0
- package/cli.ts +218 -0
- package/images/preview.png +0 -0
- package/package.json +42 -0
- package/scripts/generate-embedded-svgs.cjs +57 -0
- package/src/assembly.ts +105 -0
- package/src/crossSectionUtils.ts +42 -0
- package/src/disk.ts +136 -0
- package/src/embeddedSvgs.ts +131 -0
- package/src/images/makerchip-v1.svg +5 -0
- package/src/images/makerchip-v10.svg +5 -0
- package/src/images/makerchip-v11.svg +5 -0
- package/src/images/makerchip-v12.svg +5 -0
- package/src/images/makerchip-v13.svg +5 -0
- package/src/images/makerchip-v14.svg +3 -0
- package/src/images/makerchip-v15.svg +3 -0
- package/src/images/makerchip-v16.svg +3 -0
- package/src/images/makerchip-v17.svg +5 -0
- package/src/images/makerchip-v18.svg +5 -0
- package/src/images/makerchip-v19.svg +5 -0
- package/src/images/makerchip-v2.svg +5 -0
- package/src/images/makerchip-v20.svg +5 -0
- package/src/images/makerchip-v3.svg +5 -0
- package/src/images/makerchip-v4.svg +5 -0
- package/src/images/makerchip-v5.svg +5 -0
- package/src/images/makerchip-v6.svg +5 -0
- package/src/images/makerchip-v7.svg +5 -0
- package/src/images/makerchip-v8.svg +5 -0
- package/src/images/makerchip-v9.svg +5 -0
- package/src/main.ts +36 -0
- package/src/params.ts +110 -0
- package/src/threeMfExport.ts +123 -0
- package/src/utils.ts +32 -0
- package/tsconfig.json +19 -0
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
|
+
}
|