@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
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* *** THE HOST HALF OF THE WIRE. *** `@skinhub/viewer/protocol`.
|
|
3
|
+
*
|
|
4
|
+
* The frame's half is `app/frame/protocol.ts` inside the SkinHub app, which is a PRIVATE repository -
|
|
5
|
+
* it carries the renderer, the shader transcriptions and the export-fed material pipeline. That half
|
|
6
|
+
* is the specification. This is the same contract written from the other end of the channel.
|
|
7
|
+
*
|
|
8
|
+
* *** THE TWO FILES ARE NOT SHARED CODE AND CANNOT BE - and the reason is not that they now live in
|
|
9
|
+
* different repositories, it is what each one is MADE OF. *** The frame's half is typed in the
|
|
10
|
+
* renderer's own prop types and validates against the renderer's map list, its view enum and its
|
|
11
|
+
* placement defaults; a customer's bundle must not carry any of that. This half is typed in plain
|
|
12
|
+
* data and uses no vocabulary a customer cannot find documented in `EMBED.md`. Merging them means
|
|
13
|
+
* either shipping the renderer's surface to every integrator, or making the specification depend on a
|
|
14
|
+
* published package in order to describe itself.
|
|
15
|
+
*
|
|
16
|
+
* ═════════════════════════════════════════════════════════════════════════════════════════════
|
|
17
|
+
* *** SO THE DUPLICATION IS DELIBERATE - AND IT IS CHECKED BY A MACHINE, IN TWO PLACES. ***
|
|
18
|
+
*
|
|
19
|
+
* 1. `test/wire.test.ts`, HERE. Every name and every field this file puts on the wire is frozen in
|
|
20
|
+
* a literal, and the literals are checked EXHAUSTIVE against the types, so a field cannot be
|
|
21
|
+
* added to the wire without the freeze failing to compile. That is what makes an edit to this
|
|
22
|
+
* file deliberate rather than incidental, and it is the moment you are told to go and change the
|
|
23
|
+
* frame and bump {@link FRAME_PROTOCOL_VERSION}.
|
|
24
|
+
*
|
|
25
|
+
* 2. `app/frame/protocol.conformance.test.ts`, IN THE APP REPO - the only place both halves exist
|
|
26
|
+
* at once. It feeds this file's own `hostMessage()` output through the frame's real validator and
|
|
27
|
+
* requires ZERO rejected fields, feeds the frame's real events through {@link readFrameEvent},
|
|
28
|
+
* and compares the two key sets at the type level. That is the check that actually catches drift,
|
|
29
|
+
* because it exercises the frame's reader rather than a restatement of it.
|
|
30
|
+
*
|
|
31
|
+
* *** THE VERSION INTEGER IS THE BACKSTOP, NOT THE CHECK, and the difference is the whole point. ***
|
|
32
|
+
* A mismatch is terminal on both sides - the frame renders nothing and names which side is stale, this
|
|
33
|
+
* package stops sending - so a mismatch that HAPPENS is loud. But it only happens if somebody
|
|
34
|
+
* remembered to bump the integer. The failure the two checks above exist for is the other one: a field
|
|
35
|
+
* added to the frame, the integer left alone, both sides claiming `v: 1`, and the field silently
|
|
36
|
+
* dropped. A silently wrong render is worse than a blank frame with an explanation, and this project
|
|
37
|
+
* has been bitten by that class of failure repeatedly.
|
|
38
|
+
*
|
|
39
|
+
* ═════════════════════════════════════════════════════════════════════════════════════════════
|
|
40
|
+
* *** THE VOCABULARY HERE IS THE FRAME'S, NOT THE INTEGRATOR'S. ***
|
|
41
|
+
*
|
|
42
|
+
* `weaponType`, `sticker_id`, `offset_x` - the renderer's own names and the game's own field names.
|
|
43
|
+
* `item.ts` translates between this and `types.ts`, and that translation is the package's actual job:
|
|
44
|
+
* an integrator writing `offset_x` into a React tree is writing protobuf into their view layer.
|
|
45
|
+
*
|
|
46
|
+
* *** WHICH IS WHY THIS IS A SEPARATE ENTRY POINT AND NOT PART OF THE BARREL. *** It is exported at
|
|
47
|
+
* all because the wire is ALREADY public - `EMBED.md` §6 documents this envelope, this patch and these
|
|
48
|
+
* events in full, for the PHP / Vue / plain-`<script>` hosts the URL contract exists for - so
|
|
49
|
+
* withholding the TypeScript for a shape we publish in prose bought nothing, and made the conformance
|
|
50
|
+
* check above impossible to write. It carries no compatibility promise beyond the integer: it moves
|
|
51
|
+
* when the wire moves, which is the whole no-back-compat bargain. Reach for `SkinViewer` from the
|
|
52
|
+
* barrel unless you are writing a host in something that is not React.
|
|
53
|
+
*/
|
|
54
|
+
import type { KeychainPlacement, StickerPlacement } from '@skinhub/cdn/placement';
|
|
55
|
+
/**
|
|
56
|
+
* The discriminator on every message in both directions.
|
|
57
|
+
*
|
|
58
|
+
* It exists because `window.postMessage` is a shared bus: React DevTools, Next's dev overlay, HMR,
|
|
59
|
+
* wallet extensions and analytics tags all post into and out of frames, and several post objects with
|
|
60
|
+
* a `type` field. Anything without this key is not ours and is dropped in silence.
|
|
61
|
+
*/
|
|
62
|
+
export declare const FRAME_CHANNEL = "skinhub-viewer";
|
|
63
|
+
/**
|
|
64
|
+
* The protocol version this package speaks.
|
|
65
|
+
*
|
|
66
|
+
* *** AN INTEGER, NOT A SEMVER RANGE, because there is no range: *** there is no back-compat window
|
|
67
|
+
* and never will be. Two integers either match or they do not, and the failure text can
|
|
68
|
+
* then say which side is behind.
|
|
69
|
+
*
|
|
70
|
+
* *** IT IS ALSO THE PACKAGE'S EXPIRY DATE, AND THAT IS THE INTENT. *** When we change the wire, every
|
|
71
|
+
* published copy of this package stops working loudly and at once. That is the cost of the no-back-compat
|
|
72
|
+
* decision and it is paid deliberately, in exchange for never shipping a viewer that renders a
|
|
73
|
+
* partly-understood item.
|
|
74
|
+
*/
|
|
75
|
+
export declare const FRAME_PROTOCOL_VERSION = 1;
|
|
76
|
+
/** Five stickers plus the charm in slot 5. The frame validates the SHAPE of this and nothing else. */
|
|
77
|
+
export type PlacementSlots = [
|
|
78
|
+
StickerPlacement,
|
|
79
|
+
StickerPlacement,
|
|
80
|
+
StickerPlacement,
|
|
81
|
+
StickerPlacement,
|
|
82
|
+
StickerPlacement,
|
|
83
|
+
KeychainPlacement
|
|
84
|
+
];
|
|
85
|
+
export type FrameItem = {
|
|
86
|
+
/** `weapon_ak47`, or a glove id. The key the renderer's model table resolves. */
|
|
87
|
+
weaponType: string;
|
|
88
|
+
paintIndex: number;
|
|
89
|
+
legacyModel?: boolean;
|
|
90
|
+
float?: number;
|
|
91
|
+
seed?: number;
|
|
92
|
+
statTrak?: number | false;
|
|
93
|
+
nameTag?: string | null;
|
|
94
|
+
stickers?: PlacementSlots;
|
|
95
|
+
};
|
|
96
|
+
export type FrameSettings = {
|
|
97
|
+
camera?: {
|
|
98
|
+
fov?: number;
|
|
99
|
+
defaultZoom?: number;
|
|
100
|
+
};
|
|
101
|
+
quality?: {
|
|
102
|
+
bloom?: number;
|
|
103
|
+
bloomSpill?: number;
|
|
104
|
+
renderScale?: number;
|
|
105
|
+
antialias?: boolean;
|
|
106
|
+
shadows?: boolean;
|
|
107
|
+
};
|
|
108
|
+
environment?: {
|
|
109
|
+
map?: string | null;
|
|
110
|
+
timeOfDay?: string;
|
|
111
|
+
rain?: boolean;
|
|
112
|
+
background?: string;
|
|
113
|
+
};
|
|
114
|
+
overlays?: {
|
|
115
|
+
stickerGizmo?: boolean;
|
|
116
|
+
charmGizmo?: boolean;
|
|
117
|
+
gizmoStyle?: {
|
|
118
|
+
color?: string;
|
|
119
|
+
shadowColor?: string;
|
|
120
|
+
};
|
|
121
|
+
};
|
|
122
|
+
};
|
|
123
|
+
export type FrameInteractions = {
|
|
124
|
+
orbit?: boolean;
|
|
125
|
+
zoom?: boolean;
|
|
126
|
+
dragStickers?: boolean;
|
|
127
|
+
dragCharm?: boolean;
|
|
128
|
+
};
|
|
129
|
+
/** Everything `/frame` holds. One field per prop of the renderer that a host can set. */
|
|
130
|
+
export type FrameState = {
|
|
131
|
+
item: FrameItem;
|
|
132
|
+
view: 'gun' | 'hands' | 'agent';
|
|
133
|
+
agent: {
|
|
134
|
+
id: number;
|
|
135
|
+
pose?: string | null;
|
|
136
|
+
};
|
|
137
|
+
gloves: {
|
|
138
|
+
type: string;
|
|
139
|
+
paintIndex: number;
|
|
140
|
+
float?: number;
|
|
141
|
+
seed?: number;
|
|
142
|
+
} | null;
|
|
143
|
+
settings: FrameSettings;
|
|
144
|
+
interactions: FrameInteractions;
|
|
145
|
+
editingSlot: number;
|
|
146
|
+
};
|
|
147
|
+
/**
|
|
148
|
+
* A partial write over {@link FrameState}.
|
|
149
|
+
*
|
|
150
|
+
* *** EVERY OBJECT MERGES BY FIELD AND AN ABSENT KEY MEANS "LEAVE IT ALONE". *** That rule is not a
|
|
151
|
+
* convenience, it is the cheap-update contract: `{ item: { float } }` keeps `weaponType`, so the
|
|
152
|
+
* frame's loading gate - which is keyed on the identity VALUES - does not move. A patch that replaced
|
|
153
|
+
* rather than merged would blank the weapon on every float tick.
|
|
154
|
+
*/
|
|
155
|
+
export type FramePatch = {
|
|
156
|
+
item?: Partial<FrameItem>;
|
|
157
|
+
view?: FrameState['view'];
|
|
158
|
+
agent?: Partial<FrameState['agent']>;
|
|
159
|
+
gloves?: FrameState['gloves'];
|
|
160
|
+
settings?: FrameSettings;
|
|
161
|
+
interactions?: FrameInteractions;
|
|
162
|
+
editingSlot?: number;
|
|
163
|
+
};
|
|
164
|
+
type Envelope = {
|
|
165
|
+
channel: typeof FRAME_CHANNEL;
|
|
166
|
+
v: number;
|
|
167
|
+
from: 'host' | 'viewer';
|
|
168
|
+
};
|
|
169
|
+
export type HostMessage = (Envelope & {
|
|
170
|
+
type: 'hello';
|
|
171
|
+
}) | (Envelope & {
|
|
172
|
+
type: 'set';
|
|
173
|
+
patch: FramePatch;
|
|
174
|
+
});
|
|
175
|
+
export type FrameErrorCode = 'render-failed' | 'bad-inspect-link' | 'bad-message' | 'protocol-mismatch';
|
|
176
|
+
export type FrameError = {
|
|
177
|
+
code: FrameErrorCode;
|
|
178
|
+
message: string;
|
|
179
|
+
};
|
|
180
|
+
export type FrameEvent = (Envelope & {
|
|
181
|
+
type: 'hello';
|
|
182
|
+
state: FrameState;
|
|
183
|
+
problems: string[];
|
|
184
|
+
}) | (Envelope & {
|
|
185
|
+
type: 'ready';
|
|
186
|
+
}) | (Envelope & {
|
|
187
|
+
type: 'error';
|
|
188
|
+
error: FrameError;
|
|
189
|
+
}) | (Envelope & {
|
|
190
|
+
type: 'change';
|
|
191
|
+
item: FrameItem;
|
|
192
|
+
}) | (Envelope & {
|
|
193
|
+
type: 'editing-slot';
|
|
194
|
+
slot: number;
|
|
195
|
+
}) | (Envelope & {
|
|
196
|
+
type: 'resize';
|
|
197
|
+
width: number;
|
|
198
|
+
height: number;
|
|
199
|
+
dpr: number;
|
|
200
|
+
});
|
|
201
|
+
/** Stamps the envelope, so no call site can forget the channel, the version or the direction. */
|
|
202
|
+
export declare const hostMessage: (patch?: FramePatch) => HostMessage;
|
|
203
|
+
export type FrameEventReading =
|
|
204
|
+
/** Not ours - HMR, an extension, another library, or our own message echoing. Drop it silently. */
|
|
205
|
+
{
|
|
206
|
+
kind: 'ignore';
|
|
207
|
+
}
|
|
208
|
+
/** Ours, and the versions disagree. Terminal. */
|
|
209
|
+
| {
|
|
210
|
+
kind: 'mismatch';
|
|
211
|
+
error: FrameError;
|
|
212
|
+
} | {
|
|
213
|
+
kind: 'event';
|
|
214
|
+
event: FrameEvent;
|
|
215
|
+
};
|
|
216
|
+
/**
|
|
217
|
+
* One arriving `MessageEvent.data`, classified.
|
|
218
|
+
*
|
|
219
|
+
* *** THE HOST SIDE CHECKS THE VERSION TOO, AND IT IS NOT REDUNDANT WITH THE FRAME'S CHECK. *** The
|
|
220
|
+
* frame only learns about a mismatch once the host has SENT something. A host that configures the
|
|
221
|
+
* viewer entirely from props and never changes them still receives `hello`, `ready` and `change` - and
|
|
222
|
+
* if the frame is newer, those payloads may have moved. Reading them anyway is how a stale package
|
|
223
|
+
* hands its user a `change` event with half an item in it, which is the exact failure mode
|
|
224
|
+
* the no-back-compat rule forbids. So a mismatch heard here is fatal here as well.
|
|
225
|
+
*
|
|
226
|
+
* `from: 'viewer'` IS CHECKED because both directions share one channel and both have a `hello`.
|
|
227
|
+
* Without it a host that also embeds another host's frame could read its own outbound traffic.
|
|
228
|
+
*/
|
|
229
|
+
export declare const readFrameEvent: (data: unknown) => FrameEventReading;
|
|
230
|
+
export {};
|
|
231
|
+
//# sourceMappingURL=protocol.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"protocol.d.ts","sourceRoot":"","sources":["../src/protocol.ts"],"names":[],"mappings":"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"}
|
package/dist/protocol.js
ADDED
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* *** THE HOST HALF OF THE WIRE. *** `@skinhub/viewer/protocol`.
|
|
3
|
+
*
|
|
4
|
+
* The frame's half is `app/frame/protocol.ts` inside the SkinHub app, which is a PRIVATE repository -
|
|
5
|
+
* it carries the renderer, the shader transcriptions and the export-fed material pipeline. That half
|
|
6
|
+
* is the specification. This is the same contract written from the other end of the channel.
|
|
7
|
+
*
|
|
8
|
+
* *** THE TWO FILES ARE NOT SHARED CODE AND CANNOT BE - and the reason is not that they now live in
|
|
9
|
+
* different repositories, it is what each one is MADE OF. *** The frame's half is typed in the
|
|
10
|
+
* renderer's own prop types and validates against the renderer's map list, its view enum and its
|
|
11
|
+
* placement defaults; a customer's bundle must not carry any of that. This half is typed in plain
|
|
12
|
+
* data and uses no vocabulary a customer cannot find documented in `EMBED.md`. Merging them means
|
|
13
|
+
* either shipping the renderer's surface to every integrator, or making the specification depend on a
|
|
14
|
+
* published package in order to describe itself.
|
|
15
|
+
*
|
|
16
|
+
* ═════════════════════════════════════════════════════════════════════════════════════════════
|
|
17
|
+
* *** SO THE DUPLICATION IS DELIBERATE - AND IT IS CHECKED BY A MACHINE, IN TWO PLACES. ***
|
|
18
|
+
*
|
|
19
|
+
* 1. `test/wire.test.ts`, HERE. Every name and every field this file puts on the wire is frozen in
|
|
20
|
+
* a literal, and the literals are checked EXHAUSTIVE against the types, so a field cannot be
|
|
21
|
+
* added to the wire without the freeze failing to compile. That is what makes an edit to this
|
|
22
|
+
* file deliberate rather than incidental, and it is the moment you are told to go and change the
|
|
23
|
+
* frame and bump {@link FRAME_PROTOCOL_VERSION}.
|
|
24
|
+
*
|
|
25
|
+
* 2. `app/frame/protocol.conformance.test.ts`, IN THE APP REPO - the only place both halves exist
|
|
26
|
+
* at once. It feeds this file's own `hostMessage()` output through the frame's real validator and
|
|
27
|
+
* requires ZERO rejected fields, feeds the frame's real events through {@link readFrameEvent},
|
|
28
|
+
* and compares the two key sets at the type level. That is the check that actually catches drift,
|
|
29
|
+
* because it exercises the frame's reader rather than a restatement of it.
|
|
30
|
+
*
|
|
31
|
+
* *** THE VERSION INTEGER IS THE BACKSTOP, NOT THE CHECK, and the difference is the whole point. ***
|
|
32
|
+
* A mismatch is terminal on both sides - the frame renders nothing and names which side is stale, this
|
|
33
|
+
* package stops sending - so a mismatch that HAPPENS is loud. But it only happens if somebody
|
|
34
|
+
* remembered to bump the integer. The failure the two checks above exist for is the other one: a field
|
|
35
|
+
* added to the frame, the integer left alone, both sides claiming `v: 1`, and the field silently
|
|
36
|
+
* dropped. A silently wrong render is worse than a blank frame with an explanation, and this project
|
|
37
|
+
* has been bitten by that class of failure repeatedly.
|
|
38
|
+
*
|
|
39
|
+
* ═════════════════════════════════════════════════════════════════════════════════════════════
|
|
40
|
+
* *** THE VOCABULARY HERE IS THE FRAME'S, NOT THE INTEGRATOR'S. ***
|
|
41
|
+
*
|
|
42
|
+
* `weaponType`, `sticker_id`, `offset_x` - the renderer's own names and the game's own field names.
|
|
43
|
+
* `item.ts` translates between this and `types.ts`, and that translation is the package's actual job:
|
|
44
|
+
* an integrator writing `offset_x` into a React tree is writing protobuf into their view layer.
|
|
45
|
+
*
|
|
46
|
+
* *** WHICH IS WHY THIS IS A SEPARATE ENTRY POINT AND NOT PART OF THE BARREL. *** It is exported at
|
|
47
|
+
* all because the wire is ALREADY public - `EMBED.md` §6 documents this envelope, this patch and these
|
|
48
|
+
* events in full, for the PHP / Vue / plain-`<script>` hosts the URL contract exists for - so
|
|
49
|
+
* withholding the TypeScript for a shape we publish in prose bought nothing, and made the conformance
|
|
50
|
+
* check above impossible to write. It carries no compatibility promise beyond the integer: it moves
|
|
51
|
+
* when the wire moves, which is the whole no-back-compat bargain. Reach for `SkinViewer` from the
|
|
52
|
+
* barrel unless you are writing a host in something that is not React.
|
|
53
|
+
*/
|
|
54
|
+
/**
|
|
55
|
+
* The discriminator on every message in both directions.
|
|
56
|
+
*
|
|
57
|
+
* It exists because `window.postMessage` is a shared bus: React DevTools, Next's dev overlay, HMR,
|
|
58
|
+
* wallet extensions and analytics tags all post into and out of frames, and several post objects with
|
|
59
|
+
* a `type` field. Anything without this key is not ours and is dropped in silence.
|
|
60
|
+
*/
|
|
61
|
+
export const FRAME_CHANNEL = 'skinhub-viewer';
|
|
62
|
+
/**
|
|
63
|
+
* The protocol version this package speaks.
|
|
64
|
+
*
|
|
65
|
+
* *** AN INTEGER, NOT A SEMVER RANGE, because there is no range: *** there is no back-compat window
|
|
66
|
+
* and never will be. Two integers either match or they do not, and the failure text can
|
|
67
|
+
* then say which side is behind.
|
|
68
|
+
*
|
|
69
|
+
* *** IT IS ALSO THE PACKAGE'S EXPIRY DATE, AND THAT IS THE INTENT. *** When we change the wire, every
|
|
70
|
+
* published copy of this package stops working loudly and at once. That is the cost of the no-back-compat
|
|
71
|
+
* decision and it is paid deliberately, in exchange for never shipping a viewer that renders a
|
|
72
|
+
* partly-understood item.
|
|
73
|
+
*/
|
|
74
|
+
export const FRAME_PROTOCOL_VERSION = 1;
|
|
75
|
+
/** Stamps the envelope, so no call site can forget the channel, the version or the direction. */
|
|
76
|
+
export const hostMessage = (patch) => patch
|
|
77
|
+
? { channel: FRAME_CHANNEL, v: FRAME_PROTOCOL_VERSION, from: 'host', type: 'set', patch }
|
|
78
|
+
: { channel: FRAME_CHANNEL, v: FRAME_PROTOCOL_VERSION, from: 'host', type: 'hello' };
|
|
79
|
+
const isRecord = (value) => typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
80
|
+
/**
|
|
81
|
+
* One arriving `MessageEvent.data`, classified.
|
|
82
|
+
*
|
|
83
|
+
* *** THE HOST SIDE CHECKS THE VERSION TOO, AND IT IS NOT REDUNDANT WITH THE FRAME'S CHECK. *** The
|
|
84
|
+
* frame only learns about a mismatch once the host has SENT something. A host that configures the
|
|
85
|
+
* viewer entirely from props and never changes them still receives `hello`, `ready` and `change` - and
|
|
86
|
+
* if the frame is newer, those payloads may have moved. Reading them anyway is how a stale package
|
|
87
|
+
* hands its user a `change` event with half an item in it, which is the exact failure mode
|
|
88
|
+
* the no-back-compat rule forbids. So a mismatch heard here is fatal here as well.
|
|
89
|
+
*
|
|
90
|
+
* `from: 'viewer'` IS CHECKED because both directions share one channel and both have a `hello`.
|
|
91
|
+
* Without it a host that also embeds another host's frame could read its own outbound traffic.
|
|
92
|
+
*/
|
|
93
|
+
export const readFrameEvent = (data) => {
|
|
94
|
+
if (!isRecord(data) || data.channel !== FRAME_CHANNEL || data.from !== 'viewer')
|
|
95
|
+
return { kind: 'ignore' };
|
|
96
|
+
if (data.v !== FRAME_PROTOCOL_VERSION)
|
|
97
|
+
return { kind: 'mismatch', error: { code: 'protocol-mismatch', message: versionMessage(data.v) } };
|
|
98
|
+
if (typeof data.type !== 'string')
|
|
99
|
+
return { kind: 'ignore' };
|
|
100
|
+
/*
|
|
101
|
+
* A VERB THIS BUILD DOES NOT HAVE, ON A VERSION IT DOES: only possible if the frame gained an event
|
|
102
|
+
* without bumping the integer, which is our mistake and not the integrator's. Dropped rather than
|
|
103
|
+
* reported, because there is nothing they could do about it and an error they cannot act on is
|
|
104
|
+
* noise in their console.
|
|
105
|
+
*/
|
|
106
|
+
if (!KNOWN_EVENTS.has(data.type))
|
|
107
|
+
return { kind: 'ignore' };
|
|
108
|
+
return { kind: 'event', event: data };
|
|
109
|
+
};
|
|
110
|
+
const KNOWN_EVENTS = new Set(['hello', 'ready', 'error', 'change', 'editing-slot', 'resize']);
|
|
111
|
+
/**
|
|
112
|
+
* The sentence a developer reads when the versions disagree - the whole of what the no-back-compat
|
|
113
|
+
* decision buys, so it names the DIRECTION rather than just the numbers.
|
|
114
|
+
*
|
|
115
|
+
* A PACKAGE BEHIND THE EMBED is the ordinary case and the one with an action attached: they installed
|
|
116
|
+
* `@skinhub/viewer` some months ago and we have shipped a protocol change since. Updating fixes it.
|
|
117
|
+
*
|
|
118
|
+
* A PACKAGE AHEAD OF THE EMBED means the embedded document is stale - almost always a cached
|
|
119
|
+
* `/frame` - so the action is a reload rather than an install. Telling somebody to update a package
|
|
120
|
+
* that is already newer would send them to the one place that cannot help.
|
|
121
|
+
*/
|
|
122
|
+
const versionMessage = (received) => {
|
|
123
|
+
const seen = typeof received === 'number' ? received : JSON.stringify(received);
|
|
124
|
+
if (typeof received === 'number' && received < FRAME_PROTOCOL_VERSION)
|
|
125
|
+
return `@skinhub/viewer speaks protocol ${FRAME_PROTOCOL_VERSION} and the embed answered with ${seen}. The embedded page is out of date - it is cached, or the origin you pointed at is running an older build. Nothing has been rendered, deliberately: a partly-understood message would render a partly-correct item.`;
|
|
126
|
+
return `@skinhub/viewer speaks protocol ${FRAME_PROTOCOL_VERSION} and the embed answered with ${seen}. This package is out of date - update @skinhub/viewer. Nothing has been rendered, deliberately: a partly-understood message would render a partly-correct item.`;
|
|
127
|
+
};
|
|
128
|
+
//# sourceMappingURL=protocol.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"protocol.js","sourceRoot":"","sources":["../src/protocol.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoDG;AAIH;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,aAAa,GAAG,gBAAgB,CAAA;AAE7C;;;;;;;;;;;GAWG;AACH,MAAM,CAAC,MAAM,sBAAsB,GAAG,CAAC,CAAA;AA8FvC,iGAAiG;AACjG,MAAM,CAAC,MAAM,WAAW,GAAG,CAAC,KAAkB,EAAe,EAAE,CAC9D,KAAK;IACJ,CAAC,CAAC,EAAE,OAAO,EAAE,aAAa,EAAE,CAAC,EAAE,sBAAsB,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE;IACzF,CAAC,CAAC,EAAE,OAAO,EAAE,aAAa,EAAE,CAAC,EAAE,sBAAsB,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,CAAA;AAatF,MAAM,QAAQ,GAAG,CAAC,KAAc,EAAoC,EAAE,CACrE,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAA;AAErE;;;;;;;;;;;;GAYG;AACH,MAAM,CAAC,MAAM,cAAc,GAAG,CAAC,IAAa,EAAqB,EAAE;IAClE,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,OAAO,KAAK,aAAa,IAAI,IAAI,CAAC,IAAI,KAAK,QAAQ;QAAE,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAA;IAE1G,IAAI,IAAI,CAAC,CAAC,KAAK,sBAAsB;QACpC,OAAO,EAAE,IAAI,EAAE,UAAU,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,mBAAmB,EAAE,OAAO,EAAE,cAAc,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAA;IAEnG,IAAI,OAAO,IAAI,CAAC,IAAI,KAAK,QAAQ;QAAE,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAA;IAC5D;;;;;OAKG;IACH,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC;QAAE,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAA;IAE3D,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,IAA6B,EAAE,CAAA;AAC/D,CAAC,CAAA;AAED,MAAM,YAAY,GAAwB,IAAI,GAAG,CAAC,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,cAAc,EAAE,QAAQ,CAAC,CAAC,CAAA;AAElH;;;;;;;;;;GAUG;AACH,MAAM,cAAc,GAAG,CAAC,QAAiB,EAAU,EAAE;IACpD,MAAM,IAAI,GAAG,OAAO,QAAQ,KAAK,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAA;IAC/E,IAAI,OAAO,QAAQ,KAAK,QAAQ,IAAI,QAAQ,GAAG,sBAAsB;QACpE,OAAO,mCAAmC,sBAAsB,gCAAgC,IAAI,qNAAqN,CAAA;IAC1T,OAAO,mCAAmC,sBAAsB,gCAAgC,IAAI,kKAAkK,CAAA;AACvQ,CAAC,CAAA"}
|
package/dist/state.d.ts
ADDED
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* *** PROPS → A URL, AND THEN PROPS → PATCHES. ***
|
|
3
|
+
*
|
|
4
|
+
* ═════════════════════════════════════════════════════════════════════════════════════════════
|
|
5
|
+
* *** THE TWO DOORS, AND WHY THIS PACKAGE USES BOTH RATHER THAN PICKING ONE. ***
|
|
6
|
+
*
|
|
7
|
+
* `/frame` can be driven by a query string or by `set` messages, and both go through the same
|
|
8
|
+
* applier on the far side. This package uses the URL for the FIRST render and messages for every
|
|
9
|
+
* render after it, and the split is not an optimisation - it is the only arrangement that gets both
|
|
10
|
+
* properties an integrator will judge us on:
|
|
11
|
+
*
|
|
12
|
+
* THE FIRST PAINT IS THEIR ITEM, not ours swapped a tick later. A frame that booted on our default
|
|
13
|
+
* AK and was corrected by a message would show the wrong gun for one round trip, on a product page.
|
|
14
|
+
*
|
|
15
|
+
* NO LATER PROP CHANGE TOUCHES THE `src`. *** THIS IS THE LOAD-BEARING ONE. *** Rewriting `src`
|
|
16
|
+
* reloads the document, which throws away the GL context, re-downloads the model and re-runs every
|
|
17
|
+
* shader compile - i.e. it turns a float slider into a five-second stall. So the URL is built once,
|
|
18
|
+
* frozen, and everything after it is a patch. See `SkinViewer.tsx`, where the same rule is enforced
|
|
19
|
+
* on the element.
|
|
20
|
+
*
|
|
21
|
+
* ═════════════════════════════════════════════════════════════════════════════════════════════
|
|
22
|
+
* *** AND THE REASON {@link diffState} IS A DIFF RATHER THAN "SEND THE WHOLE STATE EVERY TIME". ***
|
|
23
|
+
*
|
|
24
|
+
* Sending everything would be correct - the frame's merge returns the SAME OBJECT when the values it
|
|
25
|
+
* is handed are the values it already has, so a restated `weaponType` costs nothing and does not
|
|
26
|
+
* reload. It would still be wrong, for one reason: `stickers` is an ARRAY WE REBUILD ON EVERY RENDER.
|
|
27
|
+
* The renderer holds its sticker draft against that array BY IDENTITY, so a fresh six-slot tuple
|
|
28
|
+
* arriving on every tick of somebody's float slider would re-seed the draft sixty times a second and
|
|
29
|
+
* fight the user's own drag. The frame's own protocol file warns about exactly this.
|
|
30
|
+
*
|
|
31
|
+
* So the diff is structural: a field is in the patch only if its VALUE moved.
|
|
32
|
+
*/
|
|
33
|
+
import type { FrameInteractions, FrameItem, FramePatch, FrameSettings } from './protocol.js';
|
|
34
|
+
import type { SkinViewerError, SkinViewerProps, ViewerGloves, ViewerView } from './types.js';
|
|
35
|
+
/**
|
|
36
|
+
* Why the frame is showing its instruction card instead of an item. See `SkinViewer.tsx` and the
|
|
37
|
+
* `?help=` note in `EMBED.md`.
|
|
38
|
+
*/
|
|
39
|
+
export type HelpReason = 'no-item' | 'bad-link' | 'unknown-weapon';
|
|
40
|
+
/**
|
|
41
|
+
* Everything this package can tell the frame, resolved from one render's props.
|
|
42
|
+
*
|
|
43
|
+
* *** ABSENT MEANS "SAY NOTHING", NOT "USE THE DEFAULT", *** all the way down. An integrator who never
|
|
44
|
+
* passes `settings.quality.bloom` must not have `bloom=1` written into their URL, because then OUR
|
|
45
|
+
* default is frozen into THEIR embed and the day we change it their picture does not move. The
|
|
46
|
+
* defaults live in one place - the frame - and this file's job is to be quiet about everything the
|
|
47
|
+
* caller did not mention.
|
|
48
|
+
*/
|
|
49
|
+
export type DesiredState = {
|
|
50
|
+
/** `null` when the props named no renderable item; {@link help} then says why. */
|
|
51
|
+
item: FrameItem | null;
|
|
52
|
+
/** The integrator's own inspect link, forwarded verbatim as `?i=`. See `item.ts`. */
|
|
53
|
+
inspectPayload: string | null;
|
|
54
|
+
help: HelpReason | null;
|
|
55
|
+
subjectError: SkinViewerError | null;
|
|
56
|
+
view?: ViewerView;
|
|
57
|
+
agent?: {
|
|
58
|
+
id?: number;
|
|
59
|
+
pose?: string | null;
|
|
60
|
+
};
|
|
61
|
+
/** `undefined` says nothing; `null` is the wearer's OWN default pair, which is a real value. */
|
|
62
|
+
gloves?: ViewerGloves | null;
|
|
63
|
+
settings?: FrameSettings;
|
|
64
|
+
interactions?: FrameInteractions;
|
|
65
|
+
editingSlot?: number;
|
|
66
|
+
};
|
|
67
|
+
/**
|
|
68
|
+
* One render's props as {@link DesiredState}. Pure, synchronous, no React - so it can run in a
|
|
69
|
+
* `useState` initialiser during SSR as well as on every subsequent render.
|
|
70
|
+
*
|
|
71
|
+
* *** IT TAKES A `Partial<>` OF ITS OWN PROP TYPE ON PURPOSE. *** The types make a missing item a
|
|
72
|
+
* compile error; this function is what happens when the types were bypassed - plain JavaScript, an
|
|
73
|
+
* `any`, a query that had not resolved - and its whole value is that it has an answer for that case
|
|
74
|
+
* rather than a `TypeError`.
|
|
75
|
+
*/
|
|
76
|
+
export declare const resolveState: (props: Partial<SkinViewerProps>) => DesiredState;
|
|
77
|
+
/**
|
|
78
|
+
* The initial `<iframe src>`, and the state that URL actually expressed.
|
|
79
|
+
*
|
|
80
|
+
* *** THE SECOND RETURN VALUE IS NOT BOOKKEEPING - IT IS THE BASELINE EVERY LATER PATCH IS MEASURED
|
|
81
|
+
* AGAINST. *** One field is deliberately NOT encodable: the stickers, which the query string can only
|
|
82
|
+
* carry inside an `?i=` payload. Rather than re-encode a placement into an inspect link here - a
|
|
83
|
+
* second implementation of a codec whose only job would be to disagree with the frame's decoder - the
|
|
84
|
+
* stickers are simply left out of the URL and reported as unsent, so the first diff after the frame
|
|
85
|
+
* announces itself carries them. They are a CHEAP field, so they arrive without a loading card, and
|
|
86
|
+
* in practice they arrive long before the model has finished downloading.
|
|
87
|
+
*
|
|
88
|
+
* When the integrator gave us an inspect link there is nothing to encode: their own payload goes
|
|
89
|
+
* through as `?i=` and carries the stickers with it.
|
|
90
|
+
*/
|
|
91
|
+
export declare const frameUrl: (origin: string, desired: DesiredState) => {
|
|
92
|
+
src: string;
|
|
93
|
+
expressed: DesiredState;
|
|
94
|
+
};
|
|
95
|
+
/**
|
|
96
|
+
* *** WHICH FIELDS RELOAD THE FRAME. *** `EMBED.md`'s cheap-vs-reload table, as a value.
|
|
97
|
+
*
|
|
98
|
+
* The component reads this to decide when to raise a caller's `loading` slot, so the slot is raised
|
|
99
|
+
* on exactly the changes that actually cover the canvas rather than on a guess. `view` and the agent
|
|
100
|
+
* are the same class but are not fields of the item, so they are handled beside it.
|
|
101
|
+
*/
|
|
102
|
+
export declare const IDENTITY_FIELDS: readonly ["weaponType", "paintIndex", "legacyModel"];
|
|
103
|
+
/** `undefined` when nothing moved, which is what lets the component skip the `postMessage` entirely. */
|
|
104
|
+
export declare const diffState: (previous: DesiredState, next: DesiredState) => FramePatch | undefined;
|
|
105
|
+
/** True when a patch would cover the canvas - see {@link IDENTITY_FIELDS}. */
|
|
106
|
+
export declare const coversCanvas: (patch: FramePatch, view: ViewerView | undefined) => boolean;
|
|
107
|
+
//# sourceMappingURL=state.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"state.d.ts","sourceRoot":"","sources":["../src/state.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AAEH,OAAO,KAAK,EAAE,iBAAiB,EAAE,SAAS,EAAE,UAAU,EAAE,aAAa,EAAkB,MAAM,eAAe,CAAA;AAE5G,OAAO,KAAK,EAAE,eAAe,EAAE,eAAe,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,YAAY,CAAA;AAE5F;;;GAGG;AACH,MAAM,MAAM,UAAU,GAAG,SAAS,GAAG,UAAU,GAAG,gBAAgB,CAAA;AAElE;;;;;;;;GAQG;AACH,MAAM,MAAM,YAAY,GAAG;IAC1B,kFAAkF;IAClF,IAAI,EAAE,SAAS,GAAG,IAAI,CAAA;IACtB,qFAAqF;IACrF,cAAc,EAAE,MAAM,GAAG,IAAI,CAAA;IAC7B,IAAI,EAAE,UAAU,GAAG,IAAI,CAAA;IACvB,YAAY,EAAE,eAAe,GAAG,IAAI,CAAA;IACpC,IAAI,CAAC,EAAE,UAAU,CAAA;IACjB,KAAK,CAAC,EAAE;QAAE,EAAE,CAAC,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE,CAAA;IAC7C,gGAAgG;IAChG,MAAM,CAAC,EAAE,YAAY,GAAG,IAAI,CAAA;IAC5B,QAAQ,CAAC,EAAE,aAAa,CAAA;IACxB,YAAY,CAAC,EAAE,iBAAiB,CAAA;IAChC,WAAW,CAAC,EAAE,MAAM,CAAA;CACpB,CAAA;AAcD;;;;;;;;GAQG;AACH,eAAO,MAAM,YAAY,GAAI,OAAO,OAAO,CAAC,eAAe,CAAC,KAAG,YAgB9D,CAAA;AAqCD;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,QAAQ,GAAI,QAAQ,MAAM,EAAE,SAAS,YAAY,KAAG;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,YAAY,CAAA;CA6DtG,CAAA;AAUD;;;;;;GAMG;AACH,eAAO,MAAM,eAAe,sDAIqB,CAAA;AAoBjD,wGAAwG;AACxG,eAAO,MAAM,SAAS,GAAI,UAAU,YAAY,EAAE,MAAM,YAAY,KAAG,UAAU,GAAG,SAuEnF,CAAA;AAkDD,8EAA8E;AAC9E,eAAO,MAAM,YAAY,GAAI,OAAO,UAAU,EAAE,MAAM,UAAU,GAAG,SAAS,KAAG,OAO9E,CAAA"}
|