@pixelvibing/cli 0.49.1 → 0.50.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 CHANGED
@@ -12,7 +12,9 @@ pixel-vibing-cli setup
12
12
 
13
13
  `setup` signs you in in the browser, makes the directory a local project, which means a
14
14
  `pixelvibing.json` and a `pixelvibing/` folder, links it to one of your platform
15
- projects, and installs the Skills into `.claude/skills/` or `.codex/skills/`. It also
15
+ projects, and installs the Skills into `.claude/skills/` or `.codex/skills/`: a hub, the
16
+ style guide's, and one for each kind of art. A block in `AGENTS.md`, and in `CLAUDE.md` when
17
+ there is one, names which Skill to load for which request. It also
16
18
  configures the remote MCP server in `.mcp.json` or `.codex/config.toml`, by a command
17
19
  that prints the token's header when the harness connects, so the token is in no file.
18
20
  Each step it finds done already is skipped.
@@ -27,7 +29,7 @@ Each step it finds done already is skipped.
27
29
  | `guide pull\|push\|revise\|show\|versions` | Read and write the project's style guide |
28
30
  | `seal` | Seal `pixelvibing/out/` into `pixelvibing/build/assets.eac` |
29
31
  | `export default\|pixi\|phaser\|godot` | Pack the art into sprite sheets and the map into placed sprites, for an engine |
30
- | `update` | Replace the installed Skills with the ones this version ships, and bring the MCP server's entry to it |
32
+ | `update` | Replace the installed Skills with the ones this version ships, add those it ships since, rewrite their block in `AGENTS.md`, and bring the MCP server's entry to it |
31
33
  | `mcp headers` | Print the header a harness sends the remote MCP server, from the kept token |
32
34
  | `editor` | Open the PixelVibing desktop app on the project |
33
35
 
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { resolve, dirname, join, relative, sep, basename } from "node:path";
2
+ import { resolve, dirname, join, relative, sep, basename, isAbsolute } from "node:path";
3
3
  import { realpath, promises } from "node:fs";
4
4
  import { promisify, parseArgs } from "node:util";
5
5
  import { randomBytes, createHash } from "node:crypto";
@@ -4165,6 +4165,12 @@ async function referenceOf(context, path) {
4165
4165
  return bytes;
4166
4166
  }
4167
4167
  async function requestOf(context, asked, args) {
4168
+ const request = await shapedRequest(context, asked, args);
4169
+ if (!flagOf(args, "no-enrich")) return request;
4170
+ if (request.kind === "ui-sketch") throw new CliError("--no-enrich is not a UI's: its layout is read as it is");
4171
+ return { ...request, body: { ...request.body, enrich: false } };
4172
+ }
4173
+ async function shapedRequest(context, asked, args) {
4168
4174
  const kind = KIND_NAMES[asked] ?? asked;
4169
4175
  const known = GENERATED[kind];
4170
4176
  if (known === void 0) throw new CliError(`generate makes ${Object.keys(GENERATED).join(", ")} (or ui), not ${asked}`);
@@ -4247,7 +4253,7 @@ async function followed(context, platform, jobId) {
4247
4253
  const generate = {
4248
4254
  name: "generate",
4249
4255
  summary: "Generate an object, a creature, concept art, icons or a UI on the platform, then pull it",
4250
- usage: "<object|creature|concept-art|icons|ui> [--instruction <text>] [--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>]… [--yes]",
4256
+ usage: "<object|creature|concept-art|icons|ui> [--instruction <text>] [--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]",
4251
4257
  options: {
4252
4258
  instruction: {
4253
4259
  type: "string",
@@ -4277,6 +4283,10 @@ const generate = {
4277
4283
  },
4278
4284
  reference: { type: "string", multiple: true, value: "<png>", description: "an image to draw from" },
4279
4285
  quality: { type: "string", value: "<quality>", description: "the platform's to choose now; ignored, and said so" },
4286
+ "no-enrich": {
4287
+ type: "boolean",
4288
+ description: "draw from --instruction as written, without the platform writing a fuller one from it and the style guide; not a UI's"
4289
+ },
4280
4290
  yes: { type: "boolean", short: "y", description: "start it without asking, once what it uses of your limit is said" },
4281
4291
  as: { type: "string", value: "<name>", description: "land it under this name instead of the platform's" },
4282
4292
  aside: { type: "boolean", description: "keep a folder's own map and art under pixelvibing/before-platform/, and write it from the platform" }
@@ -4752,7 +4762,7 @@ const move = {
4752
4762
  );
4753
4763
  }
4754
4764
  };
4755
- const version = "0.49.1";
4765
+ const version = "0.50.0";
4756
4766
  const manifest = {
4757
4767
  version
4758
4768
  };
@@ -4767,7 +4777,7 @@ function mcpEntry(apiUrl) {
4767
4777
  if (apiUrl === DEFAULT_API_URL) return { url: DEFAULT_MCP_URL, headers: `npx --yes ${PINNED_PACKAGE} mcp headers` };
4768
4778
  return { url: `${apiUrl}/mcp`, headers: `npx --yes ${PINNED_PACKAGE} mcp headers --api ${apiUrl}` };
4769
4779
  }
4770
- async function textOf(path) {
4780
+ async function textOf$1(path) {
4771
4781
  try {
4772
4782
  return await readFile(path, "utf8");
4773
4783
  } catch (error) {
@@ -4820,7 +4830,7 @@ function codexWith(text2, entry, onlyWhereConfigured) {
4820
4830
  async function configureHarness(root, harness, entry, onlyWhereConfigured = false) {
4821
4831
  const file = harness === "claude" ? CLAUDE_FILE : CODEX_FILE;
4822
4832
  const path = join(root, file);
4823
- const text2 = await textOf(path);
4833
+ const text2 = await textOf$1(path);
4824
4834
  const next = harness === "claude" ? claudeWith(text2, entry, onlyWhereConfigured) : codexWith(text2, entry, onlyWhereConfigured);
4825
4835
  if (next === null) return "absent";
4826
4836
  if (next === text2) return "current";
@@ -4956,9 +4966,127 @@ async function updateSkills(root, skills) {
4956
4966
  }
4957
4967
  return updated;
4958
4968
  }
4969
+ const BLOCK_OPEN = "<!-- pixelvibing:skills -->";
4970
+ const BLOCK_CLOSE = "<!-- /pixelvibing:skills -->";
4971
+ const ROUTED_FILES = [
4972
+ { file: "AGENTS.md", made: true },
4973
+ { file: "CLAUDE.md", made: false }
4974
+ ];
4975
+ function descriptionOf(skill) {
4976
+ return /^---\n(?:.*\n)*?description: (.+)\n(?:.*\n)*?---\n/.exec(skill.text)?.[1]?.trim() ?? "";
4977
+ }
4978
+ function routingBlock(skills) {
4979
+ const lines = skills.map((skill) => `- \`${skill.name}\` — ${descriptionOf(skill)}`);
4980
+ return [
4981
+ BLOCK_OPEN,
4982
+ "## PixelVibing art",
4983
+ "",
4984
+ "This game's art is made on PixelVibing. Before making, finding, pulling or exporting any of it,",
4985
+ "load the Skill for the request from `.claude/skills/` or `.codex/skills/` and follow it,",
4986
+ "starting with `pixelvibing`. Never write a PixelVibing token into a file or a command.",
4987
+ "",
4988
+ ...lines,
4989
+ BLOCK_CLOSE
4990
+ ].join("\n");
4991
+ }
4992
+ function markerLines(text2, marker) {
4993
+ const escaped = marker.replace(/[.*+?^${}()|[\]\\/]/g, "\\$&");
4994
+ return [...text2.matchAll(new RegExp(`^[ \\t]*${escaped}[ \\t]*(?=\\r?$)`, "gm"))].map((found) => ({
4995
+ start: found.index,
4996
+ end: found.index + found[0].length
4997
+ }));
4998
+ }
4999
+ function withBlock(text2, block) {
5000
+ const newline = text2.includes("\r\n") ? "\r\n" : "\n";
5001
+ const written = block.replace(/\n/g, newline);
5002
+ const opens = markerLines(text2, BLOCK_OPEN);
5003
+ const closes = markerLines(text2, BLOCK_CLOSE);
5004
+ if (opens.length === 0 && closes.length === 0) {
5005
+ const before = text2.replace(/(\r?\n)*$/, "");
5006
+ return `${before === "" ? "" : `${before}${newline}${newline}`}${written}${newline}`;
5007
+ }
5008
+ const [open] = opens;
5009
+ const [close] = closes;
5010
+ if (opens.length !== 1 || closes.length !== 1 || open === void 0 || close === void 0 || close.start < open.end) return null;
5011
+ return `${text2.slice(0, open.start)}${written}${text2.slice(close.end)}`;
5012
+ }
5013
+ async function writablePath(root, path) {
5014
+ let linked;
5015
+ try {
5016
+ linked = (await lstat(path)).isSymbolicLink();
5017
+ } catch (error) {
5018
+ if (error.code === "ENOENT") return path;
5019
+ throw error;
5020
+ }
5021
+ if (!linked) return path;
5022
+ let target;
5023
+ try {
5024
+ target = await realpath$1(path);
5025
+ } catch {
5026
+ return null;
5027
+ }
5028
+ const within = relative(await realpath$1(root), target);
5029
+ return within !== "" && !within.startsWith("..") && !isAbsolute(within) ? target : null;
5030
+ }
5031
+ async function textOf(path) {
5032
+ try {
5033
+ return await readFile(path, "utf8");
5034
+ } catch (error) {
5035
+ if (error.code === "ENOENT") return null;
5036
+ throw error;
5037
+ }
5038
+ }
5039
+ async function replaceFile(path, text2) {
5040
+ const aside = join(dirname(path), `.${basename(path)}.pixelvibing-${process.pid}`);
5041
+ await writeFile(aside, text2);
5042
+ try {
5043
+ await rename(aside, path);
5044
+ } catch (error) {
5045
+ await rm(aside, { force: true });
5046
+ throw error;
5047
+ }
5048
+ }
5049
+ async function writeRouting(root, skills) {
5050
+ const block = routingBlock(skills);
5051
+ const routed = [];
5052
+ for (const { file, made } of ROUTED_FILES) {
5053
+ const path = await writablePath(root, join(root, file));
5054
+ if (path === null) {
5055
+ routed.push({ file, state: "outside" });
5056
+ continue;
5057
+ }
5058
+ const text2 = await textOf(path);
5059
+ if (text2 === null && !made) {
5060
+ routed.push({ file, state: "absent" });
5061
+ continue;
5062
+ }
5063
+ const next = withBlock(text2 ?? "", block);
5064
+ if (next === null) routed.push({ file, state: "unreadable" });
5065
+ else if (next === text2) routed.push({ file, state: "current" });
5066
+ else {
5067
+ await replaceFile(path, next);
5068
+ routed.push({ file, state: "written" });
5069
+ }
5070
+ }
5071
+ return routed;
5072
+ }
5073
+ function routingWords(routed) {
5074
+ const why = {
5075
+ unreadable: `holds ${BLOCK_OPEN} and ${BLOCK_CLOSE} other than once each, on lines of their own, in that order`,
5076
+ outside: "is a link to a file outside this repository"
5077
+ };
5078
+ return {
5079
+ done: routed.filter((each) => each.state === "written").map((each) => `named the Skills to load in ${each.file}`),
5080
+ warnings: routed.flatMap((each) => {
5081
+ const reason = why[each.state];
5082
+ return reason === void 0 ? [] : [`${each.file} ${reason}: it was left as it is.
5083
+ `];
5084
+ })
5085
+ };
5086
+ }
4959
5087
  const setup = {
4960
5088
  name: "setup",
4961
- summary: "Sign in, make and link the local project, and install the Skills, doing only what is missing",
5089
+ summary: "Sign in, make and link the local project, install the Skills and name them in AGENTS.md, doing only what is missing",
4962
5090
  usage: "[--harness claude|codex]… [--project <id|name> | --idea <text>] [--name <name>] [--provider <name>]",
4963
5091
  options: {
4964
5092
  harness: {
@@ -5005,19 +5133,24 @@ const setup = {
5005
5133
  `);
5006
5134
  }
5007
5135
  }
5136
+ const routing = await writeRouting(local.root, skills);
5137
+ const said = routingWords(routing);
5138
+ done.push(...said.done);
5139
+ for (const warning of said.warnings) context.io.warn(warning);
5008
5140
  answer(
5009
5141
  context,
5010
- { root: local.root, project: linked, harnesses: installed },
5142
+ { root: local.root, project: linked, harnesses: installed, routing },
5011
5143
  done.length === 0 ? "Nothing to do: this repository is set up." : `Set up: ${done.join("; ")}.`
5012
5144
  );
5013
5145
  }
5014
5146
  };
5015
5147
  const update = {
5016
5148
  name: "update",
5017
- summary: "Replace the installed Skills this CLI ships differently, and add those it ships since",
5149
+ summary: "Replace the installed Skills this CLI ships differently, add those it ships since, and name them in AGENTS.md",
5018
5150
  run: async (context) => {
5019
5151
  const local = await projectHere(context.io.cwd);
5020
- const updated = await updateSkills(local.root, await shippedSkills());
5152
+ const skills = await shippedSkills();
5153
+ const updated = await updateSkills(local.root, skills);
5021
5154
  if (updated.length === 0) throw new CliError("no Skills of this CLI are installed here: `pixel-vibing-cli setup` installs them");
5022
5155
  const entry = mcpEntry(apiUrlOf(context));
5023
5156
  const harnesses = [];
@@ -5027,7 +5160,11 @@ const update = {
5027
5160
  ...result.installed.map((name) => `installed ${HARNESSES[result.harness]}/skills/${name}`),
5028
5161
  ...result.mcp === "written" ? [`brought the MCP server in ${HARNESS_FILES[result.harness]} to this version`] : []
5029
5162
  ]);
5030
- answer(context, { harnesses }, written.length === 0 ? "The Skills are current." : `Updated: ${written.join("; ")}.`);
5163
+ const routing = await writeRouting(local.root, skills);
5164
+ const said = routingWords(routing);
5165
+ written.push(...said.done);
5166
+ for (const warning of said.warnings) context.io.warn(warning);
5167
+ answer(context, { harnesses, routing }, written.length === 0 ? "The Skills are current." : `Updated: ${written.join("; ")}.`);
5031
5168
  }
5032
5169
  };
5033
5170
  const PROGRAM = "pixel-vibing-cli";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pixelvibing/cli",
3
- "version": "0.49.1",
3
+ "version": "0.50.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",
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: pixelvibing
3
- description: Make pixel art for this game with pixel-vibing-cli — objects, creatures, concept art and interface art (a UI laid out as JSON, skill and item icons) generated on the PixelVibing platform, listed, pulled into the project's art and its folder, and exported or sealed for the game. Use when the game needs a sprite, a prop, a creature, concept art to draw from, a level's art, its HUD or its icons, or art already made for it.
3
+ description: Start here for this game's PixelVibing art — who is signed in, the style guide first, which Skill makes which kind of art, and listing, pulling, tagging, exporting and sealing what the platform made with pixel-vibing-cli or the PixelVibing MCP server. Use whenever the game needs art made, found, pulled into the project or taken into the engine.
4
4
  ---
5
5
 
6
6
  # PixelVibing art for this game
@@ -10,78 +10,60 @@ and the platform project it generates for; `pixelvibing/` holds its art. The pla
10
10
  keeps every asset, and `pixelvibing/` holds only what was pulled from it. Nothing written
11
11
  there is ever sent back: art enters the project only by being generated.
12
12
 
13
- Every command below takes `--json`, which prints its answer as JSON on standard output.
14
- Progress and errors go to standard error, and a failure exits 1.
13
+ Two ways reach the platform, and they reach the same project:
14
+ - **The CLI**, `pixel-vibing-cli`. Every command takes `--json`, which prints its answer as
15
+ JSON on standard output. Progress and errors go to standard error, and a failure exits 1.
16
+ - **The MCP server** `pixelvibing`, which `setup` configured in this harness. Its tools take
17
+ the platform project's id as `project`; `whoami` below names it.
15
18
 
16
19
  ## Before anything
17
20
 
18
21
  1. `pixel-vibing-cli whoami --json` says who is signed in and which platform project
19
- this folder generates for.
22
+ this folder generates for (the MCP server's `whoami` says the account alone).
20
23
  - Not signed in: ask the person to run `pixel-vibing-cli login`.
21
24
  - Never ask for a token, and never write one into a file or a command you show.
22
25
  - No platform project: `pixel-vibing-cli link <project>`, or `link --idea "<what the
23
26
  game is>"` to make one.
24
- 2. Read `pixelvibing/style-guide.md`, or run `pixel-vibing-cli guide show`, before deciding
25
- what to ask for. It says what the game is and how its art looks, and every generation is
26
- held to it. Write instructions in its terms. The `pixelvibing-style-guide` Skill says
27
- when the guide itself should change.
28
-
29
- ## Generating
30
-
31
- ```bash
32
- pixel-vibing-cli generate object --instruction "<what>" --size <cols>x<rows> --yes --json
33
- pixel-vibing-cli generate creature --instruction "<what>" [--reference <png>]... --yes --json
34
- pixel-vibing-cli generate concept-art --instruction "<what>" [--size <w>x<h>] [--transparent] [--tag <tag>]... --yes --json
35
- pixel-vibing-cli generate concept-art --instruction "<what>" --pixel-art --tiles <cols>x<rows> --yes --json
36
- pixel-vibing-cli generate icons --names "<name>,<name>,..." --purpose <skill|item> [--size <16|32|64>] --yes --json
37
- pixel-vibing-cli generate ui --sketch <file.json> --instruction "<the set, in a line>" --yes --json
38
- ```
39
-
40
- Each generation uses part of the account's usage limit for the month.
41
- - **What it uses.** The command prints the most it uses and what is left, as shares of the
42
- limit, before it starts. Without `--yes` it asks, and with nobody at the terminal it starts
43
- nothing. Tell the person how much of their limit a batch will use before you start one.
44
- - **The instruction.** Describe the thing as a person would: its look, its material, what
45
- it is for in the game. Describe the thing itself, not a prompt for a model.
46
- - **The options.**
47
- - `--size` is an object's footprint in whole tiles, `1x1` unless given.
48
- - `--tiles` is how many tiles a pixel-art concept art is across, `6x4` unless given.
49
- - No quality is given: the platform draws each asset at the quality it needs. The share
50
- printed is the most it may use, and what it does not use is given back.
51
- - `--reference` is a PNG to draw from, repeated for several: at most 8 for an object
52
- or a concept art, 3 for a creature or a UI, none for icons. A UI's references are a style
53
- to follow (frames, materials, a way of drawing), never what to draw.
54
- - **Concept art.** The free kind: reference art, a place, a character sheet, a sample menu —
55
- whatever the instruction asks. It is drawn as ordinary art, not pixel art, to draw the
56
- rest from: make one first, tagged `anchor`, and pass its pulled picture
57
- (`pixelvibing/ref/<name>.png`) as `--reference` to what follows.
58
- - `--size` is its size in px, `<w>x<h>`, multiples of 16 within `1536x1024` or
59
- `1024x1536`, `1536x1024` unless given. `--transparent` cuts its background away, for
60
- one thing alone.
61
- - `--pixel-art` draws it as a level design instead: pixel art of an area some `--tiles`
62
- across, which the editor takes apart into objects and terrain.
63
- - `--tag` says what it is for, repeated for several, at most 8: `anchor`, `level-design`,
64
- `ui`, `character`, `environment`, `prop`, or one of the project's own.
65
- - **Interface art.** When the game shows the player something over the world, make it here
66
- rather than drawing it in code:
67
- - `icons` makes up to 16 icons that match, from `--names`: `--purpose skill` for a
68
- hotbar or a skill tree (each on a square badge), `--purpose item` for an inventory,
69
- potions or loot (each alone). `--size` is 16, 32 (the default) or 64 px.
70
- - `ui` draws a game's interface (a HUD, a menu, an inventory) from a layout in JSON:
71
- a canvas and up to 16 components, each with a `label` (its role, never drawn), a
72
- `kind` (`rect`, `ellipse` or `polygon`), its position and size (`x`, `y`, `width`,
73
- `height` in the canvas's pixels) and, as it needs, `caption` (text drawn on it), `note`
74
- (how it looks), `border` (a frame that stretches by nine-slice) and `hollow` (its inside
75
- transparent). Read `references/ui.md` before writing one: it gives every field and rule,
76
- `references/ui.schema.json` is the JSON Schema the file follows (name it with
77
- `"$schema"`), and `references/ui.example.json` is a whole HUD laid out. Each component
78
- comes back as its own piece. `ui-sketch` is the same kind by its platform name.
79
- - The art never carries text or numbers, but a UI's captions: draw labels,
80
- counts and values in the game.
81
- - **Success.** The asset is pulled at once. The answer's `files` are where its pictures
82
- are, relative to `pixelvibing/`.
27
+ 2. Read `pixelvibing/style-guide.md`, or run `pixel-vibing-cli guide show` (MCP:
28
+ `get_style_guide`), before deciding what to ask for. It says what the game is and how its
29
+ art looks, and every generation is held to it. Write instructions in its terms. The
30
+ `pixelvibing-style-guide` Skill says when the guide itself should change.
31
+
32
+ ## Which Skill makes what
33
+
34
+ Load the Skill for the kind before you generate it:
35
+
36
+ | The game needs | Skill |
37
+ |---|---|
38
+ | a prop, an item, a building, a piece of scenery | `pixelvibing-object` |
39
+ | a character, an enemy, an animal, a monster | `pixelvibing-creature` |
40
+ | reference art to draw the rest from, a look to hold to, or a level's area as pixel art | `pixelvibing-concept-art` |
41
+ | skill or item icons that match | `pixelvibing-icons` |
42
+ | a HUD, a menu, an inventory, a dialog box | `pixelvibing-ui` |
43
+ | another of a result, a change to it, or setting it in motion | `pixelvibing-change` |
44
+
45
+ No tool makes terrain sets, animated terrain, sounds, rotations or a creature's states: the
46
+ person makes those in the editor, `pixel-vibing-cli editor`, and you pull them as any asset.
47
+
48
+ ## What every generation shares
49
+
50
+ - **The limit.** Each generation uses part of the account's usage limit for the month. The
51
+ CLI prints the most it uses and what is left, as shares of the limit, before it starts;
52
+ without `--yes` it asks, and with nobody at the terminal it starts nothing. The MCP
53
+ server's `get_prices` says each kind's most, and `generate` starts only within
54
+ `max_percent`. Tell the person how much of their limit a batch will use before you start one.
55
+ - **The quality** is the platform's to choose. What a generation does not use is given back.
56
+ - **Enrichment.** Unless told otherwise, the platform writes a fuller instruction from yours
57
+ and the style guide before it draws. When you wrote the instruction in full yourself —
58
+ read the guide, looked at the references, know what the person wants — pass
59
+ `--no-enrich` (MCP: `enrich: false`) and it is drawn from your words as written. Leave it
60
+ on for a person's few words. It is an object's, a creature's, concept art's, an icon set's
61
+ or an animation's: a variant, an edit and a UI refuse it.
62
+ - **Following a job.** The CLI follows the job and pulls the asset when it is done. Over
63
+ MCP, `generate` answers the job's id: follow it with `get_job`, then
64
+ `pixel-vibing-cli pull <job id>` lands it in the folder.
83
65
  - **Failure.** A reached limit starts nothing and names the page where the person adds to
84
- it with a pack or a plan: tell them, and do not retry. A failed job prints its reason.
66
+ it with a pack or a plan: tell them, and do not retry. A failed job says its reason.
85
67
 
86
68
  ## Listing and pulling
87
69
 
@@ -91,6 +73,9 @@ pixel-vibing-cli pull <id|name> [--as <name>] --json
91
73
  pixel-vibing-cli tag <id|name> [<tag>...] [--none] --json
92
74
  ```
93
75
 
76
+ MCP: `list_assets`, `get_asset` (its images, each with an address that downloads it),
77
+ `list_concept_art`, `list_references`, `list_tags`, `tag_asset`.
78
+
94
79
  - **Listing.** `list` answers the newest 50 assets. When there are more, it gives a
95
80
  `next` id for `--before`. A kind is the generation that made the asset: `object`,
96
81
  `creature`, `concept-art`, `rotate`, `animate`… `--tag` lists only the concept art
@@ -101,8 +86,8 @@ pixel-vibing-cli tag <id|name> [<tag>...] [--none] --json
101
86
  sees it too, and then writes the folder from the platform. An asset of one picture
102
87
  lands as `<name>`, one of several as `<name>/<n>`; an icon set's pieces as `ui/icon/<name>`
103
88
  and a UI's as `ui/sketch/<label>`, each under `pixelvibing/out/`. A concept art is kept
104
- as a reference, under
105
- `pixelvibing/ref/`. Pulling again lands nothing while the art still holds it.
89
+ as a reference, under `pixelvibing/ref/`. Pulling again lands nothing while the art
90
+ still holds it.
106
91
  - **Collisions.** `pull` lands nothing under a name the art holds for something else. When
107
92
  it refuses, give the asset another name with `--as`. A terrain set is landed from the
108
93
  editor's Library, never from `pull`.
@@ -0,0 +1,42 @@
1
+ ---
2
+ name: pixelvibing-change
3
+ description: Change art this game already has on PixelVibing — another of an object (a variant), an object or a creature changed as you say (an edit), or one set in motion (an animation) — through the PixelVibing MCP server's generate tool, from a picture the platform keeps. Use when a result is close but not right, or needs another like it, or has to move.
4
+ ---
5
+
6
+ # Changing a result
7
+
8
+ Load the `pixelvibing` Skill first: who is signed in, the style guide, the limit.
9
+
10
+ The CLI has no command for these: they are the MCP server's `generate`, made from a
11
+ picture the account keeps, by its image id.
12
+
13
+ ## Finding the picture
14
+
15
+ `get_asset` with the asset's id or name (from `list_assets`, or `pixel-vibing-cli list
16
+ --json`) answers its `images`; each one's `id` is a `source_image`. Never invent an image id:
17
+ use only one a tool answered.
18
+
19
+ ## The kinds
20
+
21
+ ```json
22
+ { "project": "<id>", "kind": "variant", "source_image": "<image id>", "instruction": "in autumn colours", "max_percent": 40 }
23
+ { "project": "<id>", "kind": "edit", "source_image": "<image id>", "source_name": "knight", "instruction": "give it a red cape", "max_percent": 40 }
24
+ { "project": "<id>", "kind": "animate", "source_image": "<image id>", "instruction": "walks to the right", "enrich": false, "max_percent": 40 }
25
+ ```
26
+
27
+ - **`variant`** draws another of an object, keeping what makes it that object; the
28
+ instruction says what differs.
29
+ - **`edit`** changes an object or a creature as the instruction says, and only that.
30
+ `source_name` is what the picture is called, so the instruction can name it.
31
+ - **`animate`** sets an object or a creature in motion. The instruction is the motion, from
32
+ its first frame to its last: what moves, how far, and how it returns. It takes no
33
+ reference; the platform chooses how many frames. Pass `enrich: false` when the motion is
34
+ written in full; leave it on for a person's few words.
35
+
36
+ `get_job` follows the job; then `pixel-vibing-cli pull <job id>` lands it. An animation
37
+ lands as `<name>/<n>`, one picture a frame, and an export packs its frames as an animation.
38
+
39
+ ## Not here
40
+
41
+ Turning a creature into eight directions, a creature's states, terrain sets and animated
42
+ terrain, and sounds are made in the editor, `pixel-vibing-cli editor`.
@@ -0,0 +1,56 @@
1
+ ---
2
+ name: pixelvibing-concept-art
3
+ description: Generate concept art for this game on PixelVibing — the anchor look everything holds to, a place, a character sheet, a sample menu, or a level design drawn as pixel art to take apart — with pixel-vibing-cli or the PixelVibing MCP server's generate tool, and tag it for what it is for. Use before a set of assets, so they draw from one look, or to lay out an area of a level.
4
+ ---
5
+
6
+ # Concept art
7
+
8
+ Load the `pixelvibing` Skill first: who is signed in, the style guide, the limit.
9
+
10
+ Concept art is the free kind: whatever the instruction asks, drawn as ordinary art, not
11
+ pixel art, to draw the rest from. Make one first, tagged `anchor`, and pass it as a
12
+ reference to what follows.
13
+
14
+ ## With the CLI
15
+
16
+ ```bash
17
+ pixel-vibing-cli generate concept-art --instruction "<the picture>" [--size <w>x<h>] [--transparent] [--tag <tag>]... [--reference <png>]... [--no-enrich] --yes --json
18
+ pixel-vibing-cli generate concept-art --instruction "<the area>" --pixel-art --tiles <cols>x<rows> [--no-enrich] --yes --json
19
+ ```
20
+
21
+ ## With the MCP server
22
+
23
+ ```json
24
+ { "project": "<id>", "kind": "concept-art", "instruction": "<the picture>",
25
+ "size": { "width": 1536, "height": 1024 }, "background": "transparent", "tags": ["anchor"],
26
+ "reference_images": ["<image id>"], "enrich": false, "max_percent": 40 }
27
+ { "project": "<id>", "kind": "concept-art", "instruction": "<the area>", "pixel_art": true,
28
+ "tiles": { "cols": 6, "rows": 4 }, "max_percent": 40 }
29
+ ```
30
+
31
+ `get_job` follows the job; then `pixel-vibing-cli pull <job id>` keeps it under
32
+ `pixelvibing/ref/`. `list_concept_art` (by a tag too) answers each concept art's image ids,
33
+ which every other generation takes as `reference_images`.
34
+
35
+ ## Writing it
36
+
37
+ - **The instruction.** Brief it as an art director would: what is in the picture, where,
38
+ how it looks, the light, and how its parts meet. Use the style guide's words.
39
+ - **The size.** `--size` (MCP `size`) in px, `<w>x<h>`, multiples of 16 within `1536x1024`
40
+ or `1024x1536`, `1536x1024` unless given. `--transparent` (`background: "transparent"`)
41
+ cuts the background away, for one thing alone.
42
+ - **Tags** say what it is for, at most 8: `anchor` (the look everything holds to),
43
+ `level-design`, `ui`, `character`, `environment`, `prop`, or one of the project's own
44
+ (`list_tags`). `pixel-vibing-cli tag` (MCP `tag_asset`) changes them later.
45
+ - **References.** Up to 8 to draw from, such as the anchor itself.
46
+ - **A level design.** `--pixel-art --tiles <c>x<r>` (MCP `pixel_art`, `tiles`) draws an area
47
+ of the map as pixel art some tiles across, `6x4` unless given, tagged `level-design`; the
48
+ editor takes it apart into objects and terrain.
49
+ - **Enrichment.** Pass `--no-enrich` (`enrich: false`) when the brief above is complete;
50
+ leave it on when all you have is the person's few words.
51
+
52
+ ## After
53
+
54
+ - Pass its picture, `pixelvibing/ref/<name>.png`, as `--reference` (or its image id as
55
+ `reference_images`) to the objects, creatures and UI that should match it.
56
+ - Concept art is a reference, not game art: it is never exported.
@@ -0,0 +1,44 @@
1
+ ---
2
+ name: pixelvibing-creature
3
+ description: Generate one creature for this game on PixelVibing — a hero, a villager, an enemy, an animal, a monster — standing whole on one tile, with pixel-vibing-cli or the PixelVibing MCP server's generate tool. Use when the game needs a character drawn, before it is animated or turned.
4
+ ---
5
+
6
+ # A creature
7
+
8
+ Load the `pixelvibing` Skill first: who is signed in, the style guide, the limit.
9
+
10
+ ## With the CLI
11
+
12
+ ```bash
13
+ pixel-vibing-cli generate creature --instruction "<who>" [--reference <png>]... [--no-enrich] --yes --json
14
+ ```
15
+
16
+ ## With the MCP server
17
+
18
+ ```json
19
+ { "project": "<id>", "kind": "creature", "instruction": "<who>", "reference_images": ["<image id>"],
20
+ "enrich": false, "max_percent": 40 }
21
+ ```
22
+
23
+ `get_job` follows the job; then `pixel-vibing-cli pull <job id>` lands it.
24
+
25
+ ## Writing it
26
+
27
+ - **The instruction.** One or two sentences: its body and build, its colours, what it
28
+ wears or carries, and its part in the game ("the blacksmith who sells blades"). Use the
29
+ style guide's words for the look; never restate its camera or outline. No other game's
30
+ characters or names, and no text in the picture: when the person names a franchise, make
31
+ original art in its spirit and say so.
32
+ - **One creature, standing.** It is drawn whole, standing, on one tile. A pose, a crowd or a
33
+ scene is concept art (`pixelvibing-concept-art`).
34
+ - **References.** Up to 3: a character sheet or a concept art tagged `character` or
35
+ `anchor` keeps it on model.
36
+ - **Enrichment.** Pass `--no-enrich` (`enrich: false`) when the instruction above is
37
+ complete; leave it on when all you have is the person's few words.
38
+
39
+ ## After
40
+
41
+ - It lands as `pixelvibing/out/<name>.png`.
42
+ - A change to it, or a walk, an attack, an idle: the `pixelvibing-change` Skill.
43
+ - Its eight directions and its states (hurt, dead, attacking) are made in the editor,
44
+ `pixel-vibing-cli editor`.
@@ -0,0 +1,42 @@
1
+ ---
2
+ name: pixelvibing-icons
3
+ description: Generate a set of up to 16 matching icons for this game on PixelVibing — skills on square badges for a hotbar or a skill tree, or items alone for an inventory, potions or loot — with pixel-vibing-cli or the PixelVibing MCP server's generate tool. Use when the game shows the player icons rather than drawing them in code.
4
+ ---
5
+
6
+ # An icon set
7
+
8
+ Load the `pixelvibing` Skill first: who is signed in, the style guide, the limit.
9
+
10
+ ## With the CLI
11
+
12
+ ```bash
13
+ pixel-vibing-cli generate icons --names "<name>,<name>,..." --purpose <skill|item> [--size <16|32|64>] [--instruction "<theme>"] [--no-enrich] --yes --json
14
+ ```
15
+
16
+ ## With the MCP server
17
+
18
+ ```json
19
+ { "project": "<id>", "kind": "icons", "names": ["fire bolt", "ice wall"], "purpose": "skill",
20
+ "icon_size": 32, "instruction": "<theme>", "enrich": false, "max_percent": 40 }
21
+ ```
22
+
23
+ `get_job` follows the job; then `pixel-vibing-cli pull <job id>` lands each icon.
24
+
25
+ ## Writing it
26
+
27
+ - **The names.** One per icon, at most 16, none twice: what the skill or the item is, in a
28
+ few words ("red health potion", "rusty key"). Make a whole set in one generation, so the
29
+ icons match.
30
+ - **The purpose.** `skill` draws each on a square badge, for a hotbar or a skill tree;
31
+ `item` draws each alone, for an inventory or loot; `item` unless given.
32
+ - **The size.** 16, 32 or 64 px a side, 32 unless given: the size the game shows them at.
33
+ - **The theme.** `--instruction` is optional: what the icons have in common, their colours
34
+ and framing. Use the style guide's words.
35
+ - **No references.** An icon never carries text or numbers: draw counts and labels in the game.
36
+ - **Enrichment.** Pass `--no-enrich` (`enrich: false`) when the theme is complete; leave it
37
+ on when all you have is the person's few words.
38
+
39
+ ## After
40
+
41
+ - Each lands as `pixelvibing/out/ui/icon/<name>.png`.
42
+ - More icons later: a new set, with the first set's theme, so they still match.
@@ -0,0 +1,46 @@
1
+ ---
2
+ name: pixelvibing-object
3
+ description: Generate one object for this game on PixelVibing — a prop, an item, a building, a tree, a piece of scenery — on a footprint of whole tiles, with pixel-vibing-cli or the PixelVibing MCP server's generate tool. Use when the game needs one thing that stands on the map or sits in an inventory.
4
+ ---
5
+
6
+ # An object
7
+
8
+ Load the `pixelvibing` Skill first: who is signed in, the style guide, the limit.
9
+
10
+ ## With the CLI
11
+
12
+ ```bash
13
+ pixel-vibing-cli generate object --instruction "<what>" --size <cols>x<rows> [--reference <png>]... [--no-enrich] --yes --json
14
+ ```
15
+
16
+ ## With the MCP server
17
+
18
+ ```json
19
+ { "project": "<id>", "kind": "object", "instruction": "<what>", "size": { "cols": 1, "rows": 1 },
20
+ "reference_images": ["<image id>"], "enrich": false, "max_percent": 40 }
21
+ ```
22
+
23
+ `get_prices` gives `max_percent`'s floor; `get_job` follows the job; then
24
+ `pixel-vibing-cli pull <job id>` lands it under `pixelvibing/out/`.
25
+
26
+ ## Writing it
27
+
28
+ - **The instruction.** One or two sentences of the thing itself: its shape, its material
29
+ and colours, the details that make it read at its size, and what it is for in the game.
30
+ Use the style guide's words for the look; never restate its camera or outline, the
31
+ platform adds them. No artist's or other game's names, and no text in the picture.
32
+ - **The footprint.** `--size` (MCP `size`) is how many tiles it stands on, `1x1` unless
33
+ given: a crate is `1x1`, a cart `2x1`, a house `3x3`. The platform sizes the drawing to the
34
+ project's tile size.
35
+ - **References.** Up to 8 pictures to draw from: a concept art tagged `anchor` keeps every
36
+ object on one look (`pixelvibing/ref/<name>.png` for the CLI, its image id from
37
+ `list_concept_art` for MCP), and a sketch or an earlier object keeps a shape.
38
+ - **Enrichment.** Pass `--no-enrich` (`enrich: false`) when the instruction above is
39
+ complete; leave it on when all you have is the person's few words.
40
+
41
+ ## After
42
+
43
+ - It lands as `pixelvibing/out/<name>.png`, named from what was drawn; `--as` lands it under
44
+ another name.
45
+ - Another like it, a change to it, or setting it in motion: the `pixelvibing-change` Skill.
46
+ - Never generate the same object again to fix a detail: change it, or open the editor.
@@ -38,5 +38,9 @@ Do not change it for one asset: say that in the asset's instruction instead.
38
38
  top, and push.
39
39
  4. `pixel-vibing-cli guide versions` lists every version, with how and when each was made.
40
40
 
41
+ The MCP server reaches the same guide: `get_style_guide` reads it, `write_style_guide` keeps a
42
+ new version on top of the one you read (its `base`), and `revise_style_guide` asks for a
43
+ revision by an instruction. After either, `pixel-vibing-cli guide pull` brings the file up to date.
44
+
41
45
  Tell the person what you changed and why, since the guide shapes every later generation.
42
46
  Art made before the change was made under the old guide, and nothing remakes it by itself.
@@ -0,0 +1,48 @@
1
+ ---
2
+ name: pixelvibing-ui
3
+ description: Generate a game's interface on PixelVibing — a HUD, a menu, an inventory, a dialog box — from a layout of up to 16 labelled shapes in JSON, each drawn as its own matching piece that stretches by nine-slice, with pixel-vibing-cli or the PixelVibing MCP server's generate tool. Use when the game shows the player an interface over the world, rather than drawing one in code.
4
+ ---
5
+
6
+ # A UI
7
+
8
+ Load the `pixelvibing` Skill first: who is signed in, the style guide, the limit.
9
+
10
+ Read `references/ui.md` before writing a layout: it gives every field and rule.
11
+ `references/ui.schema.json` is the JSON Schema the file follows (name it with `"$schema"`),
12
+ and `references/ui.example.json` is a whole HUD laid out.
13
+
14
+ ## With the CLI
15
+
16
+ ```bash
17
+ pixel-vibing-cli generate ui --sketch <file.json> --instruction "<the set, in a line>" [--reference <png>]... --yes --json
18
+ ```
19
+
20
+ ## With the MCP server
21
+
22
+ The layout goes in the call itself, as `canvas` and `shapes`, with the same fields:
23
+
24
+ ```json
25
+ { "project": "<id>", "kind": "ui-sketch", "instruction": "gothic iron with green enamel",
26
+ "canvas": { "width": 256, "height": 256 },
27
+ "shapes": [{ "label": "Health bar", "kind": "rect", "x": 8, "y": 8, "width": 96, "height": 16, "border": 2, "note": "a full red health bar" }],
28
+ "reference_images": ["<image id>"], "max_percent": 40 }
29
+ ```
30
+
31
+ `get_job` follows the job; then `pixel-vibing-cli pull <job id>` lands each piece.
32
+
33
+ ## Writing it
34
+
35
+ - **The instruction** is the set's theme in a line, up to 600 characters; what each piece
36
+ is goes in its `label` and `note`.
37
+ - **References**, up to 3, are a style to follow (frames, materials, a way of drawing),
38
+ never what to draw. A concept art tagged `ui` is the usual one.
39
+ - **Text.** Only a `caption` is drawn as text. Counts, values and names change in play: the
40
+ game draws them.
41
+ - **No enrichment switch.** A UI's layout is read as it is; `--no-enrich` and `enrich` are
42
+ refused for it.
43
+ - `ui-sketch` is the same kind by its platform name.
44
+
45
+ ## After
46
+
47
+ - Each piece lands as `pixelvibing/out/ui/sketch/<label>.png`, a framed one with its
48
+ nine-slice insets, which an export carries to the engine.