@flighthq/effects 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 (335) hide show
  1. package/dist/autoExposureEffect.d.ts +3 -0
  2. package/dist/autoExposureEffect.d.ts.map +1 -0
  3. package/dist/autoExposureEffect.js +4 -0
  4. package/dist/autoExposureEffect.js.map +1 -0
  5. package/dist/barrelDistortionEffect.d.ts +3 -0
  6. package/dist/barrelDistortionEffect.d.ts.map +1 -0
  7. package/dist/barrelDistortionEffect.js +4 -0
  8. package/dist/barrelDistortionEffect.js.map +1 -0
  9. package/dist/bloomEffect.d.ts +6 -0
  10. package/dist/bloomEffect.d.ts.map +1 -0
  11. package/dist/bloomEffect.js +16 -0
  12. package/dist/bloomEffect.js.map +1 -0
  13. package/dist/bokehDepthOfFieldEffect.d.ts +3 -0
  14. package/dist/bokehDepthOfFieldEffect.d.ts.map +1 -0
  15. package/dist/bokehDepthOfFieldEffect.js +4 -0
  16. package/dist/bokehDepthOfFieldEffect.js.map +1 -0
  17. package/dist/brightnessContrastEffect.d.ts +3 -0
  18. package/dist/brightnessContrastEffect.d.ts.map +1 -0
  19. package/dist/brightnessContrastEffect.js +4 -0
  20. package/dist/brightnessContrastEffect.js.map +1 -0
  21. package/dist/cameraMotionBlurEffect.d.ts +3 -0
  22. package/dist/cameraMotionBlurEffect.d.ts.map +1 -0
  23. package/dist/cameraMotionBlurEffect.js +4 -0
  24. package/dist/cameraMotionBlurEffect.js.map +1 -0
  25. package/dist/channelMixerEffect.d.ts +3 -0
  26. package/dist/channelMixerEffect.d.ts.map +1 -0
  27. package/dist/channelMixerEffect.js +4 -0
  28. package/dist/channelMixerEffect.js.map +1 -0
  29. package/dist/chromaticAberrationEffect.d.ts +3 -0
  30. package/dist/chromaticAberrationEffect.d.ts.map +1 -0
  31. package/dist/chromaticAberrationEffect.js +4 -0
  32. package/dist/chromaticAberrationEffect.js.map +1 -0
  33. package/dist/colorBlindSimulationEffect.d.ts +3 -0
  34. package/dist/colorBlindSimulationEffect.d.ts.map +1 -0
  35. package/dist/colorBlindSimulationEffect.js +4 -0
  36. package/dist/colorBlindSimulationEffect.js.map +1 -0
  37. package/dist/colorGradeEffect.d.ts +3 -0
  38. package/dist/colorGradeEffect.d.ts.map +1 -0
  39. package/dist/colorGradeEffect.js +4 -0
  40. package/dist/colorGradeEffect.js.map +1 -0
  41. package/dist/colorScienceMath.d.ts +9 -0
  42. package/dist/colorScienceMath.d.ts.map +1 -0
  43. package/dist/colorScienceMath.js +135 -0
  44. package/dist/colorScienceMath.js.map +1 -0
  45. package/dist/colorTemperatureMath.d.ts +5 -0
  46. package/dist/colorTemperatureMath.d.ts.map +1 -0
  47. package/dist/colorTemperatureMath.js +45 -0
  48. package/dist/colorTemperatureMath.js.map +1 -0
  49. package/dist/contactShadowsEffect.d.ts +3 -0
  50. package/dist/contactShadowsEffect.d.ts.map +1 -0
  51. package/dist/contactShadowsEffect.js +4 -0
  52. package/dist/contactShadowsEffect.js.map +1 -0
  53. package/dist/crtEffect.d.ts +3 -0
  54. package/dist/crtEffect.d.ts.map +1 -0
  55. package/dist/crtEffect.js +4 -0
  56. package/dist/crtEffect.js.map +1 -0
  57. package/dist/customShaderEffect.d.ts +3 -0
  58. package/dist/customShaderEffect.d.ts.map +1 -0
  59. package/dist/customShaderEffect.js +4 -0
  60. package/dist/customShaderEffect.js.map +1 -0
  61. package/dist/depthMath.d.ts +4 -0
  62. package/dist/depthMath.d.ts.map +1 -0
  63. package/dist/depthMath.js +55 -0
  64. package/dist/depthMath.js.map +1 -0
  65. package/dist/directionalBlurEffect.d.ts +3 -0
  66. package/dist/directionalBlurEffect.d.ts.map +1 -0
  67. package/dist/directionalBlurEffect.js +4 -0
  68. package/dist/directionalBlurEffect.js.map +1 -0
  69. package/dist/displacementEffect.d.ts +3 -0
  70. package/dist/displacementEffect.d.ts.map +1 -0
  71. package/dist/displacementEffect.js +4 -0
  72. package/dist/displacementEffect.js.map +1 -0
  73. package/dist/ditherEffect.d.ts +3 -0
  74. package/dist/ditherEffect.d.ts.map +1 -0
  75. package/dist/ditherEffect.js +4 -0
  76. package/dist/ditherEffect.js.map +1 -0
  77. package/dist/edgeDetectMath.d.ts +6 -0
  78. package/dist/edgeDetectMath.d.ts.map +1 -0
  79. package/dist/edgeDetectMath.js +72 -0
  80. package/dist/edgeDetectMath.js.map +1 -0
  81. package/dist/exposureEffect.d.ts +3 -0
  82. package/dist/exposureEffect.d.ts.map +1 -0
  83. package/dist/exposureEffect.js +4 -0
  84. package/dist/exposureEffect.js.map +1 -0
  85. package/dist/filmEmulationEffect.d.ts +3 -0
  86. package/dist/filmEmulationEffect.d.ts.map +1 -0
  87. package/dist/filmEmulationEffect.js +4 -0
  88. package/dist/filmEmulationEffect.js.map +1 -0
  89. package/dist/filmGrainEffect.d.ts +3 -0
  90. package/dist/filmGrainEffect.d.ts.map +1 -0
  91. package/dist/filmGrainEffect.js +4 -0
  92. package/dist/filmGrainEffect.js.map +1 -0
  93. package/dist/fxaaEffect.d.ts +3 -0
  94. package/dist/fxaaEffect.d.ts.map +1 -0
  95. package/dist/fxaaEffect.js +4 -0
  96. package/dist/fxaaEffect.js.map +1 -0
  97. package/dist/gaussianMath.d.ts +5 -0
  98. package/dist/gaussianMath.d.ts.map +1 -0
  99. package/dist/gaussianMath.js +42 -0
  100. package/dist/gaussianMath.js.map +1 -0
  101. package/dist/glitchEffect.d.ts +3 -0
  102. package/dist/glitchEffect.d.ts.map +1 -0
  103. package/dist/glitchEffect.js +4 -0
  104. package/dist/glitchEffect.js.map +1 -0
  105. package/dist/godRaysEffect.d.ts +3 -0
  106. package/dist/godRaysEffect.d.ts.map +1 -0
  107. package/dist/godRaysEffect.js +4 -0
  108. package/dist/godRaysEffect.js.map +1 -0
  109. package/dist/godRaysMath.d.ts +8 -0
  110. package/dist/godRaysMath.d.ts.map +1 -0
  111. package/dist/godRaysMath.js +49 -0
  112. package/dist/godRaysMath.js.map +1 -0
  113. package/dist/grayscaleEffect.d.ts +3 -0
  114. package/dist/grayscaleEffect.d.ts.map +1 -0
  115. package/dist/grayscaleEffect.js +4 -0
  116. package/dist/grayscaleEffect.js.map +1 -0
  117. package/dist/halftoneEffect.d.ts +3 -0
  118. package/dist/halftoneEffect.d.ts.map +1 -0
  119. package/dist/halftoneEffect.js +4 -0
  120. package/dist/halftoneEffect.js.map +1 -0
  121. package/dist/hueSaturationEffect.d.ts +3 -0
  122. package/dist/hueSaturationEffect.d.ts.map +1 -0
  123. package/dist/hueSaturationEffect.js +4 -0
  124. package/dist/hueSaturationEffect.js.map +1 -0
  125. package/dist/index.d.ts +67 -0
  126. package/dist/index.d.ts.map +1 -0
  127. package/dist/index.js +67 -0
  128. package/dist/index.js.map +1 -0
  129. package/dist/invertEffect.d.ts +3 -0
  130. package/dist/invertEffect.d.ts.map +1 -0
  131. package/dist/invertEffect.js +4 -0
  132. package/dist/invertEffect.js.map +1 -0
  133. package/dist/kuwaharaEffect.d.ts +3 -0
  134. package/dist/kuwaharaEffect.d.ts.map +1 -0
  135. package/dist/kuwaharaEffect.js +4 -0
  136. package/dist/kuwaharaEffect.js.map +1 -0
  137. package/dist/kuwaharaMath.d.ts +6 -0
  138. package/dist/kuwaharaMath.d.ts.map +1 -0
  139. package/dist/kuwaharaMath.js +70 -0
  140. package/dist/kuwaharaMath.js.map +1 -0
  141. package/dist/lensDirtEffect.d.ts +3 -0
  142. package/dist/lensDirtEffect.d.ts.map +1 -0
  143. package/dist/lensDirtEffect.js +4 -0
  144. package/dist/lensDirtEffect.js.map +1 -0
  145. package/dist/lensDistortionEffect.d.ts +3 -0
  146. package/dist/lensDistortionEffect.d.ts.map +1 -0
  147. package/dist/lensDistortionEffect.js +4 -0
  148. package/dist/lensDistortionEffect.js.map +1 -0
  149. package/dist/lensFlareEffect.d.ts +3 -0
  150. package/dist/lensFlareEffect.d.ts.map +1 -0
  151. package/dist/lensFlareEffect.js +4 -0
  152. package/dist/lensFlareEffect.js.map +1 -0
  153. package/dist/liftGammaGainEffect.d.ts +3 -0
  154. package/dist/liftGammaGainEffect.d.ts.map +1 -0
  155. package/dist/liftGammaGainEffect.js +4 -0
  156. package/dist/liftGammaGainEffect.js.map +1 -0
  157. package/dist/lookupTableGradeEffect.d.ts +3 -0
  158. package/dist/lookupTableGradeEffect.d.ts.map +1 -0
  159. package/dist/lookupTableGradeEffect.js +4 -0
  160. package/dist/lookupTableGradeEffect.js.map +1 -0
  161. package/dist/lutMath.d.ts +7 -0
  162. package/dist/lutMath.d.ts.map +1 -0
  163. package/dist/lutMath.js +39 -0
  164. package/dist/lutMath.js.map +1 -0
  165. package/dist/motionBlurEffect.d.ts +3 -0
  166. package/dist/motionBlurEffect.d.ts.map +1 -0
  167. package/dist/motionBlurEffect.js +4 -0
  168. package/dist/motionBlurEffect.js.map +1 -0
  169. package/dist/outlineEffect.d.ts +3 -0
  170. package/dist/outlineEffect.d.ts.map +1 -0
  171. package/dist/outlineEffect.js +4 -0
  172. package/dist/outlineEffect.js.map +1 -0
  173. package/dist/panniniProjectionEffect.d.ts +3 -0
  174. package/dist/panniniProjectionEffect.d.ts.map +1 -0
  175. package/dist/panniniProjectionEffect.js +4 -0
  176. package/dist/panniniProjectionEffect.js.map +1 -0
  177. package/dist/pixelateEffect.d.ts +3 -0
  178. package/dist/pixelateEffect.d.ts.map +1 -0
  179. package/dist/pixelateEffect.js +4 -0
  180. package/dist/pixelateEffect.js.map +1 -0
  181. package/dist/posterizeEffect.d.ts +3 -0
  182. package/dist/posterizeEffect.d.ts.map +1 -0
  183. package/dist/posterizeEffect.js +4 -0
  184. package/dist/posterizeEffect.js.map +1 -0
  185. package/dist/radialBlurEffect.d.ts +3 -0
  186. package/dist/radialBlurEffect.d.ts.map +1 -0
  187. package/dist/radialBlurEffect.js +4 -0
  188. package/dist/radialBlurEffect.js.map +1 -0
  189. package/dist/renderEffectDefaults.d.ts +4 -0
  190. package/dist/renderEffectDefaults.d.ts.map +1 -0
  191. package/dist/renderEffectDefaults.js +111 -0
  192. package/dist/renderEffectDefaults.js.map +1 -0
  193. package/dist/renderEffectInputs.d.ts +5 -0
  194. package/dist/renderEffectInputs.d.ts.map +1 -0
  195. package/dist/renderEffectInputs.js +87 -0
  196. package/dist/renderEffectInputs.js.map +1 -0
  197. package/dist/renderEffectInterpolation.d.ts +4 -0
  198. package/dist/renderEffectInterpolation.d.ts.map +1 -0
  199. package/dist/renderEffectInterpolation.js +75 -0
  200. package/dist/renderEffectInterpolation.js.map +1 -0
  201. package/dist/renderEffectValidation.d.ts +3 -0
  202. package/dist/renderEffectValidation.d.ts.map +1 -0
  203. package/dist/renderEffectValidation.js +18 -0
  204. package/dist/renderEffectValidation.js.map +1 -0
  205. package/dist/scanlinesEffect.d.ts +3 -0
  206. package/dist/scanlinesEffect.d.ts.map +1 -0
  207. package/dist/scanlinesEffect.js +4 -0
  208. package/dist/scanlinesEffect.js.map +1 -0
  209. package/dist/screenSpaceFogEffect.d.ts +3 -0
  210. package/dist/screenSpaceFogEffect.d.ts.map +1 -0
  211. package/dist/screenSpaceFogEffect.js +4 -0
  212. package/dist/screenSpaceFogEffect.js.map +1 -0
  213. package/dist/sepiaEffect.d.ts +3 -0
  214. package/dist/sepiaEffect.d.ts.map +1 -0
  215. package/dist/sepiaEffect.js +4 -0
  216. package/dist/sepiaEffect.js.map +1 -0
  217. package/dist/sharpenEffect.d.ts +3 -0
  218. package/dist/sharpenEffect.d.ts.map +1 -0
  219. package/dist/sharpenEffect.js +4 -0
  220. package/dist/sharpenEffect.js.map +1 -0
  221. package/dist/sketchEffect.d.ts +3 -0
  222. package/dist/sketchEffect.d.ts.map +1 -0
  223. package/dist/sketchEffect.js +4 -0
  224. package/dist/sketchEffect.js.map +1 -0
  225. package/dist/smaaEffect.d.ts +3 -0
  226. package/dist/smaaEffect.d.ts.map +1 -0
  227. package/dist/smaaEffect.js +4 -0
  228. package/dist/smaaEffect.js.map +1 -0
  229. package/dist/ssaoEffect.d.ts +3 -0
  230. package/dist/ssaoEffect.d.ts.map +1 -0
  231. package/dist/ssaoEffect.js +4 -0
  232. package/dist/ssaoEffect.js.map +1 -0
  233. package/dist/ssrEffect.d.ts +3 -0
  234. package/dist/ssrEffect.d.ts.map +1 -0
  235. package/dist/ssrEffect.js +4 -0
  236. package/dist/ssrEffect.js.map +1 -0
  237. package/dist/stylizeMath.d.ts +9 -0
  238. package/dist/stylizeMath.d.ts.map +1 -0
  239. package/dist/stylizeMath.js +77 -0
  240. package/dist/stylizeMath.js.map +1 -0
  241. package/dist/taaEffect.d.ts +3 -0
  242. package/dist/taaEffect.d.ts.map +1 -0
  243. package/dist/taaEffect.js +4 -0
  244. package/dist/taaEffect.js.map +1 -0
  245. package/dist/tiltShiftEffect.d.ts +3 -0
  246. package/dist/tiltShiftEffect.d.ts.map +1 -0
  247. package/dist/tiltShiftEffect.js +4 -0
  248. package/dist/tiltShiftEffect.js.map +1 -0
  249. package/dist/toneMapEffect.d.ts +3 -0
  250. package/dist/toneMapEffect.d.ts.map +1 -0
  251. package/dist/toneMapEffect.js +4 -0
  252. package/dist/toneMapEffect.js.map +1 -0
  253. package/dist/toneMapMath.d.ts +12 -0
  254. package/dist/toneMapMath.d.ts.map +1 -0
  255. package/dist/toneMapMath.js +110 -0
  256. package/dist/toneMapMath.js.map +1 -0
  257. package/dist/vignetteEffect.d.ts +3 -0
  258. package/dist/vignetteEffect.d.ts.map +1 -0
  259. package/dist/vignetteEffect.js +4 -0
  260. package/dist/vignetteEffect.js.map +1 -0
  261. package/dist/volumetricLightEffect.d.ts +3 -0
  262. package/dist/volumetricLightEffect.d.ts.map +1 -0
  263. package/dist/volumetricLightEffect.js +4 -0
  264. package/dist/volumetricLightEffect.js.map +1 -0
  265. package/dist/whiteBalanceEffect.d.ts +3 -0
  266. package/dist/whiteBalanceEffect.d.ts.map +1 -0
  267. package/dist/whiteBalanceEffect.js +4 -0
  268. package/dist/whiteBalanceEffect.js.map +1 -0
  269. package/package.json +37 -0
  270. package/src/autoExposureEffect.test.ts +11 -0
  271. package/src/barrelDistortionEffect.test.ts +11 -0
  272. package/src/bloomEffect.test.ts +41 -0
  273. package/src/bokehDepthOfFieldEffect.test.ts +15 -0
  274. package/src/brightnessContrastEffect.test.ts +14 -0
  275. package/src/cameraMotionBlurEffect.test.ts +14 -0
  276. package/src/channelMixerEffect.test.ts +12 -0
  277. package/src/chromaticAberrationEffect.test.ts +14 -0
  278. package/src/colorBlindSimulationEffect.test.ts +13 -0
  279. package/src/colorGradeEffect.test.ts +11 -0
  280. package/src/colorScienceMath.test.ts +160 -0
  281. package/src/colorTemperatureMath.test.ts +67 -0
  282. package/src/contactShadowsEffect.test.ts +14 -0
  283. package/src/crtEffect.test.ts +16 -0
  284. package/src/customShaderEffect.test.ts +14 -0
  285. package/src/depthMath.test.ts +71 -0
  286. package/src/directionalBlurEffect.test.ts +11 -0
  287. package/src/displacementEffect.test.ts +15 -0
  288. package/src/ditherEffect.test.ts +11 -0
  289. package/src/edgeDetectMath.test.ts +84 -0
  290. package/src/exposureEffect.test.ts +7 -0
  291. package/src/filmEmulationEffect.test.ts +14 -0
  292. package/src/filmGrainEffect.test.ts +15 -0
  293. package/src/fxaaEffect.test.ts +14 -0
  294. package/src/gaussianMath.test.ts +93 -0
  295. package/src/glitchEffect.test.ts +16 -0
  296. package/src/godRaysEffect.test.ts +15 -0
  297. package/src/godRaysMath.test.ts +63 -0
  298. package/src/grayscaleEffect.test.ts +11 -0
  299. package/src/halftoneEffect.test.ts +11 -0
  300. package/src/hueSaturationEffect.test.ts +15 -0
  301. package/src/invertEffect.test.ts +11 -0
  302. package/src/kuwaharaEffect.test.ts +11 -0
  303. package/src/kuwaharaMath.test.ts +65 -0
  304. package/src/lensDirtEffect.test.ts +15 -0
  305. package/src/lensDistortionEffect.test.ts +11 -0
  306. package/src/lensFlareEffect.test.ts +16 -0
  307. package/src/liftGammaGainEffect.test.ts +15 -0
  308. package/src/lookupTableGradeEffect.test.ts +11 -0
  309. package/src/lutMath.test.ts +67 -0
  310. package/src/motionBlurEffect.test.ts +11 -0
  311. package/src/outlineEffect.test.ts +15 -0
  312. package/src/panniniProjectionEffect.test.ts +14 -0
  313. package/src/pixelateEffect.test.ts +11 -0
  314. package/src/posterizeEffect.test.ts +11 -0
  315. package/src/radialBlurEffect.test.ts +15 -0
  316. package/src/renderEffectDefaults.test.ts +70 -0
  317. package/src/renderEffectInputs.test.ts +60 -0
  318. package/src/renderEffectInterpolation.test.ts +71 -0
  319. package/src/renderEffectValidation.test.ts +37 -0
  320. package/src/scanlinesEffect.test.ts +11 -0
  321. package/src/screenSpaceFogEffect.test.ts +14 -0
  322. package/src/sepiaEffect.test.ts +11 -0
  323. package/src/sharpenEffect.test.ts +11 -0
  324. package/src/sketchEffect.test.ts +11 -0
  325. package/src/smaaEffect.test.ts +11 -0
  326. package/src/ssaoEffect.test.ts +11 -0
  327. package/src/ssrEffect.test.ts +11 -0
  328. package/src/stylizeMath.test.ts +99 -0
  329. package/src/taaEffect.test.ts +11 -0
  330. package/src/tiltShiftEffect.test.ts +15 -0
  331. package/src/toneMapEffect.test.ts +7 -0
  332. package/src/toneMapMath.test.ts +145 -0
  333. package/src/vignetteEffect.test.ts +16 -0
  334. package/src/volumetricLightEffect.test.ts +14 -0
  335. package/src/whiteBalanceEffect.test.ts +11 -0
@@ -0,0 +1,11 @@
1
+ import { createPosterizeEffect } from './posterizeEffect';
2
+
3
+ describe('createPosterizeEffect', () => {
4
+ it('tags the intent type', () => {
5
+ expect(createPosterizeEffect().kind).toBe('PosterizeEffect');
6
+ });
7
+
8
+ it('carries options', () => {
9
+ expect(createPosterizeEffect({ levels: 4 })).toMatchObject({ levels: 4 });
10
+ });
11
+ });
@@ -0,0 +1,15 @@
1
+ import { createRadialBlurEffect } from './radialBlurEffect';
2
+
3
+ describe('createRadialBlurEffect', () => {
4
+ it('tags the intent type', () => {
5
+ expect(createRadialBlurEffect().kind).toBe('RadialBlurEffect');
6
+ });
7
+
8
+ it('carries options', () => {
9
+ expect(createRadialBlurEffect({ centerX: 0.5, centerY: 0.5, strength: 0.2 })).toMatchObject({
10
+ centerX: 0.5,
11
+ centerY: 0.5,
12
+ strength: 0.2,
13
+ });
14
+ });
15
+ });
@@ -0,0 +1,70 @@
1
+ import type { BloomEffect, GrayscaleEffect, RenderEffect, ToneMapEffect, VignetteEffect } from '@flighthq/types';
2
+
3
+ import { createBloomEffect } from './bloomEffect';
4
+ import { createGrayscaleEffect } from './grayscaleEffect';
5
+ import { getRenderEffectDefaults, normalizeRenderEffect } from './renderEffectDefaults';
6
+ import { createToneMapEffect } from './toneMapEffect';
7
+ import { createVignetteEffect } from './vignetteEffect';
8
+
9
+ describe('getRenderEffectDefaults', () => {
10
+ it('returns documented defaults for BloomEffect', () => {
11
+ const d = getRenderEffectDefaults('BloomEffect');
12
+ expect(d.brightness).toBe(1);
13
+ expect(d.threshold).toBe(0.8);
14
+ expect(d.thresholdKnee).toBe(0.5);
15
+ expect(d.radius).toBe(8);
16
+ expect(d.passes).toBe(1);
17
+ });
18
+ it('returns documented defaults for ToneMapEffect', () => {
19
+ const d = getRenderEffectDefaults('ToneMapEffect');
20
+ expect(d.operator).toBe('aces');
21
+ expect(d.exposure).toBe(0);
22
+ });
23
+ it('returns a fresh copy each call (mutations do not persist)', () => {
24
+ const d1 = getRenderEffectDefaults('BloomEffect');
25
+ const d2 = getRenderEffectDefaults('BloomEffect');
26
+ d1.threshold = 99;
27
+ expect(d2.threshold).toBe(0.8);
28
+ });
29
+ it('returns empty object for unknown kind', () => {
30
+ expect(getRenderEffectDefaults('acme.UnknownEffect')).toEqual({});
31
+ });
32
+ });
33
+
34
+ describe('normalizeRenderEffect', () => {
35
+ it('fills in missing fields from defaults', () => {
36
+ const effect = createBloomEffect({ threshold: 0.9 });
37
+ const out = { kind: 'BloomEffect' } as BloomEffect;
38
+ const ok = normalizeRenderEffect(effect, out);
39
+ expect(ok).toBe(true);
40
+ expect(out.threshold).toBe(0.9); // preserved
41
+ expect((out as unknown as Record<string, unknown>).brightness).toBe(1); // filled from defaults
42
+ expect(out.radius).toBe(8); // filled from defaults
43
+ });
44
+ it('preserves explicitly set zero and false', () => {
45
+ const effect = createGrayscaleEffect({ intensity: 0 });
46
+ const out = { kind: 'GrayscaleEffect' } as GrayscaleEffect;
47
+ normalizeRenderEffect(effect, out);
48
+ expect(out.intensity).toBe(0); // 0 is explicit, should not be replaced by default 1
49
+ });
50
+ it('carries over fields not in the defaults table', () => {
51
+ const effect = createVignetteEffect({ intensity: 0.3 });
52
+ const out = { kind: 'VignetteEffect' } as VignetteEffect;
53
+ normalizeRenderEffect(effect, out);
54
+ expect(out.intensity).toBe(0.3);
55
+ expect(out.radius).toBe(1);
56
+ expect(out.softness).toBe(0.5);
57
+ });
58
+ it('returns false for unknown kind', () => {
59
+ const effect = { kind: 'acme.UnknownEffect' } as RenderEffect;
60
+ const out = { kind: 'acme.UnknownEffect' } as RenderEffect;
61
+ expect(normalizeRenderEffect(effect, out)).toBe(false);
62
+ });
63
+ it('is alias-safe when out === effect', () => {
64
+ const effect = createToneMapEffect({ exposure: 1 }) as ToneMapEffect;
65
+ const ok = normalizeRenderEffect(effect, effect);
66
+ expect(ok).toBe(true);
67
+ expect(effect.exposure).toBe(1);
68
+ expect(effect.operator).toBe('aces');
69
+ });
70
+ });
@@ -0,0 +1,60 @@
1
+ import { createBloomEffect } from './bloomEffect';
2
+ import { createBokehDepthOfFieldEffect } from './bokehDepthOfFieldEffect';
3
+ import { createColorGradeEffect } from './colorGradeEffect';
4
+ import { createGrayscaleEffect } from './grayscaleEffect';
5
+ import { getRenderEffectInputs, getRenderEffectKinds, RENDER_EFFECT_KINDS } from './renderEffectInputs';
6
+ import { createSsaoEffect } from './ssaoEffect';
7
+ import { createTaaEffect } from './taaEffect';
8
+ import { createToneMapEffect } from './toneMapEffect';
9
+
10
+ describe('getRenderEffectInputs', () => {
11
+ it('returns Hdr for BloomEffect', () => {
12
+ expect(getRenderEffectInputs(createBloomEffect())).toEqual(['Hdr']);
13
+ });
14
+
15
+ it('returns Hdr for ToneMapEffect', () => {
16
+ expect(getRenderEffectInputs(createToneMapEffect())).toEqual(['Hdr']);
17
+ });
18
+
19
+ it('returns Depth for SsaoEffect', () => {
20
+ expect(getRenderEffectInputs(createSsaoEffect())).toEqual(['Depth']);
21
+ });
22
+
23
+ it('returns Depth for BokehDepthOfFieldEffect', () => {
24
+ expect(getRenderEffectInputs(createBokehDepthOfFieldEffect())).toEqual(['Depth']);
25
+ });
26
+
27
+ it('returns Temporal for TaaEffect', () => {
28
+ expect(getRenderEffectInputs(createTaaEffect())).toEqual(['Temporal']);
29
+ });
30
+
31
+ it('returns empty array for effects that need only the color buffer', () => {
32
+ expect(getRenderEffectInputs(createGrayscaleEffect())).toEqual([]);
33
+ expect(getRenderEffectInputs(createColorGradeEffect())).toEqual([]);
34
+ });
35
+
36
+ it('returns empty array for unknown kind', () => {
37
+ expect(getRenderEffectInputs({ kind: 'acme.UnknownEffect' } as never)).toEqual([]);
38
+ });
39
+ });
40
+
41
+ describe('getRenderEffectKinds', () => {
42
+ it('returns an array containing known effect kinds', () => {
43
+ const kinds = getRenderEffectKinds();
44
+ expect(kinds).toContain('BloomEffect');
45
+ expect(kinds).toContain('ToneMapEffect');
46
+ expect(kinds).toContain('SsaoEffect');
47
+ expect(kinds).toContain('GrayscaleEffect');
48
+ });
49
+
50
+ it('returns the same reference as RENDER_EFFECT_KINDS', () => {
51
+ expect(getRenderEffectKinds()).toBe(RENDER_EFFECT_KINDS);
52
+ });
53
+
54
+ it('kinds are in alphabetical order', () => {
55
+ const kinds = getRenderEffectKinds();
56
+ for (let i = 1; i < kinds.length; i++) {
57
+ expect(kinds[i - 1].localeCompare(kinds[i])).toBeLessThan(0);
58
+ }
59
+ });
60
+ });
@@ -0,0 +1,71 @@
1
+ import type { GrayscaleEffect } from '@flighthq/types';
2
+
3
+ import { createBloomEffect } from './bloomEffect';
4
+ import { createColorGradeEffect } from './colorGradeEffect';
5
+ import { createGrayscaleEffect } from './grayscaleEffect';
6
+ import { canLerpRenderEffects, lerpRenderEffect } from './renderEffectInterpolation';
7
+
8
+ describe('canLerpRenderEffects', () => {
9
+ it('returns true for same kind', () => {
10
+ expect(canLerpRenderEffects(createBloomEffect(), createBloomEffect())).toBe(true);
11
+ });
12
+ it('returns false for different kinds', () => {
13
+ expect(canLerpRenderEffects(createBloomEffect(), createColorGradeEffect())).toBe(false);
14
+ });
15
+ });
16
+
17
+ describe('lerpRenderEffect', () => {
18
+ it('returns false and leaves out unchanged for mismatched kinds', () => {
19
+ const a = createBloomEffect({ threshold: 0.5 });
20
+ const b = createColorGradeEffect({ exposure: 1 });
21
+ const out = createBloomEffect({ threshold: 0.99 });
22
+ const result = lerpRenderEffect(a, b, 0.5, out);
23
+ expect(result).toBe(false);
24
+ expect(out.threshold).toBe(0.99);
25
+ });
26
+ it('at t=0 writes a values', () => {
27
+ const a = createBloomEffect({ threshold: 0.2, radius: 4 });
28
+ const b = createBloomEffect({ threshold: 0.8, radius: 16 });
29
+ const out = createBloomEffect();
30
+ lerpRenderEffect(a, b, 0, out);
31
+ expect(out.threshold).toBeCloseTo(0.2, 5);
32
+ expect(out.radius).toBeCloseTo(4, 5);
33
+ });
34
+ it('at t=1 writes b values', () => {
35
+ const a = createBloomEffect({ threshold: 0.2, radius: 4 });
36
+ const b = createBloomEffect({ threshold: 0.8, radius: 16 });
37
+ const out = createBloomEffect();
38
+ lerpRenderEffect(a, b, 1, out);
39
+ expect(out.threshold).toBeCloseTo(0.8, 5);
40
+ expect(out.radius).toBeCloseTo(16, 5);
41
+ });
42
+ it('at t=0.5 interpolates numeric fields', () => {
43
+ const a = createBloomEffect({ threshold: 0, radius: 0 });
44
+ const b = createBloomEffect({ threshold: 1, radius: 10 });
45
+ const out = createBloomEffect();
46
+ lerpRenderEffect(a, b, 0.5, out);
47
+ expect(out.threshold).toBeCloseTo(0.5, 5);
48
+ expect(out.radius).toBeCloseTo(5, 5);
49
+ });
50
+ it('returns true on success', () => {
51
+ const a = createBloomEffect();
52
+ const b = createBloomEffect();
53
+ const out = createBloomEffect();
54
+ expect(lerpRenderEffect(a, b, 0.5, out)).toBe(true);
55
+ });
56
+ it('is alias-safe when out === a', () => {
57
+ const a = createBloomEffect({ threshold: 0, radius: 0 });
58
+ const b = createBloomEffect({ threshold: 1, radius: 10 });
59
+ lerpRenderEffect(a, b, 0.5, a);
60
+ expect(a.threshold).toBeCloseTo(0.5, 5);
61
+ });
62
+ it('boolean fields snap at t=0.5 boundary', () => {
63
+ const a = createGrayscaleEffect({ enabled: false } as Partial<GrayscaleEffect>);
64
+ const b = createGrayscaleEffect({ enabled: true } as Partial<GrayscaleEffect>);
65
+ const out = createGrayscaleEffect();
66
+ lerpRenderEffect(a, b, 0.4, out);
67
+ expect((out as unknown as Record<string, unknown>).enabled).toBe(false);
68
+ lerpRenderEffect(a, b, 0.5, out);
69
+ expect((out as unknown as Record<string, unknown>).enabled).toBe(true);
70
+ });
71
+ });
@@ -0,0 +1,37 @@
1
+ import { createBloomEffect } from './bloomEffect';
2
+ import { createColorGradeEffect } from './colorGradeEffect';
3
+ import { validateRenderEffectList } from './renderEffectValidation';
4
+ import { createSsaoEffect } from './ssaoEffect';
5
+ import { createToneMapEffect } from './toneMapEffect';
6
+
7
+ describe('validateRenderEffectList', () => {
8
+ it('returns null when all required inputs are available', () => {
9
+ const effects = [createBloomEffect(), createSsaoEffect()];
10
+ expect(validateRenderEffectList(effects, ['Hdr', 'Depth'])).toBeNull();
11
+ });
12
+
13
+ it('returns null for effects that need only the color buffer', () => {
14
+ const effects = [createColorGradeEffect()];
15
+ expect(validateRenderEffectList(effects, [])).toBeNull();
16
+ });
17
+
18
+ it('returns the missing input when Hdr is required but unavailable', () => {
19
+ const effects = [createToneMapEffect()];
20
+ expect(validateRenderEffectList(effects, [])).toBe('Hdr');
21
+ });
22
+
23
+ it('returns the missing input when Depth is required but unavailable', () => {
24
+ const effects = [createSsaoEffect()];
25
+ expect(validateRenderEffectList(effects, ['Hdr'])).toBe('Depth');
26
+ });
27
+
28
+ it('returns null for an empty effect list', () => {
29
+ expect(validateRenderEffectList([], [])).toBeNull();
30
+ });
31
+
32
+ it('returns the first missing input in order', () => {
33
+ const effects = [createBloomEffect(), createSsaoEffect()];
34
+ // Only Hdr available — Bloom ok, Ssao fails.
35
+ expect(validateRenderEffectList(effects, ['Hdr'])).toBe('Depth');
36
+ });
37
+ });
@@ -0,0 +1,11 @@
1
+ import { createScanlinesEffect } from './scanlinesEffect';
2
+
3
+ describe('createScanlinesEffect', () => {
4
+ it('tags the intent type', () => {
5
+ expect(createScanlinesEffect().kind).toBe('ScanlinesEffect');
6
+ });
7
+
8
+ it('carries options', () => {
9
+ expect(createScanlinesEffect({ count: 240, intensity: 0.4 })).toMatchObject({ count: 240, intensity: 0.4 });
10
+ });
11
+ });
@@ -0,0 +1,14 @@
1
+ import { createScreenSpaceFogEffect } from './screenSpaceFogEffect';
2
+
3
+ describe('createScreenSpaceFogEffect', () => {
4
+ it('tags the intent type', () => {
5
+ expect(createScreenSpaceFogEffect().kind).toBe('ScreenSpaceFogEffect');
6
+ });
7
+
8
+ it('carries options', () => {
9
+ expect(createScreenSpaceFogEffect({ color: 0xaabbccff, density: 0.4 })).toMatchObject({
10
+ color: 0xaabbccff,
11
+ density: 0.4,
12
+ });
13
+ });
14
+ });
@@ -0,0 +1,11 @@
1
+ import { createSepiaEffect } from './sepiaEffect';
2
+
3
+ describe('createSepiaEffect', () => {
4
+ it('tags the intent type', () => {
5
+ expect(createSepiaEffect().kind).toBe('SepiaEffect');
6
+ });
7
+
8
+ it('carries options', () => {
9
+ expect(createSepiaEffect({ intensity: 0.6 })).toMatchObject({ intensity: 0.6 });
10
+ });
11
+ });
@@ -0,0 +1,11 @@
1
+ import { createSharpenEffect } from './sharpenEffect';
2
+
3
+ describe('createSharpenEffect', () => {
4
+ it('tags the intent type', () => {
5
+ expect(createSharpenEffect().kind).toBe('SharpenEffect');
6
+ });
7
+
8
+ it('carries options', () => {
9
+ expect(createSharpenEffect({ amount: 0.6 })).toMatchObject({ amount: 0.6 });
10
+ });
11
+ });
@@ -0,0 +1,11 @@
1
+ import { createSketchEffect } from './sketchEffect';
2
+
3
+ describe('createSketchEffect', () => {
4
+ it('tags the intent type', () => {
5
+ expect(createSketchEffect().kind).toBe('SketchEffect');
6
+ });
7
+
8
+ it('carries options', () => {
9
+ expect(createSketchEffect({ strength: 0.8 })).toMatchObject({ strength: 0.8 });
10
+ });
11
+ });
@@ -0,0 +1,11 @@
1
+ import { createSmaaEffect } from './smaaEffect';
2
+
3
+ describe('createSmaaEffect', () => {
4
+ it('tags the intent type', () => {
5
+ expect(createSmaaEffect().kind).toBe('SmaaEffect');
6
+ });
7
+
8
+ it('carries options', () => {
9
+ expect(createSmaaEffect({ threshold: 0.1 })).toMatchObject({ threshold: 0.1 });
10
+ });
11
+ });
@@ -0,0 +1,11 @@
1
+ import { createSsaoEffect } from './ssaoEffect';
2
+
3
+ describe('createSsaoEffect', () => {
4
+ it('tags the intent type', () => {
5
+ expect(createSsaoEffect().kind).toBe('SsaoEffect');
6
+ });
7
+
8
+ it('carries options', () => {
9
+ expect(createSsaoEffect({ radius: 4, intensity: 1.5 })).toMatchObject({ radius: 4, intensity: 1.5 });
10
+ });
11
+ });
@@ -0,0 +1,11 @@
1
+ import { createSsrEffect } from './ssrEffect';
2
+
3
+ describe('createSsrEffect', () => {
4
+ it('tags the intent type', () => {
5
+ expect(createSsrEffect().kind).toBe('SsrEffect');
6
+ });
7
+
8
+ it('carries options', () => {
9
+ expect(createSsrEffect({ maxDistance: 10, steps: 32 })).toMatchObject({ maxDistance: 10, steps: 32 });
10
+ });
11
+ });
@@ -0,0 +1,99 @@
1
+ import {
2
+ computeCrtMaskParams,
3
+ computeHalftoneCellParams,
4
+ computeScanlineParams,
5
+ createBayerMatrix,
6
+ } from './stylizeMath';
7
+
8
+ describe('computeCrtMaskParams', () => {
9
+ it('writes two values', () => {
10
+ const out: [number, number] = [0, 0];
11
+ computeCrtMaskParams(720, 0.5, out);
12
+ expect(typeof out[0]).toBe('number');
13
+ expect(typeof out[1]).toBe('number');
14
+ });
15
+ it('higher resolution produces larger mask scale', () => {
16
+ const out1: [number, number] = [0, 0];
17
+ const out2: [number, number] = [0, 0];
18
+ computeCrtMaskParams(360, 0, out1);
19
+ computeCrtMaskParams(720, 0, out2);
20
+ expect(out2[0]).toBeGreaterThan(out1[0]);
21
+ });
22
+ it('curvature is clamped to [0, 0.1]', () => {
23
+ const out: [number, number] = [0, 0];
24
+ computeCrtMaskParams(360, 2, out);
25
+ expect(out[1]).toBeCloseTo(0.1, 5);
26
+ });
27
+ });
28
+
29
+ describe('computeHalftoneCellParams', () => {
30
+ it('writes cellSize, cosAngle, sinAngle', () => {
31
+ const out: [number, number, number] = [0, 0, 0];
32
+ computeHalftoneCellParams(1 / 8, Math.PI / 4, out);
33
+ expect(out[0]).toBeCloseTo(8, 4);
34
+ expect(out[1]).toBeCloseTo(Math.SQRT1_2, 4);
35
+ expect(out[2]).toBeCloseTo(Math.SQRT1_2, 4);
36
+ });
37
+ it('0 angle produces cos=1, sin=0', () => {
38
+ const out: [number, number, number] = [0, 0, 0];
39
+ computeHalftoneCellParams(1 / 4, 0, out);
40
+ expect(out[1]).toBeCloseTo(1, 5);
41
+ expect(out[2]).toBeCloseTo(0, 5);
42
+ });
43
+ });
44
+
45
+ describe('computeScanlineParams', () => {
46
+ it('writes scale and intensity', () => {
47
+ const out: [number, number] = [0, 0];
48
+ computeScanlineParams(480, 0.5, out);
49
+ expect(out[0]).toBeCloseTo(1, 4);
50
+ expect(out[1]).toBeCloseTo(0.5, 4);
51
+ });
52
+ it('clamps intensity to [0, 1]', () => {
53
+ const out: [number, number] = [0, 0];
54
+ computeScanlineParams(480, 2, out);
55
+ expect(out[1]).toBeCloseTo(1, 5);
56
+ });
57
+ });
58
+
59
+ describe('createBayerMatrix', () => {
60
+ it('returns size 2 for order 1', () => {
61
+ const out = new Float32Array(4);
62
+ const size = createBayerMatrix(1, out);
63
+ expect(size).toBe(2);
64
+ });
65
+ it('returns size 4 for order 2', () => {
66
+ const out = new Float32Array(16);
67
+ const size = createBayerMatrix(2, out);
68
+ expect(size).toBe(4);
69
+ });
70
+ it('all values are in [0, 1)', () => {
71
+ const out = new Float32Array(16);
72
+ const size = createBayerMatrix(2, out);
73
+ for (let i = 0; i < size * size; i++) {
74
+ expect(out[i]).toBeGreaterThanOrEqual(0);
75
+ expect(out[i]).toBeLessThan(1);
76
+ }
77
+ });
78
+ it('all values in 2x2 matrix are unique', () => {
79
+ const out = new Float32Array(4);
80
+ createBayerMatrix(1, out);
81
+ const unique = new Set(Array.from(out));
82
+ expect(unique.size).toBe(4);
83
+ });
84
+ it('all values in 4x4 matrix are unique', () => {
85
+ const out = new Float32Array(16);
86
+ createBayerMatrix(2, out);
87
+ const unique = new Set(Array.from(out));
88
+ expect(unique.size).toBe(16);
89
+ });
90
+ it('is deterministic', () => {
91
+ const out1 = new Float32Array(16);
92
+ const out2 = new Float32Array(16);
93
+ createBayerMatrix(2, out1);
94
+ createBayerMatrix(2, out2);
95
+ for (let i = 0; i < 16; i++) {
96
+ expect(out1[i]).toBeCloseTo(out2[i], 5);
97
+ }
98
+ });
99
+ });
@@ -0,0 +1,11 @@
1
+ import { createTaaEffect } from './taaEffect';
2
+
3
+ describe('createTaaEffect', () => {
4
+ it('tags the intent type', () => {
5
+ expect(createTaaEffect().kind).toBe('TaaEffect');
6
+ });
7
+
8
+ it('carries options', () => {
9
+ expect(createTaaEffect({ feedback: 0.9 })).toMatchObject({ feedback: 0.9 });
10
+ });
11
+ });
@@ -0,0 +1,15 @@
1
+ import { createTiltShiftEffect } from './tiltShiftEffect';
2
+
3
+ describe('createTiltShiftEffect', () => {
4
+ it('tags the intent type', () => {
5
+ expect(createTiltShiftEffect().kind).toBe('TiltShiftEffect');
6
+ });
7
+
8
+ it('carries options', () => {
9
+ expect(createTiltShiftEffect({ center: 0.5, width: 0.2, blur: 4 })).toMatchObject({
10
+ center: 0.5,
11
+ width: 0.2,
12
+ blur: 4,
13
+ });
14
+ });
15
+ });
@@ -0,0 +1,7 @@
1
+ import { createToneMapEffect } from './toneMapEffect';
2
+
3
+ describe('createToneMapEffect', () => {
4
+ it('tags the intent type and operator', () => {
5
+ expect(createToneMapEffect({ operator: 'aces' })).toMatchObject({ kind: 'ToneMapEffect', operator: 'aces' });
6
+ });
7
+ });
@@ -0,0 +1,145 @@
1
+ import {
2
+ computeAcesToneMap,
3
+ computeAgxToneMap,
4
+ computeExposureScale,
5
+ computeFilmicToneMap,
6
+ computeReinhardExtendedToneMap,
7
+ computeReinhardToneMap,
8
+ computeUncharted2ToneMap,
9
+ getAcesInputMatrix,
10
+ getAcesOutputMatrix,
11
+ } from './toneMapMath';
12
+
13
+ describe('computeAcesToneMap', () => {
14
+ it('maps 0 to approximately 0', () => {
15
+ expect(computeAcesToneMap(0)).toBeCloseTo(0, 2);
16
+ });
17
+ it('output is clamped to [0, 1]', () => {
18
+ expect(computeAcesToneMap(100)).toBeLessThanOrEqual(1);
19
+ expect(computeAcesToneMap(-1)).toBeGreaterThanOrEqual(0);
20
+ });
21
+ it('x=1 returns a known reference value', () => {
22
+ // At x=1: (2.51 + 0.03) / (2.43 + 0.59 + 0.14) ≈ 0.8016
23
+ const v = computeAcesToneMap(1);
24
+ expect(v).toBeGreaterThan(0.7);
25
+ expect(v).toBeLessThan(0.9);
26
+ });
27
+ });
28
+
29
+ describe('computeAgxToneMap', () => {
30
+ it('output is in [0, 1] range', () => {
31
+ expect(computeAgxToneMap(0.5)).toBeGreaterThanOrEqual(0);
32
+ expect(computeAgxToneMap(0.5)).toBeLessThanOrEqual(1);
33
+ expect(computeAgxToneMap(100)).toBeLessThanOrEqual(1.1); // allow slight overshoot on sigmoid endpoints
34
+ });
35
+ it('increases monotonically in the normal range', () => {
36
+ expect(computeAgxToneMap(1)).toBeGreaterThan(computeAgxToneMap(0.5));
37
+ });
38
+ it('matches default when options is undefined', () => {
39
+ expect(computeAgxToneMap(0.5)).toBeCloseTo(computeAgxToneMap(0.5, undefined), 10);
40
+ expect(computeAgxToneMap(0.5)).toBeCloseTo(computeAgxToneMap(0.5, {}), 10);
41
+ });
42
+ it('custom EV range shifts the output', () => {
43
+ const defaultVal = computeAgxToneMap(0.5);
44
+ const narrow = computeAgxToneMap(0.5, { minEv: -6, maxEv: 2 });
45
+ expect(narrow).not.toBeCloseTo(defaultVal, 2);
46
+ });
47
+ });
48
+
49
+ describe('computeExposureScale', () => {
50
+ it('EV=0 returns 1', () => {
51
+ expect(computeExposureScale(0)).toBeCloseTo(1, 5);
52
+ });
53
+ it('EV=1 doubles brightness', () => {
54
+ expect(computeExposureScale(1)).toBeCloseTo(2, 5);
55
+ });
56
+ it('EV=-1 halves brightness', () => {
57
+ expect(computeExposureScale(-1)).toBeCloseTo(0.5, 5);
58
+ });
59
+ });
60
+
61
+ describe('computeFilmicToneMap', () => {
62
+ it('output is non-negative for non-negative input', () => {
63
+ expect(computeFilmicToneMap(0)).toBeGreaterThanOrEqual(0);
64
+ expect(computeFilmicToneMap(1)).toBeGreaterThanOrEqual(0);
65
+ });
66
+ it('output increases with input in the linear range', () => {
67
+ expect(computeFilmicToneMap(0.5)).toBeGreaterThan(computeFilmicToneMap(0.1));
68
+ });
69
+ it('matches default when options is undefined', () => {
70
+ expect(computeFilmicToneMap(0.5)).toBeCloseTo(computeFilmicToneMap(0.5, undefined), 10);
71
+ expect(computeFilmicToneMap(0.5)).toBeCloseTo(computeFilmicToneMap(0.5, {}), 10);
72
+ });
73
+ it('higher contrast steepens the curve', () => {
74
+ const defaultVal = computeFilmicToneMap(0.5);
75
+ const highContrast = computeFilmicToneMap(0.5, { contrast: 2.0 });
76
+ expect(highContrast).not.toBeCloseTo(defaultVal, 2);
77
+ });
78
+ it('pedestal lifts the black level', () => {
79
+ const noPedestal = computeFilmicToneMap(0.01);
80
+ const withPedestal = computeFilmicToneMap(0.01, { pedestal: 0.05 });
81
+ expect(withPedestal).toBeGreaterThan(noPedestal);
82
+ });
83
+ });
84
+
85
+ describe('computeReinhardExtendedToneMap', () => {
86
+ it('maps 0 to 0', () => {
87
+ expect(computeReinhardExtendedToneMap(0, 10)).toBeCloseTo(0, 5);
88
+ });
89
+ it('at white point x==w output is 1', () => {
90
+ expect(computeReinhardExtendedToneMap(10, 10)).toBeCloseTo(1, 4);
91
+ });
92
+ });
93
+
94
+ describe('computeReinhardToneMap', () => {
95
+ it('maps 0 to 0', () => {
96
+ expect(computeReinhardToneMap(0)).toBeCloseTo(0, 5);
97
+ });
98
+ it('output is always < 1 for positive input', () => {
99
+ expect(computeReinhardToneMap(1)).toBeLessThan(1);
100
+ expect(computeReinhardToneMap(100)).toBeLessThan(1);
101
+ });
102
+ it('x=1 maps to 0.5', () => {
103
+ expect(computeReinhardToneMap(1)).toBeCloseTo(0.5, 5);
104
+ });
105
+ });
106
+
107
+ describe('computeUncharted2ToneMap', () => {
108
+ it('output at x=0 is near 0', () => {
109
+ expect(Math.abs(computeUncharted2ToneMap(0))).toBeLessThan(0.1);
110
+ });
111
+ it('output increases with input', () => {
112
+ expect(computeUncharted2ToneMap(2)).toBeGreaterThan(computeUncharted2ToneMap(1));
113
+ });
114
+ });
115
+
116
+ describe('getAcesInputMatrix', () => {
117
+ it('writes 9 values', () => {
118
+ const out = new Float32Array(9);
119
+ getAcesInputMatrix(out);
120
+ let sum = 0;
121
+ for (let i = 0; i < 9; i++) {
122
+ sum += out[i];
123
+ }
124
+ expect(sum).toBeGreaterThan(0);
125
+ });
126
+ it('diagonal values are largest in each column', () => {
127
+ const out = new Float32Array(9);
128
+ getAcesInputMatrix(out);
129
+ // Column 0: out[0] > out[1], out[0] > out[2]
130
+ expect(out[0]).toBeGreaterThan(out[1]);
131
+ expect(out[0]).toBeGreaterThan(out[2]);
132
+ });
133
+ });
134
+
135
+ describe('getAcesOutputMatrix', () => {
136
+ it('writes 9 values', () => {
137
+ const out = new Float32Array(9);
138
+ getAcesOutputMatrix(out);
139
+ let hasNonZero = false;
140
+ for (let i = 0; i < 9; i++) {
141
+ if (out[i] !== 0) hasNonZero = true;
142
+ }
143
+ expect(hasNonZero).toBe(true);
144
+ });
145
+ });
@@ -0,0 +1,16 @@
1
+ import { createVignetteEffect } from './vignetteEffect';
2
+
3
+ describe('createVignetteEffect', () => {
4
+ it('tags the intent type', () => {
5
+ expect(createVignetteEffect().kind).toBe('VignetteEffect');
6
+ });
7
+
8
+ it('carries options', () => {
9
+ expect(createVignetteEffect({ intensity: 1, radius: 0.7, softness: 0.4, color: 0x000000ff })).toMatchObject({
10
+ intensity: 1,
11
+ radius: 0.7,
12
+ softness: 0.4,
13
+ color: 0x000000ff,
14
+ });
15
+ });
16
+ });