@skinhub/viewer 0.1.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/EMBED.md +442 -0
- package/README.md +153 -0
- package/dist/SkinViewer.d.ts +18 -0
- package/dist/SkinViewer.d.ts.map +1 -0
- package/dist/SkinViewer.js +404 -0
- package/dist/SkinViewer.js.map +1 -0
- package/dist/index.d.ts +53 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +51 -0
- package/dist/index.js.map +1 -0
- package/dist/item.d.ts +118 -0
- package/dist/item.d.ts.map +1 -0
- package/dist/item.js +319 -0
- package/dist/item.js.map +1 -0
- package/dist/link.d.ts +30 -0
- package/dist/link.d.ts.map +1 -0
- package/dist/link.js +18 -0
- package/dist/link.js.map +1 -0
- package/dist/protocol.d.ts +231 -0
- package/dist/protocol.d.ts.map +1 -0
- package/dist/protocol.js +128 -0
- package/dist/protocol.js.map +1 -0
- package/dist/state.d.ts +107 -0
- package/dist/state.d.ts.map +1 -0
- package/dist/state.js +351 -0
- package/dist/state.js.map +1 -0
- package/dist/types.d.ts +573 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +106 -0
- package/dist/types.js.map +1 -0
- package/dist/useSkinViewer.d.ts +3 -0
- package/dist/useSkinViewer.d.ts.map +1 -0
- package/dist/useSkinViewer.js +66 -0
- package/dist/useSkinViewer.js.map +1 -0
- package/dist/weapons.d.ts +109 -0
- package/dist/weapons.d.ts.map +1 -0
- package/dist/weapons.js +260 -0
- package/dist/weapons.js.map +1 -0
- package/package.json +65 -0
- package/src/SkinViewer.tsx +465 -0
- package/src/index.ts +88 -0
- package/src/item.ts +373 -0
- package/src/link.ts +33 -0
- package/src/protocol.ts +241 -0
- package/src/state.ts +389 -0
- package/src/types.ts +672 -0
- package/src/useSkinViewer.ts +80 -0
- package/src/weapons.ts +284 -0
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,573 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* *** `@skinhub/viewer` - THE PUBLIC PROP CONTRACT. ***
|
|
3
|
+
*
|
|
4
|
+
* ═════════════════════════════════════════════════════════════════════════════════════════════
|
|
5
|
+
* *** WHAT THIS PACKAGE IS, AND THE ONE SENTENCE THAT DECIDES EVERY QUESTION BELOW. ***
|
|
6
|
+
*
|
|
7
|
+
* The renderer is a page on our origin (`/frame`). This package renders an `<iframe>` at it and
|
|
8
|
+
* speaks its message protocol. Owner, 2026-08-15: *"the package is just a lightweight helper that
|
|
9
|
+
* translates the postMessages thing to actual props and state that the user can control."*
|
|
10
|
+
*
|
|
11
|
+
* *** SO THERE IS NO `three` HERE AND THERE NEVER WILL BE. *** The design rule is *"there is no raw
|
|
12
|
+
* npm renderer, ever."* An integrator installing this installs React bindings and a URL builder. The
|
|
13
|
+
* whole of the 3D - the models, the shaders, the compositing, the 19.7 GB asset export - stays on our
|
|
14
|
+
* side of the frame, which is what makes the logo enforceable and what removes every peer-dependency
|
|
15
|
+
* question about three.js at once.
|
|
16
|
+
*
|
|
17
|
+
* ═════════════════════════════════════════════════════════════════════════════════════════════
|
|
18
|
+
* *** THE RULE THIS FILE IS WRITTEN UNDER: nothing here may require knowing how SkinHub is built. ***
|
|
19
|
+
*
|
|
20
|
+
* Every name is either a word the CS2 economy already uses (`paintIndex`, `float`, `seed`,
|
|
21
|
+
* `defindex`, `statTrak`) or a word any 3D component uses (`view`, `camera`, `quality`, `bloom`).
|
|
22
|
+
* Nothing is named after a route, a store, a shader parameter or a file in our tree. A prop that only
|
|
23
|
+
* makes sense once you have read our source is a bug in this file.
|
|
24
|
+
*
|
|
25
|
+
* *** AND ONE COROLLARY WORTH STATING, because it is the difference between a wrapper and a leak: ***
|
|
26
|
+
* this file does NOT re-export `/frame`'s own vocabulary. The wire says `weaponType` and
|
|
27
|
+
* `PlacementSlots` in the game's field names (`sticker_id`, `offset_x`); an integrator says `weapon`
|
|
28
|
+
* and `{ id, offsetX }`. `item.ts` is the only place the two meet, and it is not exported for the
|
|
29
|
+
* public surface's sake - it is exported because a marketplace holding an inspect link needs the
|
|
30
|
+
* bridge in its own server code too.
|
|
31
|
+
*/
|
|
32
|
+
import type { CSSProperties, ReactNode } from 'react';
|
|
33
|
+
import { LINK, type ViewerLink } from './link.js';
|
|
34
|
+
import type { WeaponId } from './weapons.js';
|
|
35
|
+
/**
|
|
36
|
+
* A sticker on one of the weapon's five slots.
|
|
37
|
+
*
|
|
38
|
+
* `offsetX`/`offsetY` are a DELTA on the slot's authored home, in the weapon's sticker UV space,
|
|
39
|
+
* clamped to +/-0.5 - the game's own `g_vStickerNOffset` range. Omitted means "where the weapon puts
|
|
40
|
+
* it", which is what an unmodified applied sticker looks like in game.
|
|
41
|
+
*/
|
|
42
|
+
export type SkinViewerSticker = {
|
|
43
|
+
/** `sticker_id` - the id in `@skinhub/cdn`'s `stickers.json`. */
|
|
44
|
+
id: number;
|
|
45
|
+
/**
|
|
46
|
+
* Which of the five slots, `0`..`4`. Omitted uses the sticker's position in the `stickers` array,
|
|
47
|
+
* which is what makes `stickers={[a, null, b]}` mean "slot 0 and slot 2".
|
|
48
|
+
*/
|
|
49
|
+
slot?: 0 | 1 | 2 | 3 | 4;
|
|
50
|
+
/** Scratch, `0` (mint) to `1` (scraped off). Default `0`. */
|
|
51
|
+
wear?: number;
|
|
52
|
+
/** Degrees, any value; `370` renders as `10`. Default `0`. */
|
|
53
|
+
rotation?: number;
|
|
54
|
+
/** -0.5..0.5. Default `0` - the slot's authored position. */
|
|
55
|
+
offsetX?: number;
|
|
56
|
+
offsetY?: number;
|
|
57
|
+
};
|
|
58
|
+
/** A charm hanging off the weapon's charm anchor. Knives have no anchor and ignore this. */
|
|
59
|
+
export type SkinViewerCharm = {
|
|
60
|
+
/** The id in `@skinhub/cdn`'s `keychains.json`. */
|
|
61
|
+
id: number;
|
|
62
|
+
/**
|
|
63
|
+
* The charm's template - its `pattern` on the wire. It is not a variant: it drives a
|
|
64
|
+
* hue/saturation/brightness adjust on the charm's own albedo, so two charms with the same `id` and
|
|
65
|
+
* a different `seed` are the same model in different colours. Default `0`.
|
|
66
|
+
*/
|
|
67
|
+
seed?: number;
|
|
68
|
+
/**
|
|
69
|
+
* Displacement from the weapon's charm anchor, in the game's own `offset x/y/z`. Omitted hangs it
|
|
70
|
+
* where the weapon hangs it. Values outside the authored charm region are pulled back into it by
|
|
71
|
+
* the renderer rather than rejected.
|
|
72
|
+
*
|
|
73
|
+
* *** `readonly` IS AN INPUT CONVENIENCE AND AN OUTPUT NUISANCE, so it is worth stating: *** a
|
|
74
|
+
* mutable `[number, number, number]` assigns to this fine, which is what makes passing one in easy.
|
|
75
|
+
* Reading it back off an `onChange` item gives you the readonly type, so moving one axis needs a
|
|
76
|
+
* copy - `[...charm.offset]` - rather than an index write.
|
|
77
|
+
*/
|
|
78
|
+
offset?: readonly [x: number, y: number, z: number];
|
|
79
|
+
};
|
|
80
|
+
/** The half of an item that is not its identity. Everything here updates IN PLACE - see {@link CHEAP_FIELDS}. */
|
|
81
|
+
type ItemConfiguration = {
|
|
82
|
+
/**
|
|
83
|
+
* The finish. `1449` is AK-47 | AUTOEXEC, `0` is the correct value for a VANILLA item and renders
|
|
84
|
+
* the bare model rather than an error.
|
|
85
|
+
*/
|
|
86
|
+
paintIndex: number;
|
|
87
|
+
/**
|
|
88
|
+
* Which mesh variant to load. Most finishes declare it themselves and this is then ignored; pass it
|
|
89
|
+
* when they do not, from `skin.legacy_model` on the `@skinhub/cdn` row you already have.
|
|
90
|
+
*
|
|
91
|
+
* IT IS IDENTITY AND NOT A DETAIL: both the weapon-space textures and the composite scale constants
|
|
92
|
+
* are authored per variant, so the wrong one is the wrong picture rather than a slightly different
|
|
93
|
+
* one. 1,182 of 2,161 catalogue rows are legacy.
|
|
94
|
+
*/
|
|
95
|
+
legacyModel?: boolean;
|
|
96
|
+
/**
|
|
97
|
+
* Wear, `0`..`1`. `paintwear` on the wire; every marketplace calls it the float.
|
|
98
|
+
*
|
|
99
|
+
* NOT EVERY FINISH RUNS 0..1. A kit declares its own `wear_remap_min`/`wear_remap_max` and the
|
|
100
|
+
* renderer CLAMPS into that range rather than remapping, so `0.9` on a kit that stops at `0.4`
|
|
101
|
+
* renders at `0.4`. If you are drawing a float slider, take the kit's real range from
|
|
102
|
+
* `@skinhub/cdn` rather than assuming 0..1.
|
|
103
|
+
*
|
|
104
|
+
* Omitted renders at the kit's own best condition, which is the flattering example of the item.
|
|
105
|
+
*/
|
|
106
|
+
float?: number;
|
|
107
|
+
/** The paint seed - which roll of the finish this is. Default `0`. */
|
|
108
|
+
seed?: number;
|
|
109
|
+
/**
|
|
110
|
+
* The StatTrak counter's value, or `false` for an item with no counter.
|
|
111
|
+
*
|
|
112
|
+
* ONE FIELD RATHER THAN A BOOLEAN AND A COUNT, because that is what the item is: the game has no
|
|
113
|
+
* StatTrak-with-no-count. `0` is a real, legal, freshly-minted counter and is NOT the same as
|
|
114
|
+
* `false`. Default `false`.
|
|
115
|
+
*/
|
|
116
|
+
statTrak?: number | false;
|
|
117
|
+
/** The name plate's text, or `null`/omitted for no plate. Trimmed; the game shows 20 characters. */
|
|
118
|
+
nameTag?: string | null;
|
|
119
|
+
/**
|
|
120
|
+
* Up to five stickers. Array position is the slot unless a sticker names its own; `null` leaves a
|
|
121
|
+
* slot empty, so `[a, null, b]` is slots 0 and 2.
|
|
122
|
+
*/
|
|
123
|
+
stickers?: readonly (SkinViewerSticker | null)[];
|
|
124
|
+
/** The charm, or `null`/omitted for none. */
|
|
125
|
+
charm?: SkinViewerCharm | null;
|
|
126
|
+
};
|
|
127
|
+
/**
|
|
128
|
+
* *** WHICH ITEM FIELDS UPDATE IN PLACE, WRITTEN DOWN AS A VALUE. ***
|
|
129
|
+
*
|
|
130
|
+
* The owner's requirement, verbatim: changing `float`, `seed`, `statTrak`, `nameTag`, the stickers or
|
|
131
|
+
* the charm *"must NOT reload the viewer - that's a must to make it feel just like in our website."*
|
|
132
|
+
* Changing the weapon or the paint kit *"shows nothing until the model has loaded, behind the loading
|
|
133
|
+
* card"*.
|
|
134
|
+
*
|
|
135
|
+
* This list is the FIRST half. It is here, as a value, because {@link SkinViewerProps.loading} is
|
|
136
|
+
* raised off its complement - see `SkinViewer.tsx`'s `isIdentityChange` - and because a contract an
|
|
137
|
+
* integrator relies on should be readable without opening the renderer.
|
|
138
|
+
*/
|
|
139
|
+
export declare const CHEAP_FIELDS: readonly ["float", "seed", "statTrak", "nameTag", "stickers", "charm"];
|
|
140
|
+
/**
|
|
141
|
+
* *** WHICH WEAPON, SAID TWO WAYS, AND EXACTLY ONE OF THEM. ***
|
|
142
|
+
*
|
|
143
|
+
* An integrator holds a catalogue row (`weapon: 'weapon_ak47'`, which is `skin.weapon.id` on a
|
|
144
|
+
* `@skinhub/cdn` row) or a decoded inspect link (`defindex: 7`). Both are the AK-47.
|
|
145
|
+
*
|
|
146
|
+
* `?: never` ON THE OTHER MEMBER rather than a runtime check, for the same reason the top-level
|
|
147
|
+
* subject union uses it: an item naming a weapon two ways that disagree is a state with no sensible
|
|
148
|
+
* precedence rule, so it is made unrepresentable instead of arbitrated.
|
|
149
|
+
*
|
|
150
|
+
* `weapon` IS THE ONE TO REACH FOR. It needs no lookup and therefore cannot go stale; `defindex` is
|
|
151
|
+
* resolved against a checked-in 63-row table (see `weapons.ts`) and a number that table has never
|
|
152
|
+
* heard of reports `unknown-weapon` rather than rendering the wrong gun.
|
|
153
|
+
*/
|
|
154
|
+
export type SkinViewerItem = ItemConfiguration & ({
|
|
155
|
+
/**
|
|
156
|
+
* `'weapon_ak47'`, or a glove id (`'sporty_gloves'`). HUD aliases are accepted: `skins.json`
|
|
157
|
+
* gives the twenty VANILLA knife rows an `sfui_wpnhud_*` id, and that renders the knife here
|
|
158
|
+
* rather than failing, so `row.weapon.id` can be passed straight through.
|
|
159
|
+
*/
|
|
160
|
+
weapon: WeaponId;
|
|
161
|
+
defindex?: never;
|
|
162
|
+
} | {
|
|
163
|
+
/** `7` - the item definition index a decoded inspect link and a Steam inventory row carry. */
|
|
164
|
+
defindex: number;
|
|
165
|
+
weapon?: never;
|
|
166
|
+
});
|
|
167
|
+
/**
|
|
168
|
+
* What the item is being shown ON. All three are the same item under the same lighting, finish,
|
|
169
|
+
* stickers and charm - the difference is the camera and what is holding the weapon.
|
|
170
|
+
*
|
|
171
|
+
* `gun` the item alone, orbitable, framed to the viewport. The default.
|
|
172
|
+
* `hands` CS2's first-person viewmodel, driven by the game's own clips. Orbit is off here because
|
|
173
|
+
* there is nothing to orbit: the weapon is welded to the eye.
|
|
174
|
+
* `agent` an operator holding the weapon, at conversational distance, orbitable.
|
|
175
|
+
*
|
|
176
|
+
* *** A VIEW CHANGE RELOADS. *** It rebuilds the rig, so it goes behind the loading card exactly as a
|
|
177
|
+
* weapon change does.
|
|
178
|
+
*/
|
|
179
|
+
export type ViewerView = 'gun' | 'hands' | 'agent';
|
|
180
|
+
/** The person holding the weapon, in `hands` and `agent`. Ignored in `gun` - nobody is on screen. */
|
|
181
|
+
export type ViewerAgent = {
|
|
182
|
+
/** An agent's item definition index; `5036` is the default Terrorist and the default here. */
|
|
183
|
+
id?: number;
|
|
184
|
+
/**
|
|
185
|
+
* Which main-menu performance they play, by clip leaf name, or `null` (the default) to let the
|
|
186
|
+
* WEAPON choose it - an AK gives the AK idle, an AWP re-poses on its own.
|
|
187
|
+
*/
|
|
188
|
+
pose?: string | null;
|
|
189
|
+
};
|
|
190
|
+
/**
|
|
191
|
+
* What the operator has on their hands, or `null` for their own default pair.
|
|
192
|
+
*
|
|
193
|
+
* *** `null` IS NOT "BARE HANDS". *** Every agent ships a pair of their own and that is what `null`
|
|
194
|
+
* gets you. There is no way to render an operator with no gloves, because the game has no such state.
|
|
195
|
+
*/
|
|
196
|
+
export type ViewerGloves = {
|
|
197
|
+
/** `'sporty_gloves'`, `'specialist_gloves'`, … */
|
|
198
|
+
type: string;
|
|
199
|
+
paintIndex: number;
|
|
200
|
+
/** Default `0.06`, the kit's own best condition. */
|
|
201
|
+
float?: number;
|
|
202
|
+
seed?: number;
|
|
203
|
+
};
|
|
204
|
+
/**
|
|
205
|
+
* *** THE MAPS, AS A CLOSED UNION. *** The owner asked for this directly: `background` is
|
|
206
|
+
* *"'transparent' or a real map id, not a free string"*.
|
|
207
|
+
*
|
|
208
|
+
* WHAT THAT COSTS, said out loud rather than discovered: this list is a COPY of the app's own, so a
|
|
209
|
+
* map added to the export after this package was published is not typeable until the package is
|
|
210
|
+
* upgraded. That is the deliberate trade - the rule is *"no back-compat
|
|
211
|
+
* boilerplate, upgrade when you need to"* - and the failure is legible either way: the frame reports
|
|
212
|
+
* an unknown map in its `problems` and keeps the lighting it had.
|
|
213
|
+
*/
|
|
214
|
+
export declare const MAP_NAMES: readonly ["Ancient", "Anubis", "Baggage", "Cache", "Dust II", "Inferno", "Italy", "Mirage", "Nuke", "Office", "Overpass", "Train", "Vertigo", "Warehouse"];
|
|
215
|
+
export type MapName = (typeof MAP_NAMES)[number];
|
|
216
|
+
export type TimeOfDay = 'Day' | 'Night';
|
|
217
|
+
/**
|
|
218
|
+
* What is BEHIND the item.
|
|
219
|
+
*
|
|
220
|
+
* *** `'transparent'` IS THE DEFAULT AND IT IS THE WHOLE POINT OF AN EMBED. *** The frame paints no
|
|
221
|
+
* background of its own and mounts no video element, so the canvas composites straight over your
|
|
222
|
+
* page. Naming a map instead shows that map's video plate, which is a 30-60 MB download.
|
|
223
|
+
*
|
|
224
|
+
* TWO THINGS THAT SURPRISE PEOPLE, both stated in `EMBED.md` §9: bloom outside the item's outline is
|
|
225
|
+
* additive light with no alpha, so the halo reads weaker over your page than over a map (which is why
|
|
226
|
+
* {@link ViewerQualitySettings.bloomSpill} ships at `0` here); and a transparent iframe is still not
|
|
227
|
+
* click-through - it takes pointer events over its whole rectangle.
|
|
228
|
+
*/
|
|
229
|
+
export type ViewerBackground = 'transparent' | MapName;
|
|
230
|
+
export type ViewerCameraSettings = {
|
|
231
|
+
/**
|
|
232
|
+
* Vertical field of view in degrees, `1`..`179`. Default `26` - a long lens, which is what keeps a
|
|
233
|
+
* rifle from looking bent. Changing it RE-FRAMES rather than zooms.
|
|
234
|
+
*
|
|
235
|
+
* Ignored in `hands`, which uses CS2's own `viewmodel_fov`. They are different quantities.
|
|
236
|
+
*/
|
|
237
|
+
fov?: number;
|
|
238
|
+
/**
|
|
239
|
+
* A MULTIPLIER on the solved fit distance, `0.05`..`20`. Default `1`; `1.2` is 20% closer.
|
|
240
|
+
*
|
|
241
|
+
* NEVER A DISTANCE, because a fixed distance cannot be right in two differently-shaped containers -
|
|
242
|
+
* the camera fits the item to the canvas aspect, so the same AK sits at a different distance in a
|
|
243
|
+
* 3:4 card than on a full-bleed page.
|
|
244
|
+
*/
|
|
245
|
+
defaultZoom?: number;
|
|
246
|
+
};
|
|
247
|
+
export type ViewerQualitySettings = {
|
|
248
|
+
/**
|
|
249
|
+
* CS2's bloom as a strength multiplier, `0`..`10`. Default `1` (the game's own look); `2` is heavy.
|
|
250
|
+
*
|
|
251
|
+
* *** `0` DISABLES IT OUTRIGHT *** - no post-processing chain is mounted and no offscreen target is
|
|
252
|
+
* allocated, so it is genuinely the cheaper path rather than the same path at zero strength. A page
|
|
253
|
+
* with a grid of viewers wants this off.
|
|
254
|
+
*/
|
|
255
|
+
bloom?: number;
|
|
256
|
+
/**
|
|
257
|
+
* How much of the bloom is allowed past the item's outline, `0`..`10`. **Default `0` in the embed**,
|
|
258
|
+
* where our own site ships `1`.
|
|
259
|
+
*
|
|
260
|
+
* The default differs on purpose: a halo spreading onto the surrounding page is a house look on a
|
|
261
|
+
* full-bleed showcase, and a product page's layout did not ask for light leaking out of the canvas
|
|
262
|
+
* box. Opt in. Ignored while {@link bloom} is `0`.
|
|
263
|
+
*/
|
|
264
|
+
bloomSpill?: number;
|
|
265
|
+
/**
|
|
266
|
+
* A CEILING on `devicePixelRatio`, `0.25`..`3`. Default `1.5`.
|
|
267
|
+
*
|
|
268
|
+
* *** THE SINGLE BIGGEST PERFORMANCE LEVER: `2` is four times the fragments of `1`. *** A page
|
|
269
|
+
* rendering a grid of viewers wants this low.
|
|
270
|
+
*/
|
|
271
|
+
renderScale?: number;
|
|
272
|
+
/**
|
|
273
|
+
* Multisampling. Default `true`.
|
|
274
|
+
*
|
|
275
|
+
* *** ONLY REACHABLE WHILE {@link bloom} IS ABOVE `0`. *** With bloom off the scene renders straight
|
|
276
|
+
* to the canvas, whose antialiasing is fixed when the WebGL context is created; so `bloom: 0` with
|
|
277
|
+
* `antialias: false` is not an error and is not ignored either - it is antialiased anyway.
|
|
278
|
+
*/
|
|
279
|
+
antialias?: boolean;
|
|
280
|
+
/**
|
|
281
|
+
* The item shadowing itself. Default `false`, which is the reference picture: the lighting rig was
|
|
282
|
+
* calibrated without it and there is no ground plane for a shadow to land on.
|
|
283
|
+
*/
|
|
284
|
+
shadows?: boolean;
|
|
285
|
+
};
|
|
286
|
+
export type ViewerEnvironmentSettings = {
|
|
287
|
+
/**
|
|
288
|
+
* WHICH MAP'S LIGHT. Default `'Ancient'`; `null` is our calibrated reference rig, which is what
|
|
289
|
+
* every fidelity measurement behind this renderer was taken against.
|
|
290
|
+
*
|
|
291
|
+
* *** THIS IS THE LIGHT, {@link background} IS THE PICTURE, AND THEY ARE SEPARATE ON PURPOSE. ***
|
|
292
|
+
* Naming a map lights your item with the probe and sun CS2 bakes into that map's own menu scene.
|
|
293
|
+
* The common embed is `{ map: 'Mirage' }` with the default transparent background: Mirage's light,
|
|
294
|
+
* your page behind it.
|
|
295
|
+
*/
|
|
296
|
+
map?: MapName | null;
|
|
297
|
+
/** Default `'Night'`. Falls back on its own for a map that has only one. */
|
|
298
|
+
timeOfDay?: TimeOfDay;
|
|
299
|
+
/** Wet surfaces on maps whose own data says it rains. Default `true`. */
|
|
300
|
+
rain?: boolean;
|
|
301
|
+
/** See {@link ViewerBackground}. Default `'transparent'`. */
|
|
302
|
+
background?: ViewerBackground;
|
|
303
|
+
};
|
|
304
|
+
/**
|
|
305
|
+
* *** OVERLAYS ARE A CATEGORY, NOT ONE FLAG, and they are INDEPENDENT of dragging. ***
|
|
306
|
+
*
|
|
307
|
+
* The sticker outline is an editing AFFORDANCE, not part of the item. Both combinations are
|
|
308
|
+
* legitimate and both are supported: dragging on with the gizmo hidden (invisible hit targets, your
|
|
309
|
+
* own UI drawing the guides), and the gizmo shown with dragging off (show where a sticker sits, let
|
|
310
|
+
* nobody move it). They must not be collapsed into one prop, which is why they live in different
|
|
311
|
+
* groups - see {@link ViewerInteractions}.
|
|
312
|
+
*/
|
|
313
|
+
export type ViewerOverlaySettings = {
|
|
314
|
+
/** The outline and handles on the OPEN sticker. Default `false`. */
|
|
315
|
+
stickerGizmo?: boolean;
|
|
316
|
+
/** The charm's billboard handle. Default `false`. */
|
|
317
|
+
charmGizmo?: boolean;
|
|
318
|
+
/** Colour and readability of the gizmo chrome, for a host with its own design. */
|
|
319
|
+
gizmoStyle?: {
|
|
320
|
+
/** Any CSS colour. */
|
|
321
|
+
color?: string;
|
|
322
|
+
/** The dark under-stroke that keeps the chrome readable over a pale kit. */
|
|
323
|
+
shadowColor?: string;
|
|
324
|
+
};
|
|
325
|
+
};
|
|
326
|
+
/**
|
|
327
|
+
* *** THE FOUR GROUPS ARE THE FOUR THE FRAME SPEAKS, AND NO MORE. ***
|
|
328
|
+
*
|
|
329
|
+
* The design notes also sketch `autoRotation` and `sound`. They are deliberately absent: the
|
|
330
|
+
* `/frame` protocol carries neither today, so a prop for them would be a prop that silently does
|
|
331
|
+
* nothing - which is worse than a missing feature, because it is a missing feature you cannot see.
|
|
332
|
+
* They arrive here in the same change that adds them to the wire, and the type is what forces that.
|
|
333
|
+
*/
|
|
334
|
+
export type ViewerSettings = {
|
|
335
|
+
camera?: ViewerCameraSettings;
|
|
336
|
+
quality?: ViewerQualitySettings;
|
|
337
|
+
environment?: ViewerEnvironmentSettings;
|
|
338
|
+
overlays?: ViewerOverlaySettings;
|
|
339
|
+
};
|
|
340
|
+
/**
|
|
341
|
+
* WHAT THE USER MAY DO WITH THE MOUSE. Orbiting and zooming are on; EDITING IS OFF.
|
|
342
|
+
*
|
|
343
|
+
* Editing defaults to off because a viewer that silently let a visitor move a sticker would
|
|
344
|
+
* desynchronise the host's own database without warning. Owner's brief: the integrator adds charms in
|
|
345
|
+
* their own UI, and we let the user move stickers *"if they enabled that"*.
|
|
346
|
+
*/
|
|
347
|
+
export type ViewerInteractions = {
|
|
348
|
+
/** Drag to turn the item, right-drag to pan. Default `true`. Always off in `hands`. */
|
|
349
|
+
orbit?: boolean;
|
|
350
|
+
/** Wheel to dolly. Default `true`. */
|
|
351
|
+
zoom?: boolean;
|
|
352
|
+
/**
|
|
353
|
+
* Let the user move and rotate a PLACED sticker. Default `false`.
|
|
354
|
+
*
|
|
355
|
+
* *** IF YOU TURN THIS ON, HANDLE {@link SkinViewerProps.onChange}, *** or you will not be able to
|
|
356
|
+
* save what your user did.
|
|
357
|
+
*/
|
|
358
|
+
dragStickers?: boolean;
|
|
359
|
+
/** The same, for the charm. Default `false`. */
|
|
360
|
+
dragCharm?: boolean;
|
|
361
|
+
};
|
|
362
|
+
export type SkinViewerErrorCode =
|
|
363
|
+
/** A model, texture or index file failed to load, or the GL context was lost. UNRECOVERABLE. */
|
|
364
|
+
'render-failed'
|
|
365
|
+
/** The `inspectLink` did not decode - a bad CRC, a truncated body, or not a masked link at all. */
|
|
366
|
+
| 'bad-inspect-link'
|
|
367
|
+
/** `defindex` named a weapon this build has no id for. Pass `weapon` instead, or upgrade. */
|
|
368
|
+
| 'unknown-weapon'
|
|
369
|
+
/** Neither `inspectLink` nor `item` arrived at runtime. See {@link SkinViewerProps}. */
|
|
370
|
+
| 'no-item'
|
|
371
|
+
/**
|
|
372
|
+
* *** THE EMBED NEVER ANSWERED. *** Nothing at {@link SkinViewerProps.origin} announced itself
|
|
373
|
+
* within {@link CONNECT_TIMEOUT_MS}, so there is no conversation and nothing has rendered.
|
|
374
|
+
*
|
|
375
|
+
* *** IT EXISTS BECAUSE THE BROWSER WILL NOT TELL US OTHERWISE. *** A cross-origin `<iframe>` fires
|
|
376
|
+
* `load` for a 404, a 500 and a corporate block page exactly as it does for the real thing, fires no
|
|
377
|
+
* `error` for any of them, and its document cannot be read. Without a timer the component would sit
|
|
378
|
+
* at `'connecting'` for ever showing an empty box - which is the single worst failure an integrator
|
|
379
|
+
* can be handed, because there is nothing at all to search for.
|
|
380
|
+
*
|
|
381
|
+
* The likely causes, in the order they actually happen: a network or corporate proxy blocking the
|
|
382
|
+
* origin, an `origin` prop pointing somewhere that does not serve `/frame`, or a
|
|
383
|
+
* `Content-Security-Policy` on the HOST page whose `frame-src` does not allow it.
|
|
384
|
+
*
|
|
385
|
+
* *** NOT PERMANENT. *** The iframe stays mounted underneath your `fallback`, so a slow connection
|
|
386
|
+
* that arrives late clears this by itself. `reload()` retries deliberately.
|
|
387
|
+
*/
|
|
388
|
+
| 'unreachable'
|
|
389
|
+
/**
|
|
390
|
+
* A field was rejected on the way in and DROPPED, naming its path. Not fatal: the field keeps its
|
|
391
|
+
* previous value and the rest of the update is applied. Nothing is ever coerced - `float: '0.3'` is
|
|
392
|
+
* rejected rather than parsed.
|
|
393
|
+
*/
|
|
394
|
+
| 'bad-message'
|
|
395
|
+
/**
|
|
396
|
+
* *** THE ONE TERMINAL FAILURE. *** This package and the embed do not speak the same protocol
|
|
397
|
+
* version, so the frame has rendered NOTHING - no canvas, no partial picture - and will ignore
|
|
398
|
+
* every later message. The message names which side is out of date. A
|
|
399
|
+
* silently wrong render is worse than a blank frame with an explanation.
|
|
400
|
+
*/
|
|
401
|
+
| 'protocol-mismatch';
|
|
402
|
+
export type SkinViewerError = {
|
|
403
|
+
code: SkinViewerErrorCode;
|
|
404
|
+
/** A sentence a developer can act on. Safe to show in a dev overlay; not localised. */
|
|
405
|
+
message: string;
|
|
406
|
+
};
|
|
407
|
+
/** The box the frame reported, on the `resize` event. See {@link SkinViewerProps.onResize}. */
|
|
408
|
+
export type ViewerResize = {
|
|
409
|
+
width: number;
|
|
410
|
+
height: number;
|
|
411
|
+
dpr: number;
|
|
412
|
+
};
|
|
413
|
+
/**
|
|
414
|
+
* *** EXACTLY ONE OF `inspectLink` OR `item`, ENFORCED IN THE TYPES. ***
|
|
415
|
+
*
|
|
416
|
+
* Owner's requirement, and it is a TYPE requirement rather than a runtime one: *"a discriminated
|
|
417
|
+
* union, so a missing or doubled item is a compile error, not a runtime surprise."*
|
|
418
|
+
*
|
|
419
|
+
* `?: never` on the other member is what does it. Passing both is an excess-property error at the
|
|
420
|
+
* call site; passing neither is a missing-property error. An integrator holds one or the other - a
|
|
421
|
+
* link out of a trade offer, or the fields already in their database - and the state where both are
|
|
422
|
+
* present and disagree is one this package would have to invent a precedence rule for. There is no
|
|
423
|
+
* rule; there is no such call.
|
|
424
|
+
*
|
|
425
|
+
* *** AND WHEN THE TYPES ARE BYPASSED, THE VIEWER TEACHES. *** Plain JavaScript, an `any`, data that
|
|
426
|
+
* was still `undefined` when the component mounted: the frame renders a short instruction card rather
|
|
427
|
+
* than a blank box or - worse - our default AK-47, which would look like a successful render of the
|
|
428
|
+
* wrong item. `onError` fires with `no-item` at the same time. See `SkinViewer.tsx`.
|
|
429
|
+
*/
|
|
430
|
+
export type ViewerSubject = {
|
|
431
|
+
inspectLink: string;
|
|
432
|
+
item?: never;
|
|
433
|
+
} | {
|
|
434
|
+
item: SkinViewerItem;
|
|
435
|
+
inspectLink?: never;
|
|
436
|
+
};
|
|
437
|
+
export type SkinViewerProps = ViewerSubject & {
|
|
438
|
+
/** Default `'gun'`. See {@link ViewerView}. */
|
|
439
|
+
view?: ViewerView;
|
|
440
|
+
/** Who is holding it, in the two views that have somebody holding it. See {@link ViewerAgent}. */
|
|
441
|
+
agent?: ViewerAgent;
|
|
442
|
+
/** What they have on their hands, or `null` for their own default pair. See {@link ViewerGloves}. */
|
|
443
|
+
gloves?: ViewerGloves | null;
|
|
444
|
+
/** Four groups, shallow-merged per group over our defaults. See {@link ViewerSettings}. */
|
|
445
|
+
settings?: ViewerSettings;
|
|
446
|
+
/** See {@link ViewerInteractions}. Orbiting and zooming are on, editing is off. */
|
|
447
|
+
interactions?: ViewerInteractions;
|
|
448
|
+
/**
|
|
449
|
+
* Which slot (`0`..`4`, or `5` for the charm) has its handles open, or `-1` for none.
|
|
450
|
+
*
|
|
451
|
+
* CONTROLLED WHEN PASSED, UNCONTROLLED WHEN NOT. The uncontrolled case is the one most integrators
|
|
452
|
+
* want: with `interactions.dragStickers` on, a click opens the sticker and this never appears in
|
|
453
|
+
* their code. Pass it when your own UI has a slot list that has to stay in step.
|
|
454
|
+
*/
|
|
455
|
+
editingSlot?: number;
|
|
456
|
+
/** Fires when the USER opens a slot by clicking a sticker or the charm. */
|
|
457
|
+
onEditingSlotChange?: (slot: number) => void;
|
|
458
|
+
/**
|
|
459
|
+
* Fires when the viewer has STOPPED LOADING - the finish has reached the GPU and the item is on
|
|
460
|
+
* screen textured.
|
|
461
|
+
*
|
|
462
|
+
* *** IT IS A LEVEL, NOT AN EDGE. *** It fires again after every reload, because a weapon change or
|
|
463
|
+
* a view change raises the loading gate and lowers it again. It also fires if the render FAILED,
|
|
464
|
+
* because that is equally the moment to take your own placeholder down; use {@link onError} to tell
|
|
465
|
+
* the two apart.
|
|
466
|
+
*/
|
|
467
|
+
onReady?: () => void;
|
|
468
|
+
/** See {@link SkinViewerError}. */
|
|
469
|
+
onError?: (error: SkinViewerError) => void;
|
|
470
|
+
/**
|
|
471
|
+
* The user moved a sticker or the charm - which only happens with `interactions.dragStickers` or
|
|
472
|
+
* `.dragCharm`. Fires on every pointer move during a drag.
|
|
473
|
+
*
|
|
474
|
+
* *** IT HANDS BACK A COMPLETE ITEM, NOT A DIFF. *** Store it verbatim and pass it straight back in
|
|
475
|
+
* as `item`. It never fires for your own prop changes; it is only ever the user talking.
|
|
476
|
+
*
|
|
477
|
+
* The returned item is always in the `{ weapon }` form, never `{ defindex }`, because that is what
|
|
478
|
+
* the frame reports and translating it back to a number would be a lookup that can fail.
|
|
479
|
+
*/
|
|
480
|
+
onChange?: (item: SkinViewerItem) => void;
|
|
481
|
+
/**
|
|
482
|
+
* The frame's own box changed, throttled to one per animation frame.
|
|
483
|
+
*
|
|
484
|
+
* You own the box and the viewer fills it - but RESIZING CHANGES THE PICTURE, not just its scale:
|
|
485
|
+
* the camera fits the item to the canvas aspect, so animating a panel open beside the frame
|
|
486
|
+
* re-frames the item.
|
|
487
|
+
*/
|
|
488
|
+
onResize?: (size: ViewerResize) => void;
|
|
489
|
+
/** On the wrapper element, which is `position: relative` and fills whatever you give it. */
|
|
490
|
+
className?: string;
|
|
491
|
+
style?: CSSProperties;
|
|
492
|
+
/** The `<iframe>`'s accessible name. Default `'SkinHub viewer'`; pass the item's name. */
|
|
493
|
+
title?: string;
|
|
494
|
+
/**
|
|
495
|
+
* *** DRAWN OVER THE IFRAME, NOT INSIDE IT, AND CLEARED ON `ready`. ***
|
|
496
|
+
*
|
|
497
|
+
* A React element cannot cross a `postMessage` boundary - there is no way to hand a node to a
|
|
498
|
+
* document on another origin - so this is composited on YOUR side, absolutely positioned over the
|
|
499
|
+
* frame. That is the honest implementation and it has one consequence worth knowing: an opaque node
|
|
500
|
+
* hides the frame's own loading card rather than replacing it.
|
|
501
|
+
*
|
|
502
|
+
* Omitted falls through to the frame's own, which is a reasonable default and is what the SkinHub
|
|
503
|
+
* app shows.
|
|
504
|
+
*/
|
|
505
|
+
loading?: ReactNode;
|
|
506
|
+
/**
|
|
507
|
+
* Shown OVER the frame when the viewer cannot render - see {@link SkinViewerError}. A function gets
|
|
508
|
+
* the error, so you can tell a stale package apart from a lost GL context.
|
|
509
|
+
*
|
|
510
|
+
* Omitted leaves the frame's own card, which names the failure.
|
|
511
|
+
*/
|
|
512
|
+
fallback?: ReactNode | ((error: SkinViewerError) => ReactNode);
|
|
513
|
+
/**
|
|
514
|
+
* Where `/frame` is served from. Default `'https://skinhub.gg'`.
|
|
515
|
+
*
|
|
516
|
+
* *** READ ONCE, AT MOUNT. *** Changing it later does nothing, deliberately: it is the one prop that
|
|
517
|
+
* could only be applied by reloading the frame, and a prop that quietly throws away the GL context
|
|
518
|
+
* is exactly the thing this component is built not to have. Call `reload()` from
|
|
519
|
+
* {@link useSkinViewer} if you really need to move a mounted viewer to another origin.
|
|
520
|
+
*/
|
|
521
|
+
origin?: string;
|
|
522
|
+
/**
|
|
523
|
+
* The imperative handle from {@link useSkinViewer}. Props are state; the hook is verbs.
|
|
524
|
+
*
|
|
525
|
+
* A PLAIN PROP AND NOT `ref`, because `ref` on a component means "give me the DOM node" to every
|
|
526
|
+
* React developer alive, and handing them a `{ reload }` object instead of the `<div>` they asked
|
|
527
|
+
* for would be a surprise in the one place surprises are least welcome.
|
|
528
|
+
*/
|
|
529
|
+
handle?: SkinViewerHandle;
|
|
530
|
+
};
|
|
531
|
+
/** What the viewer is doing, as {@link useSkinViewer} reports it. */
|
|
532
|
+
export type ViewerStatus =
|
|
533
|
+
/** The frame has not announced itself yet. */
|
|
534
|
+
'connecting'
|
|
535
|
+
/** Loading an item - the first one, or a new one after an identity change. */
|
|
536
|
+
| 'loading'
|
|
537
|
+
/** On screen and textured. */
|
|
538
|
+
| 'ready'
|
|
539
|
+
/** An unrecoverable failure; `error` is set. */
|
|
540
|
+
| 'error';
|
|
541
|
+
/**
|
|
542
|
+
* *** PROPS FOR STATE, A HOOK FOR VERBS. *** See {@link useSkinViewer}.
|
|
543
|
+
*
|
|
544
|
+
* `reload` is stable for the life of the hook. THE HANDLE OBJECT IS NOT - it is rebuilt when
|
|
545
|
+
* {@link status}, {@link error} or {@link problems} move, because that is how a React value
|
|
546
|
+
* re-renders the tree reading it. Put `viewer.reload` in a dependency array, not `viewer`.
|
|
547
|
+
*/
|
|
548
|
+
export type SkinViewerHandle = {
|
|
549
|
+
/** The private channel to the mounted component. See `link.ts`. */
|
|
550
|
+
readonly [LINK]: ViewerLink;
|
|
551
|
+
/**
|
|
552
|
+
* Tear the frame down and load it again from the item that is on screen NOW.
|
|
553
|
+
*
|
|
554
|
+
* *** THE ONLY THING IN THIS PACKAGE THAT REMOUNTS THE IFRAME, AND IT IS DELIBERATELY IMPERATIVE. ***
|
|
555
|
+
* Nothing you can pass as a prop reloads the viewer - that is the whole cheap-update contract - so
|
|
556
|
+
* the escape hatch for "the GL context died" or "the assets were re-published" has to be a verb.
|
|
557
|
+
*/
|
|
558
|
+
reload: () => void;
|
|
559
|
+
/** What the viewer is doing. See {@link ViewerStatus}. */
|
|
560
|
+
status: ViewerStatus;
|
|
561
|
+
/** The last unrecoverable failure, or `null`. */
|
|
562
|
+
error: SkinViewerError | null;
|
|
563
|
+
/**
|
|
564
|
+
* Anything the frame could not read in the URL this package built for it.
|
|
565
|
+
*
|
|
566
|
+
* *** AN ENTRY HERE IS OUR BUG, NOT YOURS. *** You passed props; this package turned them into a
|
|
567
|
+
* query string; the frame is telling us which part of that string it did not accept. It is exposed
|
|
568
|
+
* rather than swallowed because the alternative is a picture that is quietly missing a field.
|
|
569
|
+
*/
|
|
570
|
+
problems: readonly string[];
|
|
571
|
+
};
|
|
572
|
+
export {};
|
|
573
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
|