@datamoc/mw_games 0.38.0 → 0.40.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/CHANGELOG.md +75 -0
- package/api-surface.json +500 -2
- package/data/microgm-opt.PROVENANCE.md +20 -0
- package/data/microgm-opt.sf2 +0 -0
- package/dist/assets/SvgParts.d.ts +31 -0
- package/dist/assets/SvgParts.d.ts.map +1 -0
- package/dist/assets/SvgParts.js +54 -0
- package/dist/assets/SvgParts.js.map +1 -0
- package/dist/assets/SvgSource.d.ts +3 -0
- package/dist/assets/SvgSource.d.ts.map +1 -0
- package/dist/assets/SvgSource.js +22 -0
- package/dist/assets/SvgSource.js.map +1 -0
- package/dist/assets/index.d.ts +2 -0
- package/dist/assets/index.d.ts.map +1 -1
- package/dist/assets/index.js +1 -0
- package/dist/assets/index.js.map +1 -1
- package/dist/assets/svg.d.ts.map +1 -1
- package/dist/assets/svg.js +9 -5
- package/dist/assets/svg.js.map +1 -1
- package/dist/mw_games.global.js +110 -110
- package/dist/mwl/presentation.d.ts.map +1 -1
- package/dist/mwl/presentation.js +25 -18
- package/dist/mwl/presentation.js.map +1 -1
- package/dist/physics/PhysicsWorld.d.ts +49 -17
- package/dist/physics/PhysicsWorld.d.ts.map +1 -1
- package/dist/physics/PhysicsWorld.js +297 -59
- package/dist/physics/PhysicsWorld.js.map +1 -1
- package/dist/physics/XpbdWorld.d.ts +1 -1
- package/dist/physics/XpbdWorld.js +1 -1
- package/dist/physics/cloth/index.d.ts +98 -0
- package/dist/physics/cloth/index.d.ts.map +1 -0
- package/dist/physics/cloth/index.js +207 -0
- package/dist/physics/cloth/index.js.map +1 -0
- package/dist/physics/index.d.ts +4 -0
- package/dist/physics/index.d.ts.map +1 -1
- package/dist/physics/index.js +2 -0
- package/dist/physics/index.js.map +1 -1
- package/dist/physics/spring/index.d.ts +90 -0
- package/dist/physics/spring/index.d.ts.map +1 -0
- package/dist/physics/spring/index.js +97 -0
- package/dist/physics/spring/index.js.map +1 -0
- package/dist/skeleton/index.d.ts +94 -13
- package/dist/skeleton/index.d.ts.map +1 -1
- package/dist/skeleton/index.js +192 -73
- package/dist/skeleton/index.js.map +1 -1
- package/dist/two-d/presentation/MwlPresentation.d.ts +12 -0
- package/dist/two-d/presentation/MwlPresentation.d.ts.map +1 -1
- package/dist/two-d/presentation/MwlPresentation.js +204 -153
- package/dist/two-d/presentation/MwlPresentation.js.map +1 -1
- package/dist/two-d/render/ClothSprite.d.ts +83 -0
- package/dist/two-d/render/ClothSprite.d.ts.map +1 -0
- package/dist/two-d/render/ClothSprite.js +105 -0
- package/dist/two-d/render/ClothSprite.js.map +1 -0
- package/dist/two-d/render/HazeLayer.d.ts +112 -0
- package/dist/two-d/render/HazeLayer.d.ts.map +1 -0
- package/dist/two-d/render/HazeLayer.js +185 -0
- package/dist/two-d/render/HazeLayer.js.map +1 -0
- package/dist/two-d/render/NeonGlow.d.ts +100 -0
- package/dist/two-d/render/NeonGlow.d.ts.map +1 -0
- package/dist/two-d/render/NeonGlow.js +183 -0
- package/dist/two-d/render/NeonGlow.js.map +1 -0
- package/dist/two-d/render/SkeletalSprite.d.ts +5 -2
- package/dist/two-d/render/SkeletalSprite.d.ts.map +1 -1
- package/dist/two-d/render/SkeletalSprite.js +27 -3
- package/dist/two-d/render/SkeletalSprite.js.map +1 -1
- package/dist/two-d/render/SpringSprite.d.ts +40 -0
- package/dist/two-d/render/SpringSprite.d.ts.map +1 -0
- package/dist/two-d/render/SpringSprite.js +39 -0
- package/dist/two-d/render/SpringSprite.js.map +1 -0
- package/dist/two-d/render/SpriteDeform.d.ts +156 -0
- package/dist/two-d/render/SpriteDeform.d.ts.map +1 -0
- package/dist/two-d/render/SpriteDeform.js +278 -0
- package/dist/two-d/render/SpriteDeform.js.map +1 -0
- package/dist/two-d/render/SvgSkeleton.d.ts +54 -0
- package/dist/two-d/render/SvgSkeleton.d.ts.map +1 -0
- package/dist/two-d/render/SvgSkeleton.js +112 -0
- package/dist/two-d/render/SvgSkeleton.js.map +1 -0
- package/dist/two-d/render/index.d.ts +12 -0
- package/dist/two-d/render/index.d.ts.map +1 -1
- package/dist/two-d/render/index.js +6 -0
- package/dist/two-d/render/index.js.map +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +11 -7
- package/sbom.cdx.json +6 -58
- package/tools/asset-report.d.mts +37 -0
- package/tools/asset-report.mjs +157 -0
- package/tools/compile-resources.d.mts +24 -0
- package/tools/compile-resources.mjs +138 -5
- package/tools/emit-page.d.mts +9 -1
- package/tools/emit-page.mjs +31 -3
- package/tools/vite.mjs +6 -1
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
import { Sprite, Texture } from 'pixi.js';
|
|
2
|
+
import { reducedMotion } from '../../core/Motion.js';
|
|
3
|
+
/** the default breeze, in field cells per second, behind a bare `time` with no layer drift */
|
|
4
|
+
const BREEZE_X = 0.35;
|
|
5
|
+
const BREEZE_Y = 0.12;
|
|
6
|
+
function lattice(ix, iy, seed) {
|
|
7
|
+
const hash = Math.sin(ix * 127.1 + iy * 311.7 + seed * 74.7) * 43758.5453;
|
|
8
|
+
return hash - Math.floor(hash);
|
|
9
|
+
}
|
|
10
|
+
function octave(x, y, seed) {
|
|
11
|
+
const x0 = Math.floor(x);
|
|
12
|
+
const y0 = Math.floor(y);
|
|
13
|
+
const fx = x - x0;
|
|
14
|
+
const fy = y - y0;
|
|
15
|
+
const sx = fx * fx * (3 - 2 * fx);
|
|
16
|
+
const sy = fy * fy * (3 - 2 * fy);
|
|
17
|
+
const top = lattice(x0, y0, seed) + (lattice(x0 + 1, y0, seed) - lattice(x0, y0, seed)) * sx;
|
|
18
|
+
const bottom = lattice(x0, y0 + 1, seed) + (lattice(x0 + 1, y0 + 1, seed) - lattice(x0, y0 + 1, seed)) * sx;
|
|
19
|
+
return Math.min(1, Math.max(0, top + (bottom - top) * sy));
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* A deterministic wisp field in 0..1: two octaves of value noise over an integer lattice,
|
|
23
|
+
* smoothstep-interpolated so neighbouring samples always blend rather than step. Pure and
|
|
24
|
+
* seed-stable within a run: the same `(x, y, time, seed)` paints the same wisp, which is
|
|
25
|
+
* what makes haze testable as arithmetic instead of eyeballed as weather. Time wanders
|
|
26
|
+
* the lookup along a slow breeze, so a still coordinate still breathes.
|
|
27
|
+
*
|
|
28
|
+
* @example
|
|
29
|
+
* ```ts
|
|
30
|
+
* import { hazeField } from '@datamoc/mw_games/two-d/render';
|
|
31
|
+
*
|
|
32
|
+
* console.log(hazeField(3, 5, 1.5, 7) === hazeField(3, 5, 1.5, 7)); // true - same sky twice
|
|
33
|
+
* console.log(hazeField(3, 5, 1.5, 7) >= 0 && hazeField(3, 5, 1.5, 7) <= 1); // true - always a density
|
|
34
|
+
* ```
|
|
35
|
+
*/
|
|
36
|
+
export function hazeField(x, y, time, seed) {
|
|
37
|
+
if (![x, y, time, seed].every(Number.isFinite)) {
|
|
38
|
+
throw new RangeError(`a haze sample needs finite x, y, time and seed, saw (${x}, ${y}, ${time}, ${seed})`);
|
|
39
|
+
}
|
|
40
|
+
const driftedX = x + time * BREEZE_X;
|
|
41
|
+
const driftedY = y + time * BREEZE_Y;
|
|
42
|
+
return (octave(driftedX / 8, driftedY / 8, seed) * 0.65 + octave(driftedX / 3 + 11, driftedY / 3 + 7, seed + 1) * 0.35);
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Paint a white haze sheet with per-pixel alpha into `pixels` (`width * height` RGBA).
|
|
46
|
+
* The layer tints the sprite itself, so one buffer serves any colour. Pure, like
|
|
47
|
+
* `paintFogPixels`: density 0 paints fully transparent, and raising the density never
|
|
48
|
+
* thins a pixel that was already covered.
|
|
49
|
+
*
|
|
50
|
+
* @example
|
|
51
|
+
* ```ts
|
|
52
|
+
* import { paintHazePixels } from '@datamoc/mw_games/two-d/render';
|
|
53
|
+
*
|
|
54
|
+
* const pixels = new Uint8ClampedArray(4 * 2 * 4);
|
|
55
|
+
* paintHazePixels(pixels, 4, 2, { time: 0, density: 1, seed: 3 });
|
|
56
|
+
* console.log(pixels.some((v, i) => i % 4 === 3 && v > 0)); // true - full density always shows some haze
|
|
57
|
+
* ```
|
|
58
|
+
*/
|
|
59
|
+
export function paintHazePixels(pixels, width, height, paint) {
|
|
60
|
+
if (!(pixels instanceof Uint8Array || pixels instanceof Uint8ClampedArray) ||
|
|
61
|
+
pixels.length !== width * height * 4) {
|
|
62
|
+
throw new RangeError(`haze needs a pixel buffer of ${width * height * 4} bytes`);
|
|
63
|
+
}
|
|
64
|
+
if (!Number.isFinite(paint.time) || !Number.isFinite(paint.seed)) {
|
|
65
|
+
throw new RangeError(`haze needs a finite time and seed, saw (${paint.time}, ${paint.seed})`);
|
|
66
|
+
}
|
|
67
|
+
if (!Number.isFinite(paint.density) || paint.density < 0 || paint.density > 1) {
|
|
68
|
+
throw new RangeError(`haze needs density between 0 and 1, saw ${paint.density}`);
|
|
69
|
+
}
|
|
70
|
+
const drift = paint.drift ?? { x: 0, y: 0 };
|
|
71
|
+
if (!Number.isFinite(drift.x) || !Number.isFinite(drift.y)) {
|
|
72
|
+
throw new RangeError(`haze needs a finite drift, saw (${drift.x}, ${drift.y})`);
|
|
73
|
+
}
|
|
74
|
+
for (let y = 0; y < height; y++) {
|
|
75
|
+
for (let x = 0; x < width; x++) {
|
|
76
|
+
const alpha = Math.round(255 *
|
|
77
|
+
paint.density *
|
|
78
|
+
hazeField(x + drift.x * paint.time, y + drift.y * paint.time, paint.time, paint.seed));
|
|
79
|
+
pixels.set([255, 255, 255, alpha], (y * width + x) * 4);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* An atmospheric haze sheet: translucent weather and mood with soft edges, drift and
|
|
85
|
+
* density, on the GPU path (roadmap 425). Distinct from `FogLayer`, which is fog of war:
|
|
86
|
+
* this never hides gameplay, it only colours the air. The canvas stays small and scales
|
|
87
|
+
* up with linear filtering, so one refresh costs O(cells) and edges stay soft at any
|
|
88
|
+
* size. Stack several planes with different densities, drifts, tints and scales for depth.
|
|
89
|
+
* Needs a DOM canvas; `paintHazePixels` is the same shading without one.
|
|
90
|
+
*
|
|
91
|
+
* @example
|
|
92
|
+
* ```ts
|
|
93
|
+
* import { HazeLayer } from '@datamoc/mw_games/two-d/render';
|
|
94
|
+
*
|
|
95
|
+
* const far = new HazeLayer({ width: 400, height: 225, density: 0.3, tint: 0x9db8d6, drift: { x: 0.1, y: 0 } });
|
|
96
|
+
* const near = new HazeLayer({ width: 400, height: 225, density: 0.5, tint: 0xcfd8e6, drift: { x: 0.4, y: 0.05 } });
|
|
97
|
+
* far.update(1 / 60); // each plane drifts at its own pace, which reads as depth
|
|
98
|
+
* near.update(1 / 60);
|
|
99
|
+
* ```
|
|
100
|
+
*/
|
|
101
|
+
export class HazeLayer extends Sprite {
|
|
102
|
+
constructor(options) {
|
|
103
|
+
if (!Number.isFinite(options.width) || options.width <= 0) {
|
|
104
|
+
throw new RangeError(`a haze sheet needs width above 0, saw ${options.width}`);
|
|
105
|
+
}
|
|
106
|
+
if (!Number.isFinite(options.height) || options.height <= 0) {
|
|
107
|
+
throw new RangeError(`a haze sheet needs height above 0, saw ${options.height}`);
|
|
108
|
+
}
|
|
109
|
+
const cellsX = options.cellsX ?? 64;
|
|
110
|
+
const cellsY = options.cellsY ?? 36;
|
|
111
|
+
if (!Number.isInteger(cellsX) || cellsX < 1) {
|
|
112
|
+
throw new RangeError(`a haze sheet needs integer cellsX of at least 1, saw ${cellsX}`);
|
|
113
|
+
}
|
|
114
|
+
if (!Number.isInteger(cellsY) || cellsY < 1) {
|
|
115
|
+
throw new RangeError(`a haze sheet needs integer cellsY of at least 1, saw ${cellsY}`);
|
|
116
|
+
}
|
|
117
|
+
const density = options.density ?? 0.5;
|
|
118
|
+
if (!Number.isFinite(density) || density < 0 || density > 1) {
|
|
119
|
+
throw new RangeError(`a haze sheet needs density between 0 and 1, saw ${density}`);
|
|
120
|
+
}
|
|
121
|
+
const drift = options.drift ?? { x: 0.25, y: 0 };
|
|
122
|
+
if (!Number.isFinite(drift.x) || !Number.isFinite(drift.y)) {
|
|
123
|
+
throw new RangeError(`a haze sheet needs a finite drift, saw (${drift.x}, ${drift.y})`);
|
|
124
|
+
}
|
|
125
|
+
if (options.seed !== undefined && !Number.isFinite(options.seed)) {
|
|
126
|
+
throw new RangeError(`a haze sheet needs a finite seed, saw ${options.seed}`);
|
|
127
|
+
}
|
|
128
|
+
const canvas = document.createElement('canvas');
|
|
129
|
+
canvas.width = cellsX;
|
|
130
|
+
canvas.height = cellsY;
|
|
131
|
+
const context = canvas.getContext('2d');
|
|
132
|
+
if (!context)
|
|
133
|
+
throw new Error('HazeLayer needs a 2D canvas context');
|
|
134
|
+
super(Texture.from(canvas));
|
|
135
|
+
this.time = 0;
|
|
136
|
+
this.context = context;
|
|
137
|
+
this.image = context.createImageData(cellsX, cellsY);
|
|
138
|
+
this.cellsX = cellsX;
|
|
139
|
+
this.cellsY = cellsY;
|
|
140
|
+
this.density = density;
|
|
141
|
+
this.drift = { ...drift };
|
|
142
|
+
this.seed = options.seed ?? 1;
|
|
143
|
+
this.intent = options.intent ?? 'decorative';
|
|
144
|
+
this.tint = options.tint ?? 0xffffff;
|
|
145
|
+
this.alpha = options.opacity ?? 1;
|
|
146
|
+
this.scale.set(options.width / cellsX, options.height / cellsY);
|
|
147
|
+
this.eventMode = 'none';
|
|
148
|
+
this.refresh();
|
|
149
|
+
}
|
|
150
|
+
/** seconds of drift accumulated so far */
|
|
151
|
+
get elapsed() {
|
|
152
|
+
return this.time;
|
|
153
|
+
}
|
|
154
|
+
/** swap the coverage; takes effect on the next `update` */
|
|
155
|
+
setDensity(density) {
|
|
156
|
+
if (!Number.isFinite(density) || density < 0 || density > 1) {
|
|
157
|
+
throw new RangeError(`a haze sheet needs density between 0 and 1, saw ${density}`);
|
|
158
|
+
}
|
|
159
|
+
this.density = density;
|
|
160
|
+
}
|
|
161
|
+
/** advance the drift and repaint; under reduced motion a decorative sheet holds still */
|
|
162
|
+
update(dt) {
|
|
163
|
+
if (!Number.isFinite(dt) || dt < 0) {
|
|
164
|
+
throw new RangeError(`a haze update needs dt of at least 0, saw ${dt}`);
|
|
165
|
+
}
|
|
166
|
+
if (!reducedMotion() || this.intent !== 'decorative')
|
|
167
|
+
this.time += dt;
|
|
168
|
+
this.refresh();
|
|
169
|
+
}
|
|
170
|
+
refresh() {
|
|
171
|
+
paintHazePixels(this.image.data, this.cellsX, this.cellsY, {
|
|
172
|
+
time: this.time,
|
|
173
|
+
density: this.density,
|
|
174
|
+
seed: this.seed,
|
|
175
|
+
drift: this.drift,
|
|
176
|
+
});
|
|
177
|
+
this.context.putImageData(this.image, 0, 0);
|
|
178
|
+
this.texture.source.update();
|
|
179
|
+
}
|
|
180
|
+
/** the texture is generated for this sheet alone, so it goes with it */
|
|
181
|
+
destroy() {
|
|
182
|
+
super.destroy({ texture: true, textureSource: true });
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
//# sourceMappingURL=HazeLayer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"HazeLayer.js","sourceRoot":"","sources":["../../../src/two-d/render/HazeLayer.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import { Sprite } from 'pixi.js';
|
|
2
|
+
import { type MotionIntent } from '../../core/Motion.ts';
|
|
3
|
+
/**
|
|
4
|
+
* How much light a soft glow still carries at `distance` from its centre: 1 at the
|
|
5
|
+
* centre, easing to exactly 0 at `radius`, 0 past it. Pure, so a sign's falloff is
|
|
6
|
+
* checkable as arithmetic: the middle of a tube is always brighter than its rim.
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* ```ts
|
|
10
|
+
* import { glowFalloff } from '@datamoc/mw_games/two-d/render';
|
|
11
|
+
*
|
|
12
|
+
* console.log(glowFalloff(0, 24)); // 1 - the centre burns full
|
|
13
|
+
* console.log(glowFalloff(24, 24)); // 0 - the rim carries nothing
|
|
14
|
+
* console.log(glowFalloff(48, 24)); // 0 - past the rim stays dark
|
|
15
|
+
* ```
|
|
16
|
+
*/
|
|
17
|
+
export declare function glowFalloff(distance: number, radius: number): number;
|
|
18
|
+
export interface GlowPaint {
|
|
19
|
+
/** glow colour as a hex number */
|
|
20
|
+
color: number;
|
|
21
|
+
/** light radius in pixels; must be above 0 */
|
|
22
|
+
radius: number;
|
|
23
|
+
/** peak strength, 0 (dark) to 1 (full); validated */
|
|
24
|
+
intensity: number;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Paint a `size * size` radial glow (the sprite is square, `size` is odd) into `pixels`
|
|
28
|
+
* as RGBA bytes. Centre pixels carry the colour at full intensity, rim pixels fade to
|
|
29
|
+
* transparent, and intensity scales every channel linearly, so doubling it doubles the
|
|
30
|
+
* light. Pure, like `paintFogPixels`.
|
|
31
|
+
*
|
|
32
|
+
* @example
|
|
33
|
+
* ```ts
|
|
34
|
+
* import { paintGlowPixels } from '@datamoc/mw_games/two-d/render';
|
|
35
|
+
*
|
|
36
|
+
* const size = 5;
|
|
37
|
+
* const pixels = new Uint8ClampedArray(size * size * 4);
|
|
38
|
+
* paintGlowPixels(pixels, size, { color: 0xff0000, radius: 2, intensity: 1 });
|
|
39
|
+
* console.log(pixels[0] > pixels[pixels.length - 4]); // true - the centre burns redder than the rim
|
|
40
|
+
* ```
|
|
41
|
+
*/
|
|
42
|
+
export declare function paintGlowPixels(pixels: Uint8ClampedArray | Uint8Array, size: number, paint: GlowPaint): void;
|
|
43
|
+
export interface NeonGlowOptions {
|
|
44
|
+
/** glow colour as a hex number */
|
|
45
|
+
color: number;
|
|
46
|
+
/** light radius in world pixels; must be above 0 */
|
|
47
|
+
radius: number;
|
|
48
|
+
/** peak strength, 0 to 1; default 1 */
|
|
49
|
+
intensity?: number;
|
|
50
|
+
/** slow breathing of the light; default none (a steady sign) */
|
|
51
|
+
flicker?: {
|
|
52
|
+
amount: number;
|
|
53
|
+
frequency: number;
|
|
54
|
+
};
|
|
55
|
+
/** what the flicker is for under reduced motion; default `decorative`, which holds the light steady */
|
|
56
|
+
intent?: MotionIntent;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* A soft neon glow from a shape or mask: a radial sprite drawn additively, the overlay
|
|
60
|
+
* `Halo` already provides, with colour, radius, intensity and flicker (roadmap 426). A
|
|
61
|
+
* global bloom stays out on purpose: one sprite per sign is cheaper, composes with
|
|
62
|
+
* z-order like any other sprite, and never washes the whole scene. Mask a glow by
|
|
63
|
+
* parenting it under the shape it lights, or leave it bare for a free halo around a sign.
|
|
64
|
+
* Needs a DOM canvas; `paintGlowPixels` is the same falloff without one.
|
|
65
|
+
*
|
|
66
|
+
* @example
|
|
67
|
+
* ```ts
|
|
68
|
+
* import { NeonGlow } from '@datamoc/mw_games/two-d/render';
|
|
69
|
+
*
|
|
70
|
+
* const sign = new NeonGlow({ color: 0x37e0ff, radius: 48, flicker: { amount: 0.15, frequency: 2 } });
|
|
71
|
+
* sign.position.set(200, 120);
|
|
72
|
+
* sign.update(1 / 60); // the tube breathes; under reduced motion it holds steady instead
|
|
73
|
+
* ```
|
|
74
|
+
*/
|
|
75
|
+
export declare class NeonGlow extends Sprite {
|
|
76
|
+
private canvas;
|
|
77
|
+
private color;
|
|
78
|
+
private radius;
|
|
79
|
+
private peak;
|
|
80
|
+
private readonly flickerAmount;
|
|
81
|
+
private readonly flickerFrequency;
|
|
82
|
+
private readonly intent;
|
|
83
|
+
private clock;
|
|
84
|
+
constructor(options: NeonGlowOptions);
|
|
85
|
+
/** seconds of flicker accumulated so far */
|
|
86
|
+
get elapsed(): number;
|
|
87
|
+
/** swap the colour; repaints once */
|
|
88
|
+
setColor(color: number): void;
|
|
89
|
+
/** swap the radius; repaints once */
|
|
90
|
+
setRadius(radius: number): void;
|
|
91
|
+
/** swap the peak strength; applies on the next `update` without a repaint */
|
|
92
|
+
setIntensity(intensity: number): void;
|
|
93
|
+
/** advance the flicker; under reduced motion a decorative glow holds its peak instead */
|
|
94
|
+
update(dt: number): void;
|
|
95
|
+
private static paintCanvas;
|
|
96
|
+
private repaint;
|
|
97
|
+
/** the texture is generated for this glow alone, so it goes with it */
|
|
98
|
+
destroy(): void;
|
|
99
|
+
}
|
|
100
|
+
//# sourceMappingURL=NeonGlow.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"NeonGlow.d.ts","sourceRoot":"","sources":["../../../src/two-d/render/NeonGlow.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAW,MAAM,SAAS,CAAC;AAC1C,OAAO,EAAiB,KAAK,YAAY,EAAE,MAAM,sBAAsB,CAAC;AAUxE;;;;;;;;;;;;;GAaG;AACH,wBAAgB,WAAW,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAUpE;AAED,MAAM,WAAW,SAAS;IACzB,kCAAkC;IAClC,KAAK,EAAE,MAAM,CAAC;IACd,8CAA8C;IAC9C,MAAM,EAAE,MAAM,CAAC;IACf,qDAAqD;IACrD,SAAS,EAAE,MAAM,CAAC;CAClB;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,iBAAiB,GAAG,UAAU,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,SAAS,GAAG,IAAI,CAwB5G;AAED,MAAM,WAAW,eAAe;IAC/B,kCAAkC;IAClC,KAAK,EAAE,MAAM,CAAC;IACd,oDAAoD;IACpD,MAAM,EAAE,MAAM,CAAC;IACf,uCAAuC;IACvC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,gEAAgE;IAChE,OAAO,CAAC,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAE,CAAC;IAChD,uGAAuG;IACvG,MAAM,CAAC,EAAE,YAAY,CAAC;CACtB;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,qBAAa,QAAS,SAAQ,MAAM;IACnC,OAAO,CAAC,MAAM,CAAoB;IAClC,OAAO,CAAC,KAAK,CAAS;IACtB,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,IAAI,CAAS;IACrB,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAS;IACvC,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAS;IAC1C,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAe;IACtC,OAAO,CAAC,KAAK,CAAK;IAElB,YAAY,OAAO,EAAE,eAAe,EA8BnC;IAED,4CAA4C;IAC5C,IAAI,OAAO,IAAI,MAAM,CAEpB;IAED,qCAAqC;IACrC,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAI5B;IAED,qCAAqC;IACrC,SAAS,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAM9B;IAED,6EAA6E;IAC7E,YAAY,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAKpC;IAED,yFAAyF;IACzF,MAAM,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,CAOvB;IAED,OAAO,CAAC,MAAM,CAAC,WAAW;IAa1B,OAAO,CAAC,OAAO;IAQf,uEAAuE;IAC9D,OAAO,IAAI,IAAI,CAEvB;CACD"}
|
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
import { Sprite, Texture } from 'pixi.js';
|
|
2
|
+
import { reducedMotion } from '../../core/Motion.js';
|
|
3
|
+
/** split a hex colour number into 0..255 channels; throws a RangeError outside `0x000000`-`0xffffff` */
|
|
4
|
+
function splitColor(color) {
|
|
5
|
+
if (!Number.isInteger(color) || color < 0 || color > 0xffffff) {
|
|
6
|
+
throw new RangeError(`a glow needs an integer color between 0x000000 and 0xffffff, saw ${color}`);
|
|
7
|
+
}
|
|
8
|
+
return [(color >> 16) & 0xff, (color >> 8) & 0xff, color & 0xff];
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* How much light a soft glow still carries at `distance` from its centre: 1 at the
|
|
12
|
+
* centre, easing to exactly 0 at `radius`, 0 past it. Pure, so a sign's falloff is
|
|
13
|
+
* checkable as arithmetic: the middle of a tube is always brighter than its rim.
|
|
14
|
+
*
|
|
15
|
+
* @example
|
|
16
|
+
* ```ts
|
|
17
|
+
* import { glowFalloff } from '@datamoc/mw_games/two-d/render';
|
|
18
|
+
*
|
|
19
|
+
* console.log(glowFalloff(0, 24)); // 1 - the centre burns full
|
|
20
|
+
* console.log(glowFalloff(24, 24)); // 0 - the rim carries nothing
|
|
21
|
+
* console.log(glowFalloff(48, 24)); // 0 - past the rim stays dark
|
|
22
|
+
* ```
|
|
23
|
+
*/
|
|
24
|
+
export function glowFalloff(distance, radius) {
|
|
25
|
+
if (!Number.isFinite(distance) || !Number.isFinite(radius) || radius <= 0) {
|
|
26
|
+
throw new RangeError(`a glow falloff needs a finite distance and a radius above 0, saw (${distance}, ${radius})`);
|
|
27
|
+
}
|
|
28
|
+
if (distance <= 0)
|
|
29
|
+
return 1;
|
|
30
|
+
if (distance >= radius)
|
|
31
|
+
return 0;
|
|
32
|
+
const t = 1 - (distance / radius) * (distance / radius);
|
|
33
|
+
return t * t;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Paint a `size * size` radial glow (the sprite is square, `size` is odd) into `pixels`
|
|
37
|
+
* as RGBA bytes. Centre pixels carry the colour at full intensity, rim pixels fade to
|
|
38
|
+
* transparent, and intensity scales every channel linearly, so doubling it doubles the
|
|
39
|
+
* light. Pure, like `paintFogPixels`.
|
|
40
|
+
*
|
|
41
|
+
* @example
|
|
42
|
+
* ```ts
|
|
43
|
+
* import { paintGlowPixels } from '@datamoc/mw_games/two-d/render';
|
|
44
|
+
*
|
|
45
|
+
* const size = 5;
|
|
46
|
+
* const pixels = new Uint8ClampedArray(size * size * 4);
|
|
47
|
+
* paintGlowPixels(pixels, size, { color: 0xff0000, radius: 2, intensity: 1 });
|
|
48
|
+
* console.log(pixels[0] > pixels[pixels.length - 4]); // true - the centre burns redder than the rim
|
|
49
|
+
* ```
|
|
50
|
+
*/
|
|
51
|
+
export function paintGlowPixels(pixels, size, paint) {
|
|
52
|
+
if (!Number.isInteger(size) || size < 1) {
|
|
53
|
+
throw new RangeError(`a glow needs an integer size of at least 1, saw ${size}`);
|
|
54
|
+
}
|
|
55
|
+
if (!(pixels instanceof Uint8Array || pixels instanceof Uint8ClampedArray) || pixels.length !== size * size * 4) {
|
|
56
|
+
throw new RangeError(`a glow needs a pixel buffer of ${size * size * 4} bytes`);
|
|
57
|
+
}
|
|
58
|
+
if (!Number.isFinite(paint.radius) || paint.radius <= 0) {
|
|
59
|
+
throw new RangeError(`a glow needs a radius above 0, saw ${paint.radius}`);
|
|
60
|
+
}
|
|
61
|
+
if (!Number.isFinite(paint.intensity) || paint.intensity < 0 || paint.intensity > 1) {
|
|
62
|
+
throw new RangeError(`a glow needs intensity between 0 and 1, saw ${paint.intensity}`);
|
|
63
|
+
}
|
|
64
|
+
const [r, g, b] = splitColor(paint.color);
|
|
65
|
+
const centre = (size - 1) / 2;
|
|
66
|
+
for (let y = 0; y < size; y++) {
|
|
67
|
+
for (let x = 0; x < size; x++) {
|
|
68
|
+
const light = glowFalloff(Math.hypot(x - centre, y - centre), paint.radius) * paint.intensity;
|
|
69
|
+
pixels.set([Math.round(r * light), Math.round(g * light), Math.round(b * light), Math.round(255 * light)], (y * size + x) * 4);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* A soft neon glow from a shape or mask: a radial sprite drawn additively, the overlay
|
|
75
|
+
* `Halo` already provides, with colour, radius, intensity and flicker (roadmap 426). A
|
|
76
|
+
* global bloom stays out on purpose: one sprite per sign is cheaper, composes with
|
|
77
|
+
* z-order like any other sprite, and never washes the whole scene. Mask a glow by
|
|
78
|
+
* parenting it under the shape it lights, or leave it bare for a free halo around a sign.
|
|
79
|
+
* Needs a DOM canvas; `paintGlowPixels` is the same falloff without one.
|
|
80
|
+
*
|
|
81
|
+
* @example
|
|
82
|
+
* ```ts
|
|
83
|
+
* import { NeonGlow } from '@datamoc/mw_games/two-d/render';
|
|
84
|
+
*
|
|
85
|
+
* const sign = new NeonGlow({ color: 0x37e0ff, radius: 48, flicker: { amount: 0.15, frequency: 2 } });
|
|
86
|
+
* sign.position.set(200, 120);
|
|
87
|
+
* sign.update(1 / 60); // the tube breathes; under reduced motion it holds steady instead
|
|
88
|
+
* ```
|
|
89
|
+
*/
|
|
90
|
+
export class NeonGlow extends Sprite {
|
|
91
|
+
constructor(options) {
|
|
92
|
+
if (!Number.isFinite(options.radius) || options.radius <= 0) {
|
|
93
|
+
throw new RangeError(`a glow needs a radius above 0, saw ${options.radius}`);
|
|
94
|
+
}
|
|
95
|
+
const intensity = options.intensity ?? 1;
|
|
96
|
+
if (!Number.isFinite(intensity) || intensity < 0 || intensity > 1) {
|
|
97
|
+
throw new RangeError(`a glow needs intensity between 0 and 1, saw ${intensity}`);
|
|
98
|
+
}
|
|
99
|
+
const flicker = options.flicker ?? { amount: 0, frequency: 1 };
|
|
100
|
+
if (!Number.isFinite(flicker.amount) || flicker.amount < 0 || flicker.amount > 1) {
|
|
101
|
+
throw new RangeError(`a glow needs a flicker amount between 0 and 1, saw ${flicker.amount}`);
|
|
102
|
+
}
|
|
103
|
+
if (!Number.isFinite(flicker.frequency) || flicker.frequency <= 0) {
|
|
104
|
+
throw new RangeError(`a glow needs a flicker frequency above 0, saw ${flicker.frequency}`);
|
|
105
|
+
}
|
|
106
|
+
//paintCanvas validates the colour through paintGlowPixels before super() runs
|
|
107
|
+
const canvas = NeonGlow.paintCanvas(options.color, options.radius);
|
|
108
|
+
super(Texture.from(canvas));
|
|
109
|
+
this.clock = 0;
|
|
110
|
+
this.canvas = canvas;
|
|
111
|
+
this.color = options.color;
|
|
112
|
+
this.radius = options.radius;
|
|
113
|
+
this.peak = intensity;
|
|
114
|
+
this.flickerAmount = flicker.amount;
|
|
115
|
+
this.flickerFrequency = flicker.frequency;
|
|
116
|
+
this.intent = options.intent ?? 'decorative';
|
|
117
|
+
//additive like Halo: light adds, never covers
|
|
118
|
+
this.blendMode = 'add';
|
|
119
|
+
this.anchor.set(0.5);
|
|
120
|
+
this.eventMode = 'none';
|
|
121
|
+
this.alpha = this.peak;
|
|
122
|
+
}
|
|
123
|
+
/** seconds of flicker accumulated so far */
|
|
124
|
+
get elapsed() {
|
|
125
|
+
return this.clock;
|
|
126
|
+
}
|
|
127
|
+
/** swap the colour; repaints once */
|
|
128
|
+
setColor(color) {
|
|
129
|
+
splitColor(color);
|
|
130
|
+
this.color = color;
|
|
131
|
+
this.repaint();
|
|
132
|
+
}
|
|
133
|
+
/** swap the radius; repaints once */
|
|
134
|
+
setRadius(radius) {
|
|
135
|
+
if (!Number.isFinite(radius) || radius <= 0) {
|
|
136
|
+
throw new RangeError(`a glow needs a radius above 0, saw ${radius}`);
|
|
137
|
+
}
|
|
138
|
+
this.radius = radius;
|
|
139
|
+
this.repaint();
|
|
140
|
+
}
|
|
141
|
+
/** swap the peak strength; applies on the next `update` without a repaint */
|
|
142
|
+
setIntensity(intensity) {
|
|
143
|
+
if (!Number.isFinite(intensity) || intensity < 0 || intensity > 1) {
|
|
144
|
+
throw new RangeError(`a glow needs intensity between 0 and 1, saw ${intensity}`);
|
|
145
|
+
}
|
|
146
|
+
this.peak = intensity;
|
|
147
|
+
}
|
|
148
|
+
/** advance the flicker; under reduced motion a decorative glow holds its peak instead */
|
|
149
|
+
update(dt) {
|
|
150
|
+
if (!Number.isFinite(dt) || dt < 0) {
|
|
151
|
+
throw new RangeError(`a glow update needs dt of at least 0, saw ${dt}`);
|
|
152
|
+
}
|
|
153
|
+
if (!reducedMotion() || this.intent !== 'decorative')
|
|
154
|
+
this.clock += dt;
|
|
155
|
+
const wave = 1 + this.flickerAmount * Math.sin(2 * Math.PI * this.flickerFrequency * this.clock);
|
|
156
|
+
this.alpha = Math.min(1, Math.max(0, this.peak * wave));
|
|
157
|
+
}
|
|
158
|
+
static paintCanvas(color, radius) {
|
|
159
|
+
const size = Math.ceil(radius) * 2 + 1;
|
|
160
|
+
const canvas = document.createElement('canvas');
|
|
161
|
+
canvas.width = size;
|
|
162
|
+
canvas.height = size;
|
|
163
|
+
const context = canvas.getContext('2d');
|
|
164
|
+
if (!context)
|
|
165
|
+
throw new Error('NeonGlow needs a 2D canvas context');
|
|
166
|
+
const image = context.createImageData(size, size);
|
|
167
|
+
paintGlowPixels(image.data, size, { color, radius, intensity: 1 });
|
|
168
|
+
context.putImageData(image, 0, 0);
|
|
169
|
+
return canvas;
|
|
170
|
+
}
|
|
171
|
+
repaint() {
|
|
172
|
+
//a radius change resizes the canvas, so the texture is rebuilt rather than updated
|
|
173
|
+
const old = this.texture;
|
|
174
|
+
this.canvas = NeonGlow.paintCanvas(this.color, this.radius);
|
|
175
|
+
this.texture = Texture.from(this.canvas);
|
|
176
|
+
old.destroy(true);
|
|
177
|
+
}
|
|
178
|
+
/** the texture is generated for this glow alone, so it goes with it */
|
|
179
|
+
destroy() {
|
|
180
|
+
super.destroy({ texture: true, textureSource: true });
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
//# sourceMappingURL=NeonGlow.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"NeonGlow.js","sourceRoot":"","sources":["../../../src/two-d/render/NeonGlow.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Container } from 'pixi.js';
|
|
2
|
-
import { type Mixer, type Pose, type SkeletonBones } from '../../skeleton/index.ts';
|
|
2
|
+
import { type Mixer, type Pose, type TransformPose, type SkeletonBones } from '../../skeleton/index.ts';
|
|
3
3
|
import { TintedSprite } from './TintedSprite.ts';
|
|
4
4
|
import type { Texture2D } from './Types2D.ts';
|
|
5
5
|
/**
|
|
@@ -39,13 +39,16 @@ export declare class SkeletalSprite extends Container {
|
|
|
39
39
|
private readonly skeleton;
|
|
40
40
|
private readonly parts;
|
|
41
41
|
private readonly mixer;
|
|
42
|
+
private diagnostics?;
|
|
42
43
|
constructor(skeleton: SkeletonBones, mixer?: Mixer);
|
|
43
44
|
/** bind a drawn part to a bone by name; the sprite's own anchor decides how it hangs */
|
|
44
45
|
bind(bone: string, texture: Texture2D): TintedSprite;
|
|
45
46
|
/** the sprite bound to a bone, or undefined for an unbound one */
|
|
46
47
|
part(bone: string): TintedSprite | undefined;
|
|
47
48
|
/** apply a pose directly; `update` does this itself when a mixer was given */
|
|
48
|
-
apply(pose: Pose): void;
|
|
49
|
+
apply(pose: Pose | TransformPose): void;
|
|
50
|
+
/** Explicit development opt-in. Disabled rigs allocate no overlay and draw no diagnostics. */
|
|
51
|
+
setDiagnostics(enabled: boolean): void;
|
|
49
52
|
/** advance the mixer and place every part; needs a mixer, refuses without one */
|
|
50
53
|
update(_dt: number): void;
|
|
51
54
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SkeletalSprite.d.ts","sourceRoot":"","sources":["../../../src/two-d/render/SkeletalSprite.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,
|
|
1
|
+
{"version":3,"file":"SkeletalSprite.d.ts","sourceRoot":"","sources":["../../../src/two-d/render/SkeletalSprite.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAoB,MAAM,SAAS,CAAC;AACtD,OAAO,EAIN,KAAK,KAAK,EACV,KAAK,IAAI,EACT,KAAK,aAAa,EAClB,KAAK,aAAa,EAClB,MAAM,yBAAyB,CAAC;AACjC,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACjD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAE9C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AACH,qBAAa,cAAe,SAAQ,SAAS;IAC5C,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAgB;IACzC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAmC;IACzD,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAoB;IAC1C,OAAO,CAAC,WAAW,CAAC,CAAW;IAE/B,YAAY,QAAQ,EAAE,aAAa,EAAE,KAAK,CAAC,EAAE,KAAK,EAIjD;IAED,wFAAwF;IACxF,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,SAAS,GAAG,YAAY,CAKnD;IAED,kEAAkE;IAClE,IAAI,CAAC,IAAI,EAAE,MAAM,GAAG,YAAY,GAAG,SAAS,CAE3C;IAED,8EAA8E;IAC9E,KAAK,CAAC,IAAI,EAAE,IAAI,GAAG,aAAa,GAAG,IAAI,CAuBtC;IAED,8FAA8F;IAC9F,cAAc,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAMrC;IAED,iFAAiF;IACjF,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAGxB;CACD;AAED,MAAM,WAAW,YAAY;IAC5B,qCAAqC;IACrC,QAAQ,EAAE,MAAM,CAAC;IACjB,uDAAuD;IACvD,MAAM,EAAE,MAAM,CAAC;IACf,0FAA0F;IAC1F,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,mFAAmF;IACnF,SAAS,CAAC,EAAE,MAAM,CAAC;CACnB;AAED;;;;GAIG;AACH;;;;;;;;;;;GAWG;AACH,qBAAa,gBAAgB;IAC5B,QAAQ,CAAC,MAAM,EAAE,KAAK,CAAC;QAAE,CAAC,EAAE,MAAM,CAAC;QAAC,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAM;IACtD,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAuC;IAChE,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAS;IAChC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAS;IACnC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAS;IAEnC,YAAY,OAAO,EAAE,YAAY,EAUhC;IAED,2DAA2D;IAC3D,IAAI,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,IAAI,CAG/B;IAED,iGAAiG;IACjG,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CA+BxB;CACD;AAED;;;GAGG;AACH;;;;;;;;;;;;;GAaG;AACH,qBAAa,QAAS,SAAQ,SAAS;IACtC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAmB;IACzC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAiB;IAE1C,YAAY,KAAK,EAAE,gBAAgB,EAAE,QAAQ,EAAE,SAAS,SAAS,EAAE,EAUlE;IAED,MAAM,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,CAQvB;CACD"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Container } from 'pixi.js';
|
|
1
|
+
import { Container, Graphics, Matrix } from 'pixi.js';
|
|
2
2
|
import { advance as advanceMixer, resolve, } from '../../skeleton/index.js';
|
|
3
3
|
import { TintedSprite } from './TintedSprite.js';
|
|
4
4
|
/**
|
|
@@ -59,8 +59,32 @@ export class SkeletalSprite extends Container {
|
|
|
59
59
|
const transform = transforms.get(bone);
|
|
60
60
|
if (!transform)
|
|
61
61
|
throw new Error(`skeletal sprite binds no bone named ${bone}`);
|
|
62
|
-
|
|
63
|
-
sprite.
|
|
62
|
+
const { a, b, c, d } = transform.matrix;
|
|
63
|
+
sprite.setFromMatrix(new Matrix(a, b, c, d, transform.x, transform.y));
|
|
64
|
+
}
|
|
65
|
+
if (this.diagnostics) {
|
|
66
|
+
this.setChildIndex(this.diagnostics, this.children.length - 1);
|
|
67
|
+
const graphics = this.diagnostics.clear();
|
|
68
|
+
for (const bone of transforms.values()) {
|
|
69
|
+
graphics.moveTo(bone.x, bone.y).lineTo(bone.tipX, bone.tipY).stroke({ color: 0x00ffff, width: 2 });
|
|
70
|
+
graphics.circle(bone.x, bone.y, 4).fill(0xffdd00);
|
|
71
|
+
graphics.circle(bone.tipX, bone.tipY, 2).fill(0xff4488);
|
|
72
|
+
graphics
|
|
73
|
+
.moveTo(bone.x - 7, bone.y)
|
|
74
|
+
.lineTo(bone.x + 7, bone.y)
|
|
75
|
+
.moveTo(bone.x, bone.y - 7)
|
|
76
|
+
.lineTo(bone.x, bone.y + 7)
|
|
77
|
+
.stroke({ color: 0xffdd00, width: 1 });
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
/** Explicit development opt-in. Disabled rigs allocate no overlay and draw no diagnostics. */
|
|
82
|
+
setDiagnostics(enabled) {
|
|
83
|
+
if (enabled && !this.diagnostics)
|
|
84
|
+
this.diagnostics = this.addChild(new Graphics());
|
|
85
|
+
if (!enabled && this.diagnostics) {
|
|
86
|
+
this.diagnostics.destroy();
|
|
87
|
+
this.diagnostics = undefined;
|
|
64
88
|
}
|
|
65
89
|
}
|
|
66
90
|
/** advance the mixer and place every part; needs a mixer, refuses without one */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SkeletalSprite.js","sourceRoot":"","sources":["../../../src/two-d/render/SkeletalSprite.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"SkeletalSprite.js","sourceRoot":"","sources":["../../../src/two-d/render/SkeletalSprite.ts"],"names":[],"mappings":"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"}
|