makeables 0.5.0 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/assets/stickers/community/brew-fx.webp +0 -0
- package/dist/assets/stickers/community/brew.webp +0 -0
- package/dist/assets/stickers/community/crafter-fx.webp +0 -0
- package/dist/assets/stickers/community/crafter.webp +0 -0
- package/dist/assets/stickers/community/friday-fx.webp +0 -0
- package/dist/assets/stickers/community/friday.webp +0 -0
- package/dist/assets/stickers/community/provenance.json +43 -0
- package/dist/assets/stickers/typingmind/absolutely-right-fx.webp +0 -0
- package/dist/assets/stickers/typingmind/absolutely-right.webp +0 -0
- package/dist/assets/stickers/typingmind/agi-disco-fx.webp +0 -0
- package/dist/assets/stickers/typingmind/agi-disco.webp +0 -0
- package/dist/assets/stickers/typingmind/agi-is-coming-fx.webp +0 -0
- package/dist/assets/stickers/typingmind/agi-is-coming.webp +0 -0
- package/dist/assets/stickers/typingmind/cmd-enter-fx.webp +0 -0
- package/dist/assets/stickers/typingmind/cmd-enter.webp +0 -0
- package/dist/assets/stickers/typingmind/emotional-support-fx.webp +0 -0
- package/dist/assets/stickers/typingmind/emotional-support.webp +0 -0
- package/dist/assets/stickers/typingmind/energy-fx.webp +0 -0
- package/dist/assets/stickers/typingmind/energy.webp +0 -0
- package/dist/assets/stickers/typingmind/motion-fx.webp +0 -0
- package/dist/assets/stickers/typingmind/motion.webp +0 -0
- package/dist/assets/stickers/typingmind/provenance.json +97 -0
- package/dist/assets/stickers/typingmind/typingmind-fx.webp +0 -0
- package/dist/assets/stickers/typingmind/typingmind.webp +0 -0
- package/dist/assets/stickers/typingmind/youre-cooked-fx.webp +0 -0
- package/dist/assets/stickers/typingmind/youre-cooked.webp +0 -0
- package/dist/{chunk-WVXA65H6.js → chunk-4AJQBAFB.js} +2757 -293
- package/dist/cli.js +75 -18
- package/dist/{mcp-LKLESPJC.js → mcp-LXTO7XOO.js} +11 -2
- package/package.json +3 -3
package/dist/cli.js
CHANGED
|
@@ -40,15 +40,15 @@ import {
|
|
|
40
40
|
svgNodeXml,
|
|
41
41
|
version,
|
|
42
42
|
writeAtomic
|
|
43
|
-
} from "./chunk-
|
|
43
|
+
} from "./chunk-4AJQBAFB.js";
|
|
44
44
|
|
|
45
45
|
// src/cli.ts
|
|
46
46
|
import { spawnSync as spawnSync2 } from "child_process";
|
|
47
47
|
import { constants as constants2 } from "fs";
|
|
48
|
-
import { access, lstat as lstat2, open as open2, readFile as
|
|
48
|
+
import { access, lstat as lstat2, open as open2, readFile as readFile6 } from "fs/promises";
|
|
49
49
|
import { dirname as dirname3, extname as extname4, resolve as resolve5 } from "path";
|
|
50
50
|
import { parseArgs } from "util";
|
|
51
|
-
import
|
|
51
|
+
import sharp6 from "sharp";
|
|
52
52
|
import { zodToJsonSchema } from "zod-to-json-schema";
|
|
53
53
|
|
|
54
54
|
// src/card-import.ts
|
|
@@ -908,14 +908,51 @@ async function referenceImage(command, file, options, out, reference) {
|
|
|
908
908
|
}
|
|
909
909
|
}
|
|
910
910
|
|
|
911
|
+
// src/sticker-material.ts
|
|
912
|
+
import { readFile as readFile4, stat as stat3 } from "fs/promises";
|
|
913
|
+
import { basename as basename2 } from "path";
|
|
914
|
+
import sharp4 from "sharp";
|
|
915
|
+
async function bindStickerMap(design, layerId, path) {
|
|
916
|
+
if (design.product !== "sticker") throw new InputError("Optical maps require a sticker.");
|
|
917
|
+
const layer = design.front.layers.find((layer2) => layer2.id === layerId);
|
|
918
|
+
if (layer?.kind !== "image") throw new InputError("Choose a front image layer with --id.");
|
|
919
|
+
const info = await stat3(path);
|
|
920
|
+
if (!info.isFile() || info.size > 4e6)
|
|
921
|
+
throw new InputError("Use an optical image below 4 MB.");
|
|
922
|
+
const bytes = await readFile4(path);
|
|
923
|
+
const meta = await sharp4(bytes, { limitInputPixels: 16777216 }).metadata();
|
|
924
|
+
if (!meta.width || !meta.height || meta.width > 4096 || meta.height > 4096 || !["png", "webp"].includes(meta.format ?? ""))
|
|
925
|
+
throw new InputError("Use an RGB PNG or WebP optical map up to 4096 \xD7 4096.");
|
|
926
|
+
const asset = design.sticker?.effectMap?.asset ?? "optical-map";
|
|
927
|
+
if (design.front.layers.some((item) => item.kind === "image" && item.asset === asset))
|
|
928
|
+
throw new InputError(
|
|
929
|
+
"The optical-map asset is used as artwork. Rename it before binding a map."
|
|
930
|
+
);
|
|
931
|
+
return badgeDesignSchema.parse({
|
|
932
|
+
...design,
|
|
933
|
+
assets: {
|
|
934
|
+
...design.assets,
|
|
935
|
+
[asset]: {
|
|
936
|
+
source: "image",
|
|
937
|
+
name: basename2(path).slice(0, 80),
|
|
938
|
+
data: `data:image/${meta.format};base64,${bytes.toString("base64")}`
|
|
939
|
+
}
|
|
940
|
+
},
|
|
941
|
+
sticker: {
|
|
942
|
+
...design.sticker ?? defaultStickerMaterial,
|
|
943
|
+
effectMap: { asset, layer: layerId }
|
|
944
|
+
}
|
|
945
|
+
});
|
|
946
|
+
}
|
|
947
|
+
|
|
911
948
|
// src/wallet.ts
|
|
912
949
|
import { spawn } from "child_process";
|
|
913
950
|
import { createHash as createHash3 } from "crypto";
|
|
914
951
|
import { existsSync as existsSync2 } from "fs";
|
|
915
|
-
import { chmod, lstat, mkdir as mkdir2, mkdtemp, readFile as
|
|
952
|
+
import { chmod, lstat, mkdir as mkdir2, mkdtemp, readFile as readFile5, rename as rename2, rm as rm2, writeFile as writeFile2 } from "fs/promises";
|
|
916
953
|
import { homedir as homedir2, tmpdir as tmpdir2 } from "os";
|
|
917
954
|
import { dirname as dirname2, extname as extname3, join as join3, resolve as resolve4 } from "path";
|
|
918
|
-
import
|
|
955
|
+
import sharp5 from "sharp";
|
|
919
956
|
|
|
920
957
|
// src/wallet-release.json
|
|
921
958
|
var wallet_release_default = {
|
|
@@ -1106,13 +1143,13 @@ async function walletArtwork(file, side2 = "front") {
|
|
|
1106
1143
|
if (design.product !== "card") throw new InputError("Wallet artwork requires a card document.");
|
|
1107
1144
|
source = (await renderBadge(design, { face: side2, person: {} })).png;
|
|
1108
1145
|
} else {
|
|
1109
|
-
source = await
|
|
1146
|
+
source = await readFile5(input);
|
|
1110
1147
|
if (extname3(input).toLowerCase() === ".svg") {
|
|
1111
1148
|
const result = checkSubmittedSvg(source.toString("utf8"));
|
|
1112
1149
|
if (!result.ok) throw new InputError(result.error);
|
|
1113
1150
|
}
|
|
1114
1151
|
}
|
|
1115
|
-
return
|
|
1152
|
+
return sharp5(source, { limitInputPixels: 24e6, density: 144 }).rotate().resize(1536, 969, { fit: "contain", background: "#000000" }).flatten({ background: "#000000" }).toColourspace("srgb").png().toBuffer();
|
|
1116
1153
|
}
|
|
1117
1154
|
async function walletCommand(command, values, progress) {
|
|
1118
1155
|
const need = (flag) => {
|
|
@@ -1187,6 +1224,7 @@ var commands = [
|
|
|
1187
1224
|
"designs list",
|
|
1188
1225
|
"new card --design <slug> | --style <id> --out <new-file> [--dry-run]",
|
|
1189
1226
|
"material set --file <design.json> --params <json|@file>",
|
|
1227
|
+
"material map --file <sticker.json> --id <image-layer> --ref <optical.png|optical.webp>",
|
|
1190
1228
|
"new badge --style <id> --out <new-file> [--dry-run]",
|
|
1191
1229
|
"new sticker --style <id> --out <new-file> [--dry-run]",
|
|
1192
1230
|
"layer list --file <design.json>",
|
|
@@ -1379,6 +1417,7 @@ From a built checkout: npm run studio -- <command>`,
|
|
|
1379
1417
|
"new card": ["design", "style", "file", "name", "out", "dry-run"],
|
|
1380
1418
|
"new sticker": ["style", "out", "dry-run"],
|
|
1381
1419
|
"material set": ["file", "params"],
|
|
1420
|
+
"material map": ["file", "id", "ref"],
|
|
1382
1421
|
"new badge": ["style", "out", "dry-run"],
|
|
1383
1422
|
"layer list": ["file"],
|
|
1384
1423
|
"layer add": ["file", "sticker", "side"],
|
|
@@ -1552,7 +1591,7 @@ Run makeables skills get core for setup.`,
|
|
|
1552
1591
|
}
|
|
1553
1592
|
if (command === "mcp") {
|
|
1554
1593
|
try {
|
|
1555
|
-
const { runMcp } = await import("./mcp-
|
|
1594
|
+
const { runMcp } = await import("./mcp-LXTO7XOO.js");
|
|
1556
1595
|
await runMcp(values.root ?? process.cwd());
|
|
1557
1596
|
} catch (error) {
|
|
1558
1597
|
process.stderr.write(
|
|
@@ -1611,7 +1650,7 @@ Keep this process running while you design.`,
|
|
|
1611
1650
|
const info = await lstat2(path2);
|
|
1612
1651
|
if (!info.isFile() || info.size > 12e6)
|
|
1613
1652
|
throw new InputError("Expected a params file below 12 MB.");
|
|
1614
|
-
params = JSON.parse(await
|
|
1653
|
+
params = JSON.parse(await readFile6(path2, "utf8"));
|
|
1615
1654
|
} else if (values.params) params = JSON.parse(values.params);
|
|
1616
1655
|
}
|
|
1617
1656
|
const result2 = await studioRequest(
|
|
@@ -1653,7 +1692,7 @@ Keep this process running while you design.`,
|
|
|
1653
1692
|
emit(
|
|
1654
1693
|
{ styles },
|
|
1655
1694
|
[
|
|
1656
|
-
values.product === "sticker" ? "npx makeables new sticker --style
|
|
1695
|
+
values.product === "sticker" ? "npx makeables new sticker --style typingmind-absolutely-right --out sticker.json" : values.product === "card" ? "npx makeables new card --style pearl --out card.json" : "npx makeables design create --style opalo-lunar --out badge.json"
|
|
1657
1696
|
],
|
|
1658
1697
|
`${style(`${styles.length} starting points`, "1", !json)}
|
|
1659
1698
|
|
|
@@ -1724,7 +1763,7 @@ ${dryRun ? "Dry run. No files changed." : "2 faces \xB7 editable layers"}`,
|
|
|
1724
1763
|
const info = await handle.stat();
|
|
1725
1764
|
if (!info.isFile() || info.size > 2 * 1024 * 1024)
|
|
1726
1765
|
throw new InputError("Expected a JSON file smaller than 2 MB.");
|
|
1727
|
-
input = JSON.parse(await
|
|
1766
|
+
input = JSON.parse(await readFile6(handle, "utf8"));
|
|
1728
1767
|
} finally {
|
|
1729
1768
|
await handle.close();
|
|
1730
1769
|
}
|
|
@@ -1743,7 +1782,7 @@ Schema and layout constraints passed.`,
|
|
|
1743
1782
|
}
|
|
1744
1783
|
async function readParams(value) {
|
|
1745
1784
|
return JSON.parse(
|
|
1746
|
-
value.startsWith("@") ? await
|
|
1785
|
+
value.startsWith("@") ? await readFile6(resolve5(value.slice(1)), "utf8") : value
|
|
1747
1786
|
);
|
|
1748
1787
|
}
|
|
1749
1788
|
async function cardCommand(command, values, json) {
|
|
@@ -1754,7 +1793,9 @@ async function cardCommand(command, values, json) {
|
|
|
1754
1793
|
};
|
|
1755
1794
|
const renderHint = (path, face, design) => `npx makeables render --file ${JSON.stringify(path)} --side ${face} --out ${design.product ?? "badge"}.png --overwrite`;
|
|
1756
1795
|
if (command === "new sticker") {
|
|
1757
|
-
const preset = stickerStyles.find(
|
|
1796
|
+
const preset = stickerStyles.find(
|
|
1797
|
+
(entry) => entry.source === (values.style ?? "typingmind-absolutely-right")
|
|
1798
|
+
);
|
|
1758
1799
|
if (!preset)
|
|
1759
1800
|
throw new InputError("Unknown sticker style. Run makeables styles list --product sticker.");
|
|
1760
1801
|
const design = badgeDesignSchema.parse(structuredClone(preset));
|
|
@@ -1802,11 +1843,27 @@ ${path ?? `No file written. Add --out ${kind}.json.`}`,
|
|
|
1802
1843
|
);
|
|
1803
1844
|
return true;
|
|
1804
1845
|
}
|
|
1846
|
+
if (command === "material map") {
|
|
1847
|
+
const path = resolve5(need(file, "file"));
|
|
1848
|
+
const next = await bindStickerMap(
|
|
1849
|
+
await readBadge(path),
|
|
1850
|
+
need(values.id, "id"),
|
|
1851
|
+
need(values.ref, "ref")
|
|
1852
|
+
);
|
|
1853
|
+
await writeAtomic(path, JSON.stringify(next, null, 2));
|
|
1854
|
+
emit(
|
|
1855
|
+
{ material: next.sticker },
|
|
1856
|
+
["Preview the foil, glitter and relief in the sticker studio."],
|
|
1857
|
+
"Optical map attached.",
|
|
1858
|
+
json
|
|
1859
|
+
);
|
|
1860
|
+
return true;
|
|
1861
|
+
}
|
|
1805
1862
|
if (command === "material set") {
|
|
1806
1863
|
const path = resolve5(need(file, "file"));
|
|
1807
1864
|
const design = await readBadge(path);
|
|
1808
1865
|
const raw = need(values.params, "params");
|
|
1809
|
-
const input = JSON.parse(raw.startsWith("@") ? await
|
|
1866
|
+
const input = JSON.parse(raw.startsWith("@") ? await readFile6(raw.slice(1), "utf8") : raw);
|
|
1810
1867
|
if (design.product === "sticker") {
|
|
1811
1868
|
const patch2 = stickerMaterialSchema.partial().strict().safeParse(input);
|
|
1812
1869
|
if (!patch2.success)
|
|
@@ -1912,7 +1969,7 @@ ${path ?? `No file written. Add --out ${kind}.json.`}`,
|
|
|
1912
1969
|
if (number !== void 0 && !Number.isInteger(number))
|
|
1913
1970
|
throw new InputError("--number must be an integer.");
|
|
1914
1971
|
const face = side(values.side);
|
|
1915
|
-
const value = JSON.parse(await
|
|
1972
|
+
const value = JSON.parse(await readFile6(resolve5(path), "utf8"));
|
|
1916
1973
|
const pkg = value?.format === "makeables-package" ? await readPackageJson(value) : void 0;
|
|
1917
1974
|
if (pkg && ["photo", "name", "role", "number"].some((key) => values[key] !== void 0))
|
|
1918
1975
|
throw new InputError(
|
|
@@ -1976,11 +2033,11 @@ ${path ?? `No file written. Add --out ${kind}.json.`}`,
|
|
|
1976
2033
|
if (command === "validate") {
|
|
1977
2034
|
const path = resolve5(need(file, "file"));
|
|
1978
2035
|
if (extname4(path).toLowerCase() === ".svg") {
|
|
1979
|
-
const source = await
|
|
2036
|
+
const source = await readFile6(path, "utf8");
|
|
1980
2037
|
const result2 = checkSubmittedSvg(source);
|
|
1981
2038
|
if (!result2.ok) throw new InputError(result2.error);
|
|
1982
2039
|
const preview = values.out ? await newPath(need(values.out, "out")) : void 0;
|
|
1983
|
-
if (preview) await
|
|
2040
|
+
if (preview) await sharp6(Buffer.from(result2.svg)).png().toFile(preview);
|
|
1984
2041
|
emit(
|
|
1985
2042
|
{
|
|
1986
2043
|
valid: true,
|
|
@@ -1997,7 +2054,7 @@ ${path ?? `No file written. Add --out ${kind}.json.`}`,
|
|
|
1997
2054
|
return true;
|
|
1998
2055
|
}
|
|
1999
2056
|
if (values.out) throw new InputError("--out is only used to preview SVG validation.");
|
|
2000
|
-
const input = JSON.parse(await
|
|
2057
|
+
const input = JSON.parse(await readFile6(path, "utf8"));
|
|
2001
2058
|
const result = badgeDesignSchema.safeParse(input);
|
|
2002
2059
|
if (!result.success)
|
|
2003
2060
|
throw new InputError(
|
|
@@ -15,7 +15,7 @@ import {
|
|
|
15
15
|
stickerStyles,
|
|
16
16
|
version,
|
|
17
17
|
writeAtomic
|
|
18
|
-
} from "./chunk-
|
|
18
|
+
} from "./chunk-4AJQBAFB.js";
|
|
19
19
|
|
|
20
20
|
// src/mcp.ts
|
|
21
21
|
import { readFile as readFile2 } from "fs/promises";
|
|
@@ -236,7 +236,16 @@ async function createMakeablesMcp(root, html) {
|
|
|
236
236
|
description: "Inspect a local design and its revision, or load the bundled guides, catalog and shared document/patch schema.",
|
|
237
237
|
inputSchema: {
|
|
238
238
|
section: z.enum(["document", "catalog", "schema", "guide"]).default("document"),
|
|
239
|
-
guide: z.enum([
|
|
239
|
+
guide: z.enum([
|
|
240
|
+
"core",
|
|
241
|
+
"cards",
|
|
242
|
+
"badges",
|
|
243
|
+
"stickers",
|
|
244
|
+
"sticker-art-direction",
|
|
245
|
+
"design",
|
|
246
|
+
"images",
|
|
247
|
+
"wallet"
|
|
248
|
+
]).optional(),
|
|
240
249
|
file: file.optional()
|
|
241
250
|
},
|
|
242
251
|
annotations: readOnly
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "makeables",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.6.0",
|
|
4
4
|
"description": "Create editable cards, badges and stickers with layered designs, live materials and your coding agent.",
|
|
5
5
|
"homepage": "https://makeables.dev",
|
|
6
6
|
"repository": {
|
|
@@ -51,9 +51,9 @@
|
|
|
51
51
|
"@types/proper-lockfile": "4.1.4",
|
|
52
52
|
"tsup": "^8.4.0",
|
|
53
53
|
"typescript": "^5.8.3",
|
|
54
|
-
"@makeables/design": "0.0.1",
|
|
55
54
|
"@makeables/testing": "0.0.0",
|
|
56
|
-
"@makeables/renderer": "0.0.1"
|
|
55
|
+
"@makeables/renderer": "0.0.1",
|
|
56
|
+
"@makeables/design": "0.0.1"
|
|
57
57
|
},
|
|
58
58
|
"engines": {
|
|
59
59
|
"node": ">=22"
|