@ffxiark/character-viewer 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,145 @@
1
+ declare const RACE_GENDER_CONFIGS: readonly [{
2
+ readonly name: "HumeM";
3
+ readonly index: 1;
4
+ }, {
5
+ readonly name: "HumeF";
6
+ readonly index: 2;
7
+ }, {
8
+ readonly name: "ElvaanM";
9
+ readonly index: 3;
10
+ }, {
11
+ readonly name: "ElvaanF";
12
+ readonly index: 4;
13
+ }, {
14
+ readonly name: "TaruM";
15
+ readonly index: 5;
16
+ }, {
17
+ readonly name: "TaruF";
18
+ readonly index: 6;
19
+ }, {
20
+ readonly name: "Mithra";
21
+ readonly index: 7;
22
+ }, {
23
+ readonly name: "Galka";
24
+ readonly index: 8;
25
+ }];
26
+ type RaceGenderName = (typeof RACE_GENDER_CONFIGS)[number]["name"];
27
+ declare const ITEM_MODEL_SLOTS: readonly ["Face", "Head", "Body", "Hands", "Legs", "Feet", "Main", "Sub", "Range"];
28
+ type ItemModelSlotName = (typeof ITEM_MODEL_SLOTS)[number];
29
+ interface CharacterItemLook {
30
+ race: RaceGenderName;
31
+ face: number;
32
+ items: Partial<Record<ItemModelSlotName, number>>;
33
+ }
34
+
35
+ /** Armor + weapon visual slots used at render time (flat appearance API). */
36
+ declare const MODEL_SLOT_IDS: readonly ["head", "body", "hands", "legs", "feet", "main", "sub", "range"];
37
+ type ModelSlotId = (typeof MODEL_SLOT_IDS)[number];
38
+ declare const ARMOR_SLOT_IDS: readonly ["head", "body", "hands", "legs", "feet"];
39
+ type ArmorSlotId = (typeof ARMOR_SLOT_IDS)[number];
40
+ declare const WEAPON_SLOT_IDS: readonly ["main", "sub", "range"];
41
+ type WeaponSlotId = (typeof WEAPON_SLOT_IDS)[number];
42
+ declare const MAIN_WEAPON_TYPES: readonly ["hand_to_hand", "dagger", "sword", "great_sword", "axe", "great_axe", "scythe", "polearm", "katana", "great_katana", "club", "staff"];
43
+ type MainWeaponType = (typeof MAIN_WEAPON_TYPES)[number];
44
+ declare const SUB_WEAPON_TYPES: readonly ["shield", "hand_to_hand", "dagger", "sword", "axe", "katana", "club"];
45
+ type SubWeaponType = (typeof SUB_WEAPON_TYPES)[number];
46
+ declare const RANGED_TYPES: readonly ["none", "throwing", "archery", "marksmanship", "stringed", "wind", "handbell"];
47
+ type RangedType = (typeof RANGED_TYPES)[number];
48
+ /** Picker category excluding `ranged.none` (not an item lookup). */
49
+ type WeaponPickerType = MainWeaponType | SubWeaponType | Exclude<RangedType, "none">;
50
+ type PickerSlot = WeaponSlotId | ArmorSlotId;
51
+ declare function isArmorSlot(slot: PickerSlot): slot is ArmorSlotId;
52
+ declare function isWeaponSlot(slot: PickerSlot): slot is WeaponSlotId;
53
+ declare function weaponTypesForSlot(slot: WeaponSlotId): readonly string[];
54
+
55
+ /** Windower/API-aligned appearance (raceId 0–7, faceId 0–31, equipment item IDs). */
56
+ interface CharacterAppearanceById {
57
+ raceId: number;
58
+ faceId: number;
59
+ itemIds?: Partial<Record<ModelSlotId, number>>;
60
+ }
61
+ /** Tooling shape — only `race` string differs from ById. */
62
+ interface CharacterAppearanceByName {
63
+ race: RaceGenderName;
64
+ faceId: number;
65
+ itemIds?: Partial<Record<ModelSlotId, number>>;
66
+ }
67
+ type CharacterAppearance = CharacterAppearanceById | CharacterAppearanceByName;
68
+ interface AppearanceResolution {
69
+ resolvedModels: Partial<Record<ModelSlotId, number>>;
70
+ missingItems: Partial<Record<ModelSlotId, number>>;
71
+ meshCount: number;
72
+ }
73
+ type CharacterViewerErrorCode = "webgl_unavailable" | "asset_fetch_failed" | "invalid_appearance";
74
+ declare class CharacterViewerError extends Error {
75
+ readonly code: CharacterViewerErrorCode;
76
+ constructor(code: CharacterViewerErrorCode, message: string);
77
+ }
78
+ type ViewerStatus = "loading" | "ready" | "error";
79
+ interface ViewerDebugInfo {
80
+ status: ViewerStatus;
81
+ meshCount: number;
82
+ raceId: number;
83
+ raceName: RaceGenderName | null;
84
+ faceId: number;
85
+ resolvedModels: Partial<Record<ModelSlotId, number>>;
86
+ missingItems: Partial<Record<ModelSlotId, number>>;
87
+ framingRadius: number;
88
+ orbit: {
89
+ x: number;
90
+ y: number;
91
+ radius: number;
92
+ };
93
+ error: string | null;
94
+ }
95
+ type ViewerState = {
96
+ status: "loading";
97
+ } | {
98
+ status: "ready";
99
+ meshCount: number;
100
+ framingRadius: number;
101
+ appearance: {
102
+ raceId: number;
103
+ raceName: RaceGenderName;
104
+ faceId: number;
105
+ };
106
+ resolution: AppearanceResolution;
107
+ orbit: {
108
+ x: number;
109
+ y: number;
110
+ radius: number;
111
+ };
112
+ debugInfo?: ViewerDebugInfo;
113
+ } | {
114
+ status: "error";
115
+ error: CharacterViewerError;
116
+ };
117
+ declare const DEFAULT_VIEWER_BACKGROUND = "#14171f";
118
+ interface ViewerOverlayState {
119
+ status: ViewerStatus;
120
+ meshCount: number;
121
+ orbit: {
122
+ x: number;
123
+ y: number;
124
+ radius: number;
125
+ framingRadius: number;
126
+ };
127
+ isDragging: boolean;
128
+ canRotate: boolean;
129
+ canZoom: boolean;
130
+ resolution: AppearanceResolution | null;
131
+ resetView: () => void;
132
+ setOrbit: (patch: Partial<{
133
+ x: number;
134
+ y: number;
135
+ radius: number;
136
+ }>) => void;
137
+ }
138
+
139
+ interface StudioLighting {
140
+ ambient: [number, number, number, number];
141
+ diffuse0Dir: [number, number, number];
142
+ diffuse0Color: [number, number, number, number];
143
+ }
144
+
145
+ export { type AppearanceResolution as A, type CharacterAppearance as C, DEFAULT_VIEWER_BACKGROUND as D, type ModelSlotId as M, type PickerSlot as P, type RaceGenderName as R, type StudioLighting as S, type ViewerDebugInfo as V, type WeaponPickerType as W, type CharacterAppearanceById as a, type CharacterAppearanceByName as b, type CharacterItemLook as c, ARMOR_SLOT_IDS as d, type ArmorSlotId as e, CharacterViewerError as f, type CharacterViewerErrorCode as g, MAIN_WEAPON_TYPES as h, MODEL_SLOT_IDS as i, type MainWeaponType as j, RANGED_TYPES as k, type RangedType as l, SUB_WEAPON_TYPES as m, type SubWeaponType as n, type ViewerOverlayState as o, type ViewerState as p, type ViewerStatus as q, WEAPON_SLOT_IDS as r, type WeaponSlotId as s, isArmorSlot as t, isWeaponSlot as u, weaponTypesForSlot as w };
@@ -0,0 +1,118 @@
1
+ import * as react from 'react';
2
+ import { CSSProperties, ReactNode, Ref } from 'react';
3
+ import { C as CharacterAppearance, S as StudioLighting, f as CharacterViewerError, o as ViewerOverlayState, p as ViewerState, A as AppearanceResolution } from './lighting-Bn1ftR_s.js';
4
+ export { a as CharacterAppearanceById, b as CharacterAppearanceByName, M as ModelSlotId, V as ViewerDebugInfo } from './lighting-Bn1ftR_s.js';
5
+
6
+ /** Two-axis orbit. X = horizontal model spin, Y = vertical camera tilt. */
7
+ interface RotateOptions {
8
+ enabled?: boolean;
9
+ initialX?: number;
10
+ x?: number;
11
+ onXChange?: (x: number) => void;
12
+ initialY?: number;
13
+ y?: number;
14
+ onYChange?: (y: number) => void;
15
+ xLimit?: number;
16
+ yLimit?: [number, number];
17
+ sensitivity?: number | {
18
+ x?: number;
19
+ y?: number;
20
+ };
21
+ smoothing?: number;
22
+ autoRotate?: boolean;
23
+ autoRotateSpeed?: number;
24
+ }
25
+ interface CharacterViewerCanvasOptions {
26
+ /** Omitted = transparent alpha canvas. */
27
+ backgroundColor?: string;
28
+ className?: string;
29
+ lighting?: "default" | "day" | "night" | StudioLighting;
30
+ pixelRatio?: number;
31
+ }
32
+ interface CharacterViewerFallbacks {
33
+ loading?: ReactNode | false;
34
+ empty?: ReactNode;
35
+ error?: ReactNode | ((error: CharacterViewerError) => ReactNode);
36
+ }
37
+ /**
38
+ * Race, face, and equipped item IDs for the 3D character viewer.
39
+ * @see CharacterAppearanceById — primary Windower/API shape
40
+ */
41
+ interface CharacterViewerProps {
42
+ appearance: CharacterAppearance;
43
+ width?: number | string;
44
+ height?: number | string;
45
+ minHeight?: number;
46
+ className?: string;
47
+ style?: CSSProperties;
48
+ canvas?: CharacterViewerCanvasOptions;
49
+ /** Drag orbit (X spin + Y tilt). Default: true */
50
+ rotate?: boolean | RotateOptions;
51
+ /** Scroll/pinch zoom. Default: false */
52
+ zoom?: boolean;
53
+ /** Play race idle animation. Default: true */
54
+ idleAnimation?: boolean;
55
+ /**
56
+ * Pause render loop.
57
+ * `true` — paused. Omitted/`false` — running (auto-pauses offscreen).
58
+ * `{ offscreen: false }` — keep rendering when scrolled away.
59
+ */
60
+ pause?: boolean | {
61
+ offscreen?: boolean;
62
+ };
63
+ showResetButton?: boolean;
64
+ cursor?: "default" | "grab" | "none";
65
+ pointerEvents?: "auto" | "none";
66
+ fallbacks?: CharacterViewerFallbacks;
67
+ overlay?: (state: ViewerOverlayState) => ReactNode;
68
+ debug?: boolean;
69
+ ariaLabel?: string;
70
+ role?: string;
71
+ tabIndex?: number;
72
+ onStateChange?: (state: ViewerState) => void;
73
+ ref?: Ref<CharacterViewerHandle>;
74
+ }
75
+ interface CharacterViewerHandle {
76
+ resetView(): void;
77
+ getState(): ViewerState;
78
+ getOrbit(): {
79
+ x: number;
80
+ y: number;
81
+ radius: number;
82
+ };
83
+ setOrbit(patch: Partial<{
84
+ x: number;
85
+ y: number;
86
+ radius: number;
87
+ }>): void;
88
+ }
89
+
90
+ declare function CharacterViewer({ appearance, width, height, minHeight, className, style, canvas, rotate, zoom, idleAnimation, pause, showResetButton, cursor, pointerEvents, fallbacks, overlay, debug, ariaLabel, role, tabIndex, onStateChange, ref, }: CharacterViewerProps): react.JSX.Element;
91
+
92
+ type UseCharacterSceneOptions = Pick<CharacterViewerProps, "rotate" | "zoom" | "idleAnimation" | "pause" | "canvas" | "debug" | "onStateChange">;
93
+ interface CharacterSceneState {
94
+ viewerState: ViewerState;
95
+ resolution: AppearanceResolution | null;
96
+ isDragging: boolean;
97
+ canvasHandlers: {
98
+ onPointerDown: (event: React.PointerEvent<HTMLCanvasElement>) => void;
99
+ onPointerMove: (event: React.PointerEvent<HTMLCanvasElement>) => void;
100
+ onPointerUp: (event: React.PointerEvent<HTMLCanvasElement>) => void;
101
+ onPointerLeave: (event: React.PointerEvent<HTMLCanvasElement>) => void;
102
+ onWheel: (event: React.WheelEvent<HTMLCanvasElement>) => void;
103
+ };
104
+ resetView: () => void;
105
+ getOrbit: () => {
106
+ x: number;
107
+ y: number;
108
+ radius: number;
109
+ };
110
+ setOrbit: (patch: Partial<{
111
+ x: number;
112
+ y: number;
113
+ radius: number;
114
+ }>) => void;
115
+ }
116
+ declare function useCharacterScene(canvasRef: React.RefObject<HTMLCanvasElement | null>, appearance: CharacterAppearance, options?: UseCharacterSceneOptions): CharacterSceneState;
117
+
118
+ export { AppearanceResolution, CharacterAppearance, type CharacterSceneState, CharacterViewer, type CharacterViewerCanvasOptions, CharacterViewerError, type CharacterViewerFallbacks, type CharacterViewerHandle, type CharacterViewerProps, type RotateOptions, type UseCharacterSceneOptions, ViewerOverlayState, ViewerState, useCharacterScene };