@jbrowse/render-core 4.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.
Files changed (164) hide show
  1. package/LICENSE +201 -0
  2. package/esm/OverlayCanvas.d.ts +29 -0
  3. package/esm/OverlayCanvas.js +43 -0
  4. package/esm/RenderCanvas.d.ts +76 -0
  5. package/esm/RenderCanvas.js +38 -0
  6. package/esm/RenderLifecycleMixin.d.ts +180 -0
  7. package/esm/RenderLifecycleMixin.js +279 -0
  8. package/esm/ScrollLockedOverlay.d.ts +28 -0
  9. package/esm/ScrollLockedOverlay.js +42 -0
  10. package/esm/blockClipUtils.d.ts +27 -0
  11. package/esm/blockClipUtils.js +101 -0
  12. package/esm/canvas2dUtils.d.ts +372 -0
  13. package/esm/canvas2dUtils.js +564 -0
  14. package/esm/canvasContext.d.ts +68 -0
  15. package/esm/canvasContext.js +74 -0
  16. package/esm/colorRampLut.d.ts +17 -0
  17. package/esm/colorRampLut.js +25 -0
  18. package/esm/coverageBand.d.ts +107 -0
  19. package/esm/coverageBand.js +109 -0
  20. package/esm/coverageBandBuffers.d.ts +30 -0
  21. package/esm/coverageBandBuffers.js +13 -0
  22. package/esm/createRenderingBackend.d.ts +52 -0
  23. package/esm/createRenderingBackend.js +58 -0
  24. package/esm/displayPhase.d.ts +155 -0
  25. package/esm/displayPhase.js +97 -0
  26. package/esm/globalRenderingBackend.d.ts +90 -0
  27. package/esm/globalRenderingBackend.js +53 -0
  28. package/esm/gpuDevice.d.ts +91 -0
  29. package/esm/gpuDevice.js +277 -0
  30. package/esm/graphicsCapabilities.d.ts +98 -0
  31. package/esm/graphicsCapabilities.js +165 -0
  32. package/esm/hal/createHal.d.ts +22 -0
  33. package/esm/hal/createHal.js +91 -0
  34. package/esm/hal/deviceGpuCache.d.ts +36 -0
  35. package/esm/hal/deviceGpuCache.js +120 -0
  36. package/esm/hal/gpuHalBase.d.ts +55 -0
  37. package/esm/hal/gpuHalBase.js +81 -0
  38. package/esm/hal/index.d.ts +7 -0
  39. package/esm/hal/index.js +5 -0
  40. package/esm/hal/mockHal.d.ts +153 -0
  41. package/esm/hal/mockHal.js +297 -0
  42. package/esm/hal/oomReporter.d.ts +15 -0
  43. package/esm/hal/oomReporter.js +22 -0
  44. package/esm/hal/passIds.d.ts +22 -0
  45. package/esm/hal/passIds.js +36 -0
  46. package/esm/hal/regionRegistry.d.ts +11 -0
  47. package/esm/hal/regionRegistry.js +66 -0
  48. package/esm/hal/types.d.ts +116 -0
  49. package/esm/hal/types.js +1 -0
  50. package/esm/hal/webgl2Hal.d.ts +47 -0
  51. package/esm/hal/webgl2Hal.js +490 -0
  52. package/esm/hal/webgpuHal.d.ts +169 -0
  53. package/esm/hal/webgpuHal.js +722 -0
  54. package/esm/installUpload.d.ts +91 -0
  55. package/esm/installUpload.js +94 -0
  56. package/esm/instanceCache.d.ts +43 -0
  57. package/esm/instanceCache.js +53 -0
  58. package/esm/instancePass.d.ts +50 -0
  59. package/esm/instancePass.js +34 -0
  60. package/esm/keyedRenderingBackend.d.ts +41 -0
  61. package/esm/keyedRenderingBackend.js +19 -0
  62. package/esm/mapUploadSync.d.ts +31 -0
  63. package/esm/mapUploadSync.js +45 -0
  64. package/esm/namedReactions.d.ts +29 -0
  65. package/esm/namedReactions.js +62 -0
  66. package/esm/perRegionRenderingBackend.d.ts +114 -0
  67. package/esm/perRegionRenderingBackend.js +93 -0
  68. package/esm/recoveryBudget.d.ts +40 -0
  69. package/esm/recoveryBudget.js +56 -0
  70. package/esm/regionDataMap.d.ts +60 -0
  71. package/esm/regionDataMap.js +98 -0
  72. package/esm/renderBlock.d.ts +25 -0
  73. package/esm/renderBlock.js +10 -0
  74. package/esm/renderingBackendBase.d.ts +71 -0
  75. package/esm/renderingBackendBase.js +50 -0
  76. package/esm/shaders/antialias.js.generated.d.ts +4 -0
  77. package/esm/shaders/antialias.js.generated.js +25 -0
  78. package/esm/shaders/capsule.generated.d.ts +1 -0
  79. package/esm/shaders/capsule.generated.js +3 -0
  80. package/esm/shaders/colorRampLut.generated.d.ts +1 -0
  81. package/esm/shaders/colorRampLut.generated.js +3 -0
  82. package/esm/shaders/coverageBand.generated.d.ts +2 -0
  83. package/esm/shaders/coverageBand.generated.js +4 -0
  84. package/esm/shaders/coverageBar.generated.d.ts +4 -0
  85. package/esm/shaders/coverageBar.generated.js +6 -0
  86. package/esm/shaders/coverageBar.iface.generated.d.ts +85 -0
  87. package/esm/shaders/coverageBar.iface.generated.js +114 -0
  88. package/esm/shaders/coverageIndicator.generated.d.ts +4 -0
  89. package/esm/shaders/coverageIndicator.generated.js +6 -0
  90. package/esm/shaders/coverageIndicator.iface.generated.d.ts +85 -0
  91. package/esm/shaders/coverageIndicator.iface.generated.js +114 -0
  92. package/esm/shaders/coverageInterbase.generated.d.ts +4 -0
  93. package/esm/shaders/coverageInterbase.generated.js +6 -0
  94. package/esm/shaders/coverageInterbase.iface.generated.d.ts +93 -0
  95. package/esm/shaders/coverageInterbase.iface.generated.js +134 -0
  96. package/esm/shaders/coverageMod.generated.d.ts +4 -0
  97. package/esm/shaders/coverageMod.generated.js +6 -0
  98. package/esm/shaders/coverageMod.iface.generated.d.ts +97 -0
  99. package/esm/shaders/coverageMod.iface.generated.js +144 -0
  100. package/esm/shaders/coverageSnp.generated.d.ts +4 -0
  101. package/esm/shaders/coverageSnp.generated.js +6 -0
  102. package/esm/shaders/coverageSnp.iface.generated.d.ts +97 -0
  103. package/esm/shaders/coverageSnp.iface.generated.js +144 -0
  104. package/esm/shaders/hpmath.js.generated.d.ts +3 -0
  105. package/esm/shaders/hpmath.js.generated.js +48 -0
  106. package/esm/shaders/pointGlyph.generated.d.ts +1 -0
  107. package/esm/shaders/pointGlyph.generated.js +3 -0
  108. package/esm/shaders/pointGlyph.js.generated.d.ts +1 -0
  109. package/esm/shaders/pointGlyph.js.generated.js +7 -0
  110. package/esm/shaders/rowRect.generated.d.ts +3 -0
  111. package/esm/shaders/rowRect.generated.js +5 -0
  112. package/esm/shaders/rowRect.js.generated.d.ts +2 -0
  113. package/esm/shaders/rowRect.js.generated.js +13 -0
  114. package/esm/shaders/scoreScale.js.generated.d.ts +1 -0
  115. package/esm/shaders/scoreScale.js.generated.js +46 -0
  116. package/esm/slangPass.d.ts +49 -0
  117. package/esm/slangPass.js +22 -0
  118. package/esm/useEventCallback.d.ts +1 -0
  119. package/esm/useEventCallback.js +19 -0
  120. package/esm/useGraphicsCapabilities.d.ts +17 -0
  121. package/esm/useGraphicsCapabilities.js +38 -0
  122. package/esm/useRenderingBackend.d.ts +83 -0
  123. package/esm/useRenderingBackend.js +422 -0
  124. package/esm/useTabVisibilityRerender.d.ts +13 -0
  125. package/esm/useTabVisibilityRerender.js +39 -0
  126. package/esm/webgpuUtils.d.ts +23 -0
  127. package/esm/webgpuUtils.js +76 -0
  128. package/package.json +91 -0
  129. package/src/shaders/antialias.js.generated.ts +33 -0
  130. package/src/shaders/antialias.slang +112 -0
  131. package/src/shaders/capsule.generated.ts +4 -0
  132. package/src/shaders/capsule.slang +62 -0
  133. package/src/shaders/colorPack.slang +26 -0
  134. package/src/shaders/colorRampLut.generated.ts +4 -0
  135. package/src/shaders/colorRampLut.slang +51 -0
  136. package/src/shaders/coverageBand.generated.ts +6 -0
  137. package/src/shaders/coverageBand.slang +276 -0
  138. package/src/shaders/coverageBar.generated.ts +10 -0
  139. package/src/shaders/coverageBar.iface.generated.ts +172 -0
  140. package/src/shaders/coverageBar.slang +37 -0
  141. package/src/shaders/coverageIndicator.generated.ts +10 -0
  142. package/src/shaders/coverageIndicator.iface.generated.ts +172 -0
  143. package/src/shaders/coverageIndicator.slang +61 -0
  144. package/src/shaders/coverageInterbase.generated.ts +10 -0
  145. package/src/shaders/coverageInterbase.iface.generated.ts +198 -0
  146. package/src/shaders/coverageInterbase.slang +63 -0
  147. package/src/shaders/coverageMod.generated.ts +10 -0
  148. package/src/shaders/coverageMod.iface.generated.ts +211 -0
  149. package/src/shaders/coverageMod.slang +36 -0
  150. package/src/shaders/coverageSnp.generated.ts +10 -0
  151. package/src/shaders/coverageSnp.iface.generated.ts +211 -0
  152. package/src/shaders/coverageSnp.slang +52 -0
  153. package/src/shaders/diagonalGrid.slang +25 -0
  154. package/src/shaders/glyphEdgeAlpha.test.ts +241 -0
  155. package/src/shaders/hpmath.js.generated.ts +47 -0
  156. package/src/shaders/hpmath.slang +226 -0
  157. package/src/shaders/pointGlyph.generated.ts +4 -0
  158. package/src/shaders/pointGlyph.js.generated.ts +9 -0
  159. package/src/shaders/pointGlyph.slang +93 -0
  160. package/src/shaders/rowRect.generated.ts +8 -0
  161. package/src/shaders/rowRect.js.generated.ts +17 -0
  162. package/src/shaders/rowRect.slang +160 -0
  163. package/src/shaders/scoreScale.js.generated.ts +51 -0
  164. package/src/shaders/scoreScale.slang +68 -0
package/package.json ADDED
@@ -0,0 +1,91 @@
1
+ {
2
+ "name": "@jbrowse/render-core",
3
+ "version": "4.3.0",
4
+ "type": "module",
5
+ "description": "GPU/Canvas2D rendering primitives for JBrowse displays: the HAL, the draw-lifecycle mixin, per-region/global backend bases, and the React backend hooks",
6
+ "keywords": [
7
+ "jbrowse",
8
+ "jbrowse2",
9
+ "webgl",
10
+ "webgpu",
11
+ "rendering"
12
+ ],
13
+ "license": "Apache-2.0",
14
+ "homepage": "https://jbrowse.org",
15
+ "bugs": "https://github.com/GMOD/jbrowse-components/issues",
16
+ "repository": {
17
+ "type": "git",
18
+ "url": "https://github.com/GMOD/jbrowse-components.git",
19
+ "directory": "packages/render-core"
20
+ },
21
+ "author": "JBrowse Team",
22
+ "//files": "src/shaders ships the shared .slang modules (hpmath, antialias, capsule, colorPack, coverageBand, diagonalGrid, pointGlyph, rowRect, scoreScale) that any shader imports, plus the coverage-band entry-point passes drawn by two plugins. @jbrowse/shader-tools resolves its include path here, so an out-of-tree plugin can compile its own .slang against them.",
23
+ "files": [
24
+ "esm",
25
+ "src/shaders"
26
+ ],
27
+ "exports": {
28
+ "./RenderCanvas": "./esm/RenderCanvas.js",
29
+ "./RenderLifecycleMixin": "./esm/RenderLifecycleMixin.js",
30
+ "./blockClipUtils": "./esm/blockClipUtils.js",
31
+ "./canvas2dUtils": "./esm/canvas2dUtils.js",
32
+ "./canvasContext": "./esm/canvasContext.js",
33
+ "./colorRampLut": "./esm/colorRampLut.js",
34
+ "./coverageBand": "./esm/coverageBand.js",
35
+ "./coverageBandBuffers": "./esm/coverageBandBuffers.js",
36
+ "./createRenderingBackend": "./esm/createRenderingBackend.js",
37
+ "./displayPhase": "./esm/displayPhase.js",
38
+ "./globalRenderingBackend": "./esm/globalRenderingBackend.js",
39
+ "./gpuDevice": "./esm/gpuDevice.js",
40
+ "./graphicsCapabilities": "./esm/graphicsCapabilities.js",
41
+ "./hal": "./esm/hal/index.js",
42
+ "./installUpload": "./esm/installUpload.js",
43
+ "./instanceCache": "./esm/instanceCache.js",
44
+ "./instancePass": "./esm/instancePass.js",
45
+ "./keyedRenderingBackend": "./esm/keyedRenderingBackend.js",
46
+ "./namedReactions": "./esm/namedReactions.js",
47
+ "./OverlayCanvas": "./esm/OverlayCanvas.js",
48
+ "./perRegionRenderingBackend": "./esm/perRegionRenderingBackend.js",
49
+ "./regionDataMap": "./esm/regionDataMap.js",
50
+ "./renderBlock": "./esm/renderBlock.js",
51
+ "./renderingBackendBase": "./esm/renderingBackendBase.js",
52
+ "./ScrollLockedOverlay": "./esm/ScrollLockedOverlay.js",
53
+ "./shaders/antialias": "./esm/shaders/antialias.js.generated.js",
54
+ "./shaders/capsuleConsts": "./esm/shaders/capsule.generated.js",
55
+ "./shaders/colorRampLutConsts": "./esm/shaders/colorRampLut.generated.js",
56
+ "./shaders/coverageBar": "./esm/shaders/coverageBar.generated.js",
57
+ "./shaders/coverageIndicator": "./esm/shaders/coverageIndicator.generated.js",
58
+ "./shaders/coverageInterbase": "./esm/shaders/coverageInterbase.generated.js",
59
+ "./shaders/coverageMod": "./esm/shaders/coverageMod.generated.js",
60
+ "./shaders/coverageSnp": "./esm/shaders/coverageSnp.generated.js",
61
+ "./shaders/hpmath": "./esm/shaders/hpmath.js.generated.js",
62
+ "./shaders/pointGlyph": "./esm/shaders/pointGlyph.js.generated.js",
63
+ "./shaders/pointGlyphConsts": "./esm/shaders/pointGlyph.generated.js",
64
+ "./shaders/rowRect": "./esm/shaders/rowRect.js.generated.js",
65
+ "./shaders/rowRectConsts": "./esm/shaders/rowRect.generated.js",
66
+ "./shaders/scoreScale": "./esm/shaders/scoreScale.js.generated.js",
67
+ "./slangPass": "./esm/slangPass.js",
68
+ "./useGraphicsCapabilities": "./esm/useGraphicsCapabilities.js",
69
+ "./useRenderingBackend": "./esm/useRenderingBackend.js",
70
+ "./useTabVisibilityRerender": "./esm/useTabVisibilityRerender.js"
71
+ },
72
+ "dependencies": {
73
+ "@jbrowse/mobx-state-tree": "^6.5.1",
74
+ "mobx": "^7.0.3"
75
+ },
76
+ "peerDependencies": {
77
+ "react": ">=19.0.0"
78
+ },
79
+ "//publishConfig": "Generated from `exports` above by scripts/generate-publish-exports.ts (`pnpm autogen`) — edit that map, never this one. The two describe the same subpaths against different trees, and only this one is what an installed consumer resolves, so drift between them is invisible until someone unpacks the tarball. It used to end in a `./*` wildcard, which served every emitted file including the ones src/index.ts withholds as internal.",
80
+ "publishConfig": {
81
+ "access": "public"
82
+ },
83
+ "sideEffects": false,
84
+ "scripts": {
85
+ "build:esm": "node ../../node_modules/typescript7/bin/tsc --build tsconfig.build.esm.json",
86
+ "build": "pnpm build:esm",
87
+ "test": "cd ../..; jest --passWithNoTests packages/render-core",
88
+ "clean": "rimraf esm *.tsbuildinfo",
89
+ "prebuild": "pnpm clean"
90
+ }
91
+ }
@@ -0,0 +1,33 @@
1
+ // AUTO-GENERATED by packages/shader-tools/src/shader-codegen from antialias.slang.
2
+ // Do not edit. Run `pnpm gen:shaders` to regenerate.
3
+
4
+ // Scalar twins of antialias.slang, transliterated from slangc's WGSL so
5
+ // the Canvas2D and SVG paths run the shader's own math. See adr-051.
6
+
7
+ function _clamp(x: number, lo: number, hi: number) {
8
+ return _min(_max(x, lo), hi)
9
+ }
10
+
11
+ function _max(a: number, b: number) {
12
+ return b > a || Number.isNaN(a) ? b : a
13
+ }
14
+
15
+ function _min(a: number, b: number) {
16
+ return b < a || Number.isNaN(a) ? b : a
17
+ }
18
+
19
+ export function aaPx(dpr: number): number {
20
+ return (1.0 / _max(dpr, 1.0))
21
+ }
22
+
23
+ export function aaHalfPx(dpr: number): number {
24
+ return (0.5 * aaPx(dpr))
25
+ }
26
+
27
+ export function aaRamp(signedInk: number, widthPx: number): number {
28
+ return _clamp(((signedInk / widthPx) + 0.5), 0.0, 1.0)
29
+ }
30
+
31
+ export function edgeCoverage(signedInkCssPx: number, dpr: number): number {
32
+ return aaRamp(signedInkCssPx, aaPx(dpr))
33
+ }
@@ -0,0 +1,112 @@
1
+ // Shared edge-antialiasing ramps.
2
+ //
3
+ // Every GPU mark in the tree fades its edge over one OUTPUT pixel. What differs
4
+ // between shaders is how wide that is in the units the fragment measures in,
5
+ // and there are exactly two answers:
6
+ //
7
+ // - Analytic, when the fragment's distance is a true perpendicular distance
8
+ // in CSS px. The HAL sizes the backing store by getDpr() and sets the
9
+ // viewport to canvas.width/height (DEVICE px) while coordinates stay CSS
10
+ // px, so one output sample spans 1/dpr CSS px. `aaPx` is that number, and
11
+ // `edgeCoverage` is the only thing that should be spelling it.
12
+ // - Measured, when it is not — a quad-local SDF whose scale differs per
13
+ // shape, or a varying whose foreshortening the shader cannot state.
14
+ // `aaGradient` is that number.
15
+ //
16
+ // `aaGradient` is deliberately not `fwidth`. fwidth is |ddx| + |ddy|, which
17
+ // overshoots a true gradient by up to sqrt(2), worst on the diagonals — where
18
+ // a dotplot line, a synteny ribbon edge and a chevron arm all live. The dotplot
19
+ // capsule, the synteny fill and the glyph SDFs each found that separately, in
20
+ // three plugins, before this module existed.
21
+ //
22
+ // `aaRamp` — linear in the signed distance — is the shape every mark in the
23
+ // tree fades on, and that is measured rather than preferred. Scored against
24
+ // exact area coverage of a pixel by a straight edge, the linear ramp is closer
25
+ // at EVERY angle: exact on an axis-aligned edge, where the cubic is up to 0.096
26
+ // of full ink out, and 0.043 against 0.067 worst case at 45 degrees. A band
27
+ // built as a difference of two ramps is exact at every width with the linear
28
+ // one; the cubic over-inks a half-pixel band by 37% (0.688 where 0.500 is the
29
+ // coverage). `scripts/aa_ramp_coverage_study.ts` is the measurement.
30
+ //
31
+ // There WAS a second shape here, `aaSmoothRamp` — `smoothstep(-h, h, d)` — and
32
+ // it is gone rather than deprecated, because a shader function nothing calls is
33
+ // dead-code-eliminated out of every compiled shader and the js-skip check says
34
+ // so out loud. Four shaders took it: synteny's `perpCoverage` and
35
+ // `vertCoverage`, the dotplot capsule, and `glyphEdgeAlpha`, and through it
36
+ // every point glyph. It read softer on a curve, which is it carrying more ink
37
+ // on both sides of the half-max contour rather than resolving the curve better.
38
+ // Re-deriving that shape is the study's job, not this module's — it models both
39
+ // in JS and scores them, so the comparison survives the deletion.
40
+ //
41
+ // If you reintroduce a smoothstep here, note the two forms take DIFFERENT
42
+ // arguments: the smoothstep takes the HALF width where `aaRamp` takes the full.
43
+ // A conversion either way is a factor of two, and dropping it compiles.
44
+ //
45
+ // The floor on `aaGradient` exists for an SDF that is a constant, such as
46
+ // manhattan's SHAPE_BAR: zero gradient makes the ramp zero-wide and the
47
+ // division 0/0. A degenerate ramp saturates to alpha 1, which is the solid fill
48
+ // those shapes want.
49
+ // A test modelling a shader's geometry needs the ramp's reach and its shape, so
50
+ // both go to JS. Not for a Canvas2D twin — that side's rasterizer does its own
51
+ // edge AA — but because the alternative is every pad test re-spelling `0.5/dpr`
52
+ // and then agreeing with its own copy, which is what dotplotCapsulePad.test.ts
53
+ // and syntenyFillPad.test.ts each did.
54
+ //! js-export: aaPx, aaHalfPx, aaRamp, edgeCoverage
55
+ module antialias;
56
+
57
+ // Width of a ramp covering exactly one output pixel, in CSS px. THE conversion
58
+ // between the two units in this file: a fragment measuring in CSS px against a
59
+ // device-px grid asks for this and nothing else. `max(dpr, 1.0)` is defensive —
60
+ // getDpr() never returns less — and keeps a bogus uniform from inverting the
61
+ // ramp.
62
+ public float aaPx(float dpr) {
63
+ return 1.0 / max(dpr, 1.0);
64
+ }
65
+
66
+ // Half of it: how far past the ink a ramp reaches, and so exactly how far a
67
+ // vertex stage must pad its quad to hold one. A pad stated in CSS px instead
68
+ // over-reaches by dpr — 2x on a plain monitor, 4x on a retina one — and every
69
+ // fragment in the surplus shades to alpha 0.
70
+ public float aaHalfPx(float dpr) {
71
+ return 0.5 * aaPx(dpr);
72
+ }
73
+
74
+
75
+ // One output pixel of `d`, in whatever units `d` is: the true gradient
76
+ // magnitude per device pixel. Takes derivatives, so uniform control flow only.
77
+ public float aaGradient(float d) {
78
+ return max(length(float2(ddx(d), ddy(d))), 1e-5);
79
+ }
80
+
81
+ // Linear coverage over a ramp `widthPx` wide, centred on the edge. `signedInk`
82
+ // is positive inside the mark and zero on its boundary.
83
+ public float aaRamp(float signedInk, float widthPx) {
84
+ return clamp(signedInk / widthPx + 0.5, 0.0, 1.0);
85
+ }
86
+
87
+ // Coverage of a mark's edge for a fragment whose distance is a TRUE
88
+ // perpendicular distance in CSS px, so its gradient is analytically 1 and there
89
+ // is nothing for `aaGradient` to discover. `signedInkCssPx` is how far inside
90
+ // the ink the fragment is: positive within, zero on the boundary.
91
+ //
92
+ // One function, because there is one ramp. It carries no cap and no shape —
93
+ // a capsule, a butt-capped segment, a synteny ribbon edge and a wiggle bar all
94
+ // reduce to this once their own distance is in hand, and spelling the width
95
+ // again beside each of them is how `2.0 * aaHalfPx(dpr)` and
96
+ // `STROKE_AA_PX / max(dpr, 1.0)` came to be the same number under two
97
+ // constants, one of which no test could see double.
98
+ public float edgeCoverage(float signedInkCssPx, float dpr) {
99
+ return aaRamp(signedInkCssPx, aaPx(dpr));
100
+ }
101
+
102
+ // A glyph SDF's edge, measured. `coverage` is positive inside and zero on the
103
+ // edge, in whatever units the SDF uses — the gradient supplies the conversion,
104
+ // so one call covers a disc, an L1 diamond (whose gradient carries a sqrt(2)
105
+ // the others don't) and a constant-SDF bar with no per-shape constant.
106
+ //
107
+ // Callers that select between several SDFs must pick their coverage in the
108
+ // branch and call this once after it: WGSL rejects a derivative taken under a
109
+ // branch on a varying.
110
+ public float glyphEdgeAlpha(float coverage) {
111
+ return aaRamp(coverage, aaGradient(coverage));
112
+ }
@@ -0,0 +1,4 @@
1
+ // AUTO-GENERATED by packages/shader-tools/src/shader-codegen from capsule.slang.
2
+ // Do not edit. Run `pnpm gen:shaders` to regenerate.
3
+
4
+ export const CAPSULE_MIN_LEN_PX = 0.0001
@@ -0,0 +1,62 @@
1
+ // A stroked segment's frame, its quad and its distance. The round cap lives in
2
+ // `capsuleDist` and nowhere else: the edge ramp over that distance is
3
+ // `antialias`'s one `edgeCoverage`, shared with every butt-capped stroke in the
4
+ // tree. Consumers, and which half each takes:
5
+ // agent-docs/reference/SHADER_SHAPE_LIBRARY.md.
6
+ //
7
+ // `capsuleQuadLocal` pads by exactly `aaHalfPx(dpr)` past the ink. Pad less and
8
+ // the ramp is clipped at the quad edge — coverage falls to 0.5 at the boundary,
9
+ // the rasterizer cuts it to 0, and the line reads a hard 50%-alpha edge about a
10
+ // pixel narrower than `lineWidth` asked for. Pad more and the surplus fragments
11
+ // shade to alpha 0.
12
+ //
13
+ // The distance is Euclidean in CSS px, so |grad d| = 1 at every angle and the
14
+ // ramp is analytic rather than differentiated — which it has to be, since `d`
15
+ // comes off a clamp and the 2x2 quads straddling the cap/body junction would be
16
+ // differentiating a discontinuity.
17
+ //! export-consts: CAPSULE_MIN_LEN_PX
18
+ module capsule;
19
+
20
+ import antialias;
21
+ import hpmath;
22
+
23
+ // Below this length a segment has no direction to speak of and `delta / len`
24
+ // is 0/0. Any positive threshold under a visible fraction of a pixel behaves
25
+ // the same (at that length the mark IS its cap); this was `1e-3` in dotplot
26
+ // and `1e-4` in the two others, and takes the majority spelling, which is also
27
+ // the one leaving the fallback the smallest reach.
28
+ public static const float CAPSULE_MIN_LEN_PX = 1e-4;
29
+
30
+ // The segment's own frame — x along it, y across it. Cap-agnostic, which is
31
+ // what lets the butt-capped linkedReadLine orient its diagonal through it. The
32
+ // degenerate guard exists only to keep a zero-length segment's 0/0 out of the
33
+ // frame.
34
+ public struct CapsuleFrame {
35
+ public float2 tangent;
36
+ public float2 normal;
37
+ };
38
+
39
+ public CapsuleFrame capsuleFrame(float2 delta, float len) {
40
+ CapsuleFrame f;
41
+ f.tangent = len > CAPSULE_MIN_LEN_PX ? delta / len : float2(1.0, 0.0);
42
+ f.normal = float2(-f.tangent.y, f.tangent.x);
43
+ return f;
44
+ }
45
+
46
+ // Quad corner `vid` in the segment's frame, for a capsule of half-length
47
+ // `halfLenPx` and stroke half-width `halfWidthPx`, grown by the pad the module
48
+ // header describes. Center-anchored: ±(halfLen + ext) along, ±ext across.
49
+ public float2 capsuleQuadLocal(
50
+ uint vid, float halfLenPx, float halfWidthPx, float dpr
51
+ ) {
52
+ float ext = halfWidthPx + aaHalfPx(dpr);
53
+ float2 q = quadLocal(vid) * 2.0 - 1.0;
54
+ return float2(q.x * (halfLenPx + ext), q.y * ext);
55
+ }
56
+
57
+ // CSS-px distance from `local` (the segment's frame, center-anchored) to the
58
+ // segment {(-halfLen,0)..(halfLen,0)}. Collapses to distance-from-origin for a
59
+ // degenerate segment — the circular dot of radius halfWidth.
60
+ public float capsuleDist(float2 local, float halfLenPx) {
61
+ return length(float2(max(abs(local.x) - halfLenPx, 0.0), local.y));
62
+ }
@@ -0,0 +1,26 @@
1
+ // Shared color-packing helpers. A single `uint` holds an ABGR triplet as
2
+ // packed bytes, letting every shader carry color data as one vertex
3
+ // attribute instead of four floats. Pair with `cssColorToABGR` on the
4
+ // CPU side (see packages/core/src/util/colorBits.ts).
5
+ module colorPack;
6
+
7
+ // Don't put a SCALAR array in a uniform block and unpack it with this.
8
+ // slangc v2026.5.2's WGSL backend cannot compile it: a `uint palette[N]` member
9
+ // becomes a `_Array_std140_uintN` wrapper (std140 pads each element to 16
10
+ // bytes), and passing an element of one to a cross-module function SEGFAULTS the
11
+ // compiler — signal 11, no diagnostic. `[ForceInline]` here dodges the crash and
12
+ // then emits invalid WGSL (a bare `…data_0[i].x;` statement, which naga
13
+ // rejects), so there is no version of it that works. GLSL compiles the same
14
+ // source fine, so it is WGSL-specific.
15
+ //
16
+ // Declare such a palette as `float4[N]` instead — a vector element needs no
17
+ // wrapper struct, lowers correctly, AND costs the same 16 bytes per slot that
18
+ // std140 was padding the uint to anyway, so packing bought nothing here. Packing
19
+ // still earns its keep in VERTEX ATTRIBUTES, which is what this is for.
20
+ public float4 unpackRGBA(uint c) {
21
+ return float4(
22
+ float((c >> 0u) & 0xFFu),
23
+ float((c >> 8u) & 0xFFu),
24
+ float((c >> 16u) & 0xFFu),
25
+ float((c >> 24u) & 0xFFu)) / 255.0;
26
+ }
@@ -0,0 +1,4 @@
1
+ // AUTO-GENERATED by packages/shader-tools/src/shader-codegen from colorRampLut.slang.
2
+ // Do not edit. Run `pnpm gen:shaders` to regenerate.
3
+
4
+ export const RAMP_LUT_ENTRIES = 256
@@ -0,0 +1,51 @@
1
+ // Sampling a 256×1 colour-ramp LUT texture by a [0,1] scalar — the mechanism
2
+ // HiC's contact map and both LD heatmap variants reached independently, down to
3
+ // the binding slot, and wiggle density's third spelling. The module owns ONLY
4
+ // the sampling: each consumer keeps its own scale (`mapHicCount`, LD's signed
5
+ // remap plus `ldValueComputed` sentinel gate, wiggle's `normalizeScore` +
6
+ // `densityGradientT`) and declares its own `[[vk::binding(2, 0)]]
7
+ // Sampler2D<float4> colorRamp;` — a module can take a sampler as a parameter
8
+ // but not declare the binding for its importer. The TS half of the mechanism is
9
+ // `uploadColorRampLut` (../colorRampLut.ts), which puts the 256-entry
10
+ // `Uint8Array` behind these samplers; `buildColorRampLut`
11
+ // (@jbrowse/core/util/colorRamp) is what builds it on both backends.
12
+ //
13
+ // Two entry points because premultiplication follows the consumer's declared
14
+ // blend, and the `//! blend:` declaration stays per-shader: HiC and LD both
15
+ // draw under `//! blend: premultiplied` and both multiplied the sample through
16
+ // its own alpha, so that shared line lives here rather than surviving as a
17
+ // copy in each fragment — while wiggle density draws opaque ramps under the
18
+ // default straight-alpha blend, where a premultiplied return would be wrong
19
+ // the day a translucent ramp entry appears. The function name carries the
20
+ // contract, so a consumer picks the form that matches its blend declaration.
21
+ //! export-consts: RAMP_LUT_ENTRIES
22
+ module colorRampLut;
23
+
24
+ // Entries in the ramp texture. Exported because `buildColorRampLut` sizes the
25
+ // array by it and the mapping below divides by it: a table built to one number
26
+ // and sampled by another is a half-shade of drift at every entry.
27
+ public static const float RAMP_LUT_ENTRIES = 256.0;
28
+
29
+ // The colour at `t` in [0, 1], straight (non-premultiplied) alpha. Sampled at
30
+ // the texture's vertical center, mip level 0 — the ramp has no other row and no
31
+ // other level.
32
+ //
33
+ // `t` is remapped into texel space rather than passed through. The builder
34
+ // defines entry i as the colour at `i / (N - 1)`, while a linear-filtered
35
+ // texture puts entry i's center at `(i + 0.5) / N`, so sampling at `t` returns
36
+ // a blend of two neighbours at every entry but the ends — half a step off the
37
+ // table the Canvas2D and SVG twins index. `clamp` lands an out-of-range scalar
38
+ // on the end entry, which clamp-to-edge addressing also answers.
39
+ public float4 rampColor(Sampler2D<float4> ramp, float t) {
40
+ float u = (clamp(t, 0.0, 1.0) * (RAMP_LUT_ENTRIES - 1.0) + 0.5) / RAMP_LUT_ENTRIES;
41
+ return ramp.SampleLevel(float2(u, 0.5), 0.0);
42
+ }
43
+
44
+ // The same sample with its colour multiplied through its alpha, for a fragment
45
+ // returned under `//! blend: premultiplied`. Alpha itself is unchanged, so a
46
+ // consumer's own alpha test (HiC's MIN_VISIBLE_ALPHA discard) reads the same
47
+ // number either side of this call.
48
+ public float4 rampColorPremultiplied(Sampler2D<float4> ramp, float t) {
49
+ float4 c = rampColor(ramp, t);
50
+ return float4(c.rgb * c.a, c.a);
51
+ }
@@ -0,0 +1,6 @@
1
+ // AUTO-GENERATED by packages/shader-tools/src/shader-codegen from coverageBand.slang.
2
+ // Do not edit. Run `pnpm gen:shaders` to regenerate.
3
+
4
+ export const TRIANGLE_HW = 3.5
5
+
6
+ export const TRIANGLE_H = 4.5