@idosgames/characters 0.0.0-stage → 0.1.0
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 +34 -2
- package/dist/PartsManager-CAVBKvp6.d.ts +589 -0
- package/dist/PartsManager-Cn3MU-VS.d.cts +589 -0
- package/dist/chunk-64D567CX.js +1 -0
- package/dist/chunk-BU66AZ2Z.js +1 -0
- package/dist/chunk-CGF2TQVK.js +1 -0
- package/dist/chunk-OF4BH3JZ.js +2 -0
- package/dist/chunk-WKHHFTK2.js +1 -0
- package/dist/chunk-Z5I76WRJ.js +1 -0
- package/dist/contract-DhZuKNIf.d.cts +24 -0
- package/dist/contract-DhZuKNIf.d.ts +24 -0
- package/dist/gltf/index.cjs +1 -0
- package/dist/gltf/index.d.cts +150 -0
- package/dist/gltf/index.d.ts +150 -0
- package/dist/gltf/index.js +1 -0
- package/dist/image-D5NaQeFz.d.cts +8 -0
- package/dist/image-D5NaQeFz.d.ts +8 -0
- package/dist/index.cjs +1 -0
- package/dist/index.d.cts +65 -0
- package/dist/index.d.ts +65 -0
- package/dist/index.js +1 -0
- package/dist/rig2d/editor/index.cjs +81 -0
- package/dist/rig2d/editor/index.d.cts +25 -0
- package/dist/rig2d/editor/index.d.ts +25 -0
- package/dist/rig2d/editor/index.js +81 -0
- package/dist/rig2d/index.cjs +17 -0
- package/dist/rig2d/index.d.cts +190 -0
- package/dist/rig2d/index.d.ts +190 -0
- package/dist/rig2d/index.js +17 -0
- package/dist/rig2d/phaser/index.cjs +2 -0
- package/dist/rig2d/phaser/index.d.cts +106 -0
- package/dist/rig2d/phaser/index.d.ts +106 -0
- package/dist/rig2d/phaser/index.js +1 -0
- package/dist/rig2d/three/index.cjs +2 -0
- package/dist/rig2d/three/index.d.cts +63 -0
- package/dist/rig2d/three/index.d.ts +63 -0
- package/dist/rig2d/three/index.js +1 -0
- package/dist/thumbnail-BhGEEXux.d.cts +49 -0
- package/dist/thumbnail-Bp-jK70T.d.ts +49 -0
- package/dist/voxel/index.cjs +54 -0
- package/dist/voxel/index.d.cts +972 -0
- package/dist/voxel/index.d.ts +972 -0
- package/dist/voxel/index.js +54 -0
- package/package.json +101 -4
|
@@ -0,0 +1,972 @@
|
|
|
1
|
+
import * as THREE from 'three';
|
|
2
|
+
import { V as Viseme, E as Emotion, d as ActorPose, A as ActorSocket } from '../contract-DhZuKNIf.cjs';
|
|
3
|
+
export { e as EMOTIONS, i as isEmotion } from '../contract-DhZuKNIf.cjs';
|
|
4
|
+
import { R as RGBAImage } from '../image-D5NaQeFz.cjs';
|
|
5
|
+
|
|
6
|
+
type V3 = [number, number, number];
|
|
7
|
+
/**
|
|
8
|
+
* Роль кости — то, к чему обращаются анимации. Анимация «шаг» двигает legL/legR у любого
|
|
9
|
+
* персонажа, в каком бы файле ни был описан его скелет; свои кости персонажа (хвост, уши, плащ)
|
|
10
|
+
* получают вторичную анимацию по роли.
|
|
11
|
+
*/
|
|
12
|
+
declare const BONE_ROLES: readonly ["root", "body", "head", "armL", "armR", "legL", "legR", "legFL", "legFR", "legBL", "legBR", "tail", "wingL", "wingR", "ear", "hair", "cape", "antenna", "static"];
|
|
13
|
+
type BoneRole = (typeof BONE_ROLES)[number];
|
|
14
|
+
/** Роли, которые можно дать СВОЕЙ кости рецепта (основные задаёт шаблон). */
|
|
15
|
+
declare const EXTRA_BONE_ROLES: readonly ["tail", "wingL", "wingR", "ear", "hair", "cape", "antenna", "static"];
|
|
16
|
+
type ExtraBoneRole = (typeof EXTRA_BONE_ROLES)[number];
|
|
17
|
+
/**
|
|
18
|
+
* Сокет — точка, к которой крепится предмет или одежда: рука, макушка, спина… Пояс, плечи и лицо
|
|
19
|
+
* — для надеваемого (character/items).
|
|
20
|
+
*/
|
|
21
|
+
declare const SOCKETS: readonly ["handR", "handL", "headTop", "face", "back", "waist", "shoulders"];
|
|
22
|
+
type SocketName = (typeof SOCKETS)[number];
|
|
23
|
+
interface RigBone {
|
|
24
|
+
name: string;
|
|
25
|
+
role: BoneRole;
|
|
26
|
+
/** Родитель; null — корень модели (ступни). */
|
|
27
|
+
parent: string | null;
|
|
28
|
+
/** Точка вращения в пикселях модели. */
|
|
29
|
+
pivot: V3;
|
|
30
|
+
}
|
|
31
|
+
interface RigSocket {
|
|
32
|
+
name: SocketName;
|
|
33
|
+
bone: string;
|
|
34
|
+
/** Где в пикселях модели (поворачивается вместе с костью). */
|
|
35
|
+
at: V3;
|
|
36
|
+
}
|
|
37
|
+
declare const RIG_IDS: readonly ["humanoid", "quadruped", "flyer", "blob"];
|
|
38
|
+
type RigId = (typeof RIG_IDS)[number];
|
|
39
|
+
interface RigTemplate {
|
|
40
|
+
id: RigId;
|
|
41
|
+
/** Подпись в студии. */
|
|
42
|
+
label: string;
|
|
43
|
+
/** Подсказка модели: кто подходит под шаблон. */
|
|
44
|
+
hint: string;
|
|
45
|
+
bones: RigBone[];
|
|
46
|
+
sockets: RigSocket[];
|
|
47
|
+
/** Хитбокс NPC/моба в блоках (игрок — всегда 0.6×1.8). */
|
|
48
|
+
hitbox: {
|
|
49
|
+
w: number;
|
|
50
|
+
h: number;
|
|
51
|
+
};
|
|
52
|
+
/** Высота глаз в пикселях — куда смотрит камера от третьего лица и откуда «говорит» NPC. */
|
|
53
|
+
eye: number;
|
|
54
|
+
/** Пределы роста модели в пикселях (рецепт за ними масштабируется). */
|
|
55
|
+
height: {
|
|
56
|
+
min: number;
|
|
57
|
+
max: number;
|
|
58
|
+
};
|
|
59
|
+
/** Тело по умолчанию: персонаж без деталей и путь без ИИ. */
|
|
60
|
+
defaultParts: CharPart[];
|
|
61
|
+
/** Кость с лицом. */
|
|
62
|
+
faceBone: string;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
declare const RIGS: Record<RigId, RigTemplate>;
|
|
66
|
+
|
|
67
|
+
declare const CHARACTER_SPEC_VERSION: 1;
|
|
68
|
+
/** Грани коробки: front смотрит туда же, куда лицо (−z), left — на левую руку персонажа (−x). */
|
|
69
|
+
declare const FACE_NAMES: readonly ["front", "back", "left", "right", "top", "bottom"];
|
|
70
|
+
type FaceName = (typeof FACE_NAMES)[number];
|
|
71
|
+
/**
|
|
72
|
+
* Выражения лица. Обязательно только neutral — остальные, если их нет, берутся по цепочке замен
|
|
73
|
+
* (anim/emotions.ts): «испуган» без своей картинки — «удивлён», без неё — обычное лицо.
|
|
74
|
+
*/
|
|
75
|
+
declare const EXPRESSIONS: readonly ["neutral", "blink", "happy", "sad", "angry", "surprised", "scared", "tired", "hurt", "talk"];
|
|
76
|
+
type Expression = (typeof EXPRESSIONS)[number];
|
|
77
|
+
declare const WALK_STYLES: readonly ["normal", "bouncy", "heavy", "sneaky", "robotic"];
|
|
78
|
+
type WalkStyle = (typeof WALK_STYLES)[number];
|
|
79
|
+
declare const IDLE_STYLES: readonly ["calm", "fidgety", "proud"];
|
|
80
|
+
type IdleStyle = (typeof IDLE_STYLES)[number];
|
|
81
|
+
declare const CHARACTER_LIMITS: {
|
|
82
|
+
readonly parts: 64;
|
|
83
|
+
readonly bones: 16;
|
|
84
|
+
readonly palette: 32;
|
|
85
|
+
readonly textures: 48;
|
|
86
|
+
/** Всего пикселей во всех текстурах. */
|
|
87
|
+
readonly texturePixels: 32768;
|
|
88
|
+
/** Сторона одной текстуры. */
|
|
89
|
+
readonly textureSide: 32;
|
|
90
|
+
/** Сторона коробки и координаты — в пикселях модели. */
|
|
91
|
+
readonly partSide: 32;
|
|
92
|
+
readonly coord: 64;
|
|
93
|
+
};
|
|
94
|
+
/** Картинка из символов палитры; "." и пробел — прозрачно. rows[0] — верхняя строка. */
|
|
95
|
+
interface PixelTex {
|
|
96
|
+
w: number;
|
|
97
|
+
h: number;
|
|
98
|
+
rows: string[];
|
|
99
|
+
}
|
|
100
|
+
interface CharPart {
|
|
101
|
+
/** Кость, вместе с которой двигается коробка. */
|
|
102
|
+
bone: string;
|
|
103
|
+
/** [ширина x, высота y, глубина z] в пикселях. */
|
|
104
|
+
size: V3;
|
|
105
|
+
/** Центр коробки в пикселях модели. */
|
|
106
|
+
pos: V3;
|
|
107
|
+
/** Символ палитры — цвет граней без своей текстуры. */
|
|
108
|
+
color: string;
|
|
109
|
+
/** Грань → id текстуры или символ палитры. */
|
|
110
|
+
faces?: Partial<Record<FaceName, string>>;
|
|
111
|
+
/** Поворот коробки вокруг её центра, градусы [x, y, z]. */
|
|
112
|
+
rot?: V3;
|
|
113
|
+
/** Ещё одна такая же коробка зеркально по x (на парную кость: armL ↔ armR). */
|
|
114
|
+
mirror?: boolean;
|
|
115
|
+
name?: string;
|
|
116
|
+
}
|
|
117
|
+
/** Своя кость рецепта: хвост, уши, плащ… Или новая точка вращения кости шаблона (то же имя). */
|
|
118
|
+
interface ExtraBone {
|
|
119
|
+
name: string;
|
|
120
|
+
parent: string;
|
|
121
|
+
pivot: V3;
|
|
122
|
+
role: ExtraBoneRole;
|
|
123
|
+
}
|
|
124
|
+
interface FaceSpec {
|
|
125
|
+
/** Кость с лицом (по умолчанию — голова шаблона). */
|
|
126
|
+
bone: string;
|
|
127
|
+
/**
|
|
128
|
+
* Где на передней грани главной коробки кости: [x, y, w, h] в пикселях, от левого верхнего угла
|
|
129
|
+
* так, как лицо видит смотрящий на персонажа.
|
|
130
|
+
*/
|
|
131
|
+
rect: [number, number, number, number];
|
|
132
|
+
/** Выражение → id текстуры размером w×h. */
|
|
133
|
+
expressions: Partial<Record<Expression, string>>;
|
|
134
|
+
}
|
|
135
|
+
interface CharStyle {
|
|
136
|
+
walk: WalkStyle;
|
|
137
|
+
idle: IdleStyle;
|
|
138
|
+
/** 0 — вялый, 1 — заводной: темп и размах движений. */
|
|
139
|
+
energy: number;
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* Отделка граней — то, что превращает плоские цвета в «ткань» (как на референсе владельца
|
|
143
|
+
* 11.10.2026): мелкий шум и пятна, тёмный контур по краю каждой грани, светотень сверху вниз.
|
|
144
|
+
* Применяется к каждой грани при сборке (character/layout); модель ИИ задаёт только силу.
|
|
145
|
+
*/
|
|
146
|
+
interface CharFinish {
|
|
147
|
+
/** Шум ткани 0..1. */
|
|
148
|
+
noise: number;
|
|
149
|
+
/** Тёмный контур по краю грани 0..1. */
|
|
150
|
+
outline: number;
|
|
151
|
+
/** Светотень: верх светлее, низ темнее 0..1. */
|
|
152
|
+
shade: number;
|
|
153
|
+
/** Текселей на пиксель модели у граней без своей картинки (1..4). */
|
|
154
|
+
density: number;
|
|
155
|
+
}
|
|
156
|
+
declare const DEFAULT_FINISH: CharFinish;
|
|
157
|
+
interface CharacterSpec {
|
|
158
|
+
version: typeof CHARACTER_SPEC_VERSION;
|
|
159
|
+
name: string;
|
|
160
|
+
description: string;
|
|
161
|
+
rig: RigId;
|
|
162
|
+
/** Масштаб модели (рост NPC и мобов; игроку — в пределах 0.8–1.15). */
|
|
163
|
+
scale: number;
|
|
164
|
+
/** Символ → "#rrggbb". */
|
|
165
|
+
palette: Record<string, string>;
|
|
166
|
+
textures: Record<string, PixelTex>;
|
|
167
|
+
parts: CharPart[];
|
|
168
|
+
bones: ExtraBone[];
|
|
169
|
+
face: FaceSpec | null;
|
|
170
|
+
style: CharStyle;
|
|
171
|
+
/** Высота голоса (звуки, будущая речь NPC). */
|
|
172
|
+
voice: {
|
|
173
|
+
pitch: number;
|
|
174
|
+
};
|
|
175
|
+
/** Метки для поиска и будущего поведения NPC ("friendly", "merchant"…). */
|
|
176
|
+
tags: string[];
|
|
177
|
+
finish: CharFinish;
|
|
178
|
+
}
|
|
179
|
+
type CharacterParseResult = {
|
|
180
|
+
ok: true;
|
|
181
|
+
spec: CharacterSpec;
|
|
182
|
+
warnings: string[];
|
|
183
|
+
} | {
|
|
184
|
+
ok: false;
|
|
185
|
+
error: string;
|
|
186
|
+
truncated?: boolean;
|
|
187
|
+
};
|
|
188
|
+
type Obj = Record<string, unknown>;
|
|
189
|
+
declare const isObj: (v: unknown) => v is Obj;
|
|
190
|
+
declare function num(v: unknown, def: number, min: number, max: number): number;
|
|
191
|
+
declare function pick<T extends string>(v: unknown, allowed: readonly T[], def: T): T;
|
|
192
|
+
declare function vec3(v: unknown, lim: number, def?: V3 | null): V3 | null;
|
|
193
|
+
/** "#abc", "#aabbcc", "aabbcc", имя цвета → "#aabbcc"; иначе null. */
|
|
194
|
+
declare function normColor(v: unknown): string | null;
|
|
195
|
+
/** Прозрачные символы пиксель-арта. */
|
|
196
|
+
declare const CLEAR: Set<string>;
|
|
197
|
+
/** Парная кость: armL ↔ armR, legFL ↔ legFR, earL ↔ earR; нет пары — та же. */
|
|
198
|
+
declare function mirrorBone(name: string, exists: (n: string) => boolean): string;
|
|
199
|
+
/**
|
|
200
|
+
* Единственная дверь в игру для рецепта персонажа: объект или текст ответа модели → нормализованный
|
|
201
|
+
* рецепт. Отказ — только если это не объект или оборванный JSON.
|
|
202
|
+
*/
|
|
203
|
+
declare function parseCharacterSpec(input: unknown): CharacterParseResult;
|
|
204
|
+
/** Цвета тела шаблона по умолчанию: s — кожа/голова, t — туловище, p — ноги. */
|
|
205
|
+
declare const DEFAULT_COLORS: Record<string, string>;
|
|
206
|
+
/** JSON с отсортированными ключами: одинаковый рецепт → одинаковая строка (и хэш). */
|
|
207
|
+
declare function stableStringify(v: unknown): string;
|
|
208
|
+
/** Хэш рецепта (16 hex): ключ кэша модели, сетевой «облик», id своего моба. */
|
|
209
|
+
declare function specHash(spec: unknown): string;
|
|
210
|
+
/** Шаблон рецепта. */
|
|
211
|
+
declare function rigOfSpec(spec: CharacterSpec): RigTemplate;
|
|
212
|
+
/** Все кости рецепта (шаблон + свои) с итоговыми точками вращения и ролями. */
|
|
213
|
+
declare function bonesOf(spec: CharacterSpec): {
|
|
214
|
+
name: string;
|
|
215
|
+
role: string;
|
|
216
|
+
parent: string | null;
|
|
217
|
+
pivot: V3;
|
|
218
|
+
}[];
|
|
219
|
+
/** Имя персонажа без имени — на языке игры; Мастерская узнаёт его на обоих языках. */
|
|
220
|
+
declare function defaultCharacterName(): string;
|
|
221
|
+
/** Это имя по умолчанию (на любом языке)? */
|
|
222
|
+
declare const isDefaultCharacterName: (n: string) => boolean;
|
|
223
|
+
|
|
224
|
+
interface BoneGeo {
|
|
225
|
+
name: string;
|
|
226
|
+
role: string;
|
|
227
|
+
parent: string | null;
|
|
228
|
+
/** Точка вращения в пикселях модели. */
|
|
229
|
+
pivot: V3;
|
|
230
|
+
/** Вершины относительно pivot, пиксели. */
|
|
231
|
+
positions: Float32Array;
|
|
232
|
+
normals: Float32Array;
|
|
233
|
+
uvs: Float32Array;
|
|
234
|
+
indices: Uint16Array;
|
|
235
|
+
}
|
|
236
|
+
interface FaceDecal {
|
|
237
|
+
bone: string;
|
|
238
|
+
/** 4 угла квада (TL, TR, BR, BL снаружи) относительно pivot кости, пиксели. */
|
|
239
|
+
corners: Float32Array;
|
|
240
|
+
/** Выражение → [u0, v0, u1, v1] в атласе. */
|
|
241
|
+
uv: Partial<Record<Expression, [number, number, number, number]>>;
|
|
242
|
+
}
|
|
243
|
+
interface CharacterLayout {
|
|
244
|
+
hash: string;
|
|
245
|
+
rig: CharacterSpec["rig"];
|
|
246
|
+
bones: BoneGeo[];
|
|
247
|
+
atlas: {
|
|
248
|
+
w: number;
|
|
249
|
+
h: number;
|
|
250
|
+
data: Uint8Array;
|
|
251
|
+
};
|
|
252
|
+
face: FaceDecal | null;
|
|
253
|
+
/** Сокеты относительно pivot своей кости, пиксели. */
|
|
254
|
+
sockets: {
|
|
255
|
+
name: SocketName;
|
|
256
|
+
bone: string;
|
|
257
|
+
at: V3;
|
|
258
|
+
}[];
|
|
259
|
+
/** Рост модели (верх самой высокой коробки), пиксели. */
|
|
260
|
+
height: number;
|
|
261
|
+
/** Множитель пикселей модели: масштаб рецепта × подгонка роста под пределы шаблона. */
|
|
262
|
+
scale: number;
|
|
263
|
+
/** Высота глаз, пиксели модели. */
|
|
264
|
+
eye: number;
|
|
265
|
+
}
|
|
266
|
+
declare function layoutCharacter(spec: CharacterSpec): CharacterLayout;
|
|
267
|
+
|
|
268
|
+
interface CharacterAsset {
|
|
269
|
+
readonly layout: CharacterLayout;
|
|
270
|
+
/** Кость → геометрия (у кости без коробок — null). */
|
|
271
|
+
readonly geometries: Map<string, THREE.BufferGeometry | null>;
|
|
272
|
+
readonly texture: THREE.DataTexture;
|
|
273
|
+
refs: number;
|
|
274
|
+
}
|
|
275
|
+
/** Ресурсы рецепта (общие для всех персонажей с тем же рецептом). Отдать — releaseCharacter. */
|
|
276
|
+
declare function acquireCharacter(spec: CharacterSpec): CharacterAsset;
|
|
277
|
+
declare function releaseCharacter(a: CharacterAsset): void;
|
|
278
|
+
|
|
279
|
+
declare const CH: {
|
|
280
|
+
readonly rx: 0;
|
|
281
|
+
readonly ry: 1;
|
|
282
|
+
readonly rz: 2;
|
|
283
|
+
readonly px: 3;
|
|
284
|
+
readonly py: 4;
|
|
285
|
+
readonly pz: 5;
|
|
286
|
+
readonly sx: 6;
|
|
287
|
+
readonly sy: 7;
|
|
288
|
+
readonly sz: 8;
|
|
289
|
+
};
|
|
290
|
+
type Channel = keyof typeof CH;
|
|
291
|
+
declare const CHANNELS: Channel[];
|
|
292
|
+
/** Значения покоя каналов (масштаб — 1). */
|
|
293
|
+
declare const REST: readonly [0, 0, 0, 0, 0, 0, 1, 1, 1];
|
|
294
|
+
/** Поза: роль → 9 каналов. Нет роли — кость в покое. */
|
|
295
|
+
type Pose = Map<string, Float64Array>;
|
|
296
|
+
declare function bone(pose: Pose, role: string): Float64Array;
|
|
297
|
+
/** Прибавить к каналу (масштаб — умножить). */
|
|
298
|
+
declare function add(pose: Pose, role: string, ch: Channel, v: number): void;
|
|
299
|
+
declare function setCh(pose: Pose, role: string, ch: Channel, v: number): void;
|
|
300
|
+
declare function clearPose(pose: Pose): void;
|
|
301
|
+
/** out = a + (b − a)·w по всем ролям обеих поз (нет роли — покой). */
|
|
302
|
+
declare function lerpPose(out: Pose, a: Pose, b: Pose, w: number): void;
|
|
303
|
+
declare function copyPose(out: Pose, src: Pose): void;
|
|
304
|
+
/** Что персонаж держит — от этого поза руки и действия (лук натягивают, щит держат). */
|
|
305
|
+
declare const HELD_KINDS: readonly ["none", "block", "tool", "sword", "bow", "shield", "food", "staff", "item"];
|
|
306
|
+
type HeldKind = (typeof HELD_KINDS)[number];
|
|
307
|
+
/** Действие «держать ПКМ». */
|
|
308
|
+
type UseAction = "eat" | "drink" | "draw" | "block";
|
|
309
|
+
/**
|
|
310
|
+
* Всё, что анимация знает о персонаже за кадр. Заполняют: свой игрок (Player), сетевой
|
|
311
|
+
* (RemotePlayer по позе), NPC и моб. Новое состояние игры — новое поле здесь, потребители не
|
|
312
|
+
* меняются: у кого поля нет, у того оно в значении по умолчанию (newAnimInput).
|
|
313
|
+
*/
|
|
314
|
+
interface AnimInput {
|
|
315
|
+
/** Горизонтальная скорость, блоков/с. */
|
|
316
|
+
speed: number;
|
|
317
|
+
/** Вертикальная скорость, блоков/с. */
|
|
318
|
+
vy: number;
|
|
319
|
+
onGround: boolean;
|
|
320
|
+
inWater: boolean;
|
|
321
|
+
flying: boolean;
|
|
322
|
+
gliding: boolean;
|
|
323
|
+
sneaking: boolean;
|
|
324
|
+
sprinting: boolean;
|
|
325
|
+
riding: boolean;
|
|
326
|
+
sitting: boolean;
|
|
327
|
+
sleeping: boolean;
|
|
328
|
+
dead: boolean;
|
|
329
|
+
/** Голова относительно тела: поворот (влево +) и наклон (вверх +), радианы. */
|
|
330
|
+
lookYaw: number;
|
|
331
|
+
lookPitch: number;
|
|
332
|
+
/** Скорость поворота тела, рад/с (вторичное качание хвоста и плаща). */
|
|
333
|
+
yawRate: number;
|
|
334
|
+
held: HeldKind;
|
|
335
|
+
use: UseAction | null;
|
|
336
|
+
/** Говорит — рот открывается (речь ИИ-NPC, чат). */
|
|
337
|
+
talk: boolean;
|
|
338
|
+
/** Форма рта по тексту реплики (ролик, lipsync); задана — вместо `talk`. */
|
|
339
|
+
viseme?: Viseme;
|
|
340
|
+
}
|
|
341
|
+
declare function newAnimInput(): AnimInput;
|
|
342
|
+
/** Разовые события кадра: замах, удар по персонажу, приземление… */
|
|
343
|
+
declare const ANIM_EVENTS: readonly ["swing", "hurt", "place", "land", "jump", "throw"];
|
|
344
|
+
type AnimEvent = (typeof ANIM_EVENTS)[number];
|
|
345
|
+
|
|
346
|
+
interface CharacterViewOptions {
|
|
347
|
+
/** Табличка с именем над головой (сетевые игроки, NPC). */
|
|
348
|
+
name?: string | null;
|
|
349
|
+
/** Отбрасывает тень (дальние персонажи — нет). */
|
|
350
|
+
shadows?: boolean;
|
|
351
|
+
/** Слой рендера (кукла в инвентаре рисуется отдельной сценой — не нужен). */
|
|
352
|
+
layer?: number;
|
|
353
|
+
}
|
|
354
|
+
declare class CharacterView {
|
|
355
|
+
readonly group: THREE.Group<THREE.Object3DEventMap>;
|
|
356
|
+
private readonly root;
|
|
357
|
+
private asset;
|
|
358
|
+
spec: CharacterSpec;
|
|
359
|
+
private bones;
|
|
360
|
+
/** Кости по ролям (у одной роли может быть несколько костей: два уха). */
|
|
361
|
+
private byRole;
|
|
362
|
+
private meshes;
|
|
363
|
+
private readonly material;
|
|
364
|
+
private readonly decalMat;
|
|
365
|
+
private decal;
|
|
366
|
+
private expression;
|
|
367
|
+
private readonly sockets;
|
|
368
|
+
/** То, что висит на сокетах — переживает смену рецепта. */
|
|
369
|
+
private readonly attached;
|
|
370
|
+
private label;
|
|
371
|
+
private shadows;
|
|
372
|
+
private readonly layer;
|
|
373
|
+
private brightness;
|
|
374
|
+
constructor(spec?: CharacterSpec, opts?: CharacterViewOptions);
|
|
375
|
+
/** Рост модели в блоках. */
|
|
376
|
+
get height(): number;
|
|
377
|
+
/** Высота глаз в блоках. */
|
|
378
|
+
get eye(): number;
|
|
379
|
+
/** Какие выражения нарисованы в рецепте (для аниматора). */
|
|
380
|
+
get expressions(): Expression[];
|
|
381
|
+
get hash(): string;
|
|
382
|
+
/** Подменить рецепт (облик пришёл по сети, игрок сменил персонажа). Одежда и предметы остаются. */
|
|
383
|
+
setSpec(spec: CharacterSpec): void;
|
|
384
|
+
private build;
|
|
385
|
+
/** Снять всё, кроме того, что висит на сокетах (его переносит build). */
|
|
386
|
+
private clear;
|
|
387
|
+
applyPose(pose: Pose): void;
|
|
388
|
+
setExpression(e: Expression): void;
|
|
389
|
+
/** Свет места (как у мобов: пещера темнее). */
|
|
390
|
+
setBrightness(b: number): void;
|
|
391
|
+
/** Вспышка урона и прочие подсветки: 0 — без подсветки. */
|
|
392
|
+
setEmissive(hex: number): void;
|
|
393
|
+
setShadows(on: boolean): void;
|
|
394
|
+
/** Повесить предмет/одежду на сокет (координаты объекта — в блоках). null — снять. */
|
|
395
|
+
attach(socket: SocketName, obj: THREE.Object3D | null): void;
|
|
396
|
+
attachedAt(socket: SocketName): THREE.Object3D | null;
|
|
397
|
+
setName(name: string | null): void;
|
|
398
|
+
setLabelVisible(on: boolean): void;
|
|
399
|
+
private placeLabel;
|
|
400
|
+
/** Все меши модели (кукла инвентаря красит их в свой слой). */
|
|
401
|
+
forEachMesh(fn: (m: THREE.Mesh) => void): void;
|
|
402
|
+
dispose(): void;
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
/** Основные цвета «Путника» — остальные оттенки выводятся из них. */
|
|
406
|
+
interface LookColors {
|
|
407
|
+
skin?: string;
|
|
408
|
+
hair?: string;
|
|
409
|
+
shirt?: string;
|
|
410
|
+
pants?: string;
|
|
411
|
+
boots?: string;
|
|
412
|
+
eyes?: string;
|
|
413
|
+
}
|
|
414
|
+
/** Перекрасить палитру «Путника»: базовый цвет и согласованные с ним оттенки. */
|
|
415
|
+
declare function recolor(palette: Record<string, string>, c: LookColors): Record<string, string>;
|
|
416
|
+
declare const HUMAN_TOPS: readonly ["shirt", "tee", "sweater"];
|
|
417
|
+
declare const HUMAN_BOTTOMS: readonly ["pants", "shorts"];
|
|
418
|
+
declare const HUMAN_SHOES: readonly ["boots", "sneakers"];
|
|
419
|
+
declare const HUMAN_HAIR: readonly ["short", "long", "curly", "none"];
|
|
420
|
+
/** Наряд человека из набора частей — разнообразие NPC и основа пути без ИИ. */
|
|
421
|
+
interface HumanLook {
|
|
422
|
+
top?: (typeof HUMAN_TOPS)[number];
|
|
423
|
+
bottom?: (typeof HUMAN_BOTTOMS)[number];
|
|
424
|
+
shoes?: (typeof HUMAN_SHOES)[number];
|
|
425
|
+
hair?: (typeof HUMAN_HAIR)[number];
|
|
426
|
+
hat?: boolean;
|
|
427
|
+
colors?: LookColors & {
|
|
428
|
+
hat?: string;
|
|
429
|
+
};
|
|
430
|
+
name?: string;
|
|
431
|
+
description?: string;
|
|
432
|
+
tags?: string[];
|
|
433
|
+
}
|
|
434
|
+
/** Рецепт человека в детальном стиле: голова, волосы, нос, наряд, обувь, по желанию шляпа. */
|
|
435
|
+
declare function humanSource(look?: HumanLook): {
|
|
436
|
+
version: number;
|
|
437
|
+
name: string;
|
|
438
|
+
description: string;
|
|
439
|
+
rig: string;
|
|
440
|
+
palette: Record<string, string>;
|
|
441
|
+
textures: Record<string, PixelTex>;
|
|
442
|
+
parts: Record<string, unknown>[];
|
|
443
|
+
face: {
|
|
444
|
+
bone: string;
|
|
445
|
+
rect: number[];
|
|
446
|
+
expressions: {
|
|
447
|
+
neutral: string;
|
|
448
|
+
blink: string;
|
|
449
|
+
happy: string;
|
|
450
|
+
sad: string;
|
|
451
|
+
angry: string;
|
|
452
|
+
surprised: string;
|
|
453
|
+
scared: string;
|
|
454
|
+
tired: string;
|
|
455
|
+
hurt: string;
|
|
456
|
+
talk: string;
|
|
457
|
+
};
|
|
458
|
+
};
|
|
459
|
+
style: {
|
|
460
|
+
walk: string;
|
|
461
|
+
idle: string;
|
|
462
|
+
energy: number;
|
|
463
|
+
};
|
|
464
|
+
finish: {
|
|
465
|
+
noise: number;
|
|
466
|
+
outline: number;
|
|
467
|
+
shade: number;
|
|
468
|
+
density: number;
|
|
469
|
+
};
|
|
470
|
+
tags: string[];
|
|
471
|
+
};
|
|
472
|
+
/**
|
|
473
|
+
* Лицо «Путника» для любого рецепта: текстуры всех выражений (16×10, тот же рисунок глаз, бровей и
|
|
474
|
+
* рта) и FaceSpec на прямоугольник `rect` передней грани кости `bone`. Цвета лица — символы палитры
|
|
475
|
+
* k (брови), w (белки), b (радужка), m (губы), o (открытый рот).
|
|
476
|
+
*/
|
|
477
|
+
declare function standardFace(bone: string, rect: [number, number, number, number]): {
|
|
478
|
+
textures: {
|
|
479
|
+
[k: string]: PixelTex;
|
|
480
|
+
};
|
|
481
|
+
face: {
|
|
482
|
+
bone: string;
|
|
483
|
+
rect: [number, number, number, number];
|
|
484
|
+
expressions: {
|
|
485
|
+
neutral: string;
|
|
486
|
+
blink: string;
|
|
487
|
+
happy: string;
|
|
488
|
+
sad: string;
|
|
489
|
+
angry: string;
|
|
490
|
+
surprised: string;
|
|
491
|
+
scared: string;
|
|
492
|
+
tired: string;
|
|
493
|
+
hurt: string;
|
|
494
|
+
talk: string;
|
|
495
|
+
};
|
|
496
|
+
};
|
|
497
|
+
};
|
|
498
|
+
declare const DEFAULT_CHARACTER_SOURCE: {
|
|
499
|
+
version: number;
|
|
500
|
+
name: string;
|
|
501
|
+
description: string;
|
|
502
|
+
rig: string;
|
|
503
|
+
palette: Record<string, string>;
|
|
504
|
+
textures: Record<string, PixelTex>;
|
|
505
|
+
parts: Record<string, unknown>[];
|
|
506
|
+
face: {
|
|
507
|
+
bone: string;
|
|
508
|
+
rect: number[];
|
|
509
|
+
expressions: {
|
|
510
|
+
neutral: string;
|
|
511
|
+
blink: string;
|
|
512
|
+
happy: string;
|
|
513
|
+
sad: string;
|
|
514
|
+
angry: string;
|
|
515
|
+
surprised: string;
|
|
516
|
+
scared: string;
|
|
517
|
+
tired: string;
|
|
518
|
+
hurt: string;
|
|
519
|
+
talk: string;
|
|
520
|
+
};
|
|
521
|
+
};
|
|
522
|
+
style: {
|
|
523
|
+
walk: string;
|
|
524
|
+
idle: string;
|
|
525
|
+
energy: number;
|
|
526
|
+
};
|
|
527
|
+
finish: {
|
|
528
|
+
noise: number;
|
|
529
|
+
outline: number;
|
|
530
|
+
shade: number;
|
|
531
|
+
density: number;
|
|
532
|
+
};
|
|
533
|
+
tags: string[];
|
|
534
|
+
};
|
|
535
|
+
/** Рецепт «Путника» (разобран один раз; не менять — отдавайте копию, если надо править). */
|
|
536
|
+
declare function defaultCharacter(): CharacterSpec;
|
|
537
|
+
|
|
538
|
+
declare class Art {
|
|
539
|
+
readonly w: number;
|
|
540
|
+
readonly h: number;
|
|
541
|
+
private readonly g;
|
|
542
|
+
constructor(w: number, h: number, fill?: string);
|
|
543
|
+
px(x: number, y: number, c: string): this;
|
|
544
|
+
rect(x: number, y: number, w: number, h: number, c: string): this;
|
|
545
|
+
/** Горизонтальная линия от x0 до x1 включительно. */
|
|
546
|
+
row(y: number, x0: number, x1: number, c: string): this;
|
|
547
|
+
/** Вертикальная линия от y0 до y1 включительно. */
|
|
548
|
+
col(x: number, y0: number, y1: number, c: string): this;
|
|
549
|
+
/** Каждая клетка, где f(x, y) — правда, получает цвет c (штриховка, пряди, блики). */
|
|
550
|
+
where(f: (x: number, y: number) => boolean, c: string): this;
|
|
551
|
+
/** Зеркальная копия по горизонтали (левая и правая грань одной коробки). */
|
|
552
|
+
flipped(): Art;
|
|
553
|
+
tex(): PixelTex;
|
|
554
|
+
}
|
|
555
|
+
|
|
556
|
+
declare function nameplate(text: string): THREE.Sprite;
|
|
557
|
+
declare function disposeNameplate(s: THREE.Sprite): void;
|
|
558
|
+
|
|
559
|
+
declare function registerCharacter(spec: CharacterSpec): string;
|
|
560
|
+
declare function characterOf(hash: unknown): CharacterSpec | undefined;
|
|
561
|
+
declare function characterSpecs(hashes: Iterable<string>): Record<string, CharacterSpec>;
|
|
562
|
+
/** Подписка: рецепт стал известен (дошёл по сети). Возвращает отписку. */
|
|
563
|
+
declare function onCharacterKnown(fn: (hash: string) => void): () => void;
|
|
564
|
+
|
|
565
|
+
declare function npcCharacter(name: string, role?: string, persona?: string): CharacterSpec;
|
|
566
|
+
|
|
567
|
+
type RGB = [number, number, number];
|
|
568
|
+
/** Цвета полос фигуры сверху вниз (доли высоты фигуры). */
|
|
569
|
+
declare function bandColors(img: RGBAImage, bands: readonly [number, number][]): (RGB | null)[];
|
|
570
|
+
/**
|
|
571
|
+
* Персонаж по картинке: человек — «Путник» в цветах картинки; другие шаблоны — их тело по
|
|
572
|
+
* умолчанию в цветах полос (верх — голова, середина — тело, низ — лапы).
|
|
573
|
+
*/
|
|
574
|
+
declare function characterFromImage(img: RGBAImage, rig?: RigId, name?: string): CharacterSpec;
|
|
575
|
+
|
|
576
|
+
/** Параметры походки из стиля рецепта. */
|
|
577
|
+
interface StyleParams {
|
|
578
|
+
/** Размах ног и рук. */
|
|
579
|
+
amp: number;
|
|
580
|
+
arm: number;
|
|
581
|
+
/** Подпрыгивание при шаге, пиксели. */
|
|
582
|
+
bob: number;
|
|
583
|
+
/** Темп шага. */
|
|
584
|
+
tempo: number;
|
|
585
|
+
/** Раскачка корпуса. */
|
|
586
|
+
sway: number;
|
|
587
|
+
/** Шаг рывками (робот). */
|
|
588
|
+
quant: boolean;
|
|
589
|
+
/** Дыхание, переминание, грудь колесом. */
|
|
590
|
+
breath: number;
|
|
591
|
+
fidget: number;
|
|
592
|
+
chest: number;
|
|
593
|
+
}
|
|
594
|
+
declare function styleParams(s: CharStyle): StyleParams;
|
|
595
|
+
interface ClipCtx {
|
|
596
|
+
/** Секунд в состоянии / с начала действия. */
|
|
597
|
+
t: number;
|
|
598
|
+
/** Доля действия 0..1 (у бесконечных — 0). */
|
|
599
|
+
k: number;
|
|
600
|
+
/** Фаза шага, радианы (растёт с пройденным путём). */
|
|
601
|
+
phase: number;
|
|
602
|
+
input: AnimInput;
|
|
603
|
+
style: StyleParams;
|
|
604
|
+
/** Время с создания аниматора — для дыхания и колыханий, которые не сбрасываются. */
|
|
605
|
+
clock: number;
|
|
606
|
+
}
|
|
607
|
+
type ClipFn = (out: Pose, c: ClipCtx) => void;
|
|
608
|
+
declare const CLIPS: {
|
|
609
|
+
idle: ClipFn;
|
|
610
|
+
walk: ClipFn;
|
|
611
|
+
run: ClipFn;
|
|
612
|
+
sneak: ClipFn;
|
|
613
|
+
swim: ClipFn;
|
|
614
|
+
fly: ClipFn;
|
|
615
|
+
glide: ClipFn;
|
|
616
|
+
fall: ClipFn;
|
|
617
|
+
sit: ClipFn;
|
|
618
|
+
ride: ClipFn;
|
|
619
|
+
sleep: ClipFn;
|
|
620
|
+
dead: ClipFn;
|
|
621
|
+
hop: ClipFn;
|
|
622
|
+
swing: ClipFn;
|
|
623
|
+
place: ClipFn;
|
|
624
|
+
throw: ClipFn;
|
|
625
|
+
hurt: ClipFn;
|
|
626
|
+
land: ClipFn;
|
|
627
|
+
eat: ClipFn;
|
|
628
|
+
drink: ClipFn;
|
|
629
|
+
draw: ClipFn;
|
|
630
|
+
block: ClipFn;
|
|
631
|
+
};
|
|
632
|
+
type ClipId = keyof typeof CLIPS;
|
|
633
|
+
/** Подмена клипа состояния для шаблона: у капли ходьба и бег — прыжки. */
|
|
634
|
+
declare const RIG_CLIPS: Partial<Record<RigId, Partial<Record<ClipId, ClipId>>>>;
|
|
635
|
+
/** Длительность разовых действий, с. */
|
|
636
|
+
declare const ACTION_TIME: Partial<Record<ClipId, number>>;
|
|
637
|
+
|
|
638
|
+
/** Какое выражение лица искать для эмоции — первое, что есть в рецепте. */
|
|
639
|
+
declare const EXPRESSION_CHAIN: Record<Emotion, Expression[]>;
|
|
640
|
+
interface Posture {
|
|
641
|
+
/** "роль.канал" → добавка. */
|
|
642
|
+
add: Partial<Record<string, number>>;
|
|
643
|
+
/** Множитель темпа движений. */
|
|
644
|
+
tempo: number;
|
|
645
|
+
}
|
|
646
|
+
declare const POSTURE: Record<Emotion, Posture>;
|
|
647
|
+
/** Добавить осанку эмоции к позе с весом w (переход между эмоциями плавный). */
|
|
648
|
+
declare function applyPosture(out: Pose, e: Emotion, w: number): void;
|
|
649
|
+
/**
|
|
650
|
+
* Игровые события → эмоция. seconds — вспышка на время; без seconds — фоновое настроение, пока
|
|
651
|
+
* условие держится. Таблица — данные: новое событие игры — строка здесь и emit в game/wire.
|
|
652
|
+
*/
|
|
653
|
+
declare const EMOTION_EVENTS: {
|
|
654
|
+
damaged: {
|
|
655
|
+
emotion: "hurt";
|
|
656
|
+
seconds: number;
|
|
657
|
+
};
|
|
658
|
+
lowHealth: {
|
|
659
|
+
emotion: "tired";
|
|
660
|
+
};
|
|
661
|
+
nearDeath: {
|
|
662
|
+
emotion: "scared";
|
|
663
|
+
};
|
|
664
|
+
achievement: {
|
|
665
|
+
emotion: "happy";
|
|
666
|
+
seconds: number;
|
|
667
|
+
};
|
|
668
|
+
bossKilled: {
|
|
669
|
+
emotion: "happy";
|
|
670
|
+
seconds: number;
|
|
671
|
+
};
|
|
672
|
+
tamed: {
|
|
673
|
+
emotion: "happy";
|
|
674
|
+
seconds: number;
|
|
675
|
+
};
|
|
676
|
+
traded: {
|
|
677
|
+
emotion: "happy";
|
|
678
|
+
seconds: number;
|
|
679
|
+
};
|
|
680
|
+
petDied: {
|
|
681
|
+
emotion: "sad";
|
|
682
|
+
seconds: number;
|
|
683
|
+
};
|
|
684
|
+
explosion: {
|
|
685
|
+
emotion: "surprised";
|
|
686
|
+
seconds: number;
|
|
687
|
+
};
|
|
688
|
+
};
|
|
689
|
+
type EmotionEvent = keyof typeof EMOTION_EVENTS;
|
|
690
|
+
/** Смайлик в сообщении чата → эмоция (последний найденный); null — нет смайликов. */
|
|
691
|
+
declare function emotionFromText(text: string): Emotion | null;
|
|
692
|
+
|
|
693
|
+
type Track = [number, number][];
|
|
694
|
+
interface EmoteDef {
|
|
695
|
+
label: string;
|
|
696
|
+
/** Длительность цикла, с. */
|
|
697
|
+
duration: number;
|
|
698
|
+
/** Повторяется, пока персонаж не двинется. */
|
|
699
|
+
loop?: boolean;
|
|
700
|
+
/** Лицо на время жеста. */
|
|
701
|
+
emotion?: Emotion;
|
|
702
|
+
/** "роль.канал" → ключи. */
|
|
703
|
+
tracks: Record<string, Track>;
|
|
704
|
+
}
|
|
705
|
+
declare const EMOTES: {
|
|
706
|
+
wave: {
|
|
707
|
+
label: string;
|
|
708
|
+
duration: number;
|
|
709
|
+
emotion: "happy";
|
|
710
|
+
tracks: {
|
|
711
|
+
"armR.rz": [number, number][];
|
|
712
|
+
"armR.rx": [number, number][];
|
|
713
|
+
"head.rz": [number, number][];
|
|
714
|
+
};
|
|
715
|
+
};
|
|
716
|
+
cheer: {
|
|
717
|
+
label: string;
|
|
718
|
+
duration: number;
|
|
719
|
+
emotion: "happy";
|
|
720
|
+
tracks: {
|
|
721
|
+
"armL.rz": [number, number][];
|
|
722
|
+
"armR.rz": [number, number][];
|
|
723
|
+
"root.py": [number, number][];
|
|
724
|
+
};
|
|
725
|
+
};
|
|
726
|
+
dance: {
|
|
727
|
+
label: string;
|
|
728
|
+
duration: number;
|
|
729
|
+
loop: true;
|
|
730
|
+
emotion: "happy";
|
|
731
|
+
tracks: {
|
|
732
|
+
"root.ry": [number, number][];
|
|
733
|
+
"armL.rz": [number, number][];
|
|
734
|
+
"armR.rz": [number, number][];
|
|
735
|
+
"legL.rx": [number, number][];
|
|
736
|
+
"legR.rx": [number, number][];
|
|
737
|
+
"root.py": [number, number][];
|
|
738
|
+
"tail.ry": [number, number][];
|
|
739
|
+
};
|
|
740
|
+
};
|
|
741
|
+
point: {
|
|
742
|
+
label: string;
|
|
743
|
+
duration: number;
|
|
744
|
+
tracks: {
|
|
745
|
+
"armR.rx": [number, number][];
|
|
746
|
+
};
|
|
747
|
+
};
|
|
748
|
+
laugh: {
|
|
749
|
+
label: string;
|
|
750
|
+
duration: number;
|
|
751
|
+
emotion: "happy";
|
|
752
|
+
tracks: {
|
|
753
|
+
"body.rx": [number, number][];
|
|
754
|
+
"head.rx": [number, number][];
|
|
755
|
+
"armL.rx": [number, number][];
|
|
756
|
+
"armR.rx": [number, number][];
|
|
757
|
+
};
|
|
758
|
+
};
|
|
759
|
+
cry: {
|
|
760
|
+
label: string;
|
|
761
|
+
duration: number;
|
|
762
|
+
emotion: "sad";
|
|
763
|
+
tracks: {
|
|
764
|
+
"head.rx": [number, number][];
|
|
765
|
+
"head.rz": [number, number][];
|
|
766
|
+
"armR.rx": [number, number][];
|
|
767
|
+
"armR.ry": [number, number][];
|
|
768
|
+
"armL.rx": [number, number][];
|
|
769
|
+
"armL.ry": [number, number][];
|
|
770
|
+
};
|
|
771
|
+
};
|
|
772
|
+
bow: {
|
|
773
|
+
label: string;
|
|
774
|
+
duration: number;
|
|
775
|
+
tracks: {
|
|
776
|
+
"body.rx": [number, number][];
|
|
777
|
+
"armR.rx": [number, number][];
|
|
778
|
+
};
|
|
779
|
+
};
|
|
780
|
+
shrug: {
|
|
781
|
+
label: string;
|
|
782
|
+
duration: number;
|
|
783
|
+
tracks: {
|
|
784
|
+
"armL.rz": [number, number][];
|
|
785
|
+
"armR.rz": [number, number][];
|
|
786
|
+
"armL.rx": [number, number][];
|
|
787
|
+
"armR.rx": [number, number][];
|
|
788
|
+
"head.rz": [number, number][];
|
|
789
|
+
};
|
|
790
|
+
};
|
|
791
|
+
facepalm: {
|
|
792
|
+
label: string;
|
|
793
|
+
duration: number;
|
|
794
|
+
emotion: "tired";
|
|
795
|
+
tracks: {
|
|
796
|
+
"armR.rx": [number, number][];
|
|
797
|
+
"armR.rz": [number, number][];
|
|
798
|
+
"head.rx": [number, number][];
|
|
799
|
+
};
|
|
800
|
+
};
|
|
801
|
+
sit: {
|
|
802
|
+
label: string;
|
|
803
|
+
duration: number;
|
|
804
|
+
loop: true;
|
|
805
|
+
tracks: {
|
|
806
|
+
"legL.rx": [number, number][];
|
|
807
|
+
"legR.rx": [number, number][];
|
|
808
|
+
"root.py": [number, number][];
|
|
809
|
+
};
|
|
810
|
+
};
|
|
811
|
+
};
|
|
812
|
+
type EmoteId = keyof typeof EMOTES;
|
|
813
|
+
declare const EMOTE_IDS: EmoteId[];
|
|
814
|
+
declare function isEmote(v: unknown): v is EmoteId;
|
|
815
|
+
/** Значение дорожки в момент t (между ключами — smoothstep). */
|
|
816
|
+
declare function sampleTrack(track: Track, t: number): number;
|
|
817
|
+
/** Поза жеста в момент t (у повторяющегося — по модулю длительности). */
|
|
818
|
+
declare function sampleEmote(out: Pose, def: EmoteDef, t: number): void;
|
|
819
|
+
|
|
820
|
+
type LocoState = "idle" | "walk" | "run" | "sneak" | "swim" | "fly" | "glide" | "fall" | "ride" | "sit" | "sleep" | "dead";
|
|
821
|
+
interface LocoRule {
|
|
822
|
+
state: LocoState;
|
|
823
|
+
when: (i: AnimInput, a: Animator) => boolean;
|
|
824
|
+
clip: ClipId;
|
|
825
|
+
/** Время перехода В это состояние, с. */
|
|
826
|
+
blend: number;
|
|
827
|
+
}
|
|
828
|
+
/** Граф передвижения: первое подходящее правило сверху. */
|
|
829
|
+
declare const LOCOMOTION: LocoRule[];
|
|
830
|
+
declare class Animator {
|
|
831
|
+
readonly rig: RigId;
|
|
832
|
+
private style;
|
|
833
|
+
/** Какие выражения нарисованы в рецепте. */
|
|
834
|
+
private readonly faces;
|
|
835
|
+
/** Итоговая поза кадра (роль → каналы). */
|
|
836
|
+
readonly pose: Pose;
|
|
837
|
+
/** Выражение лица кадра. */
|
|
838
|
+
expression: Expression;
|
|
839
|
+
state: LocoState;
|
|
840
|
+
private stateT;
|
|
841
|
+
private clock;
|
|
842
|
+
private phase;
|
|
843
|
+
airTime: number;
|
|
844
|
+
private wasOnGround;
|
|
845
|
+
private readonly loco;
|
|
846
|
+
private readonly from;
|
|
847
|
+
private readonly lastLoco;
|
|
848
|
+
private blendT;
|
|
849
|
+
private blendDur;
|
|
850
|
+
private readonly tmp;
|
|
851
|
+
private actions;
|
|
852
|
+
private useClip;
|
|
853
|
+
private useW;
|
|
854
|
+
private emote;
|
|
855
|
+
/** Фоновое настроение и вспышка поверх него. */
|
|
856
|
+
private mood;
|
|
857
|
+
private flash;
|
|
858
|
+
private readonly postureW;
|
|
859
|
+
private blinkT;
|
|
860
|
+
private blinking;
|
|
861
|
+
private talkT;
|
|
862
|
+
private readonly springs;
|
|
863
|
+
constructor(rig: RigId, style: CharStyle, faces?: Iterable<Expression>);
|
|
864
|
+
/** Источник случая для моргания (по умолчанию Math.random); ролик даёт сидированный — кадр
|
|
865
|
+
* одинаков при каждом рендере. */
|
|
866
|
+
setRandom(random: () => number): void;
|
|
867
|
+
private random;
|
|
868
|
+
setStyle(style: CharStyle): void;
|
|
869
|
+
/** Эмоция: с seconds — вспышка на время, без — настроение до следующей смены. */
|
|
870
|
+
setEmotion(e: Emotion, seconds?: number): void;
|
|
871
|
+
/** Эмоция, которую сейчас показывает персонаж. */
|
|
872
|
+
get emotion(): Emotion;
|
|
873
|
+
get emoting(): EmoteId | null;
|
|
874
|
+
playEmote(id: EmoteId): void;
|
|
875
|
+
stopEmote(): void;
|
|
876
|
+
/** Разовое событие: замах, удар по персонажу, приземление… */
|
|
877
|
+
trigger(ev: AnimEvent): void;
|
|
878
|
+
update(dt: number, input?: AnimInput): Pose;
|
|
879
|
+
/** Наложить позу: перекрыть роли с весом w или прибавить отклонения от покоя. */
|
|
880
|
+
private overlay;
|
|
881
|
+
/** Выражение лица: эмоция по цепочке замен, моргание, рот при разговоре. */
|
|
882
|
+
private face;
|
|
883
|
+
}
|
|
884
|
+
|
|
885
|
+
interface VoxelActorOptions extends CharacterViewOptions {
|
|
886
|
+
/** Сид случая (моргание). */
|
|
887
|
+
seed?: number;
|
|
888
|
+
}
|
|
889
|
+
declare class VoxelActor {
|
|
890
|
+
readonly view: CharacterView;
|
|
891
|
+
private animator;
|
|
892
|
+
private readonly input;
|
|
893
|
+
private readonly seed;
|
|
894
|
+
private pose;
|
|
895
|
+
private jumpT;
|
|
896
|
+
constructor(spec?: CharacterSpec, opts?: VoxelActorOptions);
|
|
897
|
+
get group(): THREE.Group;
|
|
898
|
+
/** Рост в единицах сцены (блоках). */
|
|
899
|
+
get height(): number;
|
|
900
|
+
setSpec(spec: CharacterSpec): void;
|
|
901
|
+
setEmotion(e: Emotion): void;
|
|
902
|
+
/** Форма рта по тексту реплики; "rest" — рот закрыт. */
|
|
903
|
+
setViseme(v: Viseme): void;
|
|
904
|
+
/** Поза контракта: состояние движения держится, жест играется один раз. */
|
|
905
|
+
setPose(pose: ActorPose): void;
|
|
906
|
+
playEmote(id: EmoteId): void;
|
|
907
|
+
/** Повесить пропс на сокет; null — снять. */
|
|
908
|
+
attach(socket: ActorSocket, obj: THREE.Object3D | null): void;
|
|
909
|
+
update(dt: number): void;
|
|
910
|
+
dispose(): void;
|
|
911
|
+
private newAnimator;
|
|
912
|
+
}
|
|
913
|
+
|
|
914
|
+
declare const VOXEL_CHARACTER_SYSTEM_PROMPT: string;
|
|
915
|
+
|
|
916
|
+
declare const CREATURE_KINDS: readonly ["cat", "dog", "fox", "bear", "rabbit", "bird", "dragon", "slime", "ghost", "robot"];
|
|
917
|
+
type CreatureKind = (typeof CREATURE_KINDS)[number];
|
|
918
|
+
interface CreatureLook {
|
|
919
|
+
kind: CreatureKind;
|
|
920
|
+
name: string;
|
|
921
|
+
description?: string;
|
|
922
|
+
/** Основной цвет, светлый (морда, живот) и акцент (уши, нос, лапы). */
|
|
923
|
+
body: string;
|
|
924
|
+
light?: string;
|
|
925
|
+
accent?: string;
|
|
926
|
+
eyes?: string;
|
|
927
|
+
tags?: string[];
|
|
928
|
+
}
|
|
929
|
+
type Part = Record<string, unknown>;
|
|
930
|
+
declare function creatureSource(look: CreatureLook): {
|
|
931
|
+
version: number;
|
|
932
|
+
name: string;
|
|
933
|
+
description: string;
|
|
934
|
+
rig: string;
|
|
935
|
+
palette: Record<string, string>;
|
|
936
|
+
textures: {
|
|
937
|
+
[k: string]: PixelTex;
|
|
938
|
+
};
|
|
939
|
+
parts: Part[];
|
|
940
|
+
face: {
|
|
941
|
+
bone: string;
|
|
942
|
+
rect: [number, number, number, number];
|
|
943
|
+
expressions: {
|
|
944
|
+
neutral: string;
|
|
945
|
+
blink: string;
|
|
946
|
+
happy: string;
|
|
947
|
+
sad: string;
|
|
948
|
+
angry: string;
|
|
949
|
+
surprised: string;
|
|
950
|
+
scared: string;
|
|
951
|
+
tired: string;
|
|
952
|
+
hurt: string;
|
|
953
|
+
talk: string;
|
|
954
|
+
};
|
|
955
|
+
};
|
|
956
|
+
style: {
|
|
957
|
+
walk: string;
|
|
958
|
+
idle: string;
|
|
959
|
+
energy: number;
|
|
960
|
+
};
|
|
961
|
+
finish: {
|
|
962
|
+
noise: number;
|
|
963
|
+
outline: number;
|
|
964
|
+
shade: number;
|
|
965
|
+
density: number;
|
|
966
|
+
};
|
|
967
|
+
tags: string[];
|
|
968
|
+
};
|
|
969
|
+
/** Разобранный рецепт существа; сломанный (не должно быть) — ошибка сразу, а не тихий «Путник». */
|
|
970
|
+
declare function creatureCharacter(look: CreatureLook): CharacterSpec;
|
|
971
|
+
|
|
972
|
+
export { ACTION_TIME, ANIM_EVENTS, type AnimEvent, type AnimInput, Animator, Art, BONE_ROLES, type BoneGeo, type BoneRole, CH, CHANNELS, CHARACTER_LIMITS, CHARACTER_SPEC_VERSION, CLEAR, CLIPS, CREATURE_KINDS, type Channel, type CharFinish, type CharPart, type CharStyle, type CharacterAsset, type CharacterLayout, type CharacterParseResult, type CharacterSpec, CharacterView, type CharacterViewOptions, type ClipCtx, type ClipFn, type ClipId, type CreatureKind, type CreatureLook, DEFAULT_CHARACTER_SOURCE, DEFAULT_COLORS, DEFAULT_FINISH, EMOTES, EMOTE_IDS, EMOTION_EVENTS, EXPRESSIONS, EXPRESSION_CHAIN, EXTRA_BONE_ROLES, type EmoteDef, type EmoteId, Emotion, type EmotionEvent, type Expression, type ExtraBone, type ExtraBoneRole, FACE_NAMES, type FaceDecal, type FaceName, type FaceSpec, HELD_KINDS, HUMAN_BOTTOMS, HUMAN_HAIR, HUMAN_SHOES, HUMAN_TOPS, type HeldKind, type HumanLook, IDLE_STYLES, type IdleStyle, LOCOMOTION, type LocoState, type LookColors, POSTURE, type PixelTex, type Pose, type Posture, REST, RIGS, RIG_CLIPS, RIG_IDS, type RigBone, type RigId, type RigSocket, type RigTemplate, SOCKETS, type SocketName, type StyleParams, type Track, type UseAction, type V3, VOXEL_CHARACTER_SYSTEM_PROMPT, VoxelActor, type VoxelActorOptions, WALK_STYLES, type WalkStyle, acquireCharacter, add, applyPosture, bandColors, bone, bonesOf, characterFromImage, characterOf, characterSpecs, clearPose, copyPose, creatureCharacter, creatureSource, defaultCharacter, defaultCharacterName, disposeNameplate, emotionFromText, humanSource, isDefaultCharacterName, isEmote, isObj, layoutCharacter, lerpPose, mirrorBone, nameplate, newAnimInput, normColor, npcCharacter, num, onCharacterKnown, parseCharacterSpec, pick, recolor, registerCharacter, releaseCharacter, rigOfSpec, sampleEmote, sampleTrack, setCh, specHash, stableStringify, standardFace, styleParams, vec3 };
|