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.
- package/CHANGELOG.md +17 -0
- package/LICENSE +27 -0
- package/README.md +526 -0
- package/dist/NekoPet-B9k9Bf1o.d.mts +262 -0
- package/dist/NekoPet-DMPjoHm0.mjs +402 -0
- package/dist/index-BjAaI8iZ.d.mts +128 -0
- package/dist/index.d.mts +17 -0
- package/dist/index.mjs +5 -0
- package/dist/loadNekoRuntime-CskWI70T.mjs +41 -0
- package/dist/loadNekoRuntime-DLd1lr8Y.d.mts +11 -0
- package/dist/nekoPlacement-DUdnhZoX.mjs +76 -0
- package/dist/nekoPlacement-fXmlU6ys.d.mts +23 -0
- package/dist/nekojsRuntime-DJI-YkCi.mjs +616 -0
- package/dist/placement.d.mts +2 -0
- package/dist/placement.mjs +2 -0
- package/dist/runtime.d.mts +2 -0
- package/dist/runtime.mjs +2 -0
- package/dist/types-Ctrldouo.mjs +50 -0
- package/dist/types.d.mts +2 -0
- package/dist/types.mjs +2 -0
- package/dist/vue.d.mts +2 -0
- package/dist/vue.mjs +2 -0
- package/package.json +98 -0
|
@@ -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 };
|
package/dist/index.d.mts
ADDED
|
@@ -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 };
|