neko-vue 0.1.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.
@@ -0,0 +1,128 @@
1
+ //#region src/types/index.d.ts
2
+ /** Sprite edge length in CSS pixels for viewport bounds (`clientWidth/innerHeight - this`). */
3
+ declare const NEKOJS_SPRITE_SIZE: 32;
4
+ /**
5
+ * Pet behavior / AI mode. Values match the engine; click cycles when `allowBehaviorChange` is true.
6
+ */
7
+ declare enum BehaviorMode {
8
+ /** Follow the pointer. */
9
+ ChaseMouse = 0,
10
+ /** Flee from the pointer. */
11
+ RunAwayFromMouse = 1,
12
+ /** Wander randomly. */
13
+ RunAroundRandomly = 2,
14
+ /** Walk the screen edges. */
15
+ PaceAroundScreen = 3,
16
+ /** Ball-style chase (engine: run-around mode). */
17
+ BallChase = 4,
18
+ /** Hold the current position (no wandering). */
19
+ StayStill = 5,
20
+ /**
21
+ * Walk back to the spawn position from `createNeko` options, then stay there until the next mode.
22
+ * Last step when clicking through the behavior cycle.
23
+ */
24
+ ReturnHomeAndStay = 6
25
+ }
26
+ /** Short camelCase aliases — same values as {@link BehaviorMode}. */
27
+ declare const BehaviorModes: {
28
+ readonly chase: BehaviorMode.ChaseMouse;
29
+ readonly runAway: BehaviorMode.RunAwayFromMouse;
30
+ readonly random: BehaviorMode.RunAroundRandomly;
31
+ readonly pace: BehaviorMode.PaceAroundScreen;
32
+ readonly ballChase: BehaviorMode.BallChase;
33
+ readonly stayStill: BehaviorMode.StayStill;
34
+ readonly returnHome: BehaviorMode.ReturnHomeAndStay;
35
+ };
36
+ /**
37
+ * Default pet-click order when {@link NekoOptions.behaviorCycle} is omitted (full classic cycle).
38
+ */
39
+ declare const DEFAULT_NEKO_BEHAVIOR_CYCLE: readonly BehaviorMode[];
40
+ /**
41
+ * Options for {@link createNeko}.
42
+ *
43
+ * Note: coordinates use `options.startX || 0`, so `0` is valid; omitting `startX`/`startY`
44
+ * falls back to `0`. Horizontal bounds use `document.documentElement.clientWidth -
45
+ * {@link NEKOJS_SPRITE_SIZE}`; vertical uses `window.innerHeight - {@link NEKOJS_SPRITE_SIZE}`.
46
+ */
47
+ interface NekoOptions {
48
+ /**
49
+ * Pixels per logic tick (default: 24; logic runs ~5 ticks/sec).
50
+ */
51
+ speed?: number;
52
+ /**
53
+ * Render frame rate (default: 120).
54
+ */
55
+ fps?: number;
56
+ /**
57
+ * Initial {@link BehaviorMode} when the instance is **created**. Clicks on the pet cycle the
58
+ * live mode in the engine; changing this option later does **not** recreate the pet or override
59
+ * the current mode (see wrapper behavior).
60
+ */
61
+ behaviorMode?: BehaviorMode;
62
+ /**
63
+ * Distance at which the pet is considered idle (default: 6).
64
+ */
65
+ idleThreshold?: number;
66
+ /**
67
+ * In {@link BehaviorMode.ChaseMouse}, keep at least this many CSS pixels between the pet’s
68
+ * movement anchor and the pointer (default / omitted: 0 = original “hug the cursor” behavior).
69
+ */
70
+ cursorStandoffPx?: number;
71
+ /**
72
+ * Whether clicking the pet cycles behavior (default: true).
73
+ */
74
+ allowBehaviorChange?: boolean;
75
+ /**
76
+ * Ordered modes advanced on each pet click when {@link allowBehaviorChange} is true. Order is
77
+ * click order (wraps after the last). Omit to use {@link DEFAULT_NEKO_BEHAVIOR_CYCLE}. Non-integer
78
+ * or out-of-range values are ignored; if none remain, the default cycle is used.
79
+ */
80
+ behaviorCycle?: readonly BehaviorMode[];
81
+ /**
82
+ * Initial X position. `0` is valid; omit for default `0`.
83
+ */
84
+ startX?: number;
85
+ /**
86
+ * Initial Y position. `0` is valid; omit for default `0`.
87
+ */
88
+ startY?: number;
89
+ }
90
+ /**
91
+ * Minimal handle returned by {@link createNeko} / {@link loadNekoRuntime}. The concrete {@link Neko}
92
+ * class may expose additional helpers (e.g. `isIdle`).
93
+ */
94
+ interface NekoInstance {
95
+ /** Starts or resumes the animation interval. */
96
+ start(): void;
97
+ /** Stops the interval without removing the pet from the DOM. */
98
+ stop(): void;
99
+ /** Stops the loop, removes listeners, and deletes the pet element. */
100
+ destroy(): void;
101
+ /**
102
+ * Current engine behavior mode (updated when the user clicks the pet if `allowBehaviorChange` is
103
+ * true). The bundled `Neko` class implements this; mocks may omit it.
104
+ */
105
+ behaviorMode?: BehaviorMode;
106
+ /** Current X in viewport pixels (bundled `Neko` implements). */
107
+ x?: number;
108
+ /** Current Y in viewport pixels (bundled `Neko` implements). */
109
+ y?: number;
110
+ /**
111
+ * Spawn / home top-left from `createNeko` (`startX` / `startY`); return-home uses this. Bundled
112
+ * `Neko` implements.
113
+ */
114
+ homeX?: number;
115
+ homeY?: number;
116
+ }
117
+ type CreateNekoFn = (options?: NekoOptions) => NekoInstance;
118
+ interface LoadNekoRuntimeOptions {
119
+ /** Abort if the bundled runtime has not loaded within this time (ms). Default: 30000. */
120
+ timeoutMs?: number;
121
+ }
122
+ declare global {
123
+ interface Window {
124
+ createNeko?: CreateNekoFn;
125
+ }
126
+ }
127
+ //#endregion
128
+ export { LoadNekoRuntimeOptions as a, NekoOptions as c, DEFAULT_NEKO_BEHAVIOR_CYCLE as i, BehaviorModes as n, NEKOJS_SPRITE_SIZE as o, CreateNekoFn as r, NekoInstance as s, BehaviorMode as t };
@@ -0,0 +1,17 @@
1
+ import { i as resolveStartPosition, n as NekoStartCorner, r as cornerToStartXY } from "./nekoPlacement-fXmlU6ys.mjs";
2
+ import { a as LoadNekoRuntimeOptions, c as NekoOptions, i as DEFAULT_NEKO_BEHAVIOR_CYCLE, n as BehaviorModes, o as NEKOJS_SPRITE_SIZE, r as CreateNekoFn, s as NekoInstance, t as BehaviorMode } from "./index-BjAaI8iZ.mjs";
3
+ import { t as loadNekoRuntime } from "./loadNekoRuntime-DLd1lr8Y.mjs";
4
+ import { i as useNeko, n as NekoFollowMode, r as UseNekoOptions, t as _default } from "./NekoPet-B9k9Bf1o.mjs";
5
+
6
+ //#region src/utils/debugLog.d.ts
7
+ /** Opt-in `console` helper; prefix keeps DevTools filter easy. */
8
+ declare function nekoVueDebug(enabled: boolean, label: string, ...args: unknown[]): void;
9
+ //#endregion
10
+ //#region src/utils/prefersReducedMotion.d.ts
11
+ /**
12
+ * True when the user has requested less motion (OS / browser setting).
13
+ * Safe on SSR (returns false) and when `matchMedia` is missing.
14
+ */
15
+ declare function prefersReducedMotion(): boolean;
16
+ //#endregion
17
+ export { BehaviorMode, BehaviorModes, type CreateNekoFn, DEFAULT_NEKO_BEHAVIOR_CYCLE, type LoadNekoRuntimeOptions, NEKOJS_SPRITE_SIZE, type NekoFollowMode, type NekoInstance, type NekoOptions, _default as NekoPet, type NekoStartCorner, type UseNekoOptions, cornerToStartXY, loadNekoRuntime, nekoVueDebug, prefersReducedMotion, resolveStartPosition, useNeko };
package/dist/index.mjs ADDED
@@ -0,0 +1,5 @@
1
+ import { i as NEKOJS_SPRITE_SIZE, n as BehaviorModes, r as DEFAULT_NEKO_BEHAVIOR_CYCLE, t as BehaviorMode } from "./types-Ctrldouo.mjs";
2
+ import { n as resolveStartPosition, r as nekoVueDebug, t as cornerToStartXY } from "./nekoPlacement-DUdnhZoX.mjs";
3
+ import { t as loadNekoRuntime } from "./loadNekoRuntime-CskWI70T.mjs";
4
+ import { n as useNeko, r as prefersReducedMotion, t as NekoPet_default } from "./NekoPet-DMPjoHm0.mjs";
5
+ export { BehaviorMode, BehaviorModes, DEFAULT_NEKO_BEHAVIOR_CYCLE, NEKOJS_SPRITE_SIZE, NekoPet_default as NekoPet, cornerToStartXY, loadNekoRuntime, nekoVueDebug, prefersReducedMotion, resolveStartPosition, useNeko };
@@ -0,0 +1,41 @@
1
+ //#region src/runtime/loadNekoRuntime.ts
2
+ function isBrowser() {
3
+ return typeof document !== "undefined";
4
+ }
5
+ function getCreateNekoFromGlobal() {
6
+ if (typeof globalThis === "undefined") return void 0;
7
+ const fn = globalThis.createNeko;
8
+ return typeof fn === "function" ? fn : void 0;
9
+ }
10
+ let bundledLoadPromise = null;
11
+ /**
12
+ * Dynamically imports the bundled typed runtime (`./nekojsRuntime.ts`). Defines `window.createNeko`.
13
+ */
14
+ async function importBundledNeko() {
15
+ await import("./nekojsRuntime-DJI-YkCi.mjs");
16
+ const fn = getCreateNekoFromGlobal();
17
+ if (!fn) throw new Error("neko-vue: bundled neko.js did not define `createNeko`.");
18
+ return fn;
19
+ }
20
+ /**
21
+ * Ensures `createNeko` exists on `globalThis`: uses a global if already present, otherwise loads the
22
+ * **bundled** runtime (dynamic import, no network). Used internally by {@link useNeko}; consumers
23
+ * normally rely on `useNeko` / `<NekoPet>` only.
24
+ */
25
+ function loadNekoRuntime(options = {}) {
26
+ if (!isBrowser()) return Promise.reject(/* @__PURE__ */ new Error("neko-vue: loadNekoRuntime() can only run in a browser (no `document`). Use <ClientOnly> / `.client` components in Nuxt."));
27
+ const existingFn = getCreateNekoFromGlobal();
28
+ if (existingFn) return Promise.resolve(existingFn);
29
+ const timeoutMs = options.timeoutMs ?? 3e4;
30
+ if (!bundledLoadPromise) bundledLoadPromise = Promise.race([importBundledNeko(), new Promise((_, reject) => {
31
+ window.setTimeout(() => {
32
+ reject(/* @__PURE__ */ new Error(`neko-vue: timed out after ${timeoutMs}ms loading bundled neko.js`));
33
+ }, timeoutMs);
34
+ })]).catch((err) => {
35
+ bundledLoadPromise = null;
36
+ throw err;
37
+ });
38
+ return bundledLoadPromise;
39
+ }
40
+ //#endregion
41
+ export { loadNekoRuntime as t };
@@ -0,0 +1,11 @@
1
+ import { a as LoadNekoRuntimeOptions, r as CreateNekoFn } from "./index-BjAaI8iZ.mjs";
2
+
3
+ //#region src/runtime/loadNekoRuntime.d.ts
4
+ /**
5
+ * Ensures `createNeko` exists on `globalThis`: uses a global if already present, otherwise loads the
6
+ * **bundled** runtime (dynamic import, no network). Used internally by {@link useNeko}; consumers
7
+ * normally rely on `useNeko` / `<NekoPet>` only.
8
+ */
9
+ declare function loadNekoRuntime(options?: LoadNekoRuntimeOptions): Promise<CreateNekoFn>;
10
+ //#endregion
11
+ export { loadNekoRuntime as t };
@@ -0,0 +1,76 @@
1
+ import "./types-Ctrldouo.mjs";
2
+ //#region src/utils/debugLog.ts
3
+ /** Opt-in `console` helper; prefix keeps DevTools filter easy. */
4
+ function nekoVueDebug(enabled, label, ...args) {
5
+ if (enabled) console.log(`[neko-vue] ${label}`, ...args);
6
+ }
7
+ //#endregion
8
+ //#region src/placement/nekoPlacement.ts
9
+ function cornerToStartXY(corner, spriteSize = 32, debug = false) {
10
+ const vw = document.documentElement.clientWidth;
11
+ const vh = window.innerHeight;
12
+ nekoVueDebug(debug, "cornerToStartXY viewport", {
13
+ corner,
14
+ spriteSize,
15
+ documentElementClientWidth: vw,
16
+ windowInnerHeight: vh,
17
+ note: "If vw/vh are 0, corner math collapses to 0 — expect a second recreate after layout."
18
+ });
19
+ switch (corner) {
20
+ case "top-left": return {
21
+ startX: 0,
22
+ startY: 0
23
+ };
24
+ case "top-right": return {
25
+ startX: Math.max(0, vw - spriteSize),
26
+ startY: 0
27
+ };
28
+ case "bottom-left": return {
29
+ startX: 0,
30
+ startY: Math.max(0, vh - spriteSize)
31
+ };
32
+ case "bottom-right": return {
33
+ startX: Math.max(0, vw - spriteSize),
34
+ startY: Math.max(0, vh - spriteSize)
35
+ };
36
+ }
37
+ }
38
+ /**
39
+ * Resolves `startX` / `startY` for `createNeko`. Explicit coordinates win per axis.
40
+ * Then anchor top-left (when element is given). Then corner for any axis still unset.
41
+ */
42
+ function resolveStartPosition(input, debug = false) {
43
+ nekoVueDebug(debug, "resolveStartPosition input", {
44
+ startX: input.startX,
45
+ startY: input.startY,
46
+ startCorner: input.startCorner,
47
+ hasAnchor: Boolean(input.anchorElement)
48
+ });
49
+ let startX = input.startX;
50
+ let startY = input.startY;
51
+ const el = input.anchorElement;
52
+ if (el) {
53
+ const r = el.getBoundingClientRect();
54
+ nekoVueDebug(debug, "resolveStartPosition anchor rect", {
55
+ left: r.left,
56
+ top: r.top,
57
+ width: r.width,
58
+ height: r.height
59
+ });
60
+ if (startX === void 0) startX = Math.round(r.left);
61
+ if (startY === void 0) startY = Math.round(r.top);
62
+ }
63
+ if (input.startCorner !== void 0) {
64
+ const c = cornerToStartXY(input.startCorner, 32, debug);
65
+ if (startX === void 0) startX = c.startX;
66
+ if (startY === void 0) startY = c.startY;
67
+ }
68
+ const out = {
69
+ startX: startX ?? 0,
70
+ startY: startY ?? 0
71
+ };
72
+ nekoVueDebug(debug, "resolveStartPosition result", out);
73
+ return out;
74
+ }
75
+ //#endregion
76
+ export { resolveStartPosition as n, nekoVueDebug as r, cornerToStartXY as t };
@@ -0,0 +1,23 @@
1
+ //#region src/placement/nekoPlacement.d.ts
2
+ /** Viewport corner used to derive `startX` / `startY` (wrapper-only). */
3
+ type NekoStartCorner = "top-left" | "top-right" | "bottom-left" | "bottom-right";
4
+ declare function cornerToStartXY(corner: NekoStartCorner, spriteSize?: number, debug?: boolean): {
5
+ startX: number;
6
+ startY: number;
7
+ };
8
+ type NekoPlacementInput = {
9
+ startX?: number;
10
+ startY?: number;
11
+ startCorner?: NekoStartCorner; /** Resolved element (e.g. from `anchorRef` or `querySelector`). */
12
+ anchorElement?: HTMLElement | null;
13
+ };
14
+ /**
15
+ * Resolves `startX` / `startY` for `createNeko`. Explicit coordinates win per axis.
16
+ * Then anchor top-left (when element is given). Then corner for any axis still unset.
17
+ */
18
+ declare function resolveStartPosition(input: NekoPlacementInput, debug?: boolean): {
19
+ startX: number;
20
+ startY: number;
21
+ };
22
+ //#endregion
23
+ export { resolveStartPosition as i, NekoStartCorner as n, cornerToStartXY as r, NekoPlacementInput as t };