@flare-engine/render 0.2.0 → 0.3.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 +201 -21
- package/NOTICE +2 -0
- package/README.md +19 -8
- package/dist/index.d.mts +564 -503
- package/dist/index.d.mts.map +1 -0
- package/dist/index.d.ts +564 -503
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +1538 -1468
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1498 -1404
- package/dist/index.mjs.map +1 -1
- package/package.json +17 -14
package/dist/index.d.mts
CHANGED
|
@@ -1,11 +1,97 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
|
|
1
|
+
import { ComponentDef, Query, World } from "@flare-engine/ecs";
|
|
2
|
+
import { Rect, Vec2 } from "@flare-engine/math";
|
|
3
|
+
import { SkImageLike, SpriteFrame } from "@flare-engine/assets";
|
|
4
|
+
//#region src/camera2d.d.ts
|
|
5
|
+
/** Camera follow smoothing options. */
|
|
6
|
+
interface FollowOptions {
|
|
7
|
+
/** Smoothing factor (0 = instant, lower = faster, default 0.1). */
|
|
8
|
+
smoothing?: number;
|
|
9
|
+
/** Offset from target (e.g. look-ahead). */
|
|
10
|
+
offset?: Vec2;
|
|
11
|
+
/** Dead zone rect — camera won't move while target is inside. */
|
|
12
|
+
deadZone?: Rect;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Camera2D — 2D camera with position, zoom, rotation, follow, and shake.
|
|
16
|
+
* Pure data + methods — no Skia dependency. The renderer reads camera state
|
|
17
|
+
* to build the view transform.
|
|
18
|
+
*/
|
|
19
|
+
declare class Camera2D {
|
|
20
|
+
/** Camera position (world-space center). */
|
|
21
|
+
x: number;
|
|
22
|
+
y: number;
|
|
23
|
+
/** Zoom level (1 = 100%). */
|
|
24
|
+
zoom: number;
|
|
25
|
+
/** Rotation in radians. */
|
|
26
|
+
rotation: number;
|
|
27
|
+
/** Viewport width in pixels. */
|
|
28
|
+
viewportWidth: number;
|
|
29
|
+
/** Viewport height in pixels. */
|
|
30
|
+
viewportHeight: number;
|
|
31
|
+
/** Optional world bounds to clamp camera position. */
|
|
32
|
+
bounds: Rect | null;
|
|
33
|
+
private _follow;
|
|
34
|
+
private _shake;
|
|
35
|
+
private _shakePerlin;
|
|
36
|
+
private _shakeSeed;
|
|
37
|
+
private _shakePerlinSeed;
|
|
38
|
+
private _motionScale;
|
|
39
|
+
/** Set viewport dimensions. */
|
|
40
|
+
setViewport(width: number, height: number): void;
|
|
41
|
+
/** Start following a target position. */
|
|
42
|
+
follow(target: Vec2, options?: FollowOptions): void;
|
|
43
|
+
/** Stop following. */
|
|
44
|
+
unfollow(): void;
|
|
45
|
+
/**
|
|
46
|
+
* Global motion multiplier applied to subsequent `shake()` calls. Scales
|
|
47
|
+
* both amplitude and duration. Default 1 (no-op). 0 fully suppresses
|
|
48
|
+
* shake. Intended to be driven by `@flare-engine/a11y` reduced-motion so
|
|
49
|
+
* callers don't have to guard every shake site.
|
|
50
|
+
*
|
|
51
|
+
* Only affects future `shake()` calls — does not retroactively modify an
|
|
52
|
+
* in-flight shake.
|
|
53
|
+
*
|
|
54
|
+
* Clamped to `>= 0`.
|
|
55
|
+
*/
|
|
56
|
+
setMotionScale(scale: number): void;
|
|
57
|
+
/** Current motion scale (default 1). */
|
|
58
|
+
get motionScale(): number;
|
|
59
|
+
/** Start camera shake. */
|
|
60
|
+
shake(intensity: number, duration: number): void;
|
|
61
|
+
/**
|
|
62
|
+
* Start a Perlin-noise-based camera shake. Overwrites any in-flight
|
|
63
|
+
* shakePerlin (same semantics as shake()). Respects motionScale.
|
|
64
|
+
*/
|
|
65
|
+
shakePerlin(intensity: number, duration: number): void;
|
|
66
|
+
/**
|
|
67
|
+
* Update camera. Call once per frame.
|
|
68
|
+
* @param dt Delta time in seconds.
|
|
69
|
+
*/
|
|
70
|
+
update(dt: number): void;
|
|
71
|
+
/** Get the effective camera X (including shake + shakePerlin offsets). */
|
|
72
|
+
get effectiveX(): number;
|
|
73
|
+
/** Get the effective camera Y (including shake + shakePerlin offsets). */
|
|
74
|
+
get effectiveY(): number;
|
|
75
|
+
/** Convert world coordinates to screen coordinates. */
|
|
76
|
+
worldToScreen(worldX: number, worldY: number): Vec2;
|
|
77
|
+
/** Zero-alloc variant — writes screen coordinates into `out`. */
|
|
78
|
+
worldToScreenInto(worldX: number, worldY: number, out: Vec2): Vec2;
|
|
79
|
+
/** Convert screen coordinates to world coordinates. */
|
|
80
|
+
screenToWorld(screenX: number, screenY: number): Vec2;
|
|
81
|
+
/** Zero-alloc variant — writes world coordinates into `out`. */
|
|
82
|
+
screenToWorldInto(screenX: number, screenY: number, out: Vec2): Vec2;
|
|
83
|
+
/** Get the visible world-space bounding rect (allocates a fresh Rect). */
|
|
84
|
+
getBounds(): Rect;
|
|
85
|
+
/** Zero-alloc variant — writes the visible bounds into `out`. */
|
|
86
|
+
getBoundsInto(out: Rect): Rect;
|
|
87
|
+
private _clampToBounds;
|
|
88
|
+
}
|
|
89
|
+
//#endregion
|
|
90
|
+
//#region src/draw-order.d.ts
|
|
5
91
|
/** A drawable item with a z-order for sorting. */
|
|
6
92
|
interface Drawable {
|
|
7
|
-
|
|
8
|
-
|
|
93
|
+
/** Z-index for draw ordering. Higher values draw on top. */
|
|
94
|
+
z: number;
|
|
9
95
|
}
|
|
10
96
|
/**
|
|
11
97
|
* Sort an array of drawables by z-index (ascending = back to front).
|
|
@@ -24,175 +110,111 @@ declare function sortByDrawOrder<T extends Drawable>(items: T[], length?: number
|
|
|
24
110
|
* Stable relative order for equal z values (returns 0).
|
|
25
111
|
*/
|
|
26
112
|
declare function drawOrderCompare(a: Drawable, b: Drawable): number;
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
interface FollowOptions {
|
|
30
|
-
/** Smoothing factor (0 = instant, lower = faster, default 0.1). */
|
|
31
|
-
smoothing?: number;
|
|
32
|
-
/** Offset from target (e.g. look-ahead). */
|
|
33
|
-
offset?: Vec2;
|
|
34
|
-
/** Dead zone rect — camera won't move while target is inside. */
|
|
35
|
-
deadZone?: Rect;
|
|
36
|
-
}
|
|
37
|
-
/**
|
|
38
|
-
* Camera2D — 2D camera with position, zoom, rotation, follow, and shake.
|
|
39
|
-
* Pure data + methods — no Skia dependency. The renderer reads camera state
|
|
40
|
-
* to build the view transform.
|
|
41
|
-
*/
|
|
42
|
-
declare class Camera2D {
|
|
43
|
-
/** Camera position (world-space center). */
|
|
44
|
-
x: number;
|
|
45
|
-
y: number;
|
|
46
|
-
/** Zoom level (1 = 100%). */
|
|
47
|
-
zoom: number;
|
|
48
|
-
/** Rotation in radians. */
|
|
49
|
-
rotation: number;
|
|
50
|
-
/** Viewport width in pixels. */
|
|
51
|
-
viewportWidth: number;
|
|
52
|
-
/** Viewport height in pixels. */
|
|
53
|
-
viewportHeight: number;
|
|
54
|
-
/** Optional world bounds to clamp camera position. */
|
|
55
|
-
bounds: Rect | null;
|
|
56
|
-
private _follow;
|
|
57
|
-
private _shake;
|
|
58
|
-
private _shakePerlin;
|
|
59
|
-
private _shakeSeed;
|
|
60
|
-
private _shakePerlinSeed;
|
|
61
|
-
private _motionScale;
|
|
62
|
-
/** Set viewport dimensions. */
|
|
63
|
-
setViewport(width: number, height: number): void;
|
|
64
|
-
/** Start following a target position. */
|
|
65
|
-
follow(target: Vec2, options?: FollowOptions): void;
|
|
66
|
-
/** Stop following. */
|
|
67
|
-
unfollow(): void;
|
|
68
|
-
/**
|
|
69
|
-
* Global motion multiplier applied to subsequent `shake()` calls. Scales
|
|
70
|
-
* both amplitude and duration. Default 1 (no-op). 0 fully suppresses
|
|
71
|
-
* shake. Intended to be driven by `@flare-engine/a11y` reduced-motion so
|
|
72
|
-
* callers don't have to guard every shake site.
|
|
73
|
-
*
|
|
74
|
-
* Only affects future `shake()` calls — does not retroactively modify an
|
|
75
|
-
* in-flight shake.
|
|
76
|
-
*
|
|
77
|
-
* Clamped to `>= 0`.
|
|
78
|
-
*/
|
|
79
|
-
setMotionScale(scale: number): void;
|
|
80
|
-
/** Current motion scale (default 1). */
|
|
81
|
-
get motionScale(): number;
|
|
82
|
-
/** Start camera shake. */
|
|
83
|
-
shake(intensity: number, duration: number): void;
|
|
84
|
-
/**
|
|
85
|
-
* Start a Perlin-noise-based camera shake. Overwrites any in-flight
|
|
86
|
-
* shakePerlin (same semantics as shake()). Respects motionScale.
|
|
87
|
-
*/
|
|
88
|
-
shakePerlin(intensity: number, duration: number): void;
|
|
89
|
-
/**
|
|
90
|
-
* Update camera. Call once per frame.
|
|
91
|
-
* @param dt Delta time in seconds.
|
|
92
|
-
*/
|
|
93
|
-
update(dt: number): void;
|
|
94
|
-
/** Get the effective camera X (including shake + shakePerlin offsets). */
|
|
95
|
-
get effectiveX(): number;
|
|
96
|
-
/** Get the effective camera Y (including shake + shakePerlin offsets). */
|
|
97
|
-
get effectiveY(): number;
|
|
98
|
-
/** Convert world coordinates to screen coordinates. */
|
|
99
|
-
worldToScreen(worldX: number, worldY: number): Vec2;
|
|
100
|
-
/** Zero-alloc variant — writes screen coordinates into `out`. */
|
|
101
|
-
worldToScreenInto(worldX: number, worldY: number, out: Vec2): Vec2;
|
|
102
|
-
/** Convert screen coordinates to world coordinates. */
|
|
103
|
-
screenToWorld(screenX: number, screenY: number): Vec2;
|
|
104
|
-
/** Zero-alloc variant — writes world coordinates into `out`. */
|
|
105
|
-
screenToWorldInto(screenX: number, screenY: number, out: Vec2): Vec2;
|
|
106
|
-
/** Get the visible world-space bounding rect (allocates a fresh Rect). */
|
|
107
|
-
getBounds(): Rect;
|
|
108
|
-
/** Zero-alloc variant — writes the visible bounds into `out`. */
|
|
109
|
-
getBoundsInto(out: Rect): Rect;
|
|
110
|
-
private _clampToBounds;
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
+
//#endregion
|
|
114
|
+
//#region src/renderer.d.ts
|
|
113
115
|
/** Minimal Skia Canvas-like interface for the Renderer. */
|
|
114
116
|
interface CanvasLike {
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
117
|
+
save(): number;
|
|
118
|
+
restore(): void;
|
|
119
|
+
translate(x: number, y: number): void;
|
|
120
|
+
scale(sx: number, sy: number): void;
|
|
121
|
+
/** Rotate around (cx, cy). Angle in DEGREES — both Skia backends take degrees. */
|
|
122
|
+
rotate(degrees: number, cx: number, cy: number): void;
|
|
123
|
+
clear(color: number): void;
|
|
121
124
|
}
|
|
122
125
|
/** Stats tracked per frame. */
|
|
123
126
|
interface RenderStats {
|
|
124
|
-
|
|
125
|
-
|
|
127
|
+
/**
|
|
128
|
+
* Number of SpriteBatch flush runs emitted this frame — one per contiguous
|
|
129
|
+
* same-key (image, effect, alpha, stretch) run, NOT the number of raw canvas
|
|
130
|
+
* calls. An outline run fans into 9 canvas drawAtlas calls, a stretch run
|
|
131
|
+
* into n drawImageRect calls, a zone-bg run into n drawRect calls.
|
|
132
|
+
* Equal to batchCount whenever SpriteBatch.flush is the only writer;
|
|
133
|
+
* recordDrawCall()/recordBatch() are public and can diverge them if a
|
|
134
|
+
* custom batching system drives them independently.
|
|
135
|
+
*/
|
|
136
|
+
drawCalls: number;
|
|
137
|
+
/**
|
|
138
|
+
* Number of SpriteBatch flush runs — incremented alongside drawCalls at
|
|
139
|
+
* the same two sites in SpriteBatch.flush. Equal to drawCalls when only
|
|
140
|
+
* SpriteBatch.flush writes both; recordDrawCall()/recordBatch() are
|
|
141
|
+
* independent public methods and can produce different values if called
|
|
142
|
+
* directly by a custom batching system.
|
|
143
|
+
*/
|
|
144
|
+
batchCount: number;
|
|
126
145
|
}
|
|
127
146
|
/**
|
|
128
147
|
* Renderer — manages the Skia Canvas lifecycle for a frame.
|
|
129
148
|
* `begin()` to start, draw your content, `end()` to finish.
|
|
130
149
|
*/
|
|
131
150
|
declare class Renderer {
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
151
|
+
/** Current frame stats. */
|
|
152
|
+
readonly stats: RenderStats;
|
|
153
|
+
private _canvas;
|
|
154
|
+
private _inFrame;
|
|
155
|
+
/** Set the canvas to render to. Called once when canvas is available. */
|
|
156
|
+
setCanvas(canvas: CanvasLike): void;
|
|
157
|
+
/** Get the current canvas. Throws if not in a frame. */
|
|
158
|
+
get canvas(): CanvasLike;
|
|
159
|
+
/** Whether we are currently between begin() and end(). */
|
|
160
|
+
get inFrame(): boolean;
|
|
161
|
+
/**
|
|
162
|
+
* Begin a new frame. Clears the canvas and resets stats.
|
|
163
|
+
* @param clearColor 32-bit ARGB color to clear with (default black = 0xFF000000).
|
|
164
|
+
*/
|
|
165
|
+
begin(clearColor?: number): void;
|
|
166
|
+
/**
|
|
167
|
+
* End the current frame. Restores canvas state.
|
|
168
|
+
*/
|
|
169
|
+
end(): void;
|
|
170
|
+
/**
|
|
171
|
+
* Apply camera transform to the canvas.
|
|
172
|
+
* Call after begin() and before drawing.
|
|
173
|
+
*/
|
|
174
|
+
applyCamera(cameraX: number, cameraY: number, zoom: number, rotation: number, viewportWidth: number, viewportHeight: number): void;
|
|
175
|
+
/** Increment draw call counter. Invoked in tandem with recordBatch, once per
|
|
176
|
+
* flush run in SpriteBatch.flush. */
|
|
177
|
+
recordDrawCall(): void;
|
|
178
|
+
/** Increment batch counter. Invoked in tandem with recordDrawCall, once per
|
|
179
|
+
* flush run in SpriteBatch.flush. */
|
|
180
|
+
recordBatch(): void;
|
|
181
|
+
}
|
|
182
|
+
//#endregion
|
|
183
|
+
//#region src/sprite-effects.d.ts
|
|
162
184
|
/** Color as RGBA (0-1 per channel). */
|
|
163
185
|
interface SpriteColor {
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
186
|
+
readonly r: number;
|
|
187
|
+
readonly g: number;
|
|
188
|
+
readonly b: number;
|
|
189
|
+
readonly a: number;
|
|
168
190
|
}
|
|
169
191
|
/** A sprite effect that can be applied during rendering. */
|
|
170
192
|
interface SpriteEffect {
|
|
171
|
-
|
|
193
|
+
readonly type: string;
|
|
172
194
|
}
|
|
173
195
|
/** Tint effect — blend a color onto the sprite. */
|
|
174
196
|
interface TintEffect extends SpriteEffect {
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
197
|
+
readonly type: 'tint';
|
|
198
|
+
readonly color: SpriteColor;
|
|
199
|
+
readonly amount: number;
|
|
178
200
|
}
|
|
179
201
|
/** Flash effect — overlay a solid color that decays. */
|
|
180
202
|
interface FlashEffect extends SpriteEffect {
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
203
|
+
readonly type: 'flash';
|
|
204
|
+
readonly color: SpriteColor;
|
|
205
|
+
readonly duration: number;
|
|
206
|
+
readonly elapsed: number;
|
|
185
207
|
}
|
|
186
208
|
/** Grayscale effect — desaturate the sprite. */
|
|
187
209
|
interface GrayscaleEffect extends SpriteEffect {
|
|
188
|
-
|
|
189
|
-
|
|
210
|
+
readonly type: 'grayscale';
|
|
211
|
+
readonly amount: number;
|
|
190
212
|
}
|
|
191
213
|
/** Outline effect — draw an outline around the sprite. */
|
|
192
214
|
interface OutlineEffect extends SpriteEffect {
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
215
|
+
readonly type: 'outline';
|
|
216
|
+
readonly color: SpriteColor;
|
|
217
|
+
readonly width: number;
|
|
196
218
|
}
|
|
197
219
|
/**
|
|
198
220
|
* Opaque pre-compiled shader program. Typically a Skia `RuntimeEffect` built
|
|
@@ -205,33 +227,33 @@ type CompiledShader = object;
|
|
|
205
227
|
type ShaderUniforms = Record<string, number | readonly number[]>;
|
|
206
228
|
/** Custom shader effect — apply a pre-compiled runtime shader with uniforms. */
|
|
207
229
|
interface CustomShaderEffect extends SpriteEffect {
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
230
|
+
readonly type: 'custom';
|
|
231
|
+
readonly shader: CompiledShader;
|
|
232
|
+
readonly uniforms: ShaderUniforms;
|
|
211
233
|
}
|
|
212
234
|
/** Water surface effect — animated UV-displaced sprite with foam crests. */
|
|
213
235
|
interface WaterEffect extends SpriteEffect {
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
236
|
+
readonly type: 'water';
|
|
237
|
+
readonly color: SpriteColor;
|
|
238
|
+
readonly foamColor: SpriteColor;
|
|
239
|
+
readonly waveSpeed: number;
|
|
240
|
+
readonly waveAmplitude: number;
|
|
219
241
|
}
|
|
220
242
|
/** Fog / volumetric haze effect — animated FBM noise layered over a sprite. */
|
|
221
243
|
interface FogEffect extends SpriteEffect {
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
244
|
+
readonly type: 'fog';
|
|
245
|
+
readonly color: SpriteColor;
|
|
246
|
+
readonly density: number;
|
|
247
|
+
readonly speed: number;
|
|
248
|
+
readonly scale: number;
|
|
227
249
|
}
|
|
228
250
|
/** Fire / flame effect — value-noise FBM flame rising upward from a sprite. */
|
|
229
251
|
interface FireEffect extends SpriteEffect {
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
252
|
+
readonly type: 'fire';
|
|
253
|
+
readonly color: SpriteColor;
|
|
254
|
+
readonly tipColor: SpriteColor;
|
|
255
|
+
readonly speed: number;
|
|
256
|
+
readonly intensity: number;
|
|
235
257
|
}
|
|
236
258
|
/**
|
|
237
259
|
* Drop-shadow effect — a single offset, blurred, tinted copy of the sprite drawn
|
|
@@ -240,77 +262,77 @@ interface FireEffect extends SpriteEffect {
|
|
|
240
262
|
* the offset, blur, and tint all live in the filter, so no extra draw pass.
|
|
241
263
|
*/
|
|
242
264
|
interface DropShadowEffect extends SpriteEffect {
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
265
|
+
readonly type: 'drop-shadow';
|
|
266
|
+
/** Horizontal shadow offset in design px. */
|
|
267
|
+
readonly offsetX: number;
|
|
268
|
+
/** Vertical shadow offset in design px; positive = downward (grounding). */
|
|
269
|
+
readonly offsetY: number;
|
|
270
|
+
/** Gaussian blur sigma applied to the shadow. 0 = hard edge. */
|
|
271
|
+
readonly blur: number;
|
|
272
|
+
/** Shadow color; `a` is the shadow opacity. */
|
|
273
|
+
readonly color: SpriteColor;
|
|
252
274
|
}
|
|
253
275
|
/** Rooftop city skyline — AABB silhouettes via SDF hash fields. */
|
|
254
276
|
interface RoofsCityEffect extends SpriteEffect {
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
277
|
+
readonly type: 'roofs-city';
|
|
278
|
+
readonly skyColor: SpriteColor;
|
|
279
|
+
readonly roofColor: SpriteColor;
|
|
280
|
+
readonly scrollOffsetY: number;
|
|
281
|
+
readonly density: number;
|
|
282
|
+
/** Destination render width in logical pixels — used as shader resolution.x. */
|
|
283
|
+
readonly resolutionW: number;
|
|
284
|
+
/** Destination render height in logical pixels — used as shader resolution.y. */
|
|
285
|
+
readonly resolutionH: number;
|
|
264
286
|
}
|
|
265
287
|
/** Forest canopy — value-noise tree line. */
|
|
266
288
|
interface ForestCanopyEffect extends SpriteEffect {
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
289
|
+
readonly type: 'forest-canopy';
|
|
290
|
+
readonly skyColor: SpriteColor;
|
|
291
|
+
readonly leafColor: SpriteColor;
|
|
292
|
+
readonly scrollOffsetY: number;
|
|
293
|
+
readonly density: number;
|
|
294
|
+
readonly resolutionW: number;
|
|
295
|
+
readonly resolutionH: number;
|
|
274
296
|
}
|
|
275
297
|
/** River surface — 1D height-field wave with foam crests. */
|
|
276
298
|
interface RiverWaveEffect extends SpriteEffect {
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
299
|
+
readonly type: 'river-wave';
|
|
300
|
+
readonly waterColor: SpriteColor;
|
|
301
|
+
readonly foamColor: SpriteColor;
|
|
302
|
+
readonly scrollOffsetY: number;
|
|
303
|
+
readonly waveScale: number;
|
|
304
|
+
readonly resolutionW: number;
|
|
305
|
+
readonly resolutionH: number;
|
|
284
306
|
}
|
|
285
307
|
/** Moon surface — polar-SDF craters on a flat disc. */
|
|
286
308
|
interface MoonCraterEffect extends SpriteEffect {
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
309
|
+
readonly type: 'moon-crater';
|
|
310
|
+
readonly moonColor: SpriteColor;
|
|
311
|
+
readonly craterColor: SpriteColor;
|
|
312
|
+
readonly scrollOffsetY: number;
|
|
313
|
+
readonly craterCount: number;
|
|
314
|
+
readonly resolutionW: number;
|
|
315
|
+
readonly resolutionH: number;
|
|
294
316
|
}
|
|
295
317
|
/** Cave interior — stalactites hanging from the top edge. */
|
|
296
318
|
interface CaveInteriorEffect extends SpriteEffect {
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
319
|
+
readonly type: 'cave-interior';
|
|
320
|
+
readonly caveColor: SpriteColor;
|
|
321
|
+
readonly glowColor: SpriteColor;
|
|
322
|
+
readonly scrollOffsetY: number;
|
|
323
|
+
readonly stalactiteCount: number;
|
|
324
|
+
readonly resolutionW: number;
|
|
325
|
+
readonly resolutionH: number;
|
|
304
326
|
}
|
|
305
327
|
/** Mountain / hill ridge — FBM height-field silhouette. */
|
|
306
328
|
interface MountainHillsEffect extends SpriteEffect {
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
329
|
+
readonly type: 'mountain-hills';
|
|
330
|
+
readonly skyColor: SpriteColor;
|
|
331
|
+
readonly hillColor: SpriteColor;
|
|
332
|
+
readonly scrollOffsetY: number;
|
|
333
|
+
readonly ridgeScale: number;
|
|
334
|
+
readonly resolutionW: number;
|
|
335
|
+
readonly resolutionH: number;
|
|
314
336
|
}
|
|
315
337
|
/** Any concrete sprite effect. */
|
|
316
338
|
type AnySpriteEffect = TintEffect | FlashEffect | GrayscaleEffect | OutlineEffect | CustomShaderEffect | WaterEffect | FogEffect | FireEffect | DropShadowEffect | RoofsCityEffect | ForestCanopyEffect | RiverWaveEffect | MoonCraterEffect | CaveInteriorEffect | MountainHillsEffect;
|
|
@@ -335,72 +357,72 @@ declare function fog(color: SpriteColor, density?: number, speed?: number, scale
|
|
|
335
357
|
/** Create a fire / flame effect. Time is passed to the renderer each
|
|
336
358
|
* frame via `beginFrame(w, h, time)` — the effect itself is time-invariant. */
|
|
337
359
|
declare function fire(opts: {
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
360
|
+
color: SpriteColor;
|
|
361
|
+
tipColor: SpriteColor;
|
|
362
|
+
speed?: number;
|
|
363
|
+
intensity?: number;
|
|
342
364
|
}): FireEffect;
|
|
343
365
|
/** Create a drop-shadow effect. Defaults to a soft shadow offset downward for
|
|
344
366
|
* grounding; `color.a` is the shadow opacity. */
|
|
345
367
|
declare function dropShadow(opts: {
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
368
|
+
color: SpriteColor;
|
|
369
|
+
offsetX?: number;
|
|
370
|
+
offsetY?: number;
|
|
371
|
+
blur?: number;
|
|
350
372
|
}): DropShadowEffect;
|
|
351
373
|
/** Create a rooftop city skyline effect. */
|
|
352
374
|
declare function roofsCity(opts: {
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
375
|
+
skyColor: SpriteColor;
|
|
376
|
+
roofColor: SpriteColor;
|
|
377
|
+
scrollOffsetY?: number;
|
|
378
|
+
density?: number;
|
|
379
|
+
resolutionW?: number;
|
|
380
|
+
resolutionH?: number;
|
|
359
381
|
}): RoofsCityEffect;
|
|
360
382
|
/** Create a forest canopy effect. */
|
|
361
383
|
declare function forestCanopy(opts: {
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
384
|
+
skyColor: SpriteColor;
|
|
385
|
+
leafColor: SpriteColor;
|
|
386
|
+
scrollOffsetY?: number;
|
|
387
|
+
density?: number;
|
|
388
|
+
resolutionW?: number;
|
|
389
|
+
resolutionH?: number;
|
|
368
390
|
}): ForestCanopyEffect;
|
|
369
391
|
/** Create a river wave surface effect. */
|
|
370
392
|
declare function riverWave(opts: {
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
393
|
+
waterColor: SpriteColor;
|
|
394
|
+
foamColor: SpriteColor;
|
|
395
|
+
scrollOffsetY?: number;
|
|
396
|
+
waveScale?: number;
|
|
397
|
+
resolutionW?: number;
|
|
398
|
+
resolutionH?: number;
|
|
377
399
|
}): RiverWaveEffect;
|
|
378
400
|
/** Create a moon crater surface effect. */
|
|
379
401
|
declare function moonCrater(opts: {
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
402
|
+
moonColor: SpriteColor;
|
|
403
|
+
craterColor: SpriteColor;
|
|
404
|
+
scrollOffsetY?: number;
|
|
405
|
+
craterCount?: number;
|
|
406
|
+
resolutionW?: number;
|
|
407
|
+
resolutionH?: number;
|
|
386
408
|
}): MoonCraterEffect;
|
|
387
409
|
/** Create a cave interior effect. */
|
|
388
410
|
declare function caveInterior(opts: {
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
411
|
+
caveColor: SpriteColor;
|
|
412
|
+
glowColor: SpriteColor;
|
|
413
|
+
scrollOffsetY?: number;
|
|
414
|
+
stalactiteCount?: number;
|
|
415
|
+
resolutionW?: number;
|
|
416
|
+
resolutionH?: number;
|
|
395
417
|
}): CaveInteriorEffect;
|
|
396
418
|
/** Create a mountain / hill ridge effect. */
|
|
397
419
|
declare function mountainHills(opts: {
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
420
|
+
skyColor: SpriteColor;
|
|
421
|
+
hillColor: SpriteColor;
|
|
422
|
+
scrollOffsetY?: number;
|
|
423
|
+
ridgeScale?: number;
|
|
424
|
+
resolutionW?: number;
|
|
425
|
+
resolutionH?: number;
|
|
404
426
|
}): MountainHillsEffect;
|
|
405
427
|
/**
|
|
406
428
|
* Advance a time-based effect by `dt` seconds.
|
|
@@ -417,50 +439,51 @@ declare function updateEffect(effect: AnySpriteEffect, dt: number): AnySpriteEff
|
|
|
417
439
|
* Get the current intensity of a flash effect (1 at start, 0 at end).
|
|
418
440
|
*/
|
|
419
441
|
declare function flashIntensity(effect: FlashEffect): number;
|
|
420
|
-
|
|
442
|
+
//#endregion
|
|
443
|
+
//#region src/sprite-batch.d.ts
|
|
421
444
|
/** A single sprite draw request in the batch. */
|
|
422
445
|
interface SpriteDrawCommand {
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
446
|
+
/** Texture (Skia SkImage). */
|
|
447
|
+
image: SkImageLike;
|
|
448
|
+
/** Source rectangle in the texture. */
|
|
449
|
+
srcX: number;
|
|
450
|
+
srcY: number;
|
|
451
|
+
srcW: number;
|
|
452
|
+
srcH: number;
|
|
453
|
+
/** Destination position and size. */
|
|
454
|
+
dstX: number;
|
|
455
|
+
dstY: number;
|
|
456
|
+
dstW: number;
|
|
457
|
+
dstH: number;
|
|
458
|
+
/** Optional per-sprite effect. Shared by reference across commands in a
|
|
459
|
+
* batch — the render adapter applies it once per batch. */
|
|
460
|
+
effect: AnySpriteEffect | undefined;
|
|
461
|
+
/** Per-instance alpha multiplier. Range [0, 1]. Default 1 (fully opaque).
|
|
462
|
+
* Participates in the batch key — sprites with different alphas are
|
|
463
|
+
* placed in separate batches so the renderer can apply each alpha once
|
|
464
|
+
* per draw call without per-sprite overhead. */
|
|
465
|
+
alpha: number;
|
|
466
|
+
/** Rotation in radians, clockwise (Skia Y-down convention). Default 0.
|
|
467
|
+
* Rotation is applied about the anchor point. */
|
|
468
|
+
rotation: number;
|
|
469
|
+
/** Anchor X fraction stored for the bridge rotation path. Range [0, 1]. */
|
|
470
|
+
anchorX: number;
|
|
471
|
+
/** Anchor Y fraction stored for the bridge rotation path. Range [0, 1]. */
|
|
472
|
+
anchorY: number;
|
|
473
|
+
/**
|
|
474
|
+
* When true, the sprite is drawn via `drawImageRect` so `dstW` and `dstH`
|
|
475
|
+
* are honored independently (non-uniform scale). A 256×256 source image
|
|
476
|
+
* will fill an arbitrary W×H destination rect.
|
|
477
|
+
*
|
|
478
|
+
* Default (false/absent): drawn via the batched `drawAtlas` path (uniform
|
|
479
|
+
* scale — dstW/srcW drives both axes). Stretched sprites are NOT batched
|
|
480
|
+
* with regular sprites; each is an independent `drawImageRect` call.
|
|
481
|
+
*
|
|
482
|
+
* Rotation is unsupported in stretch mode — the RSXform similarity-transform
|
|
483
|
+
* limit does not apply, but the bridge draws a plain axis-aligned rect.
|
|
484
|
+
* Combine with a zero rotation only.
|
|
485
|
+
*/
|
|
486
|
+
stretch: boolean;
|
|
464
487
|
}
|
|
465
488
|
/**
|
|
466
489
|
* SpriteBatch — collects sprite draw commands and groups them by texture
|
|
@@ -469,57 +492,57 @@ interface SpriteDrawCommand {
|
|
|
469
492
|
* Usage:
|
|
470
493
|
* 1. Call `draw()` for each sprite, optionally passing an effect
|
|
471
494
|
* 2. Call `flush()` with an atlas draw callback to execute all batched draws
|
|
472
|
-
* 3. Batching groups by
|
|
473
|
-
*
|
|
495
|
+
* 3. Batching groups consecutive commands by `(image, effect, alpha, stretch)`
|
|
496
|
+
* identity, preserving global insertion (z-sorted) order. Sharing an effect
|
|
497
|
+
* reference and the same alpha across consecutive entities maximizes batch
|
|
498
|
+
* size while keeping sprites in correct draw order.
|
|
474
499
|
*
|
|
475
500
|
* The actual Skia Atlas draw call is delegated to a callback so this module
|
|
476
501
|
* remains testable without Skia.
|
|
477
502
|
*/
|
|
478
503
|
declare class SpriteBatch {
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
declare const MOUNTAIN_HILLS_SKSL = "\nuniform float2 resolution;\nuniform float3 skyColor;\nuniform float3 hillColor;\nuniform float scrollOffsetY;\nuniform float ridgeScale;\n\nfloat hash(float x) { return fract(sin(x * 127.1) * 43758.5453); }\n\nfloat heightField(float x, float scale) {\n float h = 0.0;\n float amp = 0.5;\n float freq = scale;\n for (int i = 0; i < 4; i++) {\n float ix = floor(x * freq);\n float fx = fract(x * freq);\n fx = fx * fx * (3.0 - 2.0 * fx);\n h += amp * mix(hash(ix), hash(ix + 1.0), fx);\n freq *= 2.0;\n amp *= 0.5;\n }\n return h;\n}\n\nhalf4 main(float2 coord) {\n float2 uv = coord / max(resolution, float2(1.0));\n float scroll = scrollOffsetY / max(resolution.y, 1.0);\n float horizon = 0.4 + 0.3 * heightField(uv.x + scroll * 0.3, ridgeScale);\n float mountains = step(uv.y, horizon);\n half3 col = mix(half3(skyColor.r, skyColor.g, skyColor.b),\n half3(hillColor.r, hillColor.g, hillColor.b),\n half(mountains));\n return half4(col, 1.0);\n}\n";
|
|
522
|
-
|
|
504
|
+
private _commands;
|
|
505
|
+
private _pool;
|
|
506
|
+
private _batches;
|
|
507
|
+
private _allocCount;
|
|
508
|
+
/** Number of queued draw commands. */
|
|
509
|
+
get count(): number;
|
|
510
|
+
/** Cumulative number of SpriteDrawCommand objects allocated because the internal
|
|
511
|
+
* command pool was empty. Steady state should be 0 after warm-up. */
|
|
512
|
+
get allocCount(): number;
|
|
513
|
+
/** Queue a sprite draw from a frame.
|
|
514
|
+
*
|
|
515
|
+
* `anchorX` / `anchorY` define the pivot point of the sprite as a
|
|
516
|
+
* fraction of its destination size — `(0, 0)` = top-left (default),
|
|
517
|
+
* `(0.5, 0.5)` = center, `(1, 1)` = bottom-right. `dstX` / `dstY`
|
|
518
|
+
* then refer to the anchor point instead of the top-left corner.
|
|
519
|
+
*
|
|
520
|
+
* `alpha` is a per-instance opacity multiplier in [0, 1]. Default 1. */
|
|
521
|
+
draw(image: SkImageLike, frame: SpriteFrame, dstX: number, dstY: number, dstW?: number, dstH?: number, effect?: AnySpriteEffect, anchorX?: number, anchorY?: number, alpha?: number, rotation?: number, stretch?: boolean): void;
|
|
522
|
+
/** Queue a raw sprite draw with explicit src/dst rects. `dstX` / `dstY`
|
|
523
|
+
* refer to the anchor point — offset by `anchorX * dstW` / `anchorY * dstH`.
|
|
524
|
+
*
|
|
525
|
+
* `alpha` is a per-instance opacity multiplier in [0, 1]. Default 1. */
|
|
526
|
+
drawRaw(image: SkImageLike, srcX: number, srcY: number, srcW: number, srcH: number, dstX: number, dstY: number, dstW: number, dstH: number, effect?: AnySpriteEffect, anchorX?: number, anchorY?: number, alpha?: number, rotation?: number, stretch?: boolean): void;
|
|
527
|
+
/**
|
|
528
|
+
* Flush all queued commands in insertion order, grouping maximal consecutive
|
|
529
|
+
* runs that share the same `(image, effect, alpha, stretch)` key into a
|
|
530
|
+
* single `drawAtlas` call. This preserves global z-order (the caller is
|
|
531
|
+
* responsible for queuing in z-sorted order) while still batching runs of
|
|
532
|
+
* same-key sprites for efficiency.
|
|
533
|
+
*
|
|
534
|
+
* @param drawAtlas Callback invoked once per run. Receives
|
|
535
|
+
* `(image, commands)` — all commands in a run share the same key and are
|
|
536
|
+
* contiguous in the original insertion order.
|
|
537
|
+
* @param renderer Optional renderer to record stats.
|
|
538
|
+
*/
|
|
539
|
+
flush(drawAtlas: (image: SkImageLike, commands: SpriteDrawCommand[]) => void, renderer?: Renderer): void;
|
|
540
|
+
/** Clear all queued commands without drawing. */
|
|
541
|
+
clear(): void;
|
|
542
|
+
private _acquire;
|
|
543
|
+
}
|
|
544
|
+
//#endregion
|
|
545
|
+
//#region src/frame-renderer.d.ts
|
|
523
546
|
/** A 4-float RGBA color buffer (r, g, b, a in [0, 1]). */
|
|
524
547
|
type ColorLike = Float32Array;
|
|
525
548
|
/**
|
|
@@ -530,11 +553,11 @@ type ColorLike = Float32Array;
|
|
|
530
553
|
* interface in contra-variant parameter positions.
|
|
531
554
|
*/
|
|
532
555
|
interface RectLike {
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
556
|
+
x: number;
|
|
557
|
+
y: number;
|
|
558
|
+
width: number;
|
|
559
|
+
height: number;
|
|
560
|
+
setXYWH(x: number, y: number, w: number, h: number): void;
|
|
538
561
|
}
|
|
539
562
|
/**
|
|
540
563
|
* A mutable similarity transform.
|
|
@@ -544,57 +567,57 @@ interface RectLike {
|
|
|
544
567
|
* RN-Skia's `SkRSXform` exposes all four fields.
|
|
545
568
|
*/
|
|
546
569
|
interface RSXformLike {
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
570
|
+
scos: number;
|
|
571
|
+
ssin: number;
|
|
572
|
+
tx: number;
|
|
573
|
+
ty: number;
|
|
574
|
+
set(scos: number, ssin: number, tx: number, ty: number): void;
|
|
552
575
|
}
|
|
553
576
|
/** A compiled SkSL runtime effect. */
|
|
554
577
|
interface RuntimeEffectLike {
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
578
|
+
makeShader(uniforms: number[]): unknown;
|
|
579
|
+
getUniformCount(): number;
|
|
580
|
+
getUniformFloatCount(): number;
|
|
581
|
+
getUniformName(index: number): string;
|
|
582
|
+
getUniform(index: number): {
|
|
583
|
+
columns: number;
|
|
584
|
+
rows: number;
|
|
585
|
+
slot: number;
|
|
586
|
+
};
|
|
564
587
|
}
|
|
565
588
|
/** Color filter factory — subset used by the frame-renderer. */
|
|
566
589
|
interface ColorFilterFactoryLike {
|
|
567
|
-
|
|
568
|
-
|
|
590
|
+
MakeBlend(color: Float32Array, mode: number): unknown;
|
|
591
|
+
MakeMatrix(matrix: number[]): unknown;
|
|
569
592
|
}
|
|
570
593
|
/** Image filter factory — optional; absent on CPU/test surfaces. */
|
|
571
594
|
interface ImageFilterFactoryLike {
|
|
572
|
-
|
|
595
|
+
MakeDropShadow(dx: number, dy: number, sigmaX: number, sigmaY: number, color: Float32Array, input: null): unknown;
|
|
573
596
|
}
|
|
574
597
|
/** Runtime-effect factory — optional; absent when SkSL is unsupported. */
|
|
575
598
|
interface RuntimeEffectFactoryLike {
|
|
576
|
-
|
|
599
|
+
Make(sksl: string): RuntimeEffectLike | null;
|
|
577
600
|
}
|
|
578
601
|
/** Paint — the writable subset the frame-renderer mutates. */
|
|
579
602
|
interface PaintLike {
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
603
|
+
setAlphaf(alpha: number): void;
|
|
604
|
+
setColor?(color: Float32Array): void;
|
|
605
|
+
setColorFilter(filter: unknown): void;
|
|
606
|
+
setShader(shader: unknown): void;
|
|
607
|
+
setImageFilter(filter: unknown): void;
|
|
585
608
|
}
|
|
586
609
|
/** Minimal draw surface the frame-renderer calls into. */
|
|
587
610
|
interface DrawSurfaceLike {
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
611
|
+
save(): number;
|
|
612
|
+
restore(): void;
|
|
613
|
+
translate(x: number, y: number): void;
|
|
614
|
+
scale(sx: number, sy: number): void;
|
|
615
|
+
/** rotate(degrees, cx, cy) — DEGREES, forwarded verbatim (both Skia backends take degrees). */
|
|
616
|
+
rotate(degrees: number, cx: number, cy: number): void;
|
|
617
|
+
clear(color: Float32Array): void;
|
|
618
|
+
drawAtlas(image: unknown, srcRects: RectLike[], dstXforms: RSXformLike[], paint: PaintLike): void;
|
|
619
|
+
drawImageRect(image: unknown, src: RectLike, dst: RectLike, paint: PaintLike): void;
|
|
620
|
+
drawRect(rect: RectLike, paint: PaintLike): void;
|
|
598
621
|
}
|
|
599
622
|
/**
|
|
600
623
|
* Opaque picture (recorded draw commands).
|
|
@@ -605,8 +628,8 @@ interface DrawSurfaceLike {
|
|
|
605
628
|
type PictureLike = object;
|
|
606
629
|
/** Picture recorder. */
|
|
607
630
|
interface PictureRecorderLike {
|
|
608
|
-
|
|
609
|
-
|
|
631
|
+
beginRecording(bounds: RectLike): DrawSurfaceLike;
|
|
632
|
+
finishRecordingAsPicture(): PictureLike;
|
|
610
633
|
}
|
|
611
634
|
/**
|
|
612
635
|
* Minimal structural view of the Skia module the frame-renderer needs.
|
|
@@ -617,47 +640,47 @@ interface PictureRecorderLike {
|
|
|
617
640
|
* on CPU surfaces and in test mocks.
|
|
618
641
|
*/
|
|
619
642
|
interface FrameRendererModule {
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
643
|
+
XYWHRect(x: number, y: number, w: number, h: number): RectLike;
|
|
644
|
+
RSXform(scos: number, ssin: number, tx: number, ty: number): RSXformLike;
|
|
645
|
+
Paint(): PaintLike;
|
|
646
|
+
PictureRecorder(): PictureRecorderLike;
|
|
647
|
+
ColorFilter: ColorFilterFactoryLike;
|
|
648
|
+
RuntimeEffect?: RuntimeEffectFactoryLike;
|
|
649
|
+
ImageFilter?: ImageFilterFactoryLike;
|
|
627
650
|
}
|
|
628
651
|
/**
|
|
629
652
|
* A single compiled postfx pass descriptor produced by the runtime.
|
|
630
653
|
*/
|
|
631
654
|
interface FrameRendererCompiledPass {
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
};
|
|
655
|
+
readonly id: string;
|
|
656
|
+
readonly shader: {
|
|
657
|
+
makeShaderWithChildren(uniforms: number[], children: unknown[]): unknown | null;
|
|
658
|
+
getUniformCount?(): number;
|
|
659
|
+
getUniformName?(index: number): string;
|
|
660
|
+
getUniform?(index: number): {
|
|
661
|
+
columns: number;
|
|
662
|
+
rows: number;
|
|
663
|
+
slot: number;
|
|
642
664
|
};
|
|
643
|
-
|
|
644
|
-
|
|
665
|
+
};
|
|
666
|
+
readonly uniforms: Float32Array;
|
|
667
|
+
readonly children: readonly unknown[];
|
|
645
668
|
}
|
|
646
669
|
/** Minimal structural view of a PostFxRuntime that the frame-renderer needs. */
|
|
647
670
|
interface FrameRendererPostFxRuntime {
|
|
648
|
-
|
|
649
|
-
|
|
671
|
+
readonly supported: boolean;
|
|
672
|
+
buildPass?(chain: FrameRendererPostFxChain, width: number, height: number): readonly FrameRendererCompiledPass[];
|
|
650
673
|
}
|
|
651
674
|
/** Minimal structural view of an EffectChain the frame-renderer needs. */
|
|
652
675
|
interface FrameRendererPostFxChain {
|
|
653
|
-
|
|
676
|
+
enabled(): Iterable<unknown>;
|
|
654
677
|
}
|
|
655
678
|
/** A resolved postfx pass descriptor with named uniforms (for React JSX). */
|
|
656
679
|
interface FrameRendererPostFxDescriptor {
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
680
|
+
readonly id: string;
|
|
681
|
+
readonly source: unknown;
|
|
682
|
+
readonly uniforms: Record<string, number | readonly number[]>;
|
|
683
|
+
readonly children: readonly unknown[];
|
|
661
684
|
}
|
|
662
685
|
/**
|
|
663
686
|
* Frame renderer that bridges a `SpriteBatch` to a picture-backed draw surface.
|
|
@@ -668,12 +691,18 @@ interface FrameRendererPostFxDescriptor {
|
|
|
668
691
|
* 3. Call `endFrame()` — returns the recorded picture.
|
|
669
692
|
*/
|
|
670
693
|
interface FrameRenderer {
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
694
|
+
readonly canvas: CanvasLike;
|
|
695
|
+
beginFrame(viewportWidth: number, viewportHeight: number, time?: number, pixelDensity?: number): void;
|
|
696
|
+
drawAtlas(image: SkImageLike, commands: SpriteDrawCommand[]): void;
|
|
697
|
+
buildPostFxPasses(runtime: FrameRendererPostFxRuntime | null, chain: FrameRendererPostFxChain | null, width: number, height: number): readonly FrameRendererPostFxDescriptor[];
|
|
698
|
+
setPostFxBinding(runtime: FrameRendererPostFxRuntime | null, chain: FrameRendererPostFxChain | null): void;
|
|
699
|
+
/**
|
|
700
|
+
* Whether `buildPostFxPasses` would attempt to build passes from the bound
|
|
701
|
+
* runtime and chain. Pure null/flag checks — never calls `runtime.buildPass`,
|
|
702
|
+
* so it is safe on platforms where building throws (React Native Web).
|
|
703
|
+
*/
|
|
704
|
+
hasPostFxBinding(): boolean;
|
|
705
|
+
endFrame(): PictureLike | null;
|
|
677
706
|
}
|
|
678
707
|
/**
|
|
679
708
|
* Create a `FrameRenderer` backed by the given structural Skia module.
|
|
@@ -682,98 +711,71 @@ interface FrameRenderer {
|
|
|
682
711
|
* `@flare-engine/render-web` (passing a CanvasKit shim) use this factory.
|
|
683
712
|
*/
|
|
684
713
|
declare function createFrameRenderer(Skia: FrameRendererModule): FrameRenderer;
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
interface Glyph {
|
|
688
|
-
/** Character code (Unicode). */
|
|
689
|
-
id: number;
|
|
690
|
-
/** Source rect in the font texture. */
|
|
691
|
-
x: number;
|
|
692
|
-
y: number;
|
|
693
|
-
width: number;
|
|
694
|
-
height: number;
|
|
695
|
-
/** Draw offset. */
|
|
696
|
-
xOffset: number;
|
|
697
|
-
yOffset: number;
|
|
698
|
-
/** Horizontal advance after this glyph. */
|
|
699
|
-
xAdvance: number;
|
|
700
|
-
}
|
|
701
|
-
/** Kerning pair. */
|
|
702
|
-
interface KerningPair {
|
|
703
|
-
first: number;
|
|
704
|
-
second: number;
|
|
705
|
-
amount: number;
|
|
706
|
-
}
|
|
707
|
-
/** Parsed bitmap font data. */
|
|
708
|
-
interface BitmapFont {
|
|
709
|
-
/** Line height in pixels. */
|
|
710
|
-
lineHeight: number;
|
|
711
|
-
/** Baseline offset. */
|
|
712
|
-
base: number;
|
|
713
|
-
/** Glyph map by character code. */
|
|
714
|
-
glyphs: Map<number, Glyph>;
|
|
715
|
-
/** Kerning map. Key = `first << 16 | second`. */
|
|
716
|
-
kernings: Map<number, number>;
|
|
717
|
-
}
|
|
714
|
+
/** Zero both branch counters unconditionally (no __DEV__ guard). */
|
|
715
|
+
declare function resetXformCounters(): void;
|
|
718
716
|
/**
|
|
719
|
-
*
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
*
|
|
728
|
-
*
|
|
717
|
+
* Cumulative `fillXforms` branch hit counts since the last reset. Both stay 0
|
|
718
|
+
* when `__DEV__` is falsy or absent.
|
|
719
|
+
*
|
|
720
|
+
* These count transform WRITES, not sprites: a run drawn with an outline effect
|
|
721
|
+
* passes through `fillXforms` 9 times (8 offset passes + 1 main pass), so it
|
|
722
|
+
* contributes 9 hits per command — the transform work the renderer actually
|
|
723
|
+
* performs. The counters are process-global: every `createFrameRenderer`
|
|
724
|
+
* instance increments the same pair, so readings sum across live renderers.
|
|
725
|
+
*
|
|
726
|
+
* Allocates one object per call — never call it from the render loop.
|
|
729
727
|
*/
|
|
730
|
-
declare function
|
|
731
|
-
|
|
728
|
+
declare function getXformCounters(): {
|
|
729
|
+
rotated: number;
|
|
730
|
+
unrotated: number;
|
|
731
|
+
};
|
|
732
|
+
//#endregion
|
|
733
|
+
//#region src/render-system.d.ts
|
|
732
734
|
/** Position component data expected by the render system. */
|
|
733
735
|
interface PositionData {
|
|
734
|
-
|
|
735
|
-
|
|
736
|
+
x: number;
|
|
737
|
+
y: number;
|
|
736
738
|
}
|
|
737
739
|
/** Sprite anchor as a fraction of the destination rect — `(0, 0)` is
|
|
738
740
|
* top-left (default), `(0.5, 0.5)` is center, `(1, 1)` is bottom-right.
|
|
739
741
|
* When present, `Position` refers to the anchor point rather than the
|
|
740
742
|
* sprite's top-left corner. */
|
|
741
743
|
interface SpriteAnchor {
|
|
742
|
-
|
|
743
|
-
|
|
744
|
+
x: number;
|
|
745
|
+
y: number;
|
|
744
746
|
}
|
|
745
747
|
/** Sprite component data expected by the render system. */
|
|
746
748
|
interface SpriteData {
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
749
|
+
image: SkImageLike;
|
|
750
|
+
frame: SpriteFrame;
|
|
751
|
+
z: number;
|
|
752
|
+
width?: number;
|
|
753
|
+
height?: number;
|
|
754
|
+
/** Optional per-sprite effect (tint, flash, grayscale, outline, custom).
|
|
755
|
+
* Shared instances are batched together — prefer reusing an effect
|
|
756
|
+
* reference across entities that should render identically. */
|
|
757
|
+
effect?: AnySpriteEffect;
|
|
758
|
+
/** Optional pivot point for the sprite. Defaults to top-left `(0, 0)`. */
|
|
759
|
+
anchor?: SpriteAnchor;
|
|
760
|
+
/** Per-instance alpha multiplier. Range [0, 1]. Default 1 (fully opaque).
|
|
761
|
+
* Mutate directly each frame — e.g. `sprite.alpha = lerp(1, 0, t)`.
|
|
762
|
+
* Sprites with different alphas are placed in separate draw batches. */
|
|
763
|
+
alpha?: number;
|
|
764
|
+
/** Rotation in radians, clockwise (Skia Y-down convention). Default 0.
|
|
765
|
+
* Applied about the sprite's anchor point. Non-uniform scale combined with
|
|
766
|
+
* rotation is unsupported — scale is inferred uniformly from dstW/srcW. */
|
|
767
|
+
rotation?: number;
|
|
768
|
+
/**
|
|
769
|
+
* When true, draw via `drawImageRect` so `width` and `height` are honored
|
|
770
|
+
* independently (non-uniform scale). Use for background tiles or any sprite
|
|
771
|
+
* that must fill a non-square destination rect exactly.
|
|
772
|
+
*
|
|
773
|
+
* Default (absent/false): drawn via the batched `drawAtlas` uniform-scale
|
|
774
|
+
* path. Stretched sprites are NOT batched with regular sprites.
|
|
775
|
+
*
|
|
776
|
+
* Rotation is unsupported in stretch mode — combine only with `rotation = 0`.
|
|
777
|
+
*/
|
|
778
|
+
stretch?: boolean;
|
|
777
779
|
}
|
|
778
780
|
/**
|
|
779
781
|
* Create a render system function.
|
|
@@ -796,5 +798,64 @@ interface SpriteData {
|
|
|
796
798
|
declare function createRenderSystem(world: World, query: Query, positionDef: ComponentDef<PositionData>, spriteDef: ComponentDef<SpriteData>, batch: SpriteBatch): () => void;
|
|
797
799
|
/** Canonical Sprite component — queried by the render system alongside `Position`. */
|
|
798
800
|
declare const Sprite: ComponentDef<SpriteData>;
|
|
799
|
-
|
|
800
|
-
|
|
801
|
+
//#endregion
|
|
802
|
+
//#region src/shaders.d.ts
|
|
803
|
+
declare const FIRE_SKSL = "\nuniform float2 resolution;\nuniform float3 color;\nuniform float3 tipColor;\nuniform float speed;\nuniform float intensity;\nuniform float time;\n\nfloat hash(float2 p) { return fract(sin(dot(p, float2(127.1, 311.7))) * 43758.5453); }\n\nfloat vnoise(float2 p) {\n float2 i = floor(p);\n float2 f = fract(p);\n float2 u = f * f * (3.0 - 2.0 * f);\n float a = hash(i);\n float b = hash(i + float2(1.0, 0.0));\n float c = hash(i + float2(0.0, 1.0));\n float d = hash(i + float2(1.0, 1.0));\n return mix(mix(a, b, u.x), mix(c, d, u.x), u.y);\n}\n\nfloat fbm(float2 p) {\n return 0.5 * vnoise(p) + 0.25 * vnoise(p * 2.0);\n}\n\nhalf4 main(float2 coord) {\n float2 uv = coord / max(resolution, float2(1.0));\n float2 np = float2(uv.x * 4.0, uv.y * 6.0 - time * speed * 2.0);\n float n = fbm(np);\n float flameMask = smoothstep(0.0, intensity, n * (1.0 - uv.y));\n float3 fireRgb = mix(color, tipColor, uv.y);\n return half4(fireRgb.r, fireRgb.g, fireRgb.b, flameMask);\n}\n";
|
|
804
|
+
declare const FOG_SKSL = "\nuniform float2 resolution;\nuniform float3 color;\nuniform float density;\nuniform float speed;\nuniform float scale;\nuniform float time;\n\nfloat hash(float2 p) {\n return fract(sin(dot(p, float2(127.1, 311.7))) * 43758.5453);\n}\n\nfloat valueNoise(float2 p) {\n float2 i = floor(p);\n float2 f = fract(p);\n float2 u = f * f * (3.0 - 2.0 * f);\n float a = hash(i);\n float b = hash(i + float2(1.0, 0.0));\n float c = hash(i + float2(0.0, 1.0));\n float d = hash(i + float2(1.0, 1.0));\n return mix(mix(a, b, u.x), mix(c, d, u.x), u.y);\n}\n\nfloat fbm(float2 p) {\n float value = 0.0;\n float amplitude = 0.5;\n for (int i = 0; i < 4; i++) {\n value += amplitude * valueNoise(p);\n p *= 2.0;\n amplitude *= 0.5;\n }\n return value;\n}\n\nhalf4 main(float2 coord) {\n float2 uv = coord / max(resolution, float2(1.0));\n float2 drift = float2(time * speed, 0.3 * time * speed);\n float n = clamp(fbm(uv * scale + drift), 0.0, 1.0);\n return half4(color.r, color.g, color.b, clamp(density * n, 0.0, 1.0));\n}\n";
|
|
805
|
+
declare const WATER_SKSL = "\nuniform float2 resolution;\nuniform float3 color;\nuniform float3 foamColor;\nuniform float waveSpeed;\nuniform float waveAmplitude;\nuniform float time;\n\nhalf4 main(float2 coord) {\n float2 uv = coord / max(resolution, float2(1.0));\n float waveDeriv = cos(uv.x * 6.2832 * 3.0 + time * waveSpeed * 2.0) * waveAmplitude * 2.0\n + cos(uv.x * 6.2832 * 5.0 - time * waveSpeed * 1.3 + 1.5) * waveAmplitude;\n float foam = smoothstep(waveAmplitude * 0.6, waveAmplitude * 1.5, waveDeriv);\n half3 tinted = half3(color.r, color.g, color.b);\n half3 final = mix(tinted, half3(foamColor.r, foamColor.g, foamColor.b), half(foam));\n return half4(final, 1.0);\n}\n";
|
|
806
|
+
declare const ROOFS_CITY_SKSL = "\nuniform float2 resolution;\nuniform float3 skyColor;\nuniform float3 roofColor;\nuniform float scrollOffsetY;\nuniform float density;\n\nfloat hash(float x) { return fract(sin(x * 127.1) * 43758.5453); }\n\nfloat buildingTop(float2 uv, float density) {\n float col = floor(uv.x * density);\n float h = 0.35 + 0.35 * hash(col);\n float w = 0.6 + 0.3 * hash(col + 7.3);\n float edge = step(abs(fract(uv.x * density) - 0.5), w * 0.5);\n return edge * step(uv.y, h);\n}\n\nhalf4 main(float2 coord) {\n float2 uv = coord / max(resolution, float2(1.0));\n uv.y = uv.y + scrollOffsetY / max(resolution.y, 1.0);\n uv.y = fract(uv.y);\n float buildings = buildingTop(uv, density);\n half3 col = mix(half3(skyColor.r, skyColor.g, skyColor.b),\n half3(roofColor.r, roofColor.g, roofColor.b),\n half(buildings));\n return half4(col, 1.0);\n}\n";
|
|
807
|
+
declare const FOREST_CANOPY_SKSL = "\nuniform float2 resolution;\nuniform float3 skyColor;\nuniform float3 leafColor;\nuniform float scrollOffsetY;\nuniform float density;\n\nfloat hash(float2 p) { return fract(sin(dot(p, float2(127.1, 311.7))) * 43758.5453); }\n\nfloat valueNoise(float2 p) {\n float2 i = floor(p);\n float2 f = fract(p);\n float2 u = f * f * (3.0 - 2.0 * f);\n return mix(mix(hash(i), hash(i + float2(1.0, 0.0)), u.x),\n mix(hash(i + float2(0.0, 1.0)), hash(i + float2(1.0, 1.0)), u.x), u.y);\n}\n\nhalf4 main(float2 coord) {\n float2 uv = coord / max(resolution, float2(1.0));\n uv.y = uv.y + scrollOffsetY / max(resolution.y, 1.0);\n float n = valueNoise(float2(uv.x * density, uv.y * 3.0));\n float treeLine = 0.55 + 0.25 * valueNoise(float2(uv.x * density * 0.5, 0.0));\n float canopy = step(uv.y, treeLine) * smoothstep(0.3, 0.7, n);\n half3 col = mix(half3(skyColor.r, skyColor.g, skyColor.b),\n half3(leafColor.r, leafColor.g, leafColor.b),\n half(canopy));\n return half4(col, 1.0);\n}\n";
|
|
808
|
+
declare const RIVER_WAVE_SKSL = "\nuniform float2 resolution;\nuniform float3 waterColor;\nuniform float3 foamColor;\nuniform float scrollOffsetY;\nuniform float waveScale;\n\nhalf4 main(float2 coord) {\n float2 uv = coord / max(resolution, float2(1.0));\n float scroll = scrollOffsetY / max(resolution.y, 1.0);\n float2 p = float2(uv.x, uv.y + scroll);\n float w1 = sin(p.x * 6.2832 * waveScale + p.y * 4.0) * 0.04;\n float w2 = sin(p.x * 6.2832 * waveScale * 1.7 - p.y * 2.5 + 1.2) * 0.02;\n float surface = 0.5 + w1 + w2;\n float inWater = step(uv.y, surface);\n float crest = smoothstep(surface - 0.015, surface, uv.y) * (1.0 - inWater) +\n smoothstep(surface + 0.015, surface, uv.y) * inWater;\n half3 base = mix(half3(foamColor.r, foamColor.g, foamColor.b),\n half3(waterColor.r, waterColor.g, waterColor.b),\n half(inWater));\n half3 col = mix(base, half3(foamColor.r, foamColor.g, foamColor.b), half(crest * 0.6));\n return half4(col, 1.0);\n}\n";
|
|
809
|
+
declare const MOON_CRATER_SKSL = "\nuniform float2 resolution;\nuniform float3 moonColor;\nuniform float3 craterColor;\nuniform float scrollOffsetY;\nuniform float craterCount;\n\nfloat hash(float2 p) { return fract(sin(dot(p, float2(127.1, 311.7))) * 43758.5453); }\n\nfloat crater(float2 uv, float2 center, float r) {\n float d = length(uv - center);\n float rim = smoothstep(r, r * 0.85, d) - smoothstep(r * 0.85, r * 0.65, d);\n float floor_ = smoothstep(r * 0.65, r * 0.4, d);\n return rim * 0.6 + floor_ * 0.25;\n}\n\nhalf4 main(float2 coord) {\n float2 uv = coord / max(resolution, float2(1.0));\n uv.y = uv.y + scrollOffsetY / max(resolution.y, 1.0);\n float c = 0.0;\n for (int i = 0; i < 6; i++) {\n float fi = float(i);\n float2 center = float2(hash(float2(fi, 0.0)), hash(float2(fi, 1.0)));\n float r = 0.04 + 0.07 * hash(float2(fi, 2.0));\n c += crater(fract(uv), center, r) * step(fi, craterCount - 1.0);\n }\n c = clamp(c, 0.0, 1.0);\n half3 col = mix(half3(moonColor.r, moonColor.g, moonColor.b),\n half3(craterColor.r, craterColor.g, craterColor.b),\n half(c));\n return half4(col, 1.0);\n}\n";
|
|
810
|
+
declare const CAVE_INTERIOR_SKSL = "\nuniform float2 resolution;\nuniform float3 caveColor;\nuniform float3 glowColor;\nuniform float scrollOffsetY;\nuniform float stalactiteCount;\n\nfloat hash(float x) { return fract(sin(x * 127.1) * 43758.5453); }\n\nfloat stalactite(float2 uv, float count) {\n float col = floor(uv.x * count);\n float tip = 0.1 + 0.2 * hash(col);\n float w = 0.3 + 0.3 * hash(col + 5.0);\n float dx = abs(fract(uv.x * count) - 0.5) / (w * 0.5);\n float shape = step(dx, 1.0) * step(uv.y, tip * (1.0 - clamp(dx, 0.0, 1.0)));\n return shape;\n}\n\nhalf4 main(float2 coord) {\n float2 uv = coord / max(resolution, float2(1.0));\n uv.y = 1.0 - uv.y;\n uv.y = uv.y + scrollOffsetY / max(resolution.y, 1.0);\n float stalac = stalactite(uv, stalactiteCount);\n float glow = smoothstep(0.8, 1.0, uv.y) * (1.0 - stalac);\n half3 col = mix(half3(caveColor.r, caveColor.g, caveColor.b),\n half3(glowColor.r, glowColor.g, glowColor.b),\n half(glow));\n col = mix(col, half3(caveColor.r, caveColor.g, caveColor.b) * half(0.3), half(stalac));\n return half4(col, 1.0);\n}\n";
|
|
811
|
+
declare const MOUNTAIN_HILLS_SKSL = "\nuniform float2 resolution;\nuniform float3 skyColor;\nuniform float3 hillColor;\nuniform float scrollOffsetY;\nuniform float ridgeScale;\n\nfloat hash(float x) { return fract(sin(x * 127.1) * 43758.5453); }\n\nfloat heightField(float x, float scale) {\n float h = 0.0;\n float amp = 0.5;\n float freq = scale;\n for (int i = 0; i < 4; i++) {\n float ix = floor(x * freq);\n float fx = fract(x * freq);\n fx = fx * fx * (3.0 - 2.0 * fx);\n h += amp * mix(hash(ix), hash(ix + 1.0), fx);\n freq *= 2.0;\n amp *= 0.5;\n }\n return h;\n}\n\nhalf4 main(float2 coord) {\n float2 uv = coord / max(resolution, float2(1.0));\n float scroll = scrollOffsetY / max(resolution.y, 1.0);\n float horizon = 0.4 + 0.3 * heightField(uv.x + scroll * 0.3, ridgeScale);\n float mountains = step(uv.y, horizon);\n half3 col = mix(half3(skyColor.r, skyColor.g, skyColor.b),\n half3(hillColor.r, hillColor.g, hillColor.b),\n half(mountains));\n return half4(col, 1.0);\n}\n";
|
|
812
|
+
//#endregion
|
|
813
|
+
//#region src/sprite-font.d.ts
|
|
814
|
+
/** A single glyph in a bitmap font. */
|
|
815
|
+
interface Glyph {
|
|
816
|
+
/** Character code (Unicode). */
|
|
817
|
+
id: number;
|
|
818
|
+
/** Source rect in the font texture. */
|
|
819
|
+
x: number;
|
|
820
|
+
y: number;
|
|
821
|
+
width: number;
|
|
822
|
+
height: number;
|
|
823
|
+
/** Draw offset. */
|
|
824
|
+
xOffset: number;
|
|
825
|
+
yOffset: number;
|
|
826
|
+
/** Horizontal advance after this glyph. */
|
|
827
|
+
xAdvance: number;
|
|
828
|
+
}
|
|
829
|
+
/** Kerning pair. */
|
|
830
|
+
interface KerningPair {
|
|
831
|
+
first: number;
|
|
832
|
+
second: number;
|
|
833
|
+
amount: number;
|
|
834
|
+
}
|
|
835
|
+
/** Parsed bitmap font data. */
|
|
836
|
+
interface BitmapFont {
|
|
837
|
+
/** Line height in pixels. */
|
|
838
|
+
lineHeight: number;
|
|
839
|
+
/** Baseline offset. */
|
|
840
|
+
base: number;
|
|
841
|
+
/** Glyph map by character code. */
|
|
842
|
+
glyphs: Map<number, Glyph>;
|
|
843
|
+
/** Kerning map. Key = `first << 16 | second`. */
|
|
844
|
+
kernings: Map<number, number>;
|
|
845
|
+
}
|
|
846
|
+
/**
|
|
847
|
+
* Parse BMFont JSON format (common output from tools like Hiero, BMFont, msdf-bmfont).
|
|
848
|
+
*/
|
|
849
|
+
declare function parseBMFontJSON(json: unknown): BitmapFont;
|
|
850
|
+
/** Get kerning between two characters. */
|
|
851
|
+
declare function getKerning(font: BitmapFont, first: number, second: number): number;
|
|
852
|
+
/** Measure the width of a text string in pixels. */
|
|
853
|
+
declare function measureText(font: BitmapFont, text: string): number;
|
|
854
|
+
/**
|
|
855
|
+
* Draw text using a SpriteBatch.
|
|
856
|
+
* Characters are batched as individual sprites from the font texture.
|
|
857
|
+
*/
|
|
858
|
+
declare function drawText(batch: SpriteBatch, font: BitmapFont, image: SkImageLike, text: string, x: number, y: number, scale?: number): void;
|
|
859
|
+
//#endregion
|
|
860
|
+
export { type AnySpriteEffect, type BitmapFont, CAVE_INTERIOR_SKSL, Camera2D, type CanvasLike, type CaveInteriorEffect, type ColorFilterFactoryLike, type ColorLike, type CompiledShader, type CustomShaderEffect, type DrawSurfaceLike, type Drawable, type DropShadowEffect, FIRE_SKSL, FOG_SKSL, FOREST_CANOPY_SKSL, type FireEffect, type FlashEffect, type FogEffect, type FollowOptions, type ForestCanopyEffect, type FrameRenderer, type FrameRendererCompiledPass, type FrameRendererModule, type FrameRendererPostFxChain, type FrameRendererPostFxDescriptor, type FrameRendererPostFxRuntime, type Glyph, type GrayscaleEffect, type ImageFilterFactoryLike, type KerningPair, MOON_CRATER_SKSL, MOUNTAIN_HILLS_SKSL, type MoonCraterEffect, type MountainHillsEffect, type OutlineEffect, type PaintLike, type PictureLike, type PictureRecorderLike, type PositionData, RIVER_WAVE_SKSL, ROOFS_CITY_SKSL, type RSXformLike, type RectLike, type RenderStats, Renderer, type RiverWaveEffect, type RoofsCityEffect, type RuntimeEffectFactoryLike, type RuntimeEffectLike, type ShaderUniforms, Sprite, type SpriteAnchor, SpriteBatch, type SpriteColor, type SpriteData, type SpriteDrawCommand, type SpriteEffect, type TintEffect, WATER_SKSL, type WaterEffect, caveInterior, createFrameRenderer, createRenderSystem, custom, drawOrderCompare, drawText, dropShadow, fire, flash, flashIntensity, fog, forestCanopy, getKerning, getXformCounters, grayscale, measureText, moonCrater, mountainHills, outline, parseBMFontJSON, resetXformCounters, riverWave, roofsCity, sortByDrawOrder, tint, updateEffect, water };
|
|
861
|
+
//# sourceMappingURL=index.d.mts.map
|