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.
Files changed (31) hide show
  1. package/README.md +1 -1
  2. package/dist/assets/stickers/community/brew-fx.webp +0 -0
  3. package/dist/assets/stickers/community/brew.webp +0 -0
  4. package/dist/assets/stickers/community/crafter-fx.webp +0 -0
  5. package/dist/assets/stickers/community/crafter.webp +0 -0
  6. package/dist/assets/stickers/community/friday-fx.webp +0 -0
  7. package/dist/assets/stickers/community/friday.webp +0 -0
  8. package/dist/assets/stickers/community/provenance.json +43 -0
  9. package/dist/assets/stickers/typingmind/absolutely-right-fx.webp +0 -0
  10. package/dist/assets/stickers/typingmind/absolutely-right.webp +0 -0
  11. package/dist/assets/stickers/typingmind/agi-disco-fx.webp +0 -0
  12. package/dist/assets/stickers/typingmind/agi-disco.webp +0 -0
  13. package/dist/assets/stickers/typingmind/agi-is-coming-fx.webp +0 -0
  14. package/dist/assets/stickers/typingmind/agi-is-coming.webp +0 -0
  15. package/dist/assets/stickers/typingmind/cmd-enter-fx.webp +0 -0
  16. package/dist/assets/stickers/typingmind/cmd-enter.webp +0 -0
  17. package/dist/assets/stickers/typingmind/emotional-support-fx.webp +0 -0
  18. package/dist/assets/stickers/typingmind/emotional-support.webp +0 -0
  19. package/dist/assets/stickers/typingmind/energy-fx.webp +0 -0
  20. package/dist/assets/stickers/typingmind/energy.webp +0 -0
  21. package/dist/assets/stickers/typingmind/motion-fx.webp +0 -0
  22. package/dist/assets/stickers/typingmind/motion.webp +0 -0
  23. package/dist/assets/stickers/typingmind/provenance.json +97 -0
  24. package/dist/assets/stickers/typingmind/typingmind-fx.webp +0 -0
  25. package/dist/assets/stickers/typingmind/typingmind.webp +0 -0
  26. package/dist/assets/stickers/typingmind/youre-cooked-fx.webp +0 -0
  27. package/dist/assets/stickers/typingmind/youre-cooked.webp +0 -0
  28. package/dist/{chunk-WVXA65H6.js → chunk-4AJQBAFB.js} +2757 -293
  29. package/dist/cli.js +75 -18
  30. package/dist/{mcp-LKLESPJC.js → mcp-LXTO7XOO.js} +11 -2
  31. 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-WVXA65H6.js";
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 readFile5 } from "fs/promises";
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 sharp5 from "sharp";
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 readFile4, rename as rename2, rm as rm2, writeFile as writeFile2 } from "fs/promises";
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 sharp4 from "sharp";
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 readFile4(input);
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 sharp4(source, { limitInputPixels: 24e6, density: 144 }).rotate().resize(1536, 969, { fit: "contain", background: "#000000" }).flatten({ background: "#000000" }).toColourspace("srgb").png().toBuffer();
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-LKLESPJC.js");
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 readFile5(path2, "utf8"));
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 good-energy --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"
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 readFile5(handle, "utf8"));
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 readFile5(resolve5(value.slice(1)), "utf8") : value
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((entry) => entry.source === (values.style ?? "good-energy"));
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 readFile5(raw.slice(1), "utf8") : raw);
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 readFile5(resolve5(path), "utf8"));
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 readFile5(path, "utf8");
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 sharp5(Buffer.from(result2.svg)).png().toFile(preview);
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 readFile5(path, "utf8"));
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-WVXA65H6.js";
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(["core", "cards", "badges", "stickers", "design", "images", "wallet"]).optional(),
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.5.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"