@jgengine/react 0.11.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 +26 -0
- package/dist/actionHud.d.ts +5 -5
- package/dist/actionHud.js +14 -12
- 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/components.d.ts +8 -1
- package/dist/components.js +8 -1
- package/dist/hooks.d.ts +20 -0
- package/dist/hooks.js +38 -0
- package/dist/hud.d.ts +21 -4
- package/dist/hud.js +38 -27
- package/dist/hudFrame.d.ts +47 -0
- package/dist/hudFrame.js +80 -0
- package/dist/hudLayout.d.ts +13 -1
- package/dist/hudLayout.js +18 -12
- 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 +9 -0
- package/dist/index.js +9 -0
- package/dist/map.d.ts +72 -10
- package/dist/map.js +84 -15
- package/dist/selectionHud.d.ts +11 -5
- package/dist/selectionHud.js +11 -5
- package/dist/slots.d.ts +44 -0
- package/dist/slots.js +37 -0
- package/package.json +2 -2
- package/skills/jgengine/SKILL.md +7 -4
- package/skills/jgengine/api.md +172 -79
- package/skills/jgengine/capabilities.md +104 -2
- package/skills/jgengine/recipes/minimal-game.md +88 -0
- package/skills/jgengine-ui/SKILL.md +15 -10
- package/skills/jgengine-ui/api.md +202 -47
- package/skills/jgengine-ui/capabilities.md +71 -2
- package/skills/jgengine-ui/recipes/portable-minimap.md +150 -0
- package/skills/jgengine-ui/reference.md +20 -7
- package/skills/jgengine-ui/references/visual-scorecard.md +1 -1
- package/skills/jgengine/reference-cartridge.md +0 -72
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import {} from "react";
|
|
3
|
+
import { AmmoCounter, ExperienceBar, HealthBar, ManaBar, ShieldBar } from "./bars.js";
|
|
4
|
+
import { HudFrame } from "./hudFrame.js";
|
|
5
|
+
import { HUD_THEME_PRESETS, defaultHudTheme, hudThemeVars } from "./hudTheme.js";
|
|
6
|
+
/**
|
|
7
|
+
* A deterministic preset matrix for {@link HudTheme} (#1034): every genre preset × (bars + a themed
|
|
8
|
+
* frame + a slot row), rendered from static values. One `hudThemeVars(theme)` block per cell drives
|
|
9
|
+
* the atomic bars, the `HudFrame variation="themed"`, and the slot chrome together — proof that a
|
|
10
|
+
* single theme restyles all the shared chrome at once. Renders identically every time (screenshots).
|
|
11
|
+
*/
|
|
12
|
+
function Slot({ index }) {
|
|
13
|
+
return (_jsx("div", { style: {
|
|
14
|
+
width: 34,
|
|
15
|
+
height: 34,
|
|
16
|
+
background: "var(--jg-slot-bg, rgba(12,14,20,0.7))",
|
|
17
|
+
border: "var(--jg-slot-border, 1px solid rgba(255,255,255,0.12))",
|
|
18
|
+
borderRadius: "var(--jg-slot-radius, 8px)",
|
|
19
|
+
display: "flex",
|
|
20
|
+
alignItems: "center",
|
|
21
|
+
justifyContent: "center",
|
|
22
|
+
fontSize: 10,
|
|
23
|
+
color: "var(--jg-bar-text, #f4f6fb)",
|
|
24
|
+
opacity: index === 0 ? 1 : 0.6,
|
|
25
|
+
}, children: index + 1 }));
|
|
26
|
+
}
|
|
27
|
+
function ThemeCell({ name, theme }) {
|
|
28
|
+
return (_jsx("div", { style: { ...hudThemeVars(theme), width: 260 }, children: _jsx(HudFrame, { variation: "themed", title: name, padding: 12, children: _jsxs("div", { style: { display: "flex", flexDirection: "column", gap: 7 }, children: [_jsx(HealthBar, { value: 78, max: 100, label: "HP", width: "100%" }), _jsx(ManaBar, { value: 50, max: 80, label: "MP", width: "100%" }), _jsx(ShieldBar, { value: 30, max: 60, label: "SH", width: "100%" }), _jsx(ExperienceBar, { value: 4, max: 10, segments: 10, showValue: false, label: "XP", width: "100%" }), _jsx(AmmoCounter, { loaded: 17, reserve: 90, magazine: 30, width: "100%" }), _jsx("div", { style: { display: "flex", gap: 6, marginTop: 2 }, children: [0, 1, 2, 3].map((index) => (_jsx(Slot, { index: index }, index))) })] }) }) }));
|
|
29
|
+
}
|
|
30
|
+
/** Renders the default theme plus every genre preset as a deterministic matrix. */
|
|
31
|
+
export function HudThemePreview({ className }) {
|
|
32
|
+
const cells = [
|
|
33
|
+
["default", defaultHudTheme],
|
|
34
|
+
...Object.entries(HUD_THEME_PRESETS),
|
|
35
|
+
];
|
|
36
|
+
return (_jsx("div", { "data-hud-theme-preview": true, className: className, style: { display: "flex", gap: 18, flexWrap: "wrap", padding: 22, fontFamily: "system-ui, sans-serif", background: "#0e1216" }, children: cells.map(([name, theme]) => (_jsx(ThemeCell, { name: name, theme: theme }, name))) }));
|
|
37
|
+
}
|
|
@@ -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
|
@@ -10,6 +10,14 @@ export * from "./settings.js";
|
|
|
10
10
|
export * from "./save.js";
|
|
11
11
|
export * from "./components.js";
|
|
12
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";
|
|
13
21
|
export * from "./keyHint.js";
|
|
14
22
|
export * from "./startScreen.js";
|
|
15
23
|
export * from "./engineStore.js";
|
|
@@ -18,6 +26,7 @@ export * from "./cards.js";
|
|
|
18
26
|
export * from "./actionHud.js";
|
|
19
27
|
export * from "./selectionHud.js";
|
|
20
28
|
export * from "./hudLayout.js";
|
|
29
|
+
export * from "./hudLayoutPersist.js";
|
|
21
30
|
export * from "./hudViewport.js";
|
|
22
31
|
export * from "./gameViewport.js";
|
|
23
32
|
export * from "./rotateDevice.js";
|
package/dist/index.js
CHANGED
|
@@ -10,6 +10,14 @@ export * from "./settings.js";
|
|
|
10
10
|
export * from "./save.js";
|
|
11
11
|
export * from "./components.js";
|
|
12
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";
|
|
13
21
|
export * from "./keyHint.js";
|
|
14
22
|
export * from "./startScreen.js";
|
|
15
23
|
export * from "./engineStore.js";
|
|
@@ -18,6 +26,7 @@ export * from "./cards.js";
|
|
|
18
26
|
export * from "./actionHud.js";
|
|
19
27
|
export * from "./selectionHud.js";
|
|
20
28
|
export * from "./hudLayout.js";
|
|
29
|
+
export * from "./hudLayoutPersist.js";
|
|
21
30
|
export * from "./hudViewport.js";
|
|
22
31
|
export * from "./gameViewport.js";
|
|
23
32
|
export * from "./rotateDevice.js";
|
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";
|
|
3
|
+
import { type MapMarker, type MarkerCollection, type MarkerKindStyle, type MarkerSource, type MarkerSet, type MarkerView } from "@jgengine/core/world/markers";
|
|
4
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,12 +44,13 @@ 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`.
|
|
43
50
|
*
|
|
44
51
|
* @capability minimap framed circular minimap with terrain bake, fog, markers, and facing arrow
|
|
45
52
|
*/
|
|
46
|
-
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;
|
|
47
54
|
/** One dot (or, with `heading`, a rotated arrow) drawn by `MinimapChrome`. */
|
|
48
55
|
export interface MinimapChromeMarker {
|
|
49
56
|
id: string;
|
|
@@ -91,7 +98,7 @@ export interface CompassProps {
|
|
|
91
98
|
/** Facing yaw (`rotationY`, forward = `(sin yaw, cos yaw)`) of the tracked entity — pass it raw, never pre-converted to a bearing. */
|
|
92
99
|
facingYaw: number;
|
|
93
100
|
center?: WorldXZ;
|
|
94
|
-
markers?:
|
|
101
|
+
markers?: MarkerCollection;
|
|
95
102
|
width?: number;
|
|
96
103
|
fov?: number;
|
|
97
104
|
kindStyles?: Record<string, MarkerKindStyle>;
|
|
@@ -99,7 +106,8 @@ export interface CompassProps {
|
|
|
99
106
|
}
|
|
100
107
|
/**
|
|
101
108
|
* Horizontal compass strip centered on the player's facing direction, with the
|
|
102
|
-
* eight cardinals and optional marker pips
|
|
109
|
+
* eight cardinals and optional marker pips from static views, an external
|
|
110
|
+
* source, or a native `MarkerSet`.
|
|
103
111
|
*/
|
|
104
112
|
export declare function Compass({ facingYaw, center, markers, width, fov, kindStyles, className, }: CompassProps): ReactNode;
|
|
105
113
|
/** Props for `MinimapPanel` — all `MinimapProps` plus the zone-label/clock header and compass slots. */
|
|
@@ -125,8 +133,62 @@ export interface MinimapPanelProps extends MinimapProps {
|
|
|
125
133
|
* @capability minimap-panel circular minimap with zone label, clock, and compass composed together
|
|
126
134
|
*/
|
|
127
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;
|
|
128
189
|
export interface WorldMapProps {
|
|
129
|
-
|
|
190
|
+
/** Static views, an external marker source, or a native JGengine MarkerSet. */
|
|
191
|
+
markers: MarkerCollection;
|
|
130
192
|
bounds: MapBounds;
|
|
131
193
|
player?: WorldXZ;
|
|
132
194
|
/** Facing yaw (`rotationY`, forward = `(sin yaw, cos yaw)`) of the player — pass it raw, never pre-converted to a bearing. */
|
package/dist/map.js
CHANGED
|
@@ -68,20 +68,42 @@ function cellStateNodes(layers, project, scale, keyPrefix) {
|
|
|
68
68
|
}
|
|
69
69
|
return nodes;
|
|
70
70
|
}
|
|
71
|
+
function markerAccess(markers) {
|
|
72
|
+
if (Array.isArray(markers)) {
|
|
73
|
+
const snapshot = markers;
|
|
74
|
+
return { subscribe: NO_SUBSCRIBE, getSnapshot: () => snapshot, getServerSnapshot: () => snapshot };
|
|
75
|
+
}
|
|
76
|
+
if ("getSnapshot" in markers) {
|
|
77
|
+
const source = markers;
|
|
78
|
+
return {
|
|
79
|
+
subscribe: (listener) => source.subscribe(listener),
|
|
80
|
+
getSnapshot: () => source.getSnapshot(),
|
|
81
|
+
getServerSnapshot: () => (source.getServerSnapshot ?? source.getSnapshot).call(source),
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
const markerSet = markers;
|
|
85
|
+
return {
|
|
86
|
+
subscribe: (listener) => markerSet.subscribe(listener),
|
|
87
|
+
getSnapshot: () => markerSet.snapshot(),
|
|
88
|
+
getServerSnapshot: () => markerSet.snapshot(),
|
|
89
|
+
};
|
|
90
|
+
}
|
|
71
91
|
export function useMarkers(markers) {
|
|
72
|
-
|
|
92
|
+
const access = useMemo(() => markerAccess(markers), [markers]);
|
|
93
|
+
return useSyncExternalStore(access.subscribe, access.getSnapshot, access.getServerSnapshot);
|
|
73
94
|
}
|
|
74
95
|
export function useFog(fog) {
|
|
75
96
|
return useSyncExternalStore(fog.subscribe, fog.cells, fog.cells);
|
|
76
97
|
}
|
|
77
98
|
/**
|
|
78
99
|
* Framed circular minimap: optional baked terrain background, reveal-on-event
|
|
79
|
-
* fog overlay, categorized marker icons, and a facing arrow. Reads
|
|
80
|
-
*
|
|
100
|
+
* fog overlay, categorized marker icons, and a facing arrow. Reads static
|
|
101
|
+
* marker views, an external marker source, or a native `MarkerSet`; supply
|
|
102
|
+
* your own `kindStyles` palette to reskin. Does not require `GameProvider`.
|
|
81
103
|
*
|
|
82
104
|
* @capability minimap framed circular minimap with terrain bake, fog, markers, and facing arrow
|
|
83
105
|
*/
|
|
84
|
-
export function Minimap({ markers, center, worldRadius, fog, size = 176, facingYaw = 0, rotate = false, kindStyles = DEFAULT_MARKER_KINDS, background, mapBounds, routes, zones, cellStates, onWorldClick, className, title = "Map", children, }) {
|
|
106
|
+
export function Minimap({ markers, center, worldRadius, fog, size = 176, facingYaw = 0, rotate = false, kindStyles = DEFAULT_MARKER_KINDS, background, mapBounds, routes, zones, cellStates, onWorldClick, className, style, title = "Map", children, }) {
|
|
85
107
|
const markerList = useMarkers(markers);
|
|
86
108
|
const fogCells = useSyncExternalStore(fog?.subscribe ?? NO_SUBSCRIBE, fog?.cells ?? NULL_CELLS, fog?.cells ?? NULL_CELLS);
|
|
87
109
|
const bearing = headingToBearing(facingYaw);
|
|
@@ -93,7 +115,7 @@ export function Minimap({ markers, center, worldRadius, fog, size = 176, facingY
|
|
|
93
115
|
};
|
|
94
116
|
const half = size / 2;
|
|
95
117
|
const clipId = `mm-clip-${size}`;
|
|
96
|
-
const sorted = [...markerList].sort((a, b) => markerKindStyle(a.kind, kindStyles).priority - markerKindStyle(b.kind, kindStyles).priority);
|
|
118
|
+
const sorted = useMemo(() => [...markerList].sort((a, b) => markerKindStyle(a.kind, kindStyles).priority - markerKindStyle(b.kind, kindStyles).priority), [markerList, kindStyles]);
|
|
97
119
|
const fogImage = useMemo(() => {
|
|
98
120
|
if (fogCells === null)
|
|
99
121
|
return null;
|
|
@@ -117,10 +139,12 @@ export function Minimap({ markers, center, worldRadius, fog, size = 176, facingY
|
|
|
117
139
|
borderRadius: 14,
|
|
118
140
|
padding: 8,
|
|
119
141
|
background: "linear-gradient(160deg, rgba(24,28,36,0.94), rgba(12,15,20,0.94))",
|
|
120
|
-
|
|
142
|
+
// Ring color reads the shared HudTheme `--jg-ring` token (#1034); fallback = the built-in ring.
|
|
143
|
+
border: "1px solid var(--jg-ring, rgba(148,163,184,0.28))",
|
|
121
144
|
boxShadow: "0 10px 30px rgba(0,0,0,0.45)",
|
|
122
145
|
color: "#e2e8f0",
|
|
123
146
|
fontFamily: "ui-sans-serif, system-ui, sans-serif",
|
|
147
|
+
...style,
|
|
124
148
|
}, children: [_jsxs("div", { style: {
|
|
125
149
|
display: "flex",
|
|
126
150
|
justifyContent: "space-between",
|
|
@@ -158,10 +182,11 @@ export function Minimap({ markers, center, worldRadius, fog, size = 176, facingY
|
|
|
158
182
|
...routeNodes(routes, projectXZ, "mm"),
|
|
159
183
|
];
|
|
160
184
|
})(), _jsx("circle", { cx: half, cy: half, r: half - 1, fill: "none", stroke: "rgba(148,163,184,0.12)" }), sorted.map((marker) => {
|
|
161
|
-
const
|
|
185
|
+
const kind = marker.kind ?? "marker";
|
|
186
|
+
const style = markerKindStyle(kind, kindStyles);
|
|
162
187
|
const projected = projectToMinimap(marker.position, view);
|
|
163
188
|
const at = projected.inside ? projected : clampToMinimapEdge(projected, size);
|
|
164
|
-
return (_jsxs("g", { "data-marker-kind":
|
|
189
|
+
return (_jsxs("g", { "data-marker-kind": kind, children: [_jsx("circle", { cx: at.x, cy: at.y, r: 7, fill: "rgba(2,6,12,0.55)" }), _jsx("text", { x: at.x, y: at.y + 3.5, textAnchor: "middle", fontSize: 10, fill: style.color, style: { fontWeight: 700 }, children: style.glyph })] }, marker.id));
|
|
165
190
|
}), _jsx("g", { transform: `translate(${half} ${half}) rotate(${(rotate ? 0 : bearing) * (180 / Math.PI)})`, children: _jsx("path", { d: "M0,-9 L6,7 L0,3 L-6,7 Z", fill: "#4ade80", stroke: "#052e16", strokeWidth: 0.75 }) })] }), _jsx("circle", { cx: half, cy: half, r: half - 1, fill: "none", stroke: "rgba(148,163,184,0.4)", strokeWidth: 1.5 }), _jsx("text", { x: half, y: 13, textAnchor: "middle", fontSize: 11, fill: "rgba(226,232,240,0.9)", style: { fontWeight: 700 }, children: "N" })] }), children] }));
|
|
166
191
|
}
|
|
167
192
|
/**
|
|
@@ -197,7 +222,6 @@ export function MinimapChrome({ view, frame = false, frameColor = "rgba(148,163,
|
|
|
197
222
|
const NO_SUBSCRIBE = () => () => undefined;
|
|
198
223
|
const NULL_CELLS = () => null;
|
|
199
224
|
const EMPTY_MARKERS_VALUE = [];
|
|
200
|
-
const EMPTY_MARKERS = () => EMPTY_MARKERS_VALUE;
|
|
201
225
|
const COMPASS_TICKS = [
|
|
202
226
|
{ cardinal: "N", bearing: 0 },
|
|
203
227
|
{ cardinal: "NE", bearing: Math.PI / 4 },
|
|
@@ -210,10 +234,11 @@ const COMPASS_TICKS = [
|
|
|
210
234
|
];
|
|
211
235
|
/**
|
|
212
236
|
* Horizontal compass strip centered on the player's facing direction, with the
|
|
213
|
-
* eight cardinals and optional marker pips
|
|
237
|
+
* eight cardinals and optional marker pips from static views, an external
|
|
238
|
+
* source, or a native `MarkerSet`.
|
|
214
239
|
*/
|
|
215
240
|
export function Compass({ facingYaw, center, markers, width = 340, fov = (Math.PI * 2) / 3, kindStyles = DEFAULT_MARKER_KINDS, className, }) {
|
|
216
|
-
const markerList =
|
|
241
|
+
const markerList = useMarkers(markers ?? EMPTY_MARKERS_VALUE);
|
|
217
242
|
const facingBearing = headingToBearing(facingYaw);
|
|
218
243
|
const half = fov / 2;
|
|
219
244
|
const toX = (bearing) => {
|
|
@@ -259,8 +284,9 @@ export function Compass({ facingYaw, center, markers, width = 340, fov = (Math.P
|
|
|
259
284
|
const x = toX(bearing);
|
|
260
285
|
if (x === null)
|
|
261
286
|
return null;
|
|
262
|
-
const
|
|
263
|
-
|
|
287
|
+
const kind = marker.kind ?? "marker";
|
|
288
|
+
const style = markerKindStyle(kind, kindStyles);
|
|
289
|
+
return (_jsx("span", { "data-compass-marker": kind, style: {
|
|
264
290
|
position: "absolute",
|
|
265
291
|
left: x,
|
|
266
292
|
bottom: 2,
|
|
@@ -293,6 +319,48 @@ export function MinimapPanel({ zoneLabel, clock, showCompass = true, compassProp
|
|
|
293
319
|
fontFamily: "ui-sans-serif, system-ui, sans-serif",
|
|
294
320
|
}, children: [zoneLabel !== undefined ? (_jsx("span", { className: zoneLabelClassName, "data-minimap-chrome-zone": true, style: { fontSize: 12, fontWeight: 700 }, children: zoneLabel })) : (_jsx("span", {})), clock !== undefined ? (_jsx("span", { className: clockClassName, "data-minimap-chrome-clock": true, style: { fontSize: 11, color: "rgba(226,232,240,0.75)" }, children: clock })) : null] })) : null, _jsx(Minimap, { ...minimapProps, children: children }), showCompass ? (_jsx("div", { className: compassClassName, "data-minimap-chrome-compass": true, style: { marginTop: 6 }, children: _jsx(Compass, { facingYaw: minimapProps.facingYaw ?? 0, center: minimapProps.center, markers: minimapProps.markers, width: minimapProps.size ?? 176, ...compassProps }) })) : null] }));
|
|
295
321
|
}
|
|
322
|
+
const TRACK_PIP_DIAMETER = {
|
|
323
|
+
dot: 6,
|
|
324
|
+
exit: 8,
|
|
325
|
+
player: 12,
|
|
326
|
+
};
|
|
327
|
+
/**
|
|
328
|
+
* Horizontal linear track minimap — a rounded progress rail with colored zone
|
|
329
|
+
* `spans` and gate/exit/player `pips` positioned by 0..1 fraction. The
|
|
330
|
+
* structural counterpart to the radial {@link Minimap} for corridor/route
|
|
331
|
+
* games: fractions are supplied by the caller (via core `trackFraction`), so it
|
|
332
|
+
* reads no store and stays presentation-only, sharing chrome with the radial
|
|
333
|
+
* minimap.
|
|
334
|
+
*
|
|
335
|
+
* @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
|
|
336
|
+
*/
|
|
337
|
+
export function MinimapTrack({ spans = [], pips = [], width = "100%", height = 12, railColor = "rgba(255,255,255,0.10)", className, style, children, }) {
|
|
338
|
+
return (_jsxs("div", { className: className, "data-minimap-track": true, style: { position: "relative", width, height, borderRadius: 9999, background: railColor, ...style }, children: [spans.map((span) => (_jsx("div", { "data-track-span": span.id, title: span.label, style: {
|
|
339
|
+
position: "absolute",
|
|
340
|
+
top: 0,
|
|
341
|
+
bottom: 0,
|
|
342
|
+
left: `${span.start * 100}%`,
|
|
343
|
+
width: `${(span.end - span.start) * 100}%`,
|
|
344
|
+
background: span.color ?? "rgba(255,255,255,0.25)",
|
|
345
|
+
opacity: 0.4,
|
|
346
|
+
borderRadius: 9999,
|
|
347
|
+
} }, span.id))), pips.map((pip) => {
|
|
348
|
+
const shape = pip.shape ?? "dot";
|
|
349
|
+
const color = pip.color ?? "#f4f6fb";
|
|
350
|
+
const common = {
|
|
351
|
+
position: "absolute",
|
|
352
|
+
top: "50%",
|
|
353
|
+
left: `${pip.at * 100}%`,
|
|
354
|
+
transform: "translate(-50%, -50%)",
|
|
355
|
+
background: color,
|
|
356
|
+
};
|
|
357
|
+
if (shape === "gate") {
|
|
358
|
+
return (_jsx("div", { "data-track-pip": pip.id, "data-pip-shape": "gate", title: pip.title ?? pip.label, style: { ...common, width: 3, height: height + 6, borderRadius: 2 } }, pip.id));
|
|
359
|
+
}
|
|
360
|
+
const diameter = TRACK_PIP_DIAMETER[shape];
|
|
361
|
+
return (_jsx("div", { "data-track-pip": pip.id, "data-pip-shape": shape, title: pip.title ?? pip.label, style: { ...common, width: diameter, height: diameter, borderRadius: 9999, border: "1px solid rgba(0,0,0,0.6)" } }, pip.id));
|
|
362
|
+
}), children] }));
|
|
363
|
+
}
|
|
296
364
|
function WorldMapFogImage({ fogCells, project, worldW, worldD, width, mapH, }) {
|
|
297
365
|
const fogImage = useMemo(() => {
|
|
298
366
|
if (fogCells === null)
|
|
@@ -361,8 +429,9 @@ export function WorldMap({ markers, bounds, player, facingYaw = 0, fog, backgrou
|
|
|
361
429
|
];
|
|
362
430
|
})(), markerList.map((marker) => {
|
|
363
431
|
const at = project(marker.position[0], marker.position[2]);
|
|
364
|
-
const
|
|
365
|
-
|
|
432
|
+
const kind = marker.kind ?? "marker";
|
|
433
|
+
const style = markerKindStyle(kind, kindStyles);
|
|
434
|
+
return (_jsxs("g", { "data-world-marker": kind, children: [_jsx("circle", { cx: at.x, cy: at.y, r: 9, fill: "rgba(2,6,12,0.6)", stroke: style.color, strokeWidth: 1.2 }), _jsx("text", { x: at.x, y: at.y + 4, textAnchor: "middle", fontSize: 12, fill: style.color, style: { fontWeight: 700 }, children: style.glyph }), marker.label !== undefined ? (_jsx("text", { x: at.x + 12, y: at.y + 4, fontSize: 11, fill: "rgba(226,232,240,0.85)", children: marker.label })) : null] }, marker.id));
|
|
366
435
|
}), player !== undefined
|
|
367
436
|
? (() => {
|
|
368
437
|
const at = project(player[0], player[1]);
|
package/dist/selectionHud.d.ts
CHANGED
|
@@ -35,6 +35,9 @@ export declare function useSelectionView(members: readonly EntitySummaryDef[], o
|
|
|
35
35
|
* A compact current/max vital meter for an entity summary; tone maps to a colour ramp. Reuse it as
|
|
36
36
|
* the vital row inside {@link EntitySummary} or any custom entity panel.
|
|
37
37
|
*
|
|
38
|
+
* @deprecated The `tone`/`vital`-API umbrella is retired (#1033). Use the atomic, purpose-named,
|
|
39
|
+
* token-themed bars from `@jgengine/react/bars` (`HealthBar`, `ShieldBar`, `ManaBar`, …) and compose
|
|
40
|
+
* your own panel — each does one readout and restyles globally via the shared `--jg-*` tokens.
|
|
38
41
|
* @capability vital-bar compact current/max vital meter for an entity summary
|
|
39
42
|
*/
|
|
40
43
|
export declare function VitalBar({ vital, width, showLabel, className, style, }: {
|
|
@@ -67,6 +70,9 @@ export declare function EntityPortrait({ entity, selected, size, vitalId, tabInd
|
|
|
67
70
|
* "who is selected" summary a single-selection or the head of a multi-selection shows. Swap the vital
|
|
68
71
|
* rows via `renderVital`.
|
|
69
72
|
*
|
|
73
|
+
* @deprecated Bundling a whole vitals array in one component is the combo anti-pattern #1033 retires.
|
|
74
|
+
* Compose your own summary — name/tags plus the atomic `@jgengine/react/bars` (`HealthBar`, …) you
|
|
75
|
+
* need — so no engine component packages multiple readouts by default. Kept during migration.
|
|
70
76
|
* @capability entity-summary primary selected-entity detail panel (name, tags, vitals)
|
|
71
77
|
*/
|
|
72
78
|
export declare function EntitySummary({ entity, renderVital, className, style, }: {
|
|
@@ -111,12 +117,12 @@ export declare function SelectionCollectionChrome({ model, itemSize, gap, window
|
|
|
111
117
|
style?: CSSProperties;
|
|
112
118
|
}): import("react").JSX.Element;
|
|
113
119
|
/**
|
|
114
|
-
*
|
|
115
|
-
*
|
|
116
|
-
* `
|
|
117
|
-
*
|
|
120
|
+
* Convenience composition: skinned glass panel with {@link EntitySummary} for the primary member
|
|
121
|
+
* beside {@link SelectionCollectionChrome} for the rest — demos/scaffold only, not a finished game
|
|
122
|
+
* face. Pass `members` (or a prebuilt `model`); swap sub-renderers or compose the headless pieces
|
|
123
|
+
* under game-owned chrome for product UI.
|
|
118
124
|
*
|
|
119
|
-
* @capability selection-panel
|
|
125
|
+
* @capability selection-panel optional selection-panel composition: summary + portrait strip / group chips
|
|
120
126
|
*/
|
|
121
127
|
export declare function SelectionPanel({ members, model: providedModel, groupThreshold, labelOf, windowSize, renderPrimary, renderMember, renderVital, onFocusChange, className, style, }: {
|
|
122
128
|
members?: readonly EntitySummaryDef[];
|