Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/ISSUE_TEMPLATE/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ blank_issues_enabled: true
contact_links:
- name: Play with the cat in your browser
url: https://pixelcat-jet.vercel.app
about: Try pixelcat without installing anything.
about: Try pixelpets without installing anything.
- name: Discussions
url: https://github.com/JOhnsonKC201/pixelpets/discussions
about: Show off your cat, share custom coats, or ask a question.
about: Show off your pet, share custom coats, or ask a question.
2 changes: 1 addition & 1 deletion .github/ISSUE_TEMPLATE/feature_request.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,4 @@ body:
id: why
attributes:
label: Why would this be delightful (or useful)?
description: pixelcat aims to feel alive without getting in your way, so ideas that fit that spirit land best.
description: pixelpets aims to feel alive without getting in your way, so ideas that fit that spirit land best.
8 changes: 8 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,14 @@ Notable changes to **pixelpets**. All art and sound are original/procedural (no
- **Calendar event titles are length-capped** before they become a bubble and a Windows toast. They come from someone else's calendar and, unlike reminders and the pinned note, arrived with no bound at all.
- **`--shot` previews stopped cropping their own canvas.** The preview window was 20px narrower than the canvas the renderer sizes itself to, so every capture quietly lost the right-hand edge and the missing pixels read as a rendering bug in whatever was being previewed. The two sizes are now tied together and pinned by a test.

### Rebrand loose ends
- **The hero banner and the social card still said PIXELCAT in pixels.** Both wordmarks are baked into generated art rather than written in markup, so the 0.3.0 rename could not reach them and no text search for the new name would ever have found them. `hero-banner.gif` is the first thing on the README, which made it the most-seen stale branding left anywhere. Both generators now render `PIXELPETS`, and the committed assets have been regenerated. The taglines went species-neutral with them: the banner reads "a cat or a dog that lives on your desktop" (matching the site), the card reads "a pet that lives on your desktop".
- **The agent integrations still called the app pixelcat** in every README title, in the setup prose, and in the `/ABSOLUTE/PATH/TO/pixelcat` checkout placeholders. Those pages are the first thing anyone wiring up a Claude Code, Codex, Cursor, Kiro or Antigravity hook reads. The placeholders moved in lockstep with the substitution in `scripts/install-hook.js` that fills them in, which a test already covers.
- **A fresh install created a shortcut called "pixelcat"** (`nsis.shortcutName`). It is cosmetic and separate from the app identity, so it was safe to correct.
- **The calendar worker introduced itself to other people's servers as `pixelcat-cal`** in its User-Agent.
- The standalone Lobby Jam page under `extras/` still carried the old name in its title and header.
- Deliberately left alone, and pinned by `tests/bridge-paths.test.js` so a future sweep has to read the reasoning first: the `appId`, the `%TEMP%/pixelcat-*` bridge paths that installed hooks already write to, the `%APPDATA%/pixelcat` legacy directory that the migration exists to find, the `PixelcatPreview` global, and the site's `pixelcat.coat` localStorage key. The `pixelcat-jet.vercel.app` URLs stay until the Vercel project itself is renamed.

### Added
- **`--shot --note="<text>"`** pins a speech bubble open in a preview capture, so wrapping and edge clamping can be checked against a real font.
- **`launch-pixelpets.vbs`**, a silent Windows launcher for running from source, is now part of the repo instead of a local-only file. `npm start` leaves a console window sitting behind the pet, which is why a shortcut wants this instead. It resolves the project from its own location rather than a hard-coded path, so moving or renaming the folder cannot leave the shortcut pointing at nothing, and it says what is wrong if dependencies were never installed rather than failing silently.
Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -414,8 +414,8 @@ file, and imported coats merge into your set by name.
## Build a standalone app

```powershell
npm run pack # portable build -> dist/win-unpacked/pixelcat.exe (no installer)
npm run dist # Windows installer -> dist/pixelcat Setup <version>.exe
npm run pack # portable build -> dist/win-unpacked/pixelpets.exe (no installer)
npm run dist # Windows installer -> dist/pixelpets Setup <version>.exe
```

`pack` works out of the box. `dist` (the NSIS installer) needs permission to
Expand Down
Binary file modified assets/hero-banner.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified assets/hero-banner.mp4
Binary file not shown.
Binary file modified assets/social-card.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 2 additions & 2 deletions extras/lobby-jam.html
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>PixelCat · Lobby Jam</title>
<title>pixelpets · Lobby Jam</title>
<style>
:root{
--bg-0:#15110d; --bg-1:#241a12; --card:#1c1611cc;
Expand Down Expand Up @@ -61,7 +61,7 @@
</head>
<body>
<main class="card">
<div class="eyebrow">PixelCat</div>
<div class="eyebrow">pixelpets</div>
<h1>Lobby <span class="accent">Jam</span></h1>
<p class="sub">An endless, improvised lo-fi guitar - every note synthesized live in code.<br>No samples, no loops. It never plays the same thing twice.</p>

Expand Down
8 changes: 4 additions & 4 deletions integrations/README.md
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
# AI agent work-status reactions

pixelcat reacts to a coding agent's work status: a **thinking** bubble while it
pixelpets reacts to a coding agent's work status: a **thinking** bubble while it
plans, a **working** spinner while it edits/tests/builds, a startled **flinch** on
errors, and a happy **hop** when it finishes. Any agent that can run a shell
command on its lifecycle events can drive the cat through the bundled helper:

```
node "/ABSOLUTE/PATH/TO/pixelcat/agent-hook.js" <state>
node "/ABSOLUTE/PATH/TO/pixelpets/agent-hook.js" <state>
```

`agent-hook.js` is **hook-safe**: it drains stdin and prints `{"continue": true}`,
Expand Down Expand Up @@ -42,7 +42,7 @@ copy it into the location noted at the top of the output.
- **Antigravity** → [`antigravity/`](antigravity/) - `.agents/hooks.json` (see notes)
- **Kiro** → [`kiro/`](kiro/) - add via the Agent Hooks UI ("Run Command")

> **Replace `/ABSOLUTE/PATH/TO/pixelcat/`** with the real path to your checkout,
> **Replace `/ABSOLUTE/PATH/TO/pixelpets/`** with the real path to your checkout,
> using forward slashes on Windows too, e.g.
> `node "C:/Users/you/pixelcat/agent-hook.js" working`.
> `node "C:/Users/you/pixelpets/agent-hook.js" working`.
> Hooks run from varying working directories, so an **absolute path is required**.
14 changes: 7 additions & 7 deletions integrations/antigravity/README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Antigravity → pixelcat
# Antigravity → pixelpets

Antigravity (2.0+) supports event-driven **hooks** that run a local shell command
at points in the agent loop. The hooks file uses a Claude-Code-style schema:
Expand All @@ -11,19 +11,19 @@ slashes on Windows too):

```json
{
"pixelcat-thinking": {
"pixelpets-thinking": {
"UserPromptSubmit": [
{ "hooks": [{ "type": "command", "command": "node \"/ABS/PATH/pixelcat/agent-hook.js\" thinking" }] }
{ "hooks": [{ "type": "command", "command": "node \"/ABS/PATH/pixelpets/agent-hook.js\" thinking" }] }
]
},
"pixelcat-working": {
"pixelpets-working": {
"PreToolUse": [
{ "matcher": "*", "hooks": [{ "type": "command", "command": "node \"/ABS/PATH/pixelcat/agent-hook.js\" working" }] }
{ "matcher": "*", "hooks": [{ "type": "command", "command": "node \"/ABS/PATH/pixelpets/agent-hook.js\" working" }] }
]
},
"pixelcat-done": {
"pixelpets-done": {
"Stop": [
{ "hooks": [{ "type": "command", "command": "node \"/ABS/PATH/pixelcat/agent-hook.js\" done" }] }
{ "hooks": [{ "type": "command", "command": "node \"/ABS/PATH/pixelpets/agent-hook.js\" done" }] }
]
}
}
Expand Down
6 changes: 3 additions & 3 deletions integrations/claude-code/README.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
# Claude Code → pixelcat
# Claude Code → pixelpets

Merge [`settings.hooks.json`](settings.hooks.json) into your `~/.claude/settings.json`
(under the `hooks` key), replacing `/ABSOLUTE/PATH/TO/pixelcat/` with your checkout
(under the `hooks` key), replacing `/ABSOLUTE/PATH/TO/pixelpets/` with your checkout
path (forward slashes on Windows too).

Mapping: `UserPromptSubmit` → thinking · `PreToolUse` → working · `Stop` → done.

Restart Claude Code (or start a new session). While pixelcat is running it will
Restart Claude Code (or start a new session). While pixelpets is running it will
show a thinking bubble, a working spinner, and a happy hop as Claude Code works.
6 changes: 3 additions & 3 deletions integrations/claude-code/settings.hooks.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,13 @@
"_comment": "Merge the hooks below into ~/.claude/settings.json. Replace the absolute path to agent-hook.js (forward slashes on Windows too).",
"hooks": {
"UserPromptSubmit": [
{ "hooks": [{ "type": "command", "command": "node \"/ABSOLUTE/PATH/TO/pixelcat/agent-hook.js\" thinking" }] }
{ "hooks": [{ "type": "command", "command": "node \"/ABSOLUTE/PATH/TO/pixelpets/agent-hook.js\" thinking" }] }
],
"PreToolUse": [
{ "hooks": [{ "type": "command", "command": "node \"/ABSOLUTE/PATH/TO/pixelcat/agent-hook.js\" working" }] }
{ "hooks": [{ "type": "command", "command": "node \"/ABSOLUTE/PATH/TO/pixelpets/agent-hook.js\" working" }] }
],
"Stop": [
{ "hooks": [{ "type": "command", "command": "node \"/ABSOLUTE/PATH/TO/pixelcat/agent-hook.js\" done" }] }
{ "hooks": [{ "type": "command", "command": "node \"/ABSOLUTE/PATH/TO/pixelpets/agent-hook.js\" done" }] }
]
}
}
4 changes: 2 additions & 2 deletions integrations/codex/README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# Codex CLI → pixelcat
# Codex CLI → pixelpets

Merge [`config.toml`](config.toml) into your `~/.codex/config.toml`, replacing
`/ABSOLUTE/PATH/TO/pixelcat/` with your checkout path (forward slashes on Windows
`/ABSOLUTE/PATH/TO/pixelpets/` with your checkout path (forward slashes on Windows
too).

Mapping: `UserPromptSubmit` → thinking · `PreToolUse` → working · `Stop` → done.
Expand Down
10 changes: 5 additions & 5 deletions integrations/codex/config.toml
Original file line number Diff line number Diff line change
@@ -1,21 +1,21 @@
# pixelcat work-status reactions for OpenAI Codex CLI.
# pixelpets work-status reactions for OpenAI Codex CLI.
# Merge these tables into ~/.codex/config.toml. Replace the absolute path to
# agent-hook.js (forward slashes on Windows too). Docs: https://developers.openai.com/codex/hooks

[[hooks.UserPromptSubmit]]
[[hooks.UserPromptSubmit.hooks]]
type = "command"
command = 'node "/ABSOLUTE/PATH/TO/pixelcat/agent-hook.js" thinking'
command = 'node "/ABSOLUTE/PATH/TO/pixelpets/agent-hook.js" thinking'

[[hooks.PreToolUse]]
[[hooks.PreToolUse.hooks]]
type = "command"
command = 'node "/ABSOLUTE/PATH/TO/pixelcat/agent-hook.js" working'
command = 'node "/ABSOLUTE/PATH/TO/pixelpets/agent-hook.js" working'

[[hooks.Stop]]
[[hooks.Stop.hooks]]
type = "command"
command = 'node "/ABSOLUTE/PATH/TO/pixelcat/agent-hook.js" done'
command = 'node "/ABSOLUTE/PATH/TO/pixelpets/agent-hook.js" done'

# Alternative (no hooks): a desktop-style notifier on turn completion -
# notify = ["node", "/ABSOLUTE/PATH/TO/pixelcat/agent-hook.js", "done"]
# notify = ["node", "/ABSOLUTE/PATH/TO/pixelpets/agent-hook.js", "done"]
4 changes: 2 additions & 2 deletions integrations/cursor/README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# Cursor → pixelcat
# Cursor → pixelpets

Copy [`hooks.json`](hooks.json) to `<your-project>/.cursor/hooks.json` (create the
`.cursor/` folder if needed), replacing `/ABSOLUTE/PATH/TO/pixelcat/` with your
`.cursor/` folder if needed), replacing `/ABSOLUTE/PATH/TO/pixelpets/` with your
checkout path (forward slashes on Windows too). Reload Cursor so it picks up the
hooks.

Expand Down
8 changes: 4 additions & 4 deletions integrations/cursor/hooks.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,16 @@
"version": 1,
"hooks": {
"beforeSubmitPrompt": [
{ "command": "node \"/ABSOLUTE/PATH/TO/pixelcat/agent-hook.js\" thinking" }
{ "command": "node \"/ABSOLUTE/PATH/TO/pixelpets/agent-hook.js\" thinking" }
],
"afterFileEdit": [
{ "command": "node \"/ABSOLUTE/PATH/TO/pixelcat/agent-hook.js\" working" }
{ "command": "node \"/ABSOLUTE/PATH/TO/pixelpets/agent-hook.js\" working" }
],
"postToolUse": [
{ "command": "node \"/ABSOLUTE/PATH/TO/pixelcat/agent-hook.js\" working" }
{ "command": "node \"/ABSOLUTE/PATH/TO/pixelpets/agent-hook.js\" working" }
],
"stop": [
{ "command": "node \"/ABSOLUTE/PATH/TO/pixelcat/agent-hook.js\" done" }
{ "command": "node \"/ABSOLUTE/PATH/TO/pixelpets/agent-hook.js\" done" }
]
}
}
14 changes: 7 additions & 7 deletions integrations/kiro/README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Kiro → pixelcat
# Kiro → pixelpets

Kiro has two surfaces - the **IDE** (UI hooks) and the **CLI** (config file).

Expand All @@ -11,9 +11,9 @@ Kiro has two surfaces - the **IDE** (UI hooks) and the **CLI** (config file).

| Trigger | Command |
|---------|---------|
| **Prompt Submit** | `node "/ABS/PATH/pixelcat/agent-hook.js" thinking` |
| **Pre Tool Use** | `node "/ABS/PATH/pixelcat/agent-hook.js" working` |
| **Agent Stop** | `node "/ABS/PATH/pixelcat/agent-hook.js" done` |
| **Prompt Submit** | `node "/ABS/PATH/pixelpets/agent-hook.js" thinking` |
| **Pre Tool Use** | `node "/ABS/PATH/pixelpets/agent-hook.js" working` |
| **Agent Stop** | `node "/ABS/PATH/pixelpets/agent-hook.js" done` |

4. **Create Hook** for each. (Timeout defaults to 60s.)

Expand All @@ -25,13 +25,13 @@ CLI hooks live in an agent JSON file - local `.kiro/agents/<name>.json` or globa
```json
"hooks": {
"userPromptSubmit": [
{ "command": "node \"/ABS/PATH/pixelcat/agent-hook.js\" thinking" }
{ "command": "node \"/ABS/PATH/pixelpets/agent-hook.js\" thinking" }
],
"preToolUse": [
{ "matcher": "*", "command": "node \"/ABS/PATH/pixelcat/agent-hook.js\" working" }
{ "matcher": "*", "command": "node \"/ABS/PATH/pixelpets/agent-hook.js\" working" }
],
"stop": [
{ "command": "node \"/ABS/PATH/pixelcat/agent-hook.js\" done" }
{ "command": "node \"/ABS/PATH/pixelpets/agent-hook.js\" done" }
]
}
```
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@
"perMachine": false,
"allowToChangeInstallationDirectory": true,
"createDesktopShortcut": true,
"shortcutName": "pixelcat"
"shortcutName": "pixelpets"
}
}
}
8 changes: 4 additions & 4 deletions scripts/install-hook.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#!/usr/bin/env node
// Print a ready-to-use pixelcat work-status hook config for a given agent, with
// Print a ready-to-use pixelpets work-status hook config for a given agent, with
// the absolute path to agent-hook.js already filled in (the one manual step in
// integrations/). It only PRINTS - copy the output into the noted location; it
// never edits your agent's config for you.
Expand Down Expand Up @@ -30,11 +30,11 @@ if (!AGENTS[agent]) {
const { file, target } = AGENTS[agent];
let txt = fs.readFileSync(path.join(root, file), 'utf8');
// Fill the placeholder directory with this checkout (longest variants first).
txt = txt.split('/ABSOLUTE/PATH/TO/pixelcat').join(dir)
.split('/ABS/PATH/pixelcat').join(dir)
txt = txt.split('/ABSOLUTE/PATH/TO/pixelpets').join(dir)
.split('/ABS/PATH/pixelpets').join(dir)
.split('/ABS/PATH').join(dir);

console.log(`# pixelcat work-status hook - ${agent}`);
console.log(`# pixelpets work-status hook - ${agent}`);
console.log(`# agent-hook.js: ${hookAbs}`);
console.log(`# place into: ${target}`);
console.log('# ' + '-'.repeat(64) + '\n');
Expand Down
6 changes: 3 additions & 3 deletions scripts/make-demo-gif.js
Original file line number Diff line number Diff line change
Expand Up @@ -294,7 +294,7 @@ function sceneIntro(frames, o = {}) {
const n = o.n || 26;
for (let i = 0; i < n; i++) {
const buf = newFrame();
if (o.title) drawText(buf, 'PIXELCAT', Math.round(H * 0.115), o.titleScale || 5, [255, 196, 92]);
if (o.title) drawText(buf, 'PIXELPETS', Math.round(H * 0.115), o.titleScale || 5, [255, 196, 92]);
caption(buf, o.caption, o.capScale || 2);
const bob = Math.round(Math.sin(i / 4) * 2);
const look = Math.round(Math.sin(i / 5) * 3);
Expand Down Expand Up @@ -648,7 +648,7 @@ function setCanvas(w, h, px, baseY) { W = w; H = h; PX = px; BASE_Y = baseY; }
function recipeDemo(wantMp4) {
setCanvas(480, 340, 6, 250); SP = buildPoses(0); PAL = paletteFor(S.PATTERNS[0]);
const frames = [];
sceneIntro(frames, { title: true, titleScale: 5, caption: 'A CAT THAT LIVES ON YOUR DESKTOP', capScale: 2 });
sceneIntro(frames, { title: true, titleScale: 5, caption: 'A CAT OR A DOG THAT LIVES ON YOUR DESKTOP', capScale: 2 });
sceneNap(frames, { caption: 'NAPS WHEN IDLE' });
sceneType(frames, { caption: 'TAPS ITS PAWS WHEN YOU TYPE' });
sceneHunt(frames, { caption: 'POUNCES TO HUNT' });
Expand All @@ -662,7 +662,7 @@ function recipeDemo(wantMp4) {
function recipeHero(wantMp4) {
setCanvas(960, 360, 8, 316); SP = buildPoses(TUX); PAL = paletteFor(S.PATTERNS[TUX]);
const frames = [];
sceneIntro(frames, { title: true, titleScale: 9, caption: 'A CAT THAT LIVES ON YOUR DESKTOP', capScale: 3, n: 30 });
sceneIntro(frames, { title: true, titleScale: 9, caption: 'A CAT OR A DOG THAT LIVES ON YOUR DESKTOP', capScale: 3, n: 30 });
sceneType(frames, { n: 22 });
scenePet(frames, { n: 26 });
maybeDump(frames, 'hero');
Expand Down
8 changes: 5 additions & 3 deletions scripts/make-social-card.js
Original file line number Diff line number Diff line change
Expand Up @@ -117,9 +117,11 @@ for (let y = top; y < H; y++) for (let x = 0; x < FADE; x++) {
}

// Wordmark + tagline + flanking hearts in the clear band on top.
drawText(buf, 'PIXELCAT', W / 2, 62, 18, ORANGE);
drawText(buf, 'A CAT THAT LIVES ON YOUR DESKTOP', W / 2, 182, 5, MUTED);
const wm = textWidth('PIXELCAT', 18);
drawText(buf, 'PIXELPETS', W / 2, 62, 18, ORANGE);
// Species-neutral since 0.3.0, when the app became a cat OR a dog. Not "CAT OR DOG"
// because FONT here is a minimal subset with no G in it.
drawText(buf, 'A PET THAT LIVES ON YOUR DESKTOP', W / 2, 182, 5, MUTED);
const wm = textWidth('PIXELPETS', 18);
drawHeart(buf, Math.round(W / 2 - wm / 2 - 78), 88, 6, PINK);
drawHeart(buf, Math.round(W / 2 + wm / 2 + 36), 88, 6, PINK);

Expand Down
2 changes: 1 addition & 1 deletion src/cal-worker.js
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ function fetchOnce(url, address) {
port: url.port || (isHttps ? 443 : 80),
path: url.pathname + url.search,
timeout: FETCH_TIMEOUT,
headers: { 'user-agent': 'pixelcat-cal', accept: 'text/calendar,*/*', host: url.host },
headers: { 'user-agent': 'pixelpets-cal', accept: 'text/calendar,*/*', host: url.host },
};
if (isHttps) opts.servername = url.hostname; // TLS SNI + cert validation against the real hostname
const req = mod.get(opts, (res) => {
Expand Down