@pixelvibing/cli 0.52.0 → 0.53.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.
@@ -4967,7 +4967,7 @@ const GENERATED = {
4967
4967
  "ui-sketch": { references: 3, words: "a UI" }
4968
4968
  };
4969
4969
  const KIND_NAMES = { ui: "ui-sketch", [OLD_CONCEPT_ART]: CONCEPT_ART };
4970
- const WORDS_ONLY = ["size", "transparent", "pixel-art", "no-pixel-art", "tag", "names", "purpose", "tiles", "sketch"];
4970
+ const WORDS_ONLY = ["size", "transparent", "pixel-art", "no-pixel-art", "tag", "mask", "names", "purpose", "tiles", "sketch"];
4971
4971
  const MORE_REFERENCES = 3;
4972
4972
  const ENRICHED = /* @__PURE__ */ new Set(["animate", "pose", "rotate", "terrain-animation"]);
4973
4973
  function listOf(given2, what) {
@@ -5075,17 +5075,17 @@ function sizeOf(given2, what) {
5075
5075
  if (match === null) throw new CliError(`${what} is <cols>x<rows>, such as 2x1, not ${given2}`);
5076
5076
  return { cols: Number(match[1]), rows: Number(match[2]) };
5077
5077
  }
5078
- async function referenceOf(context, path) {
5078
+ async function referenceOf(context, path, what = "reference") {
5079
5079
  const file = resolve(context.io.cwd, path);
5080
5080
  let size;
5081
5081
  try {
5082
5082
  size = (await stat(file)).size;
5083
5083
  } catch {
5084
- throw new CliError(`the reference ${path} cannot be read`);
5084
+ throw new CliError(`the ${what} ${path} cannot be read`);
5085
5085
  }
5086
- if (size > MAX_REFERENCE_BYTES) throw new CliError(`the reference ${path} is ${size} bytes, and one is at most ${MAX_REFERENCE_BYTES}`);
5086
+ if (size > MAX_REFERENCE_BYTES) throw new CliError(`the ${what} ${path} is ${size} bytes, and one is at most ${MAX_REFERENCE_BYTES}`);
5087
5087
  const bytes = new Uint8Array(await readFile(file));
5088
- if (!isPng(bytes)) throw new CliError(`the reference ${path} is not a PNG`);
5088
+ if (!isPng(bytes)) throw new CliError(`the ${what} ${path} is not a PNG`);
5089
5089
  return bytes;
5090
5090
  }
5091
5091
  async function requestOf(context, asked, args) {
@@ -5126,6 +5126,7 @@ async function shapedRequest(context, asked, args) {
5126
5126
  if (kind !== CONCEPT_ART) {
5127
5127
  for (const flag of ["pixel-art", "transparent"]) if (flagOf(args, flag)) throw new CliError(`--${flag} is a concept art's`);
5128
5128
  if (stringsOf(args, "tag").length > 0) throw new CliError("--tag is a concept art's");
5129
+ if (stringOf(args, "mask") !== void 0) throw new CliError("--mask is a concept art's");
5129
5130
  }
5130
5131
  if (kind === "ui-sketch") {
5131
5132
  for (const flag of ["names", "purpose", "size", "tiles"])
@@ -5153,7 +5154,15 @@ async function shapedRequest(context, asked, args) {
5153
5154
  for (const path of paths) references.push(await referenceOf(context, path));
5154
5155
  if (kind === CONCEPT_ART) {
5155
5156
  const { fields, words: words2 } = conceptFields(args, asked, instruction);
5156
- return { kind, body: { instruction, ...fields }, ...references.length > 0 ? { images: { references } } : {}, words: words2 };
5157
+ const maskPath = stringOf(args, "mask");
5158
+ const mask = maskPath === void 0 ? void 0 : await referenceOf(context, maskPath, "mask");
5159
+ const images = { ...references.length > 0 ? { references } : {}, ...mask === void 0 ? {} : { mask } };
5160
+ return {
5161
+ kind,
5162
+ body: { instruction, ...fields },
5163
+ ...Object.keys(images).length > 0 ? { images } : {},
5164
+ words: mask === void 0 ? words2 : words2.replace(/^(a concept art [^:]*?)(:)/, "$1, within its mask$2")
5165
+ };
5157
5166
  }
5158
5167
  const body = { instruction };
5159
5168
  let words = `${known.words}: ${instruction}`;
@@ -5195,7 +5204,7 @@ async function followed(context, platform, jobId) {
5195
5204
  const generate = {
5196
5205
  name: "generate",
5197
5206
  summary: "Generate an asset, a change of a picture, terrain or a sound on the platform, then pull it, keep it or write it",
5198
- usage: "<object|creature|concept-art|icons|ui|variant|edit|animate|pose|rotate|state|terrain|terrain-animation|sfx|speech|music> [--instruction <text>] [--source <image id>] [--state <state>] [--into <sprite> --name <name>] [--upper <ground> --lower <ground>] [--terrain <asset>] [--text <text> --voice <voice>] [--out <file>] [--size <c>x<r>|<w>x<h>|<px>] [--transparent] [--pixel-art] [--tiles <c>x<r>] [--tag <tag>]… [--names <list>] [--purpose skill|item] [--sketch <json>] [--reference <png>]… [--no-enrich] [--yes]",
5207
+ usage: "<object|creature|concept-art|icons|ui|variant|edit|animate|pose|rotate|state|terrain|terrain-animation|sfx|speech|music> [--instruction <text>] [--source <image id>] [--state <state>] [--into <sprite> --name <name>] [--upper <ground> --lower <ground>] [--terrain <asset>] [--text <text> --voice <voice>] [--out <file>] [--size <c>x<r>|<w>x<h>|<px>] [--transparent] [--pixel-art] [--tiles <c>x<r>] [--tag <tag>]… [--mask <png>] [--names <list>] [--purpose skill|item] [--sketch <json>] [--reference <png>]… [--no-enrich] [--yes]",
5199
5208
  options: {
5200
5209
  instruction: {
5201
5210
  type: "string",
@@ -5215,6 +5224,11 @@ const generate = {
5215
5224
  value: "<tag>",
5216
5225
  description: "what a concept art is for, such as anchor, ui, character, environment, prop or level-design; at most 8"
5217
5226
  },
5227
+ mask: {
5228
+ type: "string",
5229
+ value: "<png>",
5230
+ description: "where a concept art is drawn: an opaque black-and-white PNG in its shape, up to 1536 px a side, white drawn and black left empty"
5231
+ },
5218
5232
  names: { type: "string", value: "<list>", description: `an icon set's icons, comma-separated, at most ${MAX_ICONS}` },
5219
5233
  purpose: { type: "string", value: "skill|item", description: "whether an icon set is skills on badges or items alone; item unless given" },
5220
5234
  tiles: { type: "string", value: "<cols>x<rows>", description: "how many tiles a pixel-art concept art is across, 6x4 unless given" },
@@ -5725,7 +5739,7 @@ const move = {
5725
5739
  );
5726
5740
  }
5727
5741
  };
5728
- const version = "0.52.0";
5742
+ const version = "0.53.0";
5729
5743
  const manifest = {
5730
5744
  version
5731
5745
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pixelvibing/cli",
3
- "version": "0.52.0",
3
+ "version": "0.53.0",
4
4
  "description": "PixelVibing: pixel art game assets from the command line, and the Skills that teach coding assistants to make them.",
5
5
  "license": "MIT",
6
6
  "homepage": "https://pixelvibing.com",
@@ -16,7 +16,7 @@ reference to what follows.
16
16
  `pixel-vibing-cli generate --help` lists every option `generate` takes, with what each is for: read it for any option this Skill does not name, rather than guessing one.
17
17
 
18
18
  ```bash
19
- pixel-vibing-cli generate concept-art --instruction "<the picture>" [--size <w>x<h>] [--transparent] [--tag <tag>]... [--reference <png>]... [--no-enrich] --yes --json
19
+ pixel-vibing-cli generate concept-art --instruction "<the picture>" [--size <w>x<h>] [--transparent] [--mask <png>] [--tag <tag>]... [--reference <png>]... [--no-enrich] --yes --json
20
20
  pixel-vibing-cli generate concept-art --instruction "<the area>" --pixel-art --tiles <cols>x<rows> [--no-enrich] --yes --json
21
21
  ```
22
22
 
@@ -25,7 +25,7 @@ pixel-vibing-cli generate concept-art --instruction "<the area>" --pixel-art --t
25
25
  ```json
26
26
  { "project": "<id>", "kind": "concept-art", "instruction": "<the picture>",
27
27
  "size": { "width": 1536, "height": 1024 }, "background": "transparent", "tags": ["anchor"],
28
- "reference_images": ["<image id>"], "enrich": false, "max_percent": 40 }
28
+ "reference_images": ["<image id>"], "mask_image": "<image id>", "enrich": false, "max_percent": 40 }
29
29
  { "project": "<id>", "kind": "concept-art", "instruction": "<the area>", "pixel_art": true,
30
30
  "tiles": { "cols": 6, "rows": 4 }, "max_percent": 40 }
31
31
  ```
@@ -45,6 +45,15 @@ which every other generation takes as `reference_images`.
45
45
  `level-design`, `ui`, `character`, `environment`, `prop`, or one of the project's own
46
46
  (`list_tags`). `pixel-vibing-cli tag` (MCP `tag_asset`) changes them later.
47
47
  - **References.** Up to 8 to draw from, such as the anchor itself.
48
+ - **A mask.** Keeps the drawing to a shape you choose: an island's coastline, a
49
+ character's silhouette, a frame for a menu, the open middle of a scene. It is an opaque
50
+ PNG of black and white only, white where the art is drawn and black where the drawing is
51
+ left empty, in the drawing's shape: the `--size` (`1536x1024` unless given), or for pixel
52
+ art the `--tiles` in proportion, such as 3:2 for `6x4`. Any size in that shape is scaled
53
+ to fit, up to 1536 px a side, so a small one drawn by hand or by a script is enough. A soft edge is fine; grey
54
+ shading, colour or transparency is refused with the reason before anything is spent.
55
+ Pass it as `--mask <png>` (MCP: keep it with `upload_image`, then give its id as
56
+ `mask_image`). With `--transparent`, the black part comes back transparent as well.
48
57
  - **A level design.** `--pixel-art --tiles <c>x<r>` (MCP `pixel_art`, `tiles`) draws an area
49
58
  of the map as pixel art some tiles across, `6x4` unless given, tagged `level-design`; the
50
59
  editor takes it apart into objects and terrain.