neko-vue 0.1.0 → 0.1.1

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 (3) hide show
  1. package/CHANGELOG.md +2 -3
  2. package/README.md +85 -34
  3. package/package.json +6 -2
package/CHANGELOG.md CHANGED
@@ -1,9 +1,8 @@
1
1
  # Changelog
2
2
 
3
- All notable changes to this project will be documented in this file.
3
+ All notable changes to this project will be documented in this file. See [commit-and-tag-version](https://github.com/absolute-version/commit-and-tag-version) for commit guidelines.
4
4
 
5
- The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
- and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
5
+ ## [0.1.1](https://github.com/AscaL/neko-vue/compare/v0.1.0...v0.1.1) (2026-04-04)
7
6
 
8
7
  ## [0.1.0] - 2026-04-04
9
8
 
package/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  Vue 3 helpers for a classic viewport-fixed desktop pet: typed options, `loadNekoRuntime()`, `useNeko()`, and `NekoPet`. The default path uses programmatic `createNeko` only (no `data-autostart`).
4
4
 
5
- The pet **engine always comes from this package** (a dynamically imported chunk in `dist/`). There is **no** supported option to load `createNeko` from a remote URL or a separate script tag—only the bundled runtime, unless you assign **`window.createNeko`** yourself first (advanced / tests).
5
+ The pet **engine always comes from this package** (a dynamically imported chunk in `dist/`). There is **no** supported option to load `createNeko` from a remote URL or a separate script tag—only the bundled runtime, unless you assign **`globalThis.createNeko`** yourself first (in browsers usually **`window.createNeko`**; advanced / tests).
6
6
 
7
7
  **Peer dependency:** `vue` ^3.4 or ^3.5.
8
8
 
@@ -12,19 +12,19 @@ The pet **engine always comes from this package** (a dynamically imported chunk
12
12
 
13
13
  | Capability | Details |
14
14
  | ----------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
15
- | **Typed engine API** | `NekoOptions`, `NekoInstance`, `BehaviorMode`, `DEFAULT_NEKO_BEHAVIOR_CYCLE`, `BehaviorModes`, `NEKOJS_SPRITE_SIZE` — aligned with `createNeko`. |
16
- | **Bundled runtime** | Typed engine ships in **`dist/`** (code-split chunk); **only** dynamic import from the package—no remote URL or `<script src>` loader. |
17
- | **`<NekoPet />`** | Declarative component: speed, corner, anchor, mode (`follow` / `rest`), optional **`behavior-cycle`**, optional chase **`cursor-standoff-px`**, reduced motion, debug. |
18
- | **`useNeko()`** | Same options as **`NekoPet`** (plus **`anchorRef`**): reactive **`instance` / `isReady` / `error`**, **`setMode`**, **`destroy`**, **`restUntilFirstPetInteraction`**, **`petInteractionAwake`**, **`behaviorCycle`**, **`cursorStandoffPx`**, etc. |
19
- | **`loadNekoRuntime()`** | Advanced: `Promise<createNeko>` after bundled import, or reuse **`window.createNeko`** if already set; shared in-memory promise; SSR-safe error when misused. |
20
- | **Placement helpers** | `startCorner`, `cornerToStartXY`, `resolveStartPosition`viewport corners + anchor rects, `ResizeObserver` when anchored. |
15
+ | **Typed engine API** | `NekoOptions`, `NekoInstance`, `BehaviorMode`, `BehaviorModes`, `DEFAULT_NEKO_BEHAVIOR_CYCLE`, `NEKOJS_SPRITE_SIZE` — aligned with **`createNeko`**. |
16
+ | **Bundled runtime** | Engine lives in **`dist/`** as a separate chunk; your bundler loads it via **dynamic `import`** (no extra HTTP URL in this API). Same chunk **`loadNekoRuntime()`** / **`useNeko`** pull in. |
17
+ | **`<NekoPet />`** | Declarative wrapper: placement (**`start-corner`**, **`anchor-selector`**), **`mode`** (`follow` / `rest`), engine tuning (**`speed`**, **`fps`**, **`behavior-mode`**, **`behavior-cycle`**, **`cursor-standoff-px`**, …), motion gate, **`debug`**. |
18
+ | **`useNeko()`** | Same options as **`NekoPet`** plus **`anchorRef`**; returns **`instance`**, **`isReady`**, **`error`**, **`skippedForReducedMotion`**, **`mode`**, **`petInteractionAwake`**, **`setMode`**, **`destroy`**, etc. Calls **`loadNekoRuntime()`** internally. |
19
+ | **`loadNekoRuntime()`** | Returns **`Promise<CreateNekoFn>`** the typed **`createNeko`** factory. **Browser:** if **`globalThis.createNeko`** already exists (tests / custom setup), resolves to that; else **one shared promise** dynamic-imports the bundled runtime once. **Not in browser (e.g. SSR):** rejects immediately with a clear error (do not call on the server). |
20
+ | **Placement helpers** | **`NekoStartCorner`**, **`NekoPlacementInput`**, **`cornerToStartXY`**, **`resolveStartPosition`**corner / anchor **`startX`** / **`startY`**. In **`useNeko`**, a **`ResizeObserver`** is attached only when **`anchorRef`** is set (not for **`anchorSelector`** alone). |
21
21
  | **Motion & a11y** | `prefersReducedMotion()`; composable and component skip the pet when user prefers reduced motion (with opt-out on `NekoPet`). |
22
22
  | **Lifecycle** | Unmount → `stop()` + `destroy()`; bundled runtime removes listeners via **`AbortController`**. |
23
23
  | **Debug** | `nekoVueDebug()` for optional placement / recreate logging. |
24
24
 
25
25
  ## Source layout (this repo)
26
26
 
27
- Library code under **`src/`** is grouped by role (public API remains **`neko-vue`** `dist/index.mjs` only):
27
+ Library code under **`src/`** is grouped by role. **`vite.config.ts`** **`pack.entry`** maps **`src/index.ts`** plus **`src/entries/*.ts`** to published **`dist/*.mjs`**; **`pack.exports: false`** leaves **`package.json` `exports`** as the source of truth (see [Subpath imports](#subpath-imports)).
28
28
 
29
29
  | Folder | Role |
30
30
  | -------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------ |
@@ -33,16 +33,25 @@ Library code under **`src/`** is grouped by role (public API remains **`neko-vue
33
33
  | **`src/vue/`** | `useNeko.ts`, `NekoPet.ts` (`defineComponent`, not an SFC). |
34
34
  | **`src/placement/`** | Corner / anchor → `startX` / `startY` resolution. |
35
35
  | **`src/utils/`** | `prefersReducedMotion`, `nekoVueDebug`. |
36
- | **`src/index.ts`** | Public re-exports only. |
36
+ | **`src/entries/`** | Thin barrels for **`neko-vue/types`**, **`/placement`**, **`/runtime`**, **`/vue`** (see **`vite.config.ts`** **`pack.entry`**). |
37
+ | **`src/index.ts`** | Root public re-exports (full API). |
37
38
  | **`src/env.d.ts`** | Vite / client typings. |
38
39
 
39
40
  ## Install
40
41
 
42
+ **Vue is a peer dependency** — `neko-vue` does not ship its own copy of Vue (that would risk two Vue runtimes in one app). In a normal Vue 3 app you already have **`vue`** in `package.json`, so add only this package:
43
+
41
44
  ```bash
42
- npm install neko-vue vue
45
+ npm install neko-vue
43
46
  ```
44
47
 
45
- Use the same idea with **pnpm**, **Yarn**, or **Bun** (for example `pnpm add neko-vue vue`). You must have **Vue 3.4+** or **3.5+** installed alongside `neko-vue`.
48
+ Same idea with **pnpm**, **Yarn**, or **Bun** (for example `pnpm add neko-vue`). Your app must satisfy **`vue` ^3.4 or ^3.5** (see `peerDependencies` in `package.json`); npm will warn if it’s missing.
49
+
50
+ **Greenfield / no Vue yet** — install both once:
51
+
52
+ ```bash
53
+ npm install neko-vue vue
54
+ ```
46
55
 
47
56
  ### Subpath imports
48
57
 
@@ -53,7 +62,7 @@ Besides the root entry (`neko-vue`), published builds expose **conditional expor
53
62
  | **`neko-vue`** | Full public API (root barrel). |
54
63
  | **`neko-vue/types`** | `BehaviorMode`, `BehaviorModes`, `DEFAULT_NEKO_BEHAVIOR_CYCLE`, `NEKOJS_SPRITE_SIZE`, `NekoOptions`, `NekoInstance`, `CreateNekoFn`, `LoadNekoRuntimeOptions` — no Vue, no loader. |
55
64
  | **`neko-vue/placement`** | `cornerToStartXY`, `resolveStartPosition`, `NekoStartCorner`, `NekoPlacementInput` — no Vue. |
56
- | **`neko-vue/runtime`** | `loadNekoRuntime` only (pulls the bundled engine chunk when called). |
65
+ | **`neko-vue/runtime`** | `loadNekoRuntime` only pulls the bundled engine chunk when called. |
57
66
  | **`neko-vue/vue`** | `useNeko`, `NekoPet`, `UseNekoOptions`, `NekoFollowMode` — **requires Vue**; still loads the engine when you create a pet. |
58
67
 
59
68
  Your bundler decides how much code stays in the bundle; these subpaths make dependencies explicit and avoid importing the root barrel when you only need types or placement helpers.
@@ -128,7 +137,7 @@ If the user prefers reduced motion, **`NekoPet`** and **`useNeko`** **skip** loa
128
137
 
129
138
  ### 7. SSR (Nuxt, custom SSR)
130
139
 
131
- Never call **`useNeko`**, render **`NekoPet`**, or **`loadNekoRuntime`** on the server. Use a **`.client.vue`** component or **`<ClientOnly>`** (see [Nuxt 3](#4-nuxt-3) below).
140
+ Never call **`useNeko`**, render **`NekoPet`**, or **`loadNekoRuntime`** on the server. Use a **`.client.vue`** component or **`<ClientOnly>`** (see [Nuxt 4](#4-nuxt-4) below).
132
141
 
133
142
  ### 8. When something looks wrong
134
143
 
@@ -161,13 +170,13 @@ TypeScript picks up types from the published `dist` typings; no extra `@types` p
161
170
  | ----------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------- |
162
171
  | **`<NekoPet />`** | You want declarative props (`speed`, `start-corner`, `mode`, …) and minimal setup code. |
163
172
  | **`useNeko()`** | You need a **handle** (`setMode`, `destroy`, refs to `instance` / `isReady` / `error`) or **`anchorRef`** to tie the start position to another element. |
164
- | **`loadNekoRuntime()`** | Advanced: ensure a typed `createNeko` after the bundled runtime is loaded, or reuse an existing **`window.createNeko`** (e.g. tests). |
173
+ | **`loadNekoRuntime()`** | Advanced: ensure a typed **`createNeko`** after the bundled runtime is loaded, or reuse an existing **`globalThis.createNeko`** (e.g. tests). |
165
174
 
166
- By default, **`loadNekoRuntime()`** loads the **bundled** engine (dynamic import, no extra network hop for the pet). If **`window.createNeko`** is already a function when the loader runs, that implementation is used instead (typical in **tests** or custom setups).
175
+ By default, **`loadNekoRuntime()`** loads the **bundled** engine (dynamic import, no extra network hop for the pet). If **`globalThis.createNeko`** is already a function when the loader runs, that implementation is used instead (typical in **tests** or custom setups).
167
176
 
168
177
  ### 3. Vite, Vue CLI, or a plain SPA
169
178
 
170
- 1. Install `neko-vue` and `vue`.
179
+ 1. Install **`neko-vue`** (and **`vue`** if the project does not already depend on it).
171
180
  2. Use **`NekoPet`** in any component that only runs on the client (typical SPA entry is client-only already):
172
181
 
173
182
  ```vue
@@ -182,13 +191,17 @@ import { NekoPet } from "neko-vue";
182
191
 
183
192
  3. If you prefer the composable, call **`useNeko()` inside `setup()`** (or `<script setup>`) — see the [Composable](#composable) section.
184
193
 
185
- ### 4. Nuxt 3
194
+ ### 4. Nuxt 4
195
+
196
+ These notes match **[Nuxt 4](https://nuxt.com/)** (Vue 3). The pet is **browser-only**; keep it off the server render path.
197
+
198
+ 1. **Install:** add **`neko-vue`** with your package manager (`npm install neko-vue`, `pnpm add neko-vue`, …). You do **not** need a Nuxt module for this library. Nuxt already depends on **Vue 3**.
186
199
 
187
- 1. Install: `npx nuxi module add` is not required — add **`neko-vue`** (and ensure **`vue`** is present) with your package manager.
200
+ 2. **Client-only rendering** (pick one):
201
+ - Put the pet in a component named **`*.client.vue`** under **`components/`**, or
202
+ - Wrap it with **[`<ClientOnly>`](https://nuxt.com/docs/4.x/api/components/client-only)**.
188
203
 
189
- 2. Wrap usage so it **never runs on the server**:
190
- - Put the pet in a **`.client.vue`** component, or
191
- - Wrap with [`<ClientOnly>`](https://nuxt.com/docs/api/components/client-only).
204
+ For **`.client.vue`**, Nuxt only treats the file as client-only when you use **[auto-imports](https://nuxt.com/docs/4.x/guide/directory-structure/components#client-components)** or import from **`#components`**. Importing the file by **filesystem path** (e.g. `~/components/Foo.client.vue`) does **not** apply the client-only transform—use **`import { NekoPetClient } from '#components'`** or drop the import and use the auto-registered name.
192
205
 
193
206
  ```vue
194
207
  <!-- components/NekoPetClient.client.vue -->
@@ -202,9 +215,9 @@ import { NekoPet } from "neko-vue";
202
215
  ```
203
216
 
204
217
  ```vue
205
- <!-- pages/index.vue import path matches your Nuxt srcDir -->
218
+ <!-- e.g. app/pages/index.vue (Nuxt 4 default `app/` layout) or pages/index.vue if you use a classic root `pages/` dir -->
206
219
  <script setup lang="ts">
207
- import NekoPetClient from "~/components/NekoPetClient.client.vue";
220
+ import { NekoPetClient } from "#components";
208
221
  </script>
209
222
 
210
223
  <template>
@@ -216,7 +229,7 @@ import NekoPetClient from "~/components/NekoPetClient.client.vue";
216
229
  </template>
217
230
  ```
218
231
 
219
- If you rely on **Nuxt component auto-import**, you can omit the import and keep the file as `components/NekoPetClient.client.vue`.
232
+ Alternatively, omit the script import and use **`<NekoPetClient />`** if the file **`components/NekoPetClient.client.vue`** is picked up by Nuxt’s component scanner.
220
233
 
221
234
  ### 5. Global registration (optional)
222
235
 
@@ -276,7 +289,30 @@ import { BehaviorMode, NekoPet } from "neko-vue";
276
289
  </template>
277
290
  ```
278
291
 
279
- `NekoPet` is implemented as `defineComponent` (TypeScript) for reliable library builds; use it like any other Vue component. It **exposes** `{ instance }` (a ref to **`NekoInstance | null`**), so a template **`ref`** on **`NekoPet`** gives you the same live handle as **`useNeko()`’s `instance`**.
292
+ `NekoPet` is implemented as `defineComponent` (TypeScript) for reliable library builds; use it like any other Vue component. It **exposes** `{ instance }` (**`shallowRef<NekoInstance | null>`** from the internal **`useNeko`**). On the parent **`ref`**, Vue **unwraps** exposed refs, so **`childRef.instance`** matches the live pet handle from **`useNeko()`’s `instance`** (same timing: **`null`** until ready).
293
+
294
+ ### `NekoPet` props (reference)
295
+
296
+ In **templates**, use **kebab-case** for multi-word names (Vue maps them to camelCase). Types below match **`NekoPet`** / **`UseNekoOptions`** / **`NekoOptions`**.
297
+
298
+ | Prop (script) | Template (kebab) | Type | Default | Summary |
299
+ | ------------- | ------------------ | ---- | ------- | ------- |
300
+ | **`speed`** | `speed` | `number` | _(omit)_ | Pixels per engine logic tick (`createNeko`; default **24**; engine logic ~5 ticks/sec). |
301
+ | **`fps`** | `fps` | `number` | _(omit)_ | Sprite animation frame rate (default in engine **120**). |
302
+ | **`behaviorMode`** | `behavior-mode` | `BehaviorMode` (number) | _(omit)_ | **Initial** mode at create; live mode changes by **clicking the pet** when `allowBehaviorChange` is true. |
303
+ | **`idleThreshold`** | `idle-threshold` | `number` | _(omit)_ | Idle distance in px (engine default **6**). |
304
+ | **`cursorStandoffPx`** | `cursor-standoff-px` | `number` | _(omit / 0)_ | Chase mode: minimum distance from pointer in px; **0** or omit = sit on cursor. |
305
+ | **`allowBehaviorChange`** | `allow-behavior-change` | `boolean` | **`undefined`** | **`undefined`** = omit field → engine default **`true`**. **`false`** disables click-to-cycle. |
306
+ | **`behaviorCycle`** | `behavior-cycle` | `BehaviorMode[]` | _(omit)_ | Pet-click order; omit for **`DEFAULT_NEKO_BEHAVIOR_CYCLE`**. |
307
+ | **`startX`** | `start-x` | `number` | _(omit)_ | Initial / home X (**0** valid). |
308
+ | **`startY`** | `start-y` | `number` | _(omit)_ | Initial / home Y (**0** valid). |
309
+ | **`autoStart`** | `auto-start` | `boolean` | **`true`** | After `createNeko`, run the loop unless **`mode="rest"`** or **`false`**. |
310
+ | **`respectReducedMotion`** | `respect-reduced-motion` | `boolean` | **`true`** | Skip pet when user prefers reduced motion. |
311
+ | **`startCorner`** | `start-corner` | `string` | _(omit)_ | **`top-left`** \| **`top-right`** \| **`bottom-left`** \| **`bottom-right`** for axes without `startX`/`startY`. |
312
+ | **`anchorSelector`** | `anchor-selector` | `string` | _(omit)_ | `document.querySelector` for anchor; waits for non-zero layout. Prefer **`anchorRef`** in **`useNeko`**. |
313
+ | **`mode`** | `mode` | **`follow`** \| **`rest`** | **`follow`** | **`follow`** = loop runs; **`rest`** = stop at resolved home after create. |
314
+ | **`restUntilFirstPetInteraction`** | `rest-until-first-pet-interaction` | `boolean` | **`undefined`** | First pointer-down on sprite wakes **`follow`** without consuming first cycle step. |
315
+ | **`debug`** | `debug` | `boolean` | **`false`** | **`[neko-vue]`** console logs for placement / recreates. |
280
316
 
281
317
  **`allowBehaviorChange`:** Omit the prop to keep the **engine default** (`true`). A plain optional `Boolean` prop in Vue would otherwise become `false` when unset; here the default is explicitly `undefined`, and options passed to `createNeko` omit `undefined` fields so engine defaults apply.
282
318
 
@@ -318,6 +354,18 @@ const {
318
354
  </script>
319
355
  ```
320
356
 
357
+ ### `useNeko()` return value (reference)
358
+
359
+ | Name | What it is |
360
+ | ---- | ----------- |
361
+ | **`instance`** | **`ShallowRef<NekoInstance \| null>`** — set after load + `createNeko`; **`null`** before ready, after **`destroy`**, or while skipped for reduced motion / deferred anchor. |
362
+ | **`error`** | **`Ref<Error \| null>`** — load / `createNeko` failure; cleared at the start of each recreate attempt. |
363
+ | **`isReady`** | **`Ref<boolean>`**, **`true`** once `createNeko` succeeded for the current mount cycle. |
364
+ | **`skippedForReducedMotion`** | **`Ref<boolean>`**, **`true`** when the pet was skipped because the user prefers reduced motion (default gate on). |
365
+ | **`mode`** | Readonly ref: current **`follow`** / **`rest`**; drive with **`setMode`**, **`restAtOrigin`**, **`resumeFollow`**, or a reactive **`mode`** in options. |
366
+ | **`petInteractionAwake`** | Readonly ref; with **`restUntilFirstPetInteraction`**, **`true`** after the first pointer-down on the sprite wakes **`follow`**. |
367
+ | **`setMode`**, **`restAtOrigin`**, **`resumeFollow`**, **`destroy`** | Imperative controls (see [Follow vs rest (`mode`)](#follow-vs-rest-mode) in the composable section below). |
368
+
321
369
  **Custom click cycle and pointer standoff** (same options on **`NekoPet`** as props):
322
370
 
323
371
  ```ts
@@ -368,6 +416,7 @@ useNeko(
368
416
  - **`startX` / `startY`** — passed through to `createNeko` (remember `0` is valid).
369
417
  - **`startCorner`** — `top-left` | `top-right` | `bottom-left` | `bottom-right`; fills axes that `startX`/`startY` leave out, using `document.documentElement.clientWidth` and `window.innerHeight` minus `NEKOJS_SPRITE_SIZE` (32).
370
418
  - **`anchorRef`** (in `setup`) or **`anchorSelector`** (on `NekoPet`) — use the element’s top-left in viewport space when coordinates are omitted. If you pass either one, **`createNeko` waits** until the matched element exists and has **positive width and height** (`getBoundingClientRect()`, with `offsetWidth` / `offsetHeight` as a fallback) so the pet does not spawn at a bogus position while the anchor is still mounting or collapsed.
419
+ - **`ResizeObserver`** (in **`useNeko`** only): attached when **`anchorRef`** points at an element, so layout changes on that node can trigger a recreate. There is **no** observer for **`anchorSelector`** alone.
371
420
 
372
421
  Resolution order per axis: **explicit coordinate → anchor → corner → 0**.
373
422
 
@@ -395,7 +444,7 @@ Returning to home after the cat has moved uses a **fresh instance** (destroy + c
395
444
 
396
445
  Use this when you call **`createNeko`** outside **`useNeko`** / **`NekoPet`** (e.g. a custom lifecycle).
397
446
 
398
- - If **`window.createNeko`** already exists, **`loadNekoRuntime()`** resolves to it immediately (no import).
447
+ - If **`globalThis.createNeko`** already exists, **`loadNekoRuntime()`** resolves to it immediately (no import).
399
448
  - Otherwise it performs a **one-time** dynamic import of the bundled runtime (same code path as **`useNeko`**).
400
449
 
401
450
  ```ts
@@ -410,7 +459,7 @@ neko.start();
410
459
 
411
460
  ## Nuxt / SSR
412
461
 
413
- The pet runtime is **browser-only**. Do not run `loadNekoRuntime` or `useNeko` on the server. In Nuxt, render the pet inside [`<ClientOnly>`](https://nuxt.com/docs/api/components/client-only) or a `.client.vue` component.
462
+ The pet runtime is **browser-only**. Do not run **`loadNekoRuntime`**, **`useNeko`**, or mount **`NekoPet`** on the server. In **Nuxt 4**, use a **`*.client.vue`** component (with [auto-import or `#components`](https://nuxt.com/docs/4.x/guide/directory-structure/components#client-components)) and/or [`<ClientOnly>`](https://nuxt.com/docs/4.x/api/components/client-only). See [Nuxt 4](#4-nuxt-4) above.
414
463
 
415
464
  ## Motion preferences
416
465
 
@@ -456,10 +505,11 @@ vp test
456
505
  Runs Vitest against **`loadNekoRuntime`**, `useNeko`, and `NekoPet` (tests set **`window.createNeko`** mocks; happy-dom), including checks that optional fields are not sent as `undefined`, that **`behaviorCycle`** / **`cursorStandoffPx`** reach `createNeko` when set, that anchor `ResizeObserver` does not recreate the pet when the layout size is unchanged, and that **`createNeko` is deferred** until an anchor element has non-zero layout when `anchorRef` is used.
457
506
 
458
507
  ```bash
459
- vp check
508
+ vp run check
509
+ vp run check:playground
460
510
  ```
461
511
 
462
- Runs format, lint, and TypeScript checks (via Vite+).
512
+ Or **`bun run check:all`** — library paths first, then **`playground/src`** and **`playground/vite.config.ts`** (bare **`vp check`** would typecheck the playground against root `node_modules` and fail). Runs format, lint, and TypeScript via Vite+.
463
513
 
464
514
  ```bash
465
515
  vp pack
@@ -467,11 +517,11 @@ vp pack
467
517
 
468
518
  Produces **`dist/`** (ESM + `.d.mts`). The playground and any `file:` consumer need a successful pack.
469
519
 
470
- **CI:** Pushes and pull requests against **`main`** run [`.github/workflows/ci.yml`](./.github/workflows/ci.yml): `voidzero-dev/setup-vp`, **`vp check`**, **`vp test`**, and **`vp pack`** (same bar as a clean local run).
520
+ **CI:** Pushes and pull requests against **`main`** run [`.github/workflows/ci.yml`](./.github/workflows/ci.yml): **`actions/checkout@v6`**, **`voidzero-dev/setup-vp`** (Node **24**), **`npm install --prefix playground`**, **`vp run check && vp run check:playground`**, **`vp test`**, **`vp pack`**.
471
521
 
472
522
  #### 2. Visual / manual test in the browser (playground)
473
523
 
474
- The **[playground](./playground/)** app imports the library through a Vite alias to the parent folder and resolves **`dist/`** via the root `package.json` `exports`. It uses **Vue Router** so each integration style has its **own route** (one pet on screen at a time):
524
+ The **[playground](./playground/)** app aliases **`neko-vue`** to **`../src/index.ts`** in **`playground/vite.config.ts`** so local edits hit the library source without reinstalling. Published consumers still use **`dist/`** via **`package.json` `exports`**. The playground uses **Vue Router** so each integration style has its **own route** (one pet on screen at a time):
475
525
 
476
526
  | Route | Demo file | What it shows |
477
527
  | ----------------- | ----------------------- | ------------------------------------------------------------------------------------------------------- |
@@ -505,14 +555,14 @@ More detail: [playground/README.md](./playground/README.md).
505
555
 
506
556
  #### 3. Try it inside another Vue app on your machine
507
557
 
508
- - **Option A — `npm pack` / `pnpm pack`:** From the repo root, run `vp pack`, then `npm pack` (or equivalent). In your app, install the generated `.tgz` (e.g. `npm install ../path/to/neko-vue-0.0.0.tgz`).
558
+ - **Option A — `npm pack` / `pnpm pack`:** From the repo root, run `vp pack`, then `npm pack` (or equivalent). In your app, install the generated `.tgz` (e.g. `npm install ../path/to/neko-vue-0.1.0.tgz`; the filename matches **`version`** in root `package.json`).
509
559
  - **Option B — `file:` dependency:** Point your app’s `package.json` at the folder that contains a built **`dist/`** (same as publishing layout).
510
560
 
511
561
  Ensure **`vp pack`** has been run so `exports` and types resolve.
512
562
 
513
563
  ### Package entry shape
514
564
 
515
- **neko-vue** ships as a **single package** with one primary export (`"."` → `dist/index.mjs`). Some libraries use a **monorepo** or **`exports` subpaths** (e.g. `pkg/composable`) for tree-shaking; doing that here would need extra **pack** outputs and an **`exports`** map (not wired yet). A **Nuxt module** would typically live in a **separate package**.
565
+ **neko-vue** is one npm package with a root export (`"."` → `dist/index.mjs`) plus conditional **`exports`** subpaths **`/types`**, **`/placement`**, **`/runtime`**, **`/vue`** (each with **`types`** + **`import`**) see [Subpath imports](#subpath-imports). A dedicated **Nuxt module** would still typically be a **separate package** if you want zero-config Nuxt integration beyond the steps in [Nuxt 4](#4-nuxt-4).
516
566
 
517
567
  ---
518
568
 
@@ -522,5 +572,6 @@ Ensure **`vp pack`** has been run so `exports` and types resolve.
522
572
  vp install
523
573
  vp test
524
574
  vp pack
525
- vp check
575
+ vp run check
576
+ vp run check:playground
526
577
  ```
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "neko-vue",
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
4
4
  "description": "Vue 3 desktop pet — typed runtime, composable, and NekoPet component.",
5
5
  "keywords": [
6
6
  "composable",
@@ -67,13 +67,17 @@
67
67
  "check": "vp check src tests vite.config.ts",
68
68
  "check:playground": "vp check playground/src playground/vite.config.ts",
69
69
  "check:all": "vp check src tests vite.config.ts && vp check playground/src playground/vite.config.ts",
70
- "prepublishOnly": "vp run build"
70
+ "prepublishOnly": "vp run build",
71
+ "release": "commit-and-tag-version"
71
72
  },
72
73
  "devDependencies": {
74
+ "@commitlint/cli": "^20.5.0",
75
+ "@commitlint/config-conventional": "^20.5.0",
73
76
  "@types/node": "^25.5.2",
74
77
  "@typescript/native-preview": "7.0.0-dev.20260404.1",
75
78
  "@vue/test-utils": "^2.4.6",
76
79
  "bumpp": "^11.0.1",
80
+ "commit-and-tag-version": "^12.7.1",
77
81
  "happy-dom": "^20.8.9",
78
82
  "typescript": "^6.0.2",
79
83
  "vite-plus": "^0.1.15",