@jgengine/react 0.10.0 → 0.12.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 +39 -2
- package/LICENSE +203 -661
- package/README.md +1 -1
- package/dist/actionHud.d.ts +174 -0
- package/dist/actionHud.js +294 -0
- package/dist/bars.d.ts +103 -0
- package/dist/bars.js +180 -0
- package/dist/barsPreview.d.ts +4 -0
- package/dist/barsPreview.js +47 -0
- package/dist/cards.d.ts +59 -0
- package/dist/cards.js +116 -0
- package/dist/chat.d.ts +3 -1
- package/dist/chat.js +2 -2
- package/dist/components.d.ts +28 -1
- package/dist/components.js +36 -1
- package/dist/display.d.ts +1 -0
- package/dist/display.js +1 -0
- package/dist/engineStore.d.ts +3 -0
- package/dist/engineStore.js +3 -0
- package/dist/fogOverlay.d.ts +3 -0
- package/dist/fogOverlay.js +3 -0
- package/dist/gameViewport.js +16 -0
- package/dist/hooks.d.ts +40 -0
- package/dist/hooks.js +69 -1
- package/dist/hud.d.ts +104 -0
- package/dist/hud.js +155 -0
- package/dist/hudFrame.d.ts +47 -0
- package/dist/hudFrame.js +80 -0
- package/dist/hudLayout.d.ts +31 -2
- package/dist/hudLayout.js +127 -10
- package/dist/hudLayoutPersist.d.ts +23 -0
- package/dist/hudLayoutPersist.js +19 -0
- package/dist/hudTheme.d.ts +76 -0
- package/dist/hudTheme.js +156 -0
- package/dist/hudThemePreview.d.ts +4 -0
- package/dist/hudThemePreview.js +37 -0
- package/dist/iconTreatment.d.ts +50 -0
- package/dist/iconTreatment.js +84 -0
- package/dist/iconsPreview.d.ts +4 -0
- package/dist/iconsPreview.js +29 -0
- package/dist/index.d.ts +17 -0
- package/dist/index.js +17 -0
- package/dist/keyHint.d.ts +30 -0
- package/dist/keyHint.js +31 -0
- package/dist/map.d.ts +141 -11
- package/dist/map.js +138 -16
- package/dist/save.d.ts +25 -0
- package/dist/save.js +37 -0
- package/dist/selectSnapshot.d.ts +2 -0
- package/dist/selectSnapshot.js +2 -0
- package/dist/selectionHud.d.ts +139 -0
- package/dist/selectionHud.js +188 -0
- package/dist/skillCheckPaint.d.ts +2 -0
- package/dist/skillCheckPaint.js +2 -0
- package/dist/slots.d.ts +44 -0
- package/dist/slots.js +37 -0
- package/dist/startScreen.d.ts +62 -0
- package/dist/startScreen.js +62 -0
- package/dist/store.d.ts +24 -0
- package/dist/store.js +9 -0
- package/package.json +4 -4
- package/skills/jgengine/SKILL.md +54 -0
- package/skills/jgengine/api.md +527 -0
- package/skills/jgengine/capabilities.md +131 -0
- package/skills/jgengine/recipes/minimal-game.md +88 -0
- package/skills/jgengine-ui/SKILL.md +41 -0
- package/skills/jgengine-ui/api.md +2007 -0
- package/skills/jgengine-ui/capabilities.md +211 -0
- package/skills/jgengine-ui/recipes/portable-minimap.md +150 -0
- package/skills/jgengine-ui/reference.md +513 -0
- package/skills/jgengine-ui/references/visual-scorecard.md +73 -0
- package/llms.txt +0 -1724
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { type CSSProperties, type ReactNode } from "react";
|
|
2
|
+
import { type GameIconName } from "./gameIcons.js";
|
|
3
|
+
/**
|
|
4
|
+
* `IconTreatment` (#1035): a procedural painted-icon face — a glyph over a school-keyed radial
|
|
5
|
+
* gradient, with a vignette inset shadow, a top gloss highlight, and optional count/keycap badges.
|
|
6
|
+
* Turns the engine's flat white `GameIcon` glyphs (and game-icons.net SVGs) into painted ability /
|
|
7
|
+
* item icons that read as AAA slots, not debug UI. Theme-aware: the frame reads the `--jg-slot-*`
|
|
8
|
+
* and `--jg-accent` `HudTheme` tokens (#1034), so a theme change re-skins every treated icon.
|
|
9
|
+
*
|
|
10
|
+
* @capability hud-icons painted-icon treatment for hotbar/action slots — glyph + gradient + count badge
|
|
11
|
+
*/
|
|
12
|
+
/** Element/school palette key — drives the radial gradient behind the glyph. */
|
|
13
|
+
export type IconSchool = "fire" | "frost" | "arcane" | "nature" | "holy" | "tech" | "shadow" | "steel" | "neutral";
|
|
14
|
+
/** Infers an {@link IconSchool} from an item id (keyword match); `neutral` when nothing matches. */
|
|
15
|
+
export declare function schoolForItem(itemId: string): IconSchool;
|
|
16
|
+
/** Infers an {@link IconSchool} from an action id (keyword match); `neutral` when nothing matches. */
|
|
17
|
+
export declare function schoolForAction(action: string): IconSchool;
|
|
18
|
+
/** Props for {@link IconTreatment}. */
|
|
19
|
+
export interface IconTreatmentProps {
|
|
20
|
+
/** A `GameIcon` name to render as the glyph. */
|
|
21
|
+
icon?: GameIconName;
|
|
22
|
+
/** Or an explicit glyph node (a game-icons.net SVG, an `<img>`, custom art). Wins over `icon`. */
|
|
23
|
+
glyph?: ReactNode;
|
|
24
|
+
/** School/element gradient behind the glyph. Default `neutral`. */
|
|
25
|
+
school?: IconSchool;
|
|
26
|
+
/** Face size in px. Default 44. */
|
|
27
|
+
size?: number;
|
|
28
|
+
/** Stack count — a badge is drawn when > 1. */
|
|
29
|
+
count?: number;
|
|
30
|
+
/** Keycap/hotkey drawn top-left. */
|
|
31
|
+
keycap?: string;
|
|
32
|
+
/** Active/selected ring using `--jg-accent`. */
|
|
33
|
+
active?: boolean;
|
|
34
|
+
className?: string;
|
|
35
|
+
style?: CSSProperties;
|
|
36
|
+
}
|
|
37
|
+
/** A painted icon face — gradient + vignette + gloss behind a glyph, with count/keycap badges. */
|
|
38
|
+
export declare function IconTreatment({ icon, glyph, school, size, count, keycap, active, className, style, }: IconTreatmentProps): import("react").JSX.Element;
|
|
39
|
+
/** Maps an item id to a treated icon — resolves a `GameIcon` glyph and an inferred school. */
|
|
40
|
+
export declare function treatedItemIcon(itemId: string, options?: {
|
|
41
|
+
size?: number;
|
|
42
|
+
count?: number;
|
|
43
|
+
keycap?: string;
|
|
44
|
+
}): ReactNode;
|
|
45
|
+
/** A ready-made `ActionButton` `renderIcon` that paints the action's `GameIcon` with a treatment. */
|
|
46
|
+
export declare function treatedActionIcon(action: {
|
|
47
|
+
id?: string;
|
|
48
|
+
label?: string;
|
|
49
|
+
icon?: ReactNode;
|
|
50
|
+
}, size?: number): ReactNode;
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import {} from "react";
|
|
3
|
+
import { GameIcon, iconForAction, iconForItemId } from "./gameIcons.js";
|
|
4
|
+
const SCHOOL_GRADIENT = {
|
|
5
|
+
fire: ["#ff8a3d", "#661805"],
|
|
6
|
+
frost: ["#8fe3ff", "#0e3357"],
|
|
7
|
+
arcane: ["#c58cff", "#341552"],
|
|
8
|
+
nature: ["#8fe36b", "#194013"],
|
|
9
|
+
holy: ["#ffe08a", "#6b4d0f"],
|
|
10
|
+
tech: ["#5fe0c8", "#0c3f3a"],
|
|
11
|
+
shadow: ["#9a7bd0", "#1b0d2b"],
|
|
12
|
+
steel: ["#c8d0da", "#333b45"],
|
|
13
|
+
neutral: ["#9aa3ad", "#242a31"],
|
|
14
|
+
};
|
|
15
|
+
const SCHOOL_RULES = [
|
|
16
|
+
[["fire", "flame", "burn", "lava", "ember", "molotov", "torch"], "fire"],
|
|
17
|
+
[["frost", "ice", "freeze", "snow", "water", "aqua", "chill"], "frost"],
|
|
18
|
+
[["arcane", "magic", "mana", "rune", "spell", "mystic", "void"], "arcane"],
|
|
19
|
+
[["nature", "leaf", "poison", "vine", "earth", "herb", "wood", "beast"], "nature"],
|
|
20
|
+
[["holy", "light", "heal", "divine", "bless", "sun", "cleric"], "holy"],
|
|
21
|
+
[["tech", "laser", "cyber", "robot", "energy", "plasma", "gadget"], "tech"],
|
|
22
|
+
[["shadow", "dark", "curse", "necro", "death", "blood", "demon"], "shadow"],
|
|
23
|
+
[["sword", "axe", "hammer", "spear", "dagger", "armor", "shield", "gun", "bow", "metal", "steel"], "steel"],
|
|
24
|
+
];
|
|
25
|
+
function schoolFrom(text) {
|
|
26
|
+
const lower = text.toLowerCase();
|
|
27
|
+
for (const [keys, school] of SCHOOL_RULES) {
|
|
28
|
+
if (keys.some((key) => lower.includes(key)))
|
|
29
|
+
return school;
|
|
30
|
+
}
|
|
31
|
+
return "neutral";
|
|
32
|
+
}
|
|
33
|
+
/** Infers an {@link IconSchool} from an item id (keyword match); `neutral` when nothing matches. */
|
|
34
|
+
export function schoolForItem(itemId) {
|
|
35
|
+
return schoolFrom(itemId);
|
|
36
|
+
}
|
|
37
|
+
/** Infers an {@link IconSchool} from an action id (keyword match); `neutral` when nothing matches. */
|
|
38
|
+
export function schoolForAction(action) {
|
|
39
|
+
return schoolFrom(action);
|
|
40
|
+
}
|
|
41
|
+
/** A painted icon face — gradient + vignette + gloss behind a glyph, with count/keycap badges. */
|
|
42
|
+
export function IconTreatment({ icon, glyph, school = "neutral", size = 44, count, keycap, active = false, className, style, }) {
|
|
43
|
+
const [g0, g1] = SCHOOL_GRADIENT[school];
|
|
44
|
+
const content = glyph ?? (icon !== undefined ? _jsx(GameIcon, { name: icon, size: Math.round(size * 0.58), color: "#fdfdff" }) : null);
|
|
45
|
+
return (_jsxs("div", { className: className, "data-icon-treatment": school, style: {
|
|
46
|
+
position: "relative",
|
|
47
|
+
width: size,
|
|
48
|
+
height: size,
|
|
49
|
+
borderRadius: "var(--jg-slot-radius, 9px)",
|
|
50
|
+
background: `radial-gradient(circle at 38% 30%, ${g0}, ${g1})`,
|
|
51
|
+
border: active ? "1px solid var(--jg-accent, #38bdf8)" : "var(--jg-slot-border, 1px solid rgba(255,255,255,0.16))",
|
|
52
|
+
boxShadow: active
|
|
53
|
+
? "0 0 0 1px var(--jg-accent, #38bdf8), 0 0 10px rgba(56,189,248,0.5), inset 0 -6px 12px rgba(0,0,0,0.5)"
|
|
54
|
+
: "inset 0 -7px 13px rgba(0,0,0,0.55), inset 0 2px 3px rgba(255,255,255,0.2)",
|
|
55
|
+
overflow: "hidden",
|
|
56
|
+
display: "flex",
|
|
57
|
+
alignItems: "center",
|
|
58
|
+
justifyContent: "center",
|
|
59
|
+
boxSizing: "border-box",
|
|
60
|
+
...style,
|
|
61
|
+
}, children: [_jsx("div", { style: { position: "absolute", inset: 0, background: "linear-gradient(180deg, rgba(255,255,255,0.3), rgba(255,255,255,0) 46%)", pointerEvents: "none" } }), _jsx("div", { style: { position: "absolute", inset: 0, borderRadius: "inherit", boxShadow: "inset 0 0 12px rgba(0,0,0,0.55)", pointerEvents: "none" } }), content, keycap !== undefined ? (_jsx("span", { style: { position: "absolute", top: 1, left: 4, fontSize: 9, fontWeight: 700, color: "#fff", opacity: 0.75, textShadow: "0 1px 2px rgba(0,0,0,0.9)" }, children: keycap })) : null, count !== undefined && count > 1 ? (_jsx("span", { "data-count": true, style: {
|
|
62
|
+
position: "absolute",
|
|
63
|
+
bottom: 1,
|
|
64
|
+
right: 3,
|
|
65
|
+
fontSize: 11,
|
|
66
|
+
fontWeight: 800,
|
|
67
|
+
color: "#fff",
|
|
68
|
+
fontVariantNumeric: "tabular-nums",
|
|
69
|
+
textShadow: "0 1px 2px #000, 0 0 3px #000",
|
|
70
|
+
}, children: count })) : null] }));
|
|
71
|
+
}
|
|
72
|
+
/** Maps an item id to a treated icon — resolves a `GameIcon` glyph and an inferred school. */
|
|
73
|
+
export function treatedItemIcon(itemId, options = {}) {
|
|
74
|
+
const icon = iconForItemId(itemId) ?? undefined;
|
|
75
|
+
return (_jsx(IconTreatment, { ...(icon === undefined ? {} : { icon }), school: schoolForItem(itemId), ...(options.size === undefined ? {} : { size: options.size }), ...(options.count === undefined ? {} : { count: options.count }), ...(options.keycap === undefined ? {} : { keycap: options.keycap }) }));
|
|
76
|
+
}
|
|
77
|
+
/** A ready-made `ActionButton` `renderIcon` that paints the action's `GameIcon` with a treatment. */
|
|
78
|
+
export function treatedActionIcon(action, size = 40) {
|
|
79
|
+
const key = action.id ?? action.label ?? "";
|
|
80
|
+
const named = iconForAction(key);
|
|
81
|
+
if (named === null)
|
|
82
|
+
return action.icon ?? null;
|
|
83
|
+
return _jsx(IconTreatment, { icon: named, school: schoolForAction(key), size: size });
|
|
84
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { IconTreatment } from "./iconTreatment.js";
|
|
3
|
+
/**
|
|
4
|
+
* A deterministic showcase of the painted {@link IconTreatment} (#1035): a school row (one gradient
|
|
5
|
+
* each) and a mock hotbar of treated item icons with count badges and an active slot. Static, so it
|
|
6
|
+
* screenshots identically every time. This is the before/after evidence vs. raw `itemId` text slots.
|
|
7
|
+
*/
|
|
8
|
+
const SCHOOLS = [
|
|
9
|
+
["fire", "bomb"],
|
|
10
|
+
["frost", "wand"],
|
|
11
|
+
["arcane", "staff"],
|
|
12
|
+
["nature", "bow"],
|
|
13
|
+
["holy", "shield"],
|
|
14
|
+
["tech", "gun"],
|
|
15
|
+
["shadow", "dagger"],
|
|
16
|
+
["steel", "sword"],
|
|
17
|
+
];
|
|
18
|
+
const HOTBAR = [
|
|
19
|
+
{ icon: "sword", school: "steel" },
|
|
20
|
+
{ icon: "bow", school: "nature" },
|
|
21
|
+
{ icon: "bomb", school: "fire", count: 12 },
|
|
22
|
+
{ icon: "shield", school: "holy" },
|
|
23
|
+
{ icon: "staff", school: "arcane" },
|
|
24
|
+
{ icon: "wand", school: "frost", count: 3 },
|
|
25
|
+
];
|
|
26
|
+
/** Renders the school-gradient row and a treated-icon hotbar — the deterministic #1035 fixture. */
|
|
27
|
+
export function IconsPreview({ className }) {
|
|
28
|
+
return (_jsxs("div", { "data-icons-preview": true, className: className, style: { display: "flex", flexDirection: "column", gap: 22, padding: 26, background: "#0e1216", fontFamily: "system-ui, sans-serif", color: "#e8edf2" }, children: [_jsxs("div", { children: [_jsx("div", { style: { fontSize: 11, fontWeight: 700, letterSpacing: 0.6, textTransform: "uppercase", opacity: 0.6, marginBottom: 8 }, children: "school gradients" }), _jsx("div", { style: { display: "flex", gap: 10 }, children: SCHOOLS.map(([school, icon]) => (_jsx(IconTreatment, { icon: icon, school: school, size: 52 }, school))) })] }), _jsxs("div", { children: [_jsx("div", { style: { fontSize: 11, fontWeight: 700, letterSpacing: 0.6, textTransform: "uppercase", opacity: 0.6, marginBottom: 8 }, children: "hotbar \u2014 treated icons + count badges (slot 1 active)" }), _jsx("div", { style: { display: "flex", gap: 6 }, children: HOTBAR.map((entry, index) => (_jsx(IconTreatment, { icon: entry.icon, school: entry.school, size: 50, keycap: String(index + 1), active: index === 0, ...(entry.count === undefined ? {} : { count: entry.count }) }, index))) })] })] }));
|
|
29
|
+
}
|
package/dist/index.d.ts
CHANGED
|
@@ -5,11 +5,28 @@ export * from "./chatBubbles.js";
|
|
|
5
5
|
export * from "./voice.js";
|
|
6
6
|
export * from "./social.js";
|
|
7
7
|
export * from "./hooks.js";
|
|
8
|
+
export * from "./store.js";
|
|
8
9
|
export * from "./settings.js";
|
|
10
|
+
export * from "./save.js";
|
|
9
11
|
export * from "./components.js";
|
|
12
|
+
export * from "./hud.js";
|
|
13
|
+
export * from "./bars.js";
|
|
14
|
+
export * from "./barsPreview.js";
|
|
15
|
+
export * from "./iconTreatment.js";
|
|
16
|
+
export * from "./iconsPreview.js";
|
|
17
|
+
export * from "./slots.js";
|
|
18
|
+
export * from "./hudTheme.js";
|
|
19
|
+
export * from "./hudThemePreview.js";
|
|
20
|
+
export * from "./hudFrame.js";
|
|
21
|
+
export * from "./keyHint.js";
|
|
22
|
+
export * from "./startScreen.js";
|
|
10
23
|
export * from "./engineStore.js";
|
|
11
24
|
export * from "./dragLayer.js";
|
|
25
|
+
export * from "./cards.js";
|
|
26
|
+
export * from "./actionHud.js";
|
|
27
|
+
export * from "./selectionHud.js";
|
|
12
28
|
export * from "./hudLayout.js";
|
|
29
|
+
export * from "./hudLayoutPersist.js";
|
|
13
30
|
export * from "./hudViewport.js";
|
|
14
31
|
export * from "./gameViewport.js";
|
|
15
32
|
export * from "./rotateDevice.js";
|
package/dist/index.js
CHANGED
|
@@ -5,11 +5,28 @@ export * from "./chatBubbles.js";
|
|
|
5
5
|
export * from "./voice.js";
|
|
6
6
|
export * from "./social.js";
|
|
7
7
|
export * from "./hooks.js";
|
|
8
|
+
export * from "./store.js";
|
|
8
9
|
export * from "./settings.js";
|
|
10
|
+
export * from "./save.js";
|
|
9
11
|
export * from "./components.js";
|
|
12
|
+
export * from "./hud.js";
|
|
13
|
+
export * from "./bars.js";
|
|
14
|
+
export * from "./barsPreview.js";
|
|
15
|
+
export * from "./iconTreatment.js";
|
|
16
|
+
export * from "./iconsPreview.js";
|
|
17
|
+
export * from "./slots.js";
|
|
18
|
+
export * from "./hudTheme.js";
|
|
19
|
+
export * from "./hudThemePreview.js";
|
|
20
|
+
export * from "./hudFrame.js";
|
|
21
|
+
export * from "./keyHint.js";
|
|
22
|
+
export * from "./startScreen.js";
|
|
10
23
|
export * from "./engineStore.js";
|
|
11
24
|
export * from "./dragLayer.js";
|
|
25
|
+
export * from "./cards.js";
|
|
26
|
+
export * from "./actionHud.js";
|
|
27
|
+
export * from "./selectionHud.js";
|
|
12
28
|
export * from "./hudLayout.js";
|
|
29
|
+
export * from "./hudLayoutPersist.js";
|
|
13
30
|
export * from "./hudViewport.js";
|
|
14
31
|
export * from "./gameViewport.js";
|
|
15
32
|
export * from "./rotateDevice.js";
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { type CSSProperties, type ReactNode } from "react";
|
|
2
|
+
/**
|
|
3
|
+
* A single keyboard/mouse key rendered as a cap. Tagged `data-jg-kbd` so tooling
|
|
4
|
+
* can find it; on its own it stays visible (hiding a lone cap would strand its
|
|
5
|
+
* label). Wrap keys + their meaning in `KeyHint` to make the whole hint vanish
|
|
6
|
+
* on touch.
|
|
7
|
+
*
|
|
8
|
+
* @capability keycap styled keyboard/mouse key cap for control hints
|
|
9
|
+
*/
|
|
10
|
+
export declare function Keycap({ children, className, style, }: {
|
|
11
|
+
children: ReactNode;
|
|
12
|
+
className?: string;
|
|
13
|
+
style?: CSSProperties;
|
|
14
|
+
}): import("react").JSX.Element;
|
|
15
|
+
/**
|
|
16
|
+
* Wraps a keyboard/mouse control hint (a cap plus what it does). Renders nothing
|
|
17
|
+
* on coarse-pointer devices — a touchscreen has no keyboard, so the hint is
|
|
18
|
+
* noise and only fights the on-screen controls for space. The `data-jg-kbd-hint`
|
|
19
|
+
* marker is also hidden by an engine stylesheet as a hydration-safe backstop, so
|
|
20
|
+
* a hint stays hidden on touch even before this component's effect runs. Put the
|
|
21
|
+
* touch equivalent (a `TouchControls` dock, a tappable button) on the coarse
|
|
22
|
+
* branch instead.
|
|
23
|
+
*
|
|
24
|
+
* @capability key-hint keyboard/mouse control hint that hides itself on touch
|
|
25
|
+
*/
|
|
26
|
+
export declare function KeyHint({ children, className, style, }: {
|
|
27
|
+
children: ReactNode;
|
|
28
|
+
className?: string;
|
|
29
|
+
style?: CSSProperties;
|
|
30
|
+
}): import("react").JSX.Element | null;
|
package/dist/keyHint.js
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import {} from "react";
|
|
3
|
+
import { useDisplayProfile } from "./display.js";
|
|
4
|
+
/**
|
|
5
|
+
* A single keyboard/mouse key rendered as a cap. Tagged `data-jg-kbd` so tooling
|
|
6
|
+
* can find it; on its own it stays visible (hiding a lone cap would strand its
|
|
7
|
+
* label). Wrap keys + their meaning in `KeyHint` to make the whole hint vanish
|
|
8
|
+
* on touch.
|
|
9
|
+
*
|
|
10
|
+
* @capability keycap styled keyboard/mouse key cap for control hints
|
|
11
|
+
*/
|
|
12
|
+
export function Keycap({ children, className, style, }) {
|
|
13
|
+
return (_jsx("kbd", { "data-jg-kbd": "", className: className, style: style, children: children }));
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Wraps a keyboard/mouse control hint (a cap plus what it does). Renders nothing
|
|
17
|
+
* on coarse-pointer devices — a touchscreen has no keyboard, so the hint is
|
|
18
|
+
* noise and only fights the on-screen controls for space. The `data-jg-kbd-hint`
|
|
19
|
+
* marker is also hidden by an engine stylesheet as a hydration-safe backstop, so
|
|
20
|
+
* a hint stays hidden on touch even before this component's effect runs. Put the
|
|
21
|
+
* touch equivalent (a `TouchControls` dock, a tappable button) on the coarse
|
|
22
|
+
* branch instead.
|
|
23
|
+
*
|
|
24
|
+
* @capability key-hint keyboard/mouse control hint that hides itself on touch
|
|
25
|
+
*/
|
|
26
|
+
export function KeyHint({ children, className, style, }) {
|
|
27
|
+
const { coarsePointer } = useDisplayProfile();
|
|
28
|
+
if (coarsePointer)
|
|
29
|
+
return null;
|
|
30
|
+
return (_jsx("span", { "data-jg-kbd-hint": "", className: className, style: style, children: children }));
|
|
31
|
+
}
|
package/dist/map.d.ts
CHANGED
|
@@ -1,12 +1,16 @@
|
|
|
1
|
-
import { type ReactNode } from "react";
|
|
1
|
+
import { type CSSProperties, type ReactNode } from "react";
|
|
2
2
|
import type { FogField } from "@jgengine/core/world/fog";
|
|
3
|
-
import { type MapMarker, type MarkerKindStyle, type MarkerSet } from "@jgengine/core/world/markers";
|
|
4
|
-
import { type WorldXZ } from "@jgengine/core/world/minimap";
|
|
3
|
+
import { type MapMarker, type MarkerCollection, type MarkerKindStyle, type MarkerSource, type MarkerSet, type MarkerView } from "@jgengine/core/world/markers";
|
|
4
|
+
import { type MinimapView, type WorldXZ } from "@jgengine/core/world/minimap";
|
|
5
5
|
import { type MapCellStates, type MapRoute, type MapZone } from "@jgengine/core/world/mapLayers";
|
|
6
|
-
|
|
6
|
+
/** Subscribe to a native marker set or external marker source, or read a static marker array. */
|
|
7
|
+
export declare function useMarkers<TMeta = unknown>(markers: MarkerSet<TMeta>): readonly MapMarker<TMeta>[];
|
|
8
|
+
export declare function useMarkers<TMarker extends MarkerView>(markers: readonly TMarker[] | MarkerSource<TMarker>): readonly TMarker[];
|
|
9
|
+
export declare function useMarkers(markers: MarkerCollection): readonly MarkerView[];
|
|
7
10
|
export declare function useFog(fog: FogField): ReturnType<FogField["cells"]>;
|
|
8
11
|
export interface MinimapProps {
|
|
9
|
-
|
|
12
|
+
/** Static views, an external marker source, or a native JGengine MarkerSet. */
|
|
13
|
+
markers: MarkerCollection;
|
|
10
14
|
center: WorldXZ;
|
|
11
15
|
worldRadius: number;
|
|
12
16
|
fog?: FogField;
|
|
@@ -27,6 +31,8 @@ export interface MinimapProps {
|
|
|
27
31
|
/** Click-to-pin seam (#285.6): receives the clicked world XZ via `unprojectFromMinimap`. */
|
|
28
32
|
onWorldClick?: (world: WorldXZ) => void;
|
|
29
33
|
className?: string;
|
|
34
|
+
/** Caller-owned outer chrome overrides, applied after the built-in defaults. */
|
|
35
|
+
style?: CSSProperties;
|
|
30
36
|
title?: string;
|
|
31
37
|
children?: ReactNode;
|
|
32
38
|
}
|
|
@@ -38,15 +44,61 @@ export interface MapBounds {
|
|
|
38
44
|
}
|
|
39
45
|
/**
|
|
40
46
|
* Framed circular minimap: optional baked terrain background, reveal-on-event
|
|
41
|
-
* fog overlay, categorized marker icons, and a facing arrow. Reads
|
|
42
|
-
*
|
|
47
|
+
* fog overlay, categorized marker icons, and a facing arrow. Reads static
|
|
48
|
+
* marker views, an external marker source, or a native `MarkerSet`; supply
|
|
49
|
+
* your own `kindStyles` palette to reskin. Does not require `GameProvider`.
|
|
50
|
+
*
|
|
51
|
+
* @capability minimap framed circular minimap with terrain bake, fog, markers, and facing arrow
|
|
43
52
|
*/
|
|
44
|
-
export declare function Minimap({ markers, center, worldRadius, fog, size, facingYaw, rotate, kindStyles, background, mapBounds, routes, zones, cellStates, onWorldClick, className, title, children, }: MinimapProps): ReactNode;
|
|
53
|
+
export declare function Minimap({ markers, center, worldRadius, fog, size, facingYaw, rotate, kindStyles, background, mapBounds, routes, zones, cellStates, onWorldClick, className, style, title, children, }: MinimapProps): ReactNode;
|
|
54
|
+
/** One dot (or, with `heading`, a rotated arrow) drawn by `MinimapChrome`. */
|
|
55
|
+
export interface MinimapChromeMarker {
|
|
56
|
+
id: string;
|
|
57
|
+
position: WorldXZ | readonly [number, number, number];
|
|
58
|
+
/** Bearing (radians) to draw an arrow instead of a dot — pass `headingToBearing(yaw)` for the player/other facing blips. */
|
|
59
|
+
heading?: number;
|
|
60
|
+
color?: string;
|
|
61
|
+
radius?: number;
|
|
62
|
+
glyph?: string;
|
|
63
|
+
glyphColor?: string;
|
|
64
|
+
strokeColor?: string;
|
|
65
|
+
strokeWidth?: number;
|
|
66
|
+
/** Clamp to the minimap edge when outside `view.worldRadius` (off-screen indicator); `false` hides it instead. Default `true`. */
|
|
67
|
+
clampToEdge?: boolean;
|
|
68
|
+
}
|
|
69
|
+
/** Props for `MinimapChrome`. */
|
|
70
|
+
export interface MinimapChromeProps {
|
|
71
|
+
/** Shared with `projectToMinimap`/`clampToMinimapEdge` — pass `view.rotate` to keep a rotating map's arrows pointed correctly. */
|
|
72
|
+
view: MinimapView;
|
|
73
|
+
/** Ring outline (+ `cardinalLabel`). Default `false` — most games draw their own frame/panel around the chrome. */
|
|
74
|
+
frame?: boolean;
|
|
75
|
+
frameColor?: string;
|
|
76
|
+
frameStrokeWidth?: number;
|
|
77
|
+
/** Label drawn at the top of the ring when `frame` is on; `false` omits it. */
|
|
78
|
+
cardinalLabel?: string | false;
|
|
79
|
+
markers?: readonly MinimapChromeMarker[];
|
|
80
|
+
markerColor?: string;
|
|
81
|
+
markerRadius?: number;
|
|
82
|
+
className?: string;
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Headless minimap chrome — nests inside a game's own `<svg>`: an optional
|
|
86
|
+
* ring frame, and edge-clamped marker dots that draw as directional arrows
|
|
87
|
+
* when a marker carries a `heading` (the compass-arrow / player-blip layer
|
|
88
|
+
* ~8 games were re-drawing by hand over `projectToMinimap`/`clampToMinimapEdge`).
|
|
89
|
+
* Renders a bare `<g>` — no background, panel, or title; compose your own
|
|
90
|
+
* content layer (routes, zones, terrain) as sibling SVG nodes for full control
|
|
91
|
+
* of z-order, or call `MinimapChrome` twice (once for `frame`, again for
|
|
92
|
+
* `markers`) to sandwich custom content between the ring and the blips.
|
|
93
|
+
*
|
|
94
|
+
* @capability minimap-chrome ring frame plus edge-clamped, heading-aware marker dots to nest inside a game's own `<svg>`
|
|
95
|
+
*/
|
|
96
|
+
export declare function MinimapChrome({ view, frame, frameColor, frameStrokeWidth, cardinalLabel, markers, markerColor, markerRadius, className, }: MinimapChromeProps): ReactNode;
|
|
45
97
|
export interface CompassProps {
|
|
46
98
|
/** Facing yaw (`rotationY`, forward = `(sin yaw, cos yaw)`) of the tracked entity — pass it raw, never pre-converted to a bearing. */
|
|
47
99
|
facingYaw: number;
|
|
48
100
|
center?: WorldXZ;
|
|
49
|
-
markers?:
|
|
101
|
+
markers?: MarkerCollection;
|
|
50
102
|
width?: number;
|
|
51
103
|
fov?: number;
|
|
52
104
|
kindStyles?: Record<string, MarkerKindStyle>;
|
|
@@ -54,11 +106,89 @@ export interface CompassProps {
|
|
|
54
106
|
}
|
|
55
107
|
/**
|
|
56
108
|
* Horizontal compass strip centered on the player's facing direction, with the
|
|
57
|
-
* eight cardinals and optional marker pips
|
|
109
|
+
* eight cardinals and optional marker pips from static views, an external
|
|
110
|
+
* source, or a native `MarkerSet`.
|
|
58
111
|
*/
|
|
59
112
|
export declare function Compass({ facingYaw, center, markers, width, fov, kindStyles, className, }: CompassProps): ReactNode;
|
|
113
|
+
/** Props for `MinimapPanel` — all `MinimapProps` plus the zone-label/clock header and compass slots. */
|
|
114
|
+
export interface MinimapPanelProps extends MinimapProps {
|
|
115
|
+
/** Zone/area name slot rendered in the chrome header — the game supplies its own zone lookup. */
|
|
116
|
+
zoneLabel?: ReactNode;
|
|
117
|
+
/** Clock readout slot rendered in the chrome header — pair with `useGameClock()` + `calendar()`. */
|
|
118
|
+
clock?: ReactNode;
|
|
119
|
+
/** Compass strip beneath the circle. Default true; pass `false` to omit it entirely. */
|
|
120
|
+
showCompass?: boolean;
|
|
121
|
+
compassProps?: Partial<Omit<CompassProps, "className">>;
|
|
122
|
+
headerClassName?: string;
|
|
123
|
+
zoneLabelClassName?: string;
|
|
124
|
+
clockClassName?: string;
|
|
125
|
+
compassClassName?: string;
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* Composed circular-minimap chrome: optional zone-label + clock header above
|
|
129
|
+
* the `Minimap`, optional `Compass` strip below. Purely a wiring layer over
|
|
130
|
+
* the existing primitives — the game supplies the zone name and clock text,
|
|
131
|
+
* this only places them; omit either slot and the header disappears.
|
|
132
|
+
*
|
|
133
|
+
* @capability minimap-panel circular minimap with zone label, clock, and compass composed together
|
|
134
|
+
*/
|
|
135
|
+
export declare function MinimapPanel({ zoneLabel, clock, showCompass, compassProps, headerClassName, zoneLabelClassName, clockClassName, compassClassName, children, ...minimapProps }: MinimapPanelProps): ReactNode;
|
|
136
|
+
/** A colored span across the {@link MinimapTrack} rail, given by 0..1 `start`/`end` fractions (e.g. from core `trackFraction`). */
|
|
137
|
+
export interface MinimapTrackSpan {
|
|
138
|
+
id: string;
|
|
139
|
+
/** 0..1 fraction where the span starts. */
|
|
140
|
+
start: number;
|
|
141
|
+
/** 0..1 fraction where the span ends. */
|
|
142
|
+
end: number;
|
|
143
|
+
/** Fill color; defaults to a translucent white. */
|
|
144
|
+
color?: string;
|
|
145
|
+
/** Tooltip / accessible label for the span. */
|
|
146
|
+
label?: string;
|
|
147
|
+
}
|
|
148
|
+
/** A point marker on the {@link MinimapTrack} rail at a 0..1 fraction (e.g. a gate, the exit, or the player). */
|
|
149
|
+
export interface MinimapTrackPip {
|
|
150
|
+
id: string;
|
|
151
|
+
/** 0..1 fraction along the rail. */
|
|
152
|
+
at: number;
|
|
153
|
+
/** Marker color; defaults to the rail foreground. */
|
|
154
|
+
color?: string;
|
|
155
|
+
/** Accessible label for the marker. */
|
|
156
|
+
label?: string;
|
|
157
|
+
/** Tooltip text (rendered as the `title` attribute). */
|
|
158
|
+
title?: string;
|
|
159
|
+
/** Silhouette: `gate` (thin tall bar) or a `dot`/`exit`/`player` circle of increasing size (default `dot`). */
|
|
160
|
+
shape?: "gate" | "dot" | "exit" | "player";
|
|
161
|
+
}
|
|
162
|
+
/** Props for {@link MinimapTrack}. */
|
|
163
|
+
export interface MinimapTrackProps {
|
|
164
|
+
/** Colored zone spans painted along the rail. */
|
|
165
|
+
spans?: readonly MinimapTrackSpan[];
|
|
166
|
+
/** Point markers (gates, exit, player) placed by 0..1 fraction. */
|
|
167
|
+
pips?: readonly MinimapTrackPip[];
|
|
168
|
+
/** Rail width (default `100%`). */
|
|
169
|
+
width?: number | string;
|
|
170
|
+
/** Rail thickness in px (default 12). */
|
|
171
|
+
height?: number;
|
|
172
|
+
/** Rail track color (default `rgba(255,255,255,0.10)`). */
|
|
173
|
+
railColor?: string;
|
|
174
|
+
className?: string;
|
|
175
|
+
style?: CSSProperties;
|
|
176
|
+
children?: ReactNode;
|
|
177
|
+
}
|
|
178
|
+
/**
|
|
179
|
+
* Horizontal linear track minimap — a rounded progress rail with colored zone
|
|
180
|
+
* `spans` and gate/exit/player `pips` positioned by 0..1 fraction. The
|
|
181
|
+
* structural counterpart to the radial {@link Minimap} for corridor/route
|
|
182
|
+
* games: fractions are supplied by the caller (via core `trackFraction`), so it
|
|
183
|
+
* reads no store and stays presentation-only, sharing chrome with the radial
|
|
184
|
+
* minimap.
|
|
185
|
+
*
|
|
186
|
+
* @capability minimap-track-hud horizontal linear track minimap (corridor/route progress) — colored zone spans and gate/player pips positioned by 0..1 fraction, sharing chrome with the radial Minimap
|
|
187
|
+
*/
|
|
188
|
+
export declare function MinimapTrack({ spans, pips, width, height, railColor, className, style, children, }: MinimapTrackProps): ReactNode;
|
|
60
189
|
export interface WorldMapProps {
|
|
61
|
-
|
|
190
|
+
/** Static views, an external marker source, or a native JGengine MarkerSet. */
|
|
191
|
+
markers: MarkerCollection;
|
|
62
192
|
bounds: MapBounds;
|
|
63
193
|
player?: WorldXZ;
|
|
64
194
|
/** Facing yaw (`rotationY`, forward = `(sin yaw, cos yaw)`) of the player — pass it raw, never pre-converted to a bearing. */
|