@flighthq/surface 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (210) hide show
  1. package/dist/index.d.ts +43 -0
  2. package/dist/index.d.ts.map +1 -0
  3. package/dist/index.js +42 -0
  4. package/dist/index.js.map +1 -0
  5. package/dist/surface.d.ts +16 -0
  6. package/dist/surface.d.ts.map +1 -0
  7. package/dist/surface.js +84 -0
  8. package/dist/surface.js.map +1 -0
  9. package/dist/surfaceAffine.d.ts +27 -0
  10. package/dist/surfaceAffine.d.ts.map +1 -0
  11. package/dist/surfaceAffine.js +159 -0
  12. package/dist/surfaceAffine.js.map +1 -0
  13. package/dist/surfaceAlpha.d.ts +27 -0
  14. package/dist/surfaceAlpha.d.ts.map +1 -0
  15. package/dist/surfaceAlpha.js +83 -0
  16. package/dist/surfaceAlpha.js.map +1 -0
  17. package/dist/surfaceBevel.d.ts +42 -0
  18. package/dist/surfaceBevel.d.ts.map +1 -0
  19. package/dist/surfaceBevel.js +102 -0
  20. package/dist/surfaceBevel.js.map +1 -0
  21. package/dist/surfaceBlur.d.ts +62 -0
  22. package/dist/surfaceBlur.d.ts.map +1 -0
  23. package/dist/surfaceBlur.js +263 -0
  24. package/dist/surfaceBlur.js.map +1 -0
  25. package/dist/surfaceChannel.d.ts +24 -0
  26. package/dist/surfaceChannel.d.ts.map +1 -0
  27. package/dist/surfaceChannel.js +126 -0
  28. package/dist/surfaceChannel.js.map +1 -0
  29. package/dist/surfaceColorMatrix.d.ts +57 -0
  30. package/dist/surfaceColorMatrix.d.ts.map +1 -0
  31. package/dist/surfaceColorMatrix.js +127 -0
  32. package/dist/surfaceColorMatrix.js.map +1 -0
  33. package/dist/surfaceCompare.d.ts +18 -0
  34. package/dist/surfaceCompare.d.ts.map +1 -0
  35. package/dist/surfaceCompare.js +64 -0
  36. package/dist/surfaceCompare.js.map +1 -0
  37. package/dist/surfaceComposite.d.ts +53 -0
  38. package/dist/surfaceComposite.d.ts.map +1 -0
  39. package/dist/surfaceComposite.js +230 -0
  40. package/dist/surfaceComposite.js.map +1 -0
  41. package/dist/surfaceConvolution.d.ts +27 -0
  42. package/dist/surfaceConvolution.d.ts.map +1 -0
  43. package/dist/surfaceConvolution.js +103 -0
  44. package/dist/surfaceConvolution.js.map +1 -0
  45. package/dist/surfaceCopy.d.ts +23 -0
  46. package/dist/surfaceCopy.d.ts.map +1 -0
  47. package/dist/surfaceCopy.js +78 -0
  48. package/dist/surfaceCopy.js.map +1 -0
  49. package/dist/surfaceCoverage.d.ts +11 -0
  50. package/dist/surfaceCoverage.d.ts.map +1 -0
  51. package/dist/surfaceCoverage.js +29 -0
  52. package/dist/surfaceCoverage.js.map +1 -0
  53. package/dist/surfaceCrop.d.ts +33 -0
  54. package/dist/surfaceCrop.d.ts.map +1 -0
  55. package/dist/surfaceCrop.js +174 -0
  56. package/dist/surfaceCrop.js.map +1 -0
  57. package/dist/surfaceDisplacement.d.ts +48 -0
  58. package/dist/surfaceDisplacement.d.ts.map +1 -0
  59. package/dist/surfaceDisplacement.js +131 -0
  60. package/dist/surfaceDisplacement.js.map +1 -0
  61. package/dist/surfaceDissolve.d.ts +21 -0
  62. package/dist/surfaceDissolve.d.ts.map +1 -0
  63. package/dist/surfaceDissolve.js +97 -0
  64. package/dist/surfaceDissolve.js.map +1 -0
  65. package/dist/surfaceDraw.d.ts +8 -0
  66. package/dist/surfaceDraw.d.ts.map +1 -0
  67. package/dist/surfaceDraw.js +14 -0
  68. package/dist/surfaceDraw.js.map +1 -0
  69. package/dist/surfaceEncode.d.ts +3 -0
  70. package/dist/surfaceEncode.d.ts.map +1 -0
  71. package/dist/surfaceEncode.js +18 -0
  72. package/dist/surfaceEncode.js.map +1 -0
  73. package/dist/surfaceFill.d.ts +12 -0
  74. package/dist/surfaceFill.d.ts.map +1 -0
  75. package/dist/surfaceFill.js +85 -0
  76. package/dist/surfaceFill.js.map +1 -0
  77. package/dist/surfaceFingerprint.d.ts +26 -0
  78. package/dist/surfaceFingerprint.d.ts.map +1 -0
  79. package/dist/surfaceFingerprint.js +99 -0
  80. package/dist/surfaceFingerprint.js.map +1 -0
  81. package/dist/surfaceFlip.d.ts +16 -0
  82. package/dist/surfaceFlip.d.ts.map +1 -0
  83. package/dist/surfaceFlip.js +98 -0
  84. package/dist/surfaceFlip.js.map +1 -0
  85. package/dist/surfaceFormat.d.ts +26 -0
  86. package/dist/surfaceFormat.d.ts.map +1 -0
  87. package/dist/surfaceFormat.js +80 -0
  88. package/dist/surfaceFormat.js.map +1 -0
  89. package/dist/surfaceFrom.d.ts +14 -0
  90. package/dist/surfaceFrom.d.ts.map +1 -0
  91. package/dist/surfaceFrom.js +87 -0
  92. package/dist/surfaceFrom.js.map +1 -0
  93. package/dist/surfaceGradient.d.ts +57 -0
  94. package/dist/surfaceGradient.d.ts.map +1 -0
  95. package/dist/surfaceGradient.js +176 -0
  96. package/dist/surfaceGradient.js.map +1 -0
  97. package/dist/surfaceGradientFill.d.ts +32 -0
  98. package/dist/surfaceGradientFill.d.ts.map +1 -0
  99. package/dist/surfaceGradientFill.js +120 -0
  100. package/dist/surfaceGradientFill.js.map +1 -0
  101. package/dist/surfaceHistogram.d.ts +20 -0
  102. package/dist/surfaceHistogram.d.ts.map +1 -0
  103. package/dist/surfaceHistogram.js +61 -0
  104. package/dist/surfaceHistogram.js.map +1 -0
  105. package/dist/surfaceImageChannel.d.ts +2 -0
  106. package/dist/surfaceImageChannel.d.ts.map +1 -0
  107. package/dist/surfaceImageChannel.js +2 -0
  108. package/dist/surfaceImageChannel.js.map +1 -0
  109. package/dist/surfaceMedian.d.ts +14 -0
  110. package/dist/surfaceMedian.d.ts.map +1 -0
  111. package/dist/surfaceMedian.js +77 -0
  112. package/dist/surfaceMedian.js.map +1 -0
  113. package/dist/surfaceMorphological.d.ts +29 -0
  114. package/dist/surfaceMorphological.d.ts.map +1 -0
  115. package/dist/surfaceMorphological.js +81 -0
  116. package/dist/surfaceMorphological.js.map +1 -0
  117. package/dist/surfaceNoise.d.ts +48 -0
  118. package/dist/surfaceNoise.d.ts.map +1 -0
  119. package/dist/surfaceNoise.js +245 -0
  120. package/dist/surfaceNoise.js.map +1 -0
  121. package/dist/surfacePaletteMap.d.ts +17 -0
  122. package/dist/surfacePaletteMap.d.ts.map +1 -0
  123. package/dist/surfacePaletteMap.js +45 -0
  124. package/dist/surfacePaletteMap.js.map +1 -0
  125. package/dist/surfacePixel.d.ts +9 -0
  126. package/dist/surfacePixel.d.ts.map +1 -0
  127. package/dist/surfacePixel.js +36 -0
  128. package/dist/surfacePixel.js.map +1 -0
  129. package/dist/surfacePixelate.d.ts +13 -0
  130. package/dist/surfacePixelate.d.ts.map +1 -0
  131. package/dist/surfacePixelate.js +61 -0
  132. package/dist/surfacePixelate.js.map +1 -0
  133. package/dist/surfaceQuery.d.ts +13 -0
  134. package/dist/surfaceQuery.d.ts.map +1 -0
  135. package/dist/surfaceQuery.js +46 -0
  136. package/dist/surfaceQuery.js.map +1 -0
  137. package/dist/surfaceRegion.d.ts +20 -0
  138. package/dist/surfaceRegion.d.ts.map +1 -0
  139. package/dist/surfaceRegion.js +28 -0
  140. package/dist/surfaceRegion.js.map +1 -0
  141. package/dist/surfaceResize.d.ts +27 -0
  142. package/dist/surfaceResize.d.ts.map +1 -0
  143. package/dist/surfaceResize.js +191 -0
  144. package/dist/surfaceResize.js.map +1 -0
  145. package/dist/surfaceRotate.d.ts +32 -0
  146. package/dist/surfaceRotate.d.ts.map +1 -0
  147. package/dist/surfaceRotate.js +143 -0
  148. package/dist/surfaceRotate.js.map +1 -0
  149. package/dist/surfaceShadow.d.ts +107 -0
  150. package/dist/surfaceShadow.d.ts.map +1 -0
  151. package/dist/surfaceShadow.js +173 -0
  152. package/dist/surfaceShadow.js.map +1 -0
  153. package/dist/surfaceSharpen.d.ts +25 -0
  154. package/dist/surfaceSharpen.d.ts.map +1 -0
  155. package/dist/surfaceSharpen.js +47 -0
  156. package/dist/surfaceSharpen.js.map +1 -0
  157. package/dist/surfaceTone.d.ts +28 -0
  158. package/dist/surfaceTone.d.ts.map +1 -0
  159. package/dist/surfaceTone.js +69 -0
  160. package/dist/surfaceTone.js.map +1 -0
  161. package/dist/surfaceTransform.d.ts +40 -0
  162. package/dist/surfaceTransform.d.ts.map +1 -0
  163. package/dist/surfaceTransform.js +163 -0
  164. package/dist/surfaceTransform.js.map +1 -0
  165. package/dist/surfaceWarp.d.ts +48 -0
  166. package/dist/surfaceWarp.d.ts.map +1 -0
  167. package/dist/surfaceWarp.js +284 -0
  168. package/dist/surfaceWarp.js.map +1 -0
  169. package/package.json +39 -0
  170. package/src/surface.test.ts +78 -0
  171. package/src/surfaceAffine.test.ts +98 -0
  172. package/src/surfaceAlpha.test.ts +113 -0
  173. package/src/surfaceBevel.test.ts +67 -0
  174. package/src/surfaceBlur.test.ts +240 -0
  175. package/src/surfaceChannel.test.ts +97 -0
  176. package/src/surfaceColorMatrix.test.ts +220 -0
  177. package/src/surfaceCompare.test.ts +92 -0
  178. package/src/surfaceComposite.test.ts +256 -0
  179. package/src/surfaceConvolution.test.ts +136 -0
  180. package/src/surfaceCopy.test.ts +54 -0
  181. package/src/surfaceCoverage.test.ts +39 -0
  182. package/src/surfaceCrop.test.ts +116 -0
  183. package/src/surfaceDisplacement.test.ts +142 -0
  184. package/src/surfaceDissolve.test.ts +99 -0
  185. package/src/surfaceDraw.test.ts +38 -0
  186. package/src/surfaceEncode.test.ts +18 -0
  187. package/src/surfaceFill.test.ts +89 -0
  188. package/src/surfaceFingerprint.test.ts +103 -0
  189. package/src/surfaceFlip.test.ts +59 -0
  190. package/src/surfaceFormat.test.ts +124 -0
  191. package/src/surfaceFrom.test.ts +62 -0
  192. package/src/surfaceGradient.test.ts +91 -0
  193. package/src/surfaceGradientFill.test.ts +107 -0
  194. package/src/surfaceHistogram.test.ts +70 -0
  195. package/src/surfaceImageChannel.test.ts +19 -0
  196. package/src/surfaceMedian.test.ts +45 -0
  197. package/src/surfaceMorphological.test.ts +75 -0
  198. package/src/surfaceNoise.test.ts +169 -0
  199. package/src/surfacePaletteMap.test.ts +55 -0
  200. package/src/surfacePixel.test.ts +99 -0
  201. package/src/surfacePixelate.test.ts +46 -0
  202. package/src/surfaceQuery.test.ts +48 -0
  203. package/src/surfaceRegion.test.ts +34 -0
  204. package/src/surfaceResize.test.ts +112 -0
  205. package/src/surfaceRotate.test.ts +119 -0
  206. package/src/surfaceShadow.test.ts +165 -0
  207. package/src/surfaceSharpen.test.ts +50 -0
  208. package/src/surfaceTone.test.ts +104 -0
  209. package/src/surfaceTransform.test.ts +134 -0
  210. package/src/surfaceWarp.test.ts +124 -0
@@ -0,0 +1,103 @@
1
+ /**
2
+ * Applies a convolution kernel to `source` and writes into `out`.
3
+ * `out` must be at least `source.width * source.height * 4` bytes.
4
+ *
5
+ * `out` must not alias `source.surface.data` — convolution reads neighboring
6
+ * pixels during kernel evaluation; overlapping source and destination produces
7
+ * undefined results.
8
+ *
9
+ * Edge modes:
10
+ * - `'clamp'` (default): repeat the nearest edge pixel
11
+ * - `'transparent'`: treat out-of-bounds samples as transparent black
12
+ * - `'wrap'`: tile the surface toroidally
13
+ * - `'mirror'`: reflect the image at boundaries
14
+ */
15
+ export function convolveSurface(out, source, options) {
16
+ const { matrix, matrixX, matrixY } = options;
17
+ if (matrixX <= 0 || matrixY <= 0)
18
+ throw new Error('Convolution filter matrix dimensions must be positive');
19
+ if (matrix.length < matrixX * matrixY)
20
+ throw new Error('Convolution filter matrix does not match its dimensions');
21
+ const rawDivisor = options.divisor ?? getConvolutionDivisor(matrix, matrixX * matrixY);
22
+ const divisor = rawDivisor === 0 ? 1 : rawDivisor;
23
+ const bias = options.bias ?? 0;
24
+ const edge = options.edge ?? 'clamp';
25
+ const preserveAlpha = options.preserveAlpha ?? true;
26
+ const offsetX = Math.floor(matrixX / 2);
27
+ const offsetY = Math.floor(matrixY / 2);
28
+ const surfaceWidth = source.surface.width;
29
+ const surfaceHeight = source.surface.height;
30
+ const data = source.surface.data;
31
+ for (let py = 0; py < source.height; py++) {
32
+ for (let px = 0; px < source.width; px++) {
33
+ let r = 0;
34
+ let g = 0;
35
+ let b = 0;
36
+ let a = 0;
37
+ for (let ky = 0; ky < matrixY; ky++) {
38
+ const rawSampleY = source.y + py + ky - offsetY;
39
+ const weight_row_start = ky * matrixX;
40
+ for (let kx = 0; kx < matrixX; kx++) {
41
+ const rawSampleX = source.x + px + kx - offsetX;
42
+ const weight = matrix[weight_row_start + kx];
43
+ let sampleX;
44
+ let sampleY;
45
+ if (rawSampleY < 0 || rawSampleY >= surfaceHeight || rawSampleX < 0 || rawSampleX >= surfaceWidth) {
46
+ if (edge === 'transparent') {
47
+ continue;
48
+ }
49
+ else if (edge === 'wrap') {
50
+ sampleX = ((rawSampleX % surfaceWidth) + surfaceWidth) % surfaceWidth;
51
+ sampleY = ((rawSampleY % surfaceHeight) + surfaceHeight) % surfaceHeight;
52
+ }
53
+ else if (edge === 'mirror') {
54
+ sampleX = resolveConvolutionMirror(rawSampleX, surfaceWidth);
55
+ sampleY = resolveConvolutionMirror(rawSampleY, surfaceHeight);
56
+ }
57
+ else {
58
+ sampleX = rawSampleX < 0 ? 0 : rawSampleX >= surfaceWidth ? surfaceWidth - 1 : rawSampleX;
59
+ sampleY = rawSampleY < 0 ? 0 : rawSampleY >= surfaceHeight ? surfaceHeight - 1 : rawSampleY;
60
+ }
61
+ }
62
+ else {
63
+ sampleX = rawSampleX;
64
+ sampleY = rawSampleY;
65
+ }
66
+ const i = (sampleY * surfaceWidth + sampleX) * 4;
67
+ r += data[i] * weight;
68
+ g += data[i + 1] * weight;
69
+ b += data[i + 2] * weight;
70
+ a += data[i + 3] * weight;
71
+ }
72
+ }
73
+ const di = (py * source.width + px) * 4;
74
+ out[di] = clampByte(r / divisor + bias);
75
+ out[di + 1] = clampByte(g / divisor + bias);
76
+ out[di + 2] = clampByte(b / divisor + bias);
77
+ if (preserveAlpha) {
78
+ const cy = Math.max(0, Math.min(surfaceHeight - 1, source.y + py));
79
+ const cx = Math.max(0, Math.min(surfaceWidth - 1, source.x + px));
80
+ out[di + 3] = data[(cy * surfaceWidth + cx) * 4 + 3];
81
+ }
82
+ else {
83
+ out[di + 3] = clampByte(a / divisor + bias);
84
+ }
85
+ }
86
+ }
87
+ }
88
+ function clampByte(value) {
89
+ return Math.max(0, Math.min(255, Math.round(value)));
90
+ }
91
+ function getConvolutionDivisor(matrix, length) {
92
+ let sum = 0;
93
+ for (let i = 0; i < length; i++) {
94
+ sum += matrix[i];
95
+ }
96
+ return sum === 0 ? 1 : sum;
97
+ }
98
+ function resolveConvolutionMirror(v, size) {
99
+ const period = 2 * size;
100
+ const wrapped = ((v % period) + period) % period;
101
+ return wrapped < size ? wrapped : period - 1 - wrapped;
102
+ }
103
+ //# sourceMappingURL=surfaceConvolution.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"surfaceConvolution.js","sourceRoot":"","sources":["../src/surfaceConvolution.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,23 @@
1
+ import type { SurfaceRegion } from '@flighthq/types';
2
+ import type { ImageChannel } from './surfaceImageChannel';
3
+ /**
4
+ * Copies one channel of `source` into a channel of `dest`. The copied size is
5
+ * the overlap of the two regions; pixels outside either surface are skipped.
6
+ *
7
+ * Safe to pass the same surface in `dest` and `source` as long as `destChannel`
8
+ * and `sourceChannel` differ (each pixel writes a different byte than it reads).
9
+ * Copying a channel to itself is always a no-op regardless of aliasing.
10
+ */
11
+ export declare function copySurfaceChannel(dest: Readonly<SurfaceRegion>, destChannel: ImageChannel, source: Readonly<SurfaceRegion>, sourceChannel: ImageChannel): void;
12
+ /**
13
+ * Copies `source` into `dest`. The copied size is the overlap of the two
14
+ * regions; pixels outside either surface are skipped. When `composite` is
15
+ * true, `source` is alpha-composited (Porter-Duff source-over) over `dest`
16
+ * instead of overwriting it.
17
+ *
18
+ * Safe to pass the same surface in `dest` and `source` when the regions do not
19
+ * overlap. Overlapping regions produce undefined results because pixels are
20
+ * written before all source reads are complete.
21
+ */
22
+ export declare function copySurfacePixels(dest: Readonly<SurfaceRegion>, source: Readonly<SurfaceRegion>, composite?: boolean): void;
23
+ //# sourceMappingURL=surfaceCopy.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"surfaceCopy.d.ts","sourceRoot":"","sources":["../src/surfaceCopy.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAErD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAE1D;;;;;;;GAOG;AACH,wBAAgB,kBAAkB,CAChC,IAAI,EAAE,QAAQ,CAAC,aAAa,CAAC,EAC7B,WAAW,EAAE,YAAY,EACzB,MAAM,EAAE,QAAQ,CAAC,aAAa,CAAC,EAC/B,aAAa,EAAE,YAAY,GAC1B,IAAI,CAiBN;AAED;;;;;;;;;GASG;AACH,wBAAgB,iBAAiB,CAC/B,IAAI,EAAE,QAAQ,CAAC,aAAa,CAAC,EAC7B,MAAM,EAAE,QAAQ,CAAC,aAAa,CAAC,EAC/B,SAAS,GAAE,OAAe,GACzB,IAAI,CAkCN"}
@@ -0,0 +1,78 @@
1
+ import { invalidateImageResource } from '@flighthq/image';
2
+ /**
3
+ * Copies one channel of `source` into a channel of `dest`. The copied size is
4
+ * the overlap of the two regions; pixels outside either surface are skipped.
5
+ *
6
+ * Safe to pass the same surface in `dest` and `source` as long as `destChannel`
7
+ * and `sourceChannel` differ (each pixel writes a different byte than it reads).
8
+ * Copying a channel to itself is always a no-op regardless of aliasing.
9
+ */
10
+ export function copySurfaceChannel(dest, destChannel, source, sourceChannel) {
11
+ const w = Math.min(dest.width, source.width);
12
+ const h = Math.min(dest.height, source.height);
13
+ for (let py = 0; py < h; py++) {
14
+ const sy = source.y + py;
15
+ const dy = dest.y + py;
16
+ if (sy < 0 || sy >= source.surface.height || dy < 0 || dy >= dest.surface.height)
17
+ continue;
18
+ for (let px = 0; px < w; px++) {
19
+ const sx = source.x + px;
20
+ const dx = dest.x + px;
21
+ if (sx < 0 || sx >= source.surface.width || dx < 0 || dx >= dest.surface.width)
22
+ continue;
23
+ const si = (sy * source.surface.width + sx) * 4;
24
+ const di = (dy * dest.surface.width + dx) * 4;
25
+ dest.surface.data[di + destChannel] = source.surface.data[si + sourceChannel];
26
+ }
27
+ }
28
+ invalidateImageResource(dest.surface);
29
+ }
30
+ /**
31
+ * Copies `source` into `dest`. The copied size is the overlap of the two
32
+ * regions; pixels outside either surface are skipped. When `composite` is
33
+ * true, `source` is alpha-composited (Porter-Duff source-over) over `dest`
34
+ * instead of overwriting it.
35
+ *
36
+ * Safe to pass the same surface in `dest` and `source` when the regions do not
37
+ * overlap. Overlapping regions produce undefined results because pixels are
38
+ * written before all source reads are complete.
39
+ */
40
+ export function copySurfacePixels(dest, source, composite = false) {
41
+ const w = Math.min(dest.width, source.width);
42
+ const h = Math.min(dest.height, source.height);
43
+ const sd = source.surface.data;
44
+ const dd = dest.surface.data;
45
+ for (let py = 0; py < h; py++) {
46
+ const sy = source.y + py;
47
+ const dy = dest.y + py;
48
+ if (sy < 0 || sy >= source.surface.height || dy < 0 || dy >= dest.surface.height)
49
+ continue;
50
+ for (let px = 0; px < w; px++) {
51
+ const sx = source.x + px;
52
+ const dx = dest.x + px;
53
+ if (sx < 0 || sx >= source.surface.width || dx < 0 || dx >= dest.surface.width)
54
+ continue;
55
+ const si = (sy * source.surface.width + sx) * 4;
56
+ const di = (dy * dest.surface.width + dx) * 4;
57
+ if (composite) {
58
+ const srcA = sd[si + 3] / 255;
59
+ const dstA = dd[di + 3] / 255;
60
+ const outA = srcA + dstA * (1 - srcA);
61
+ if (outA > 0) {
62
+ dd[di] = Math.round((sd[si] * srcA + dd[di] * dstA * (1 - srcA)) / outA);
63
+ dd[di + 1] = Math.round((sd[si + 1] * srcA + dd[di + 1] * dstA * (1 - srcA)) / outA);
64
+ dd[di + 2] = Math.round((sd[si + 2] * srcA + dd[di + 2] * dstA * (1 - srcA)) / outA);
65
+ dd[di + 3] = Math.round(outA * 255);
66
+ }
67
+ }
68
+ else {
69
+ dd[di] = sd[si];
70
+ dd[di + 1] = sd[si + 1];
71
+ dd[di + 2] = sd[si + 2];
72
+ dd[di + 3] = sd[si + 3];
73
+ }
74
+ }
75
+ }
76
+ invalidateImageResource(dest.surface);
77
+ }
78
+ //# sourceMappingURL=surfaceCopy.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"surfaceCopy.js","sourceRoot":"","sources":["../src/surfaceCopy.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,11 @@
1
+ import type { Surface } from '@flighthq/types';
2
+ /**
3
+ * Returns the fraction of pixels (0..1) that differ from `backgroundColor` by more than
4
+ * `channelTolerance` on at least one RGBA channel. This is the "did anything render" signal: a blank
5
+ * frame (the whole surface still the clear colour, or fully transparent) returns ~0; a populated
6
+ * frame returns a meaningful fraction. `backgroundColor` is a packed 0xRRGGBBAA value — pass the
7
+ * render state's clear colour. `channelTolerance` (0..255) absorbs antialiasing fringe around the
8
+ * cleared edges so a genuinely empty frame does not creep above zero.
9
+ */
10
+ export declare function getSurfaceCoverage(source: Readonly<Surface>, backgroundColor: number, channelTolerance?: number): number;
11
+ //# sourceMappingURL=surfaceCoverage.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"surfaceCoverage.d.ts","sourceRoot":"","sources":["../src/surfaceCoverage.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,iBAAiB,CAAC;AAE/C;;;;;;;GAOG;AACH,wBAAgB,kBAAkB,CAChC,MAAM,EAAE,QAAQ,CAAC,OAAO,CAAC,EACzB,eAAe,EAAE,MAAM,EACvB,gBAAgB,GAAE,MAAU,GAC3B,MAAM,CAqBR"}
@@ -0,0 +1,29 @@
1
+ /**
2
+ * Returns the fraction of pixels (0..1) that differ from `backgroundColor` by more than
3
+ * `channelTolerance` on at least one RGBA channel. This is the "did anything render" signal: a blank
4
+ * frame (the whole surface still the clear colour, or fully transparent) returns ~0; a populated
5
+ * frame returns a meaningful fraction. `backgroundColor` is a packed 0xRRGGBBAA value — pass the
6
+ * render state's clear colour. `channelTolerance` (0..255) absorbs antialiasing fringe around the
7
+ * cleared edges so a genuinely empty frame does not creep above zero.
8
+ */
9
+ export function getSurfaceCoverage(source, backgroundColor, channelTolerance = 0) {
10
+ const br = (backgroundColor >>> 24) & 0xff;
11
+ const bg = (backgroundColor >> 16) & 0xff;
12
+ const bb = (backgroundColor >> 8) & 0xff;
13
+ const ba = backgroundColor & 0xff;
14
+ const data = source.data;
15
+ const totalPixels = source.width * source.height;
16
+ if (totalPixels === 0)
17
+ return 0;
18
+ let covered = 0;
19
+ for (let i = 0; i < data.length; i += 4) {
20
+ if (Math.abs(data[i] - br) > channelTolerance ||
21
+ Math.abs(data[i + 1] - bg) > channelTolerance ||
22
+ Math.abs(data[i + 2] - bb) > channelTolerance ||
23
+ Math.abs(data[i + 3] - ba) > channelTolerance) {
24
+ covered++;
25
+ }
26
+ }
27
+ return covered / totalPixels;
28
+ }
29
+ //# sourceMappingURL=surfaceCoverage.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"surfaceCoverage.js","sourceRoot":"","sources":["../src/surfaceCoverage.ts"],"names":[],"mappings":"AAEA;;;;;;;GAOG;AACH,MAAM,UAAU,kBAAkB,CAChC,MAAyB,EACzB,eAAuB,EACvB,mBAA2B,CAAC;IAE5B,MAAM,EAAE,GAAG,CAAC,eAAe,KAAK,EAAE,CAAC,GAAG,IAAI,CAAC;IAC3C,MAAM,EAAE,GAAG,CAAC,eAAe,IAAI,EAAE,CAAC,GAAG,IAAI,CAAC;IAC1C,MAAM,EAAE,GAAG,CAAC,eAAe,IAAI,CAAC,CAAC,GAAG,IAAI,CAAC;IACzC,MAAM,EAAE,GAAG,eAAe,GAAG,IAAI,CAAC;IAClC,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC;IACzB,MAAM,WAAW,GAAG,MAAM,CAAC,KAAK,GAAG,MAAM,CAAC,MAAM,CAAC;IACjD,IAAI,WAAW,KAAK,CAAC;QAAE,OAAO,CAAC,CAAC;IAEhC,IAAI,OAAO,GAAG,CAAC,CAAC;IAChB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC;QACxC,IACE,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,GAAG,gBAAgB;YACzC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,CAAC,GAAG,gBAAgB;YAC7C,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,CAAC,GAAG,gBAAgB;YAC7C,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,CAAC,GAAG,gBAAgB,EAC7C,CAAC;YACD,OAAO,EAAE,CAAC;QACZ,CAAC;IACH,CAAC;IACD,OAAO,OAAO,GAAG,WAAW,CAAC;AAC/B,CAAC"}
@@ -0,0 +1,33 @@
1
+ import type { RectangleLike, Surface, SurfaceEdgeMode } from '@flighthq/types';
2
+ /**
3
+ * Allocates a new `Surface` containing the pixels of `source` cropped to
4
+ * `rect`. `rect` coordinates are relative to the `source` surface origin
5
+ * (not to a region offset). Pixels of `rect` that fall outside the surface
6
+ * are filled with transparent black.
7
+ *
8
+ * Returns a new `Surface` with the same `colorSpace`, `alphaType`, and
9
+ * `format` as `source`, with dimensions equal to `rect.width × rect.height`.
10
+ */
11
+ export declare function cropSurface(source: Readonly<Surface>, rect: Readonly<RectangleLike>): Surface;
12
+ /**
13
+ * Allocates a new `Surface` with `source` padded by `left`, `top`, `right`,
14
+ * and `bottom` pixels on each side. Added pixels are filled according to
15
+ * `edgeMode`:
16
+ * - `'transparent'` (default): filled with transparent black.
17
+ * - `'clamp'`: border pixels of `source` are repeated.
18
+ * - `'wrap'`: `source` is tiled.
19
+ * - `'mirror'`: `source` is mirrored at the edges.
20
+ *
21
+ * When `edgeMode` is `'transparent'`, the optional `fillColor` (packed RGBA,
22
+ * e.g. `0xffffffff` for opaque white) overrides the default transparent fill.
23
+ * It is ignored for all other edge modes.
24
+ */
25
+ export declare function extendSurface(source: Readonly<Surface>, left: number, top: number, right: number, bottom: number, edgeMode?: SurfaceEdgeMode, fillColor?: number): Surface;
26
+ /**
27
+ * Allocates a new `Surface` with the transparent border of `source` removed.
28
+ * Finds the tightest bounding box of all pixels with alpha > 0 and returns a
29
+ * new surface cropped to that box. If the entire surface is transparent,
30
+ * returns a 1×1 transparent surface.
31
+ */
32
+ export declare function trimSurface(source: Readonly<Surface>): Surface;
33
+ //# sourceMappingURL=surfaceCrop.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"surfaceCrop.d.ts","sourceRoot":"","sources":["../src/surfaceCrop.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,aAAa,EAAE,OAAO,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAE/E;;;;;;;;GAQG;AACH,wBAAgB,WAAW,CAAC,MAAM,EAAE,QAAQ,CAAC,OAAO,CAAC,EAAE,IAAI,EAAE,QAAQ,CAAC,aAAa,CAAC,GAAG,OAAO,CAiC7F;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,aAAa,CAC3B,MAAM,EAAE,QAAQ,CAAC,OAAO,CAAC,EACzB,IAAI,EAAE,MAAM,EACZ,GAAG,EAAE,MAAM,EACX,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,MAAM,EACd,QAAQ,GAAE,eAA+B,EACzC,SAAS,SAAI,GACZ,OAAO,CAkDT;AAED;;;;;GAKG;AACH,wBAAgB,WAAW,CAAC,MAAM,EAAE,QAAQ,CAAC,OAAO,CAAC,GAAG,OAAO,CAgC9D"}
@@ -0,0 +1,174 @@
1
+ import { createEntity } from '@flighthq/entity';
2
+ /**
3
+ * Allocates a new `Surface` containing the pixels of `source` cropped to
4
+ * `rect`. `rect` coordinates are relative to the `source` surface origin
5
+ * (not to a region offset). Pixels of `rect` that fall outside the surface
6
+ * are filled with transparent black.
7
+ *
8
+ * Returns a new `Surface` with the same `colorSpace`, `alphaType`, and
9
+ * `format` as `source`, with dimensions equal to `rect.width × rect.height`.
10
+ */
11
+ export function cropSurface(source, rect) {
12
+ const sw = source.width;
13
+ const sh = source.height;
14
+ const rx = Math.round(rect.x);
15
+ const ry = Math.round(rect.y);
16
+ const rw = Math.max(0, Math.round(rect.width));
17
+ const rh = Math.max(0, Math.round(rect.height));
18
+ const data = new Uint8ClampedArray(rw * rh * 4);
19
+ const sd = source.data;
20
+ for (let py = 0; py < rh; py++) {
21
+ const sy = ry + py;
22
+ if (sy < 0 || sy >= sh)
23
+ continue;
24
+ for (let px = 0; px < rw; px++) {
25
+ const sx = rx + px;
26
+ if (sx < 0 || sx >= sw)
27
+ continue;
28
+ const si = (sy * sw + sx) * 4;
29
+ const di = (py * rw + px) * 4;
30
+ data[di] = sd[si];
31
+ data[di + 1] = sd[si + 1];
32
+ data[di + 2] = sd[si + 2];
33
+ data[di + 3] = sd[si + 3];
34
+ }
35
+ }
36
+ return createEntity({
37
+ alphaType: source.alphaType,
38
+ colorSpace: source.colorSpace,
39
+ data,
40
+ format: source.format,
41
+ height: rh,
42
+ source: null,
43
+ version: 0,
44
+ width: rw,
45
+ });
46
+ }
47
+ /**
48
+ * Allocates a new `Surface` with `source` padded by `left`, `top`, `right`,
49
+ * and `bottom` pixels on each side. Added pixels are filled according to
50
+ * `edgeMode`:
51
+ * - `'transparent'` (default): filled with transparent black.
52
+ * - `'clamp'`: border pixels of `source` are repeated.
53
+ * - `'wrap'`: `source` is tiled.
54
+ * - `'mirror'`: `source` is mirrored at the edges.
55
+ *
56
+ * When `edgeMode` is `'transparent'`, the optional `fillColor` (packed RGBA,
57
+ * e.g. `0xffffffff` for opaque white) overrides the default transparent fill.
58
+ * It is ignored for all other edge modes.
59
+ */
60
+ export function extendSurface(source, left, top, right, bottom, edgeMode = 'transparent', fillColor = 0) {
61
+ const sw = source.width;
62
+ const sh = source.height;
63
+ const dw = sw + left + right;
64
+ const dh = sh + top + bottom;
65
+ const data = new Uint8ClampedArray(dw * dh * 4);
66
+ const sd = source.data;
67
+ const fr = (fillColor >>> 24) & 0xff;
68
+ const fg = (fillColor >> 16) & 0xff;
69
+ const fb = (fillColor >> 8) & 0xff;
70
+ const fa = fillColor & 0xff;
71
+ for (let py = 0; py < dh; py++) {
72
+ for (let px = 0; px < dw; px++) {
73
+ const sx = px - left;
74
+ const sy = py - top;
75
+ const di = (py * dw + px) * 4;
76
+ if (sx >= 0 && sx < sw && sy >= 0 && sy < sh) {
77
+ const si = (sy * sw + sx) * 4;
78
+ data[di] = sd[si];
79
+ data[di + 1] = sd[si + 1];
80
+ data[di + 2] = sd[si + 2];
81
+ data[di + 3] = sd[si + 3];
82
+ }
83
+ else {
84
+ const cx = resolveEdge(sx, sw, edgeMode);
85
+ const cy = resolveEdge(sy, sh, edgeMode);
86
+ if (cx !== null && cy !== null) {
87
+ const si = (cy * sw + cx) * 4;
88
+ data[di] = sd[si];
89
+ data[di + 1] = sd[si + 1];
90
+ data[di + 2] = sd[si + 2];
91
+ data[di + 3] = sd[si + 3];
92
+ }
93
+ else {
94
+ data[di] = fr;
95
+ data[di + 1] = fg;
96
+ data[di + 2] = fb;
97
+ data[di + 3] = fa;
98
+ }
99
+ }
100
+ }
101
+ }
102
+ return createEntity({
103
+ alphaType: source.alphaType,
104
+ colorSpace: source.colorSpace,
105
+ data,
106
+ format: source.format,
107
+ height: dh,
108
+ source: null,
109
+ version: 0,
110
+ width: dw,
111
+ });
112
+ }
113
+ /**
114
+ * Allocates a new `Surface` with the transparent border of `source` removed.
115
+ * Finds the tightest bounding box of all pixels with alpha > 0 and returns a
116
+ * new surface cropped to that box. If the entire surface is transparent,
117
+ * returns a 1×1 transparent surface.
118
+ */
119
+ export function trimSurface(source) {
120
+ const sw = source.width;
121
+ const sh = source.height;
122
+ const sd = source.data;
123
+ let minX = sw;
124
+ let minY = sh;
125
+ let maxX = -1;
126
+ let maxY = -1;
127
+ for (let py = 0; py < sh; py++) {
128
+ for (let px = 0; px < sw; px++) {
129
+ const a = sd[(py * sw + px) * 4 + 3];
130
+ if (a > 0) {
131
+ if (px < minX)
132
+ minX = px;
133
+ if (px > maxX)
134
+ maxX = px;
135
+ if (py < minY)
136
+ minY = py;
137
+ if (py > maxY)
138
+ maxY = py;
139
+ }
140
+ }
141
+ }
142
+ if (maxX < 0) {
143
+ return createEntity({
144
+ alphaType: source.alphaType,
145
+ colorSpace: source.colorSpace,
146
+ data: new Uint8ClampedArray(4),
147
+ format: source.format,
148
+ height: 1,
149
+ source: null,
150
+ version: 0,
151
+ width: 1,
152
+ });
153
+ }
154
+ return cropSurface(source, { x: minX, y: minY, width: maxX - minX + 1, height: maxY - minY + 1 });
155
+ }
156
+ function resolveEdge(v, size, mode) {
157
+ if (v >= 0 && v < size)
158
+ return v;
159
+ switch (mode) {
160
+ case 'clamp':
161
+ return Math.max(0, Math.min(size - 1, v));
162
+ case 'wrap':
163
+ return ((v % size) + size) % size;
164
+ case 'mirror': {
165
+ const period = 2 * size;
166
+ const wrapped = ((v % period) + period) % period;
167
+ return wrapped < size ? wrapped : period - 1 - wrapped;
168
+ }
169
+ default:
170
+ // 'transparent'
171
+ return null;
172
+ }
173
+ }
174
+ //# sourceMappingURL=surfaceCrop.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"surfaceCrop.js","sourceRoot":"","sources":["../src/surfaceCrop.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAGhD;;;;;;;;GAQG;AACH,MAAM,UAAU,WAAW,CAAC,MAAyB,EAAE,IAA6B;IAClF,MAAM,EAAE,GAAG,MAAM,CAAC,KAAK,CAAC;IACxB,MAAM,EAAE,GAAG,MAAM,CAAC,MAAM,CAAC;IACzB,MAAM,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAC9B,MAAM,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAC9B,MAAM,EAAE,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC;IAC/C,MAAM,EAAE,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC;IAChD,MAAM,IAAI,GAAG,IAAI,iBAAiB,CAAC,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC,CAAC;IAChD,MAAM,EAAE,GAAG,MAAM,CAAC,IAAI,CAAC;IACvB,KAAK,IAAI,EAAE,GAAG,CAAC,EAAE,EAAE,GAAG,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC;QAC/B,MAAM,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC;QACnB,IAAI,EAAE,GAAG,CAAC,IAAI,EAAE,IAAI,EAAE;YAAE,SAAS;QACjC,KAAK,IAAI,EAAE,GAAG,CAAC,EAAE,EAAE,GAAG,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC;YAC/B,MAAM,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC;YACnB,IAAI,EAAE,GAAG,CAAC,IAAI,EAAE,IAAI,EAAE;gBAAE,SAAS;YACjC,MAAM,EAAE,GAAG,CAAC,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC;YAC9B,MAAM,EAAE,GAAG,CAAC,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC;YAC9B,IAAI,CAAC,EAAE,CAAC,GAAG,EAAE,CAAC,EAAE,CAAC,CAAC;YAClB,IAAI,CAAC,EAAE,GAAG,CAAC,CAAC,GAAG,EAAE,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC;YAC1B,IAAI,CAAC,EAAE,GAAG,CAAC,CAAC,GAAG,EAAE,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC;YAC1B,IAAI,CAAC,EAAE,GAAG,CAAC,CAAC,GAAG,EAAE,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC;QAC5B,CAAC;IACH,CAAC;IACD,OAAO,YAAY,CAAC;QAClB,SAAS,EAAE,MAAM,CAAC,SAAS;QAC3B,UAAU,EAAE,MAAM,CAAC,UAAU;QAC7B,IAAI;QACJ,MAAM,EAAE,MAAM,CAAC,MAAM;QACrB,MAAM,EAAE,EAAE;QACV,MAAM,EAAE,IAAI;QACZ,OAAO,EAAE,CAAC;QACV,KAAK,EAAE,EAAE;KACV,CAAC,CAAC;AACL,CAAC;AAED;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,aAAa,CAC3B,MAAyB,EACzB,IAAY,EACZ,GAAW,EACX,KAAa,EACb,MAAc,EACd,WAA4B,aAAa,EACzC,SAAS,GAAG,CAAC;IAEb,MAAM,EAAE,GAAG,MAAM,CAAC,KAAK,CAAC;IACxB,MAAM,EAAE,GAAG,MAAM,CAAC,MAAM,CAAC;IACzB,MAAM,EAAE,GAAG,EAAE,GAAG,IAAI,GAAG,KAAK,CAAC;IAC7B,MAAM,EAAE,GAAG,EAAE,GAAG,GAAG,GAAG,MAAM,CAAC;IAC7B,MAAM,IAAI,GAAG,IAAI,iBAAiB,CAAC,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC,CAAC;IAChD,MAAM,EAAE,GAAG,MAAM,CAAC,IAAI,CAAC;IACvB,MAAM,EAAE,GAAG,CAAC,SAAS,KAAK,EAAE,CAAC,GAAG,IAAI,CAAC;IACrC,MAAM,EAAE,GAAG,CAAC,SAAS,IAAI,EAAE,CAAC,GAAG,IAAI,CAAC;IACpC,MAAM,EAAE,GAAG,CAAC,SAAS,IAAI,CAAC,CAAC,GAAG,IAAI,CAAC;IACnC,MAAM,EAAE,GAAG,SAAS,GAAG,IAAI,CAAC;IAC5B,KAAK,IAAI,EAAE,GAAG,CAAC,EAAE,EAAE,GAAG,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC;QAC/B,KAAK,IAAI,EAAE,GAAG,CAAC,EAAE,EAAE,GAAG,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC;YAC/B,MAAM,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC;YACrB,MAAM,EAAE,GAAG,EAAE,GAAG,GAAG,CAAC;YACpB,MAAM,EAAE,GAAG,CAAC,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC;YAC9B,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,GAAG,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,GAAG,EAAE,EAAE,CAAC;gBAC7C,MAAM,EAAE,GAAG,CAAC,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC;gBAC9B,IAAI,CAAC,EAAE,CAAC,GAAG,EAAE,CAAC,EAAE,CAAC,CAAC;gBAClB,IAAI,CAAC,EAAE,GAAG,CAAC,CAAC,GAAG,EAAE,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC;gBAC1B,IAAI,CAAC,EAAE,GAAG,CAAC,CAAC,GAAG,EAAE,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC;gBAC1B,IAAI,CAAC,EAAE,GAAG,CAAC,CAAC,GAAG,EAAE,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC;YAC5B,CAAC;iBAAM,CAAC;gBACN,MAAM,EAAE,GAAG,WAAW,CAAC,EAAE,EAAE,EAAE,EAAE,QAAQ,CAAC,CAAC;gBACzC,MAAM,EAAE,GAAG,WAAW,CAAC,EAAE,EAAE,EAAE,EAAE,QAAQ,CAAC,CAAC;gBACzC,IAAI,EAAE,KAAK,IAAI,IAAI,EAAE,KAAK,IAAI,EAAE,CAAC;oBAC/B,MAAM,EAAE,GAAG,CAAC,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC;oBAC9B,IAAI,CAAC,EAAE,CAAC,GAAG,EAAE,CAAC,EAAE,CAAC,CAAC;oBAClB,IAAI,CAAC,EAAE,GAAG,CAAC,CAAC,GAAG,EAAE,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC;oBAC1B,IAAI,CAAC,EAAE,GAAG,CAAC,CAAC,GAAG,EAAE,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC;oBAC1B,IAAI,CAAC,EAAE,GAAG,CAAC,CAAC,GAAG,EAAE,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC;gBAC5B,CAAC;qBAAM,CAAC;oBACN,IAAI,CAAC,EAAE,CAAC,GAAG,EAAE,CAAC;oBACd,IAAI,CAAC,EAAE,GAAG,CAAC,CAAC,GAAG,EAAE,CAAC;oBAClB,IAAI,CAAC,EAAE,GAAG,CAAC,CAAC,GAAG,EAAE,CAAC;oBAClB,IAAI,CAAC,EAAE,GAAG,CAAC,CAAC,GAAG,EAAE,CAAC;gBACpB,CAAC;YACH,CAAC;QACH,CAAC;IACH,CAAC;IACD,OAAO,YAAY,CAAC;QAClB,SAAS,EAAE,MAAM,CAAC,SAAS;QAC3B,UAAU,EAAE,MAAM,CAAC,UAAU;QAC7B,IAAI;QACJ,MAAM,EAAE,MAAM,CAAC,MAAM;QACrB,MAAM,EAAE,EAAE;QACV,MAAM,EAAE,IAAI;QACZ,OAAO,EAAE,CAAC;QACV,KAAK,EAAE,EAAE;KACV,CAAC,CAAC;AACL,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,WAAW,CAAC,MAAyB;IACnD,MAAM,EAAE,GAAG,MAAM,CAAC,KAAK,CAAC;IACxB,MAAM,EAAE,GAAG,MAAM,CAAC,MAAM,CAAC;IACzB,MAAM,EAAE,GAAG,MAAM,CAAC,IAAI,CAAC;IACvB,IAAI,IAAI,GAAG,EAAE,CAAC;IACd,IAAI,IAAI,GAAG,EAAE,CAAC;IACd,IAAI,IAAI,GAAG,CAAC,CAAC,CAAC;IACd,IAAI,IAAI,GAAG,CAAC,CAAC,CAAC;IACd,KAAK,IAAI,EAAE,GAAG,CAAC,EAAE,EAAE,GAAG,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC;QAC/B,KAAK,IAAI,EAAE,GAAG,CAAC,EAAE,EAAE,GAAG,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC;YAC/B,MAAM,CAAC,GAAG,EAAE,CAAC,CAAC,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC;YACrC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;gBACV,IAAI,EAAE,GAAG,IAAI;oBAAE,IAAI,GAAG,EAAE,CAAC;gBACzB,IAAI,EAAE,GAAG,IAAI;oBAAE,IAAI,GAAG,EAAE,CAAC;gBACzB,IAAI,EAAE,GAAG,IAAI;oBAAE,IAAI,GAAG,EAAE,CAAC;gBACzB,IAAI,EAAE,GAAG,IAAI;oBAAE,IAAI,GAAG,EAAE,CAAC;YAC3B,CAAC;QACH,CAAC;IACH,CAAC;IACD,IAAI,IAAI,GAAG,CAAC,EAAE,CAAC;QACb,OAAO,YAAY,CAAC;YAClB,SAAS,EAAE,MAAM,CAAC,SAAS;YAC3B,UAAU,EAAE,MAAM,CAAC,UAAU;YAC7B,IAAI,EAAE,IAAI,iBAAiB,CAAC,CAAC,CAAC;YAC9B,MAAM,EAAE,MAAM,CAAC,MAAM;YACrB,MAAM,EAAE,CAAC;YACT,MAAM,EAAE,IAAI;YACZ,OAAO,EAAE,CAAC;YACV,KAAK,EAAE,CAAC;SACT,CAAC,CAAC;IACL,CAAC;IACD,OAAO,WAAW,CAAC,MAAM,EAAE,EAAE,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,GAAG,IAAI,GAAG,CAAC,EAAE,MAAM,EAAE,IAAI,GAAG,IAAI,GAAG,CAAC,EAAE,CAAC,CAAC;AACpG,CAAC;AAED,SAAS,WAAW,CAAC,CAAS,EAAE,IAAY,EAAE,IAAqB;IACjE,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,IAAI;QAAE,OAAO,CAAC,CAAC;IACjC,QAAQ,IAAI,EAAE,CAAC;QACb,KAAK,OAAO;YACV,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,IAAI,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;QAC5C,KAAK,MAAM;YACT,OAAO,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC;QACpC,KAAK,QAAQ,CAAC,CAAC,CAAC;YACd,MAAM,MAAM,GAAG,CAAC,GAAG,IAAI,CAAC;YACxB,MAAM,OAAO,GAAG,CAAC,CAAC,CAAC,GAAG,MAAM,CAAC,GAAG,MAAM,CAAC,GAAG,MAAM,CAAC;YACjD,OAAO,OAAO,GAAG,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,GAAG,CAAC,GAAG,OAAO,CAAC;QACzD,CAAC;QACD;YACE,gBAAgB;YAChB,OAAO,IAAI,CAAC;IAChB,CAAC;AACH,CAAC"}
@@ -0,0 +1,48 @@
1
+ import type { SurfaceEdgeMode, SurfaceRegion } from '@flighthq/types';
2
+ export type SurfaceDisplacementMapMode = 'clamp' | 'color' | 'ignore' | 'wrap';
3
+ export interface SurfaceDisplacementMapOptions {
4
+ /** Map surface whose channels drive the per-pixel displacement. */
5
+ map: Readonly<SurfaceRegion>;
6
+ /** Channel index (0=R, 1=G, 2=B, 3=A) of `map` that drives X displacement. Default 0. */
7
+ componentX?: number;
8
+ /** Channel index (0=R, 1=G, 2=B, 3=A) of `map` that drives Y displacement. Default 1. */
9
+ componentY?: number;
10
+ /**
11
+ * X displacement scale in pixels. A map value of 128 produces no shift; 0
12
+ * shifts by -0.5 × scaleX; 255 shifts by +0.5 × scaleX. Default 0.
13
+ */
14
+ scaleX?: number;
15
+ /** Y displacement scale in pixels. Default 0. */
16
+ scaleY?: number;
17
+ /** How to handle sample positions that fall outside the source region. Default 'wrap'. */
18
+ mode?: SurfaceDisplacementMapMode;
19
+ /**
20
+ * Standard edge mode — when set, overrides `mode` for standard edge behaviours.
21
+ * Use for API consistency with other surface geometric ops. Default undefined
22
+ * (falls back to `mode`).
23
+ */
24
+ edgeMode?: SurfaceEdgeMode;
25
+ /** Packed 0xRRGGBBAA fill used when `mode` is 'color'. Default 0. */
26
+ fillColor?: number;
27
+ }
28
+ /**
29
+ * Warps `source` by sampling each output pixel from a displaced source position,
30
+ * writing into `out`. The displacement for pixel (px, py) is read from `map` at
31
+ * the aligned position and scaled:
32
+ *
33
+ * dx = (mapValueX / 255 - 0.5) * scaleX
34
+ * dy = (mapValueY / 255 - 0.5) * scaleY
35
+ *
36
+ * A map value of 128 is approximately neutral (< 0.2px shift). Sampling uses
37
+ * bilinear interpolation.
38
+ *
39
+ * When `edgeMode` is set, it controls out-of-bounds behaviour using the standard
40
+ * `SurfaceEdgeMode` values (`'clamp'`, `'wrap'`, `'mirror'`, `'transparent'`).
41
+ * Otherwise `mode` is used: `'wrap'` tiles, `'clamp'` holds the edge, `'ignore'`
42
+ * keeps the undisplaced source pixel, and `'color'` fills with `fillColor`.
43
+ *
44
+ * `out` must be at least `source.width * source.height * 4` bytes and must NOT
45
+ * alias `source.surface.data` — output pixels read arbitrary source positions.
46
+ */
47
+ export declare function displaceSurface(out: Uint8ClampedArray, source: Readonly<SurfaceRegion>, options: Readonly<SurfaceDisplacementMapOptions>): void;
48
+ //# sourceMappingURL=surfaceDisplacement.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"surfaceDisplacement.d.ts","sourceRoot":"","sources":["../src/surfaceDisplacement.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAEtE,MAAM,MAAM,0BAA0B,GAAG,OAAO,GAAG,OAAO,GAAG,QAAQ,GAAG,MAAM,CAAC;AAE/E,MAAM,WAAW,6BAA6B;IAC5C,mEAAmE;IACnE,GAAG,EAAE,QAAQ,CAAC,aAAa,CAAC,CAAC;IAC7B,yFAAyF;IACzF,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,yFAAyF;IACzF,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB;;;OAGG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,iDAAiD;IACjD,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,0FAA0F;IAC1F,IAAI,CAAC,EAAE,0BAA0B,CAAC;IAClC;;;;OAIG;IACH,QAAQ,CAAC,EAAE,eAAe,CAAC;IAC3B,qEAAqE;IACrE,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,eAAe,CAC7B,GAAG,EAAE,iBAAiB,EACtB,MAAM,EAAE,QAAQ,CAAC,aAAa,CAAC,EAC/B,OAAO,EAAE,QAAQ,CAAC,6BAA6B,CAAC,GAC/C,IAAI,CAwFN"}