@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.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Julian Dawson
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,155 @@
1
+ # @ffxiark/character-viewer
2
+
3
+ WebGL2 3D character viewer for FFXI. Ships a React `<CharacterViewer>` component and a headless `CharacterSceneController` for custom integrations.
4
+
5
+ ## Install
6
+
7
+ ```bash
8
+ pnpm add @ffxiark/character-viewer
9
+ # or
10
+ npm install @ffxiark/character-viewer
11
+ ```
12
+
13
+ **Peer dependencies:** `react` and `react-dom` (^19).
14
+
15
+ ## Publishing
16
+
17
+ Published to npm as [`@ffxiark/character-viewer`](https://www.npmjs.com/package/@ffxiark/character-viewer).
18
+
19
+ **Prerequisites**
20
+
21
+ 1. npm org `@ffxiark` with publish access
22
+ 2. GitHub repo secret `NPM_TOKEN` (automation token with publish rights)
23
+
24
+ **Release via GitHub**
25
+
26
+ 1. Bump `version` in `package.json` and commit
27
+ 2. Create a GitHub Release for that tag — the [Publish workflow](.github/workflows/publish.yml) runs tests, builds, and runs `pnpm publish`
28
+
29
+ **Release locally**
30
+
31
+ ```bash
32
+ pnpm test
33
+ pnpm build
34
+ npm login
35
+ pnpm publish --access public
36
+ ```
37
+
38
+ `prepublishOnly` runs tests and build automatically before publish.
39
+
40
+ ## Setup
41
+
42
+ The viewer loads `.DAT` assets at runtime. Configure where they are fetched from once at app bootstrap:
43
+
44
+ ```typescript
45
+ import { setAssetBaseUrl } from "@ffxiark/character-viewer";
46
+
47
+ setAssetBaseUrl("/api/assets");
48
+ ```
49
+
50
+ Consumers host `.DAT` files themselves (local FFXI install path, CDN, or app proxy). In `ffxiark-web`, assets are served from `/api/assets` via `FFXI_INSTALL_PATH`.
51
+
52
+ Advanced: pass a custom loader with `configureAssetLoader(loader)` or reset with `resetAssetLoader()` in tests.
53
+
54
+ ## Quick start
55
+
56
+ ```tsx
57
+ import { CharacterViewer } from "@ffxiark/character-viewer/react";
58
+
59
+ const appearance = {
60
+ raceId: 0,
61
+ faceId: 0,
62
+ itemIds: { head: 16079, body: 12638 },
63
+ };
64
+
65
+ <CharacterViewer appearance={appearance} width="100%" minHeight={400} rotate />;
66
+ ```
67
+
68
+ Omit `canvas.backgroundColor` for a transparent background (profile portraits). Use `canvas={{ backgroundColor: "#14171f" }}` for a solid panel.
69
+
70
+ ## Appearance input
71
+
72
+ **Primary — `CharacterAppearanceById`** (Windower/API):
73
+
74
+ | Field | Type | Notes |
75
+ |-------|------|-------|
76
+ | `raceId` | `number` | 0–7 (HumeM, HumeF, ElvaanM, …) |
77
+ | `faceId` | `number` | 0–31 |
78
+ | `itemIds` | `Partial<Record<ModelSlotId, number>>` | Equipment item IDs per slot |
79
+
80
+ **Runtime slots (flat):** `head`, `body`, `hands`, `legs`, `feet`, `main`, `sub`, `range`
81
+
82
+ **Wardrobe picker taxonomy** (grouping only — still maps to flat slots at render time):
83
+
84
+ | Group | Categories |
85
+ |-------|------------|
86
+ | Main | hand_to_hand, dagger, sword, great_sword, axe, great_axe, scythe, polearm, katana, great_katana, club, staff |
87
+ | Sub | shield, hand_to_hand, dagger, sword, axe, katana, club |
88
+ | Ranged | none, throwing, archery, marksmanship, stringed, wind, handbell |
89
+
90
+ Helpers: `normalizeAppearance()`, `serializeAppearance()`, `validateAppearance()`, `hasItemModel()`, `isItemInCategory()`, `mapWindowerRaceId()`.
91
+
92
+ Item→model mapping is internal to the package (`src/data/items.json`). Consumers pass item IDs only.
93
+
94
+ ## Props reference
95
+
96
+ | Group | Prop | Default | Description |
97
+ |-------|------|---------|-------------|
98
+ | Data | `appearance` | — | Required character appearance |
99
+ | Layout | `width` / `height` | `"100%"` | Shell dimensions |
100
+ | Layout | `minHeight` | `320` | Minimum shell height |
101
+ | Canvas | `canvas.backgroundColor` | transparent | Solid WebGL clear color |
102
+ | Canvas | `canvas.lighting` | `"default"` | `"default"` \| `"day"` \| `"night"` |
103
+ | Interaction | `rotate` | `true` | Drag orbit + optional auto-spin |
104
+ | Interaction | `zoom` | `false` | Wheel zoom on camera radius |
105
+ | Interaction | `pause` | offscreen auto-pause | `true` pauses render loop |
106
+ | UI | `fallbacks` | built-in | Loading / empty / error slots |
107
+ | UI | `overlay` | — | Custom overlay render prop |
108
+ | Callback | `onStateChange` | — | `ViewerState` discriminated union |
109
+ | Ref | `resetView`, `getOrbit`, `setOrbit`, `getState` | — | Imperative handle |
110
+
111
+ See `docs/examples.md` for profile, wardrobe, and headless recipes.
112
+
113
+ ## Core exports (`@ffxiark/character-viewer`)
114
+
115
+ - Types: `CharacterAppearance`, `ModelSlotId`, `ViewerState`, …
116
+ - Slot taxonomy: `MAIN_WEAPON_TYPES`, `SUB_WEAPON_TYPES`, `RANGED_TYPES`, `ARMOR_SLOT_IDS`
117
+ - Item metadata: `hasItemModel`, `isItemInCategory`, `getItemWeaponSkill`, `getItemPickerCategory`
118
+ - `CharacterSceneController` — headless WebGL boot + render
119
+ - `configureAssetLoader`, `setAssetBaseUrl`
120
+ - `DEFAULT_VIEWER_BACKGROUND` — `"#14171f"`
121
+
122
+ ## React exports (`@ffxiark/character-viewer/react`)
123
+
124
+ - `CharacterViewer`, `useCharacterScene`
125
+ - `CharacterViewerProps`, `CharacterViewerHandle`, `RotateOptions`
126
+
127
+ ## Data and tables
128
+
129
+ Item metadata lives in `src/data/items.json` and is updated manually. Each entry is sparse:
130
+
131
+ ```json
132
+ { "16583": { "m": 66, "sk": "great_sword", "slot": 1 } }
133
+ ```
134
+
135
+ | Field | Meaning |
136
+ |-------|---------|
137
+ | `m` | Model index (omit when 0) |
138
+ | `sk` | Weapon skill category (weapons only) |
139
+ | `slot` | Equip slot bitmask (`1` = main, `32` = body, …) |
140
+
141
+ `pnpm build:items` minifies `src/data/items.json` into `dist/items.json` (runs automatically after tsup in `pnpm build`).
142
+
143
+ Mesh path tables (`equipment-lookup.json`, `file-table.json`, `race-config-indices.json`) live under `src/lib/ffxi/tables/generated/` and are bundled at build time.
144
+
145
+ ## Tests
146
+
147
+ ```bash
148
+ pnpm test
149
+ pnpm build
150
+ ```
151
+
152
+ ## Notes
153
+
154
+ - Requires a local FFXI install or CDN hosting `.DAT` files; assets are not bundled.
155
+ - Item IDs resolve to model indices via internal item metadata (not exposed as raw JSON).