@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 +21 -0
- package/README.md +155 -0
- package/dist/chunk-5GGVLVIE.js +166704 -0
- package/dist/chunk-5GGVLVIE.js.map +1 -0
- package/dist/index.d.ts +108 -0
- package/dist/index.js +65 -0
- package/dist/index.js.map +1 -0
- package/dist/items.json +1 -0
- package/dist/lighting-Bn1ftR_s.d.ts +145 -0
- package/dist/react.d.ts +118 -0
- package/dist/react.js +538 -0
- package/dist/react.js.map +1 -0
- package/package.json +72 -0
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).
|