resolvcharts 0.2.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1 @@
1
+ {"version":3,"file":"series-wyqYpkXm.mjs","names":[],"sources":["../src/gpu/color.ts","../src/gpu/device.ts","../src/gpu/series.ts"],"sourcesContent":["/** Parse a CSS color (#rgb, #rrggbb, rgb(), rgba()) into linear-ish 0-1 rgba. */\nexport function parseColor(c: string): [number, number, number, number] {\n if (c.startsWith(\"#\")) {\n const h = c.slice(1);\n if (h.length === 3) {\n return [\n parseInt(h[0] as string, 16) / 15,\n parseInt(h[1] as string, 16) / 15,\n parseInt(h[2] as string, 16) / 15,\n 1,\n ];\n }\n if (h.length === 6) {\n return [\n parseInt(h.slice(0, 2), 16) / 255,\n parseInt(h.slice(2, 4), 16) / 255,\n parseInt(h.slice(4, 6), 16) / 255,\n 1,\n ];\n }\n }\n const m = /rgba?\\(([^)]+)\\)/.exec(c);\n if (m) {\n const parts = (m[1] as string).split(\",\").map((v) => Number.parseFloat(v));\n return [\n (parts[0] ?? 0) / 255,\n (parts[1] ?? 0) / 255,\n (parts[2] ?? 0) / 255,\n parts[3] ?? 1,\n ];\n }\n return [0, 0, 0, 1];\n}\n","export interface GpuRequestOptions {\n powerPreference?: \"default\" | \"low-power\" | \"high-performance\";\n /** use WebGPU compatibility mode (GLES 3.1 / D3D11 reach) */\n compat?: boolean;\n /** request \"timestamp-query\" when the adapter supports it */\n timing?: boolean;\n /**\n * Accept software (fallback) adapters such as SwiftShader. Off by default:\n * a CPU-rasterized GPU device is usually slower than the Canvas2D path.\n */\n allowFallback?: boolean;\n}\n\n/** Shared GPUDevice across charts — adapters/devices are expensive to acquire. */\nconst cache = new Map<string, Promise<GPUDevice | null>>();\n\nexport function getGpuDevice(\n opts: GpuRequestOptions = {},\n): Promise<GPUDevice | null> {\n const key = JSON.stringify(opts);\n let p = cache.get(key);\n if (!p) {\n p = (async (): Promise<GPUDevice | null> => {\n try {\n const nav = typeof navigator === \"undefined\" ? null : navigator;\n const gpu = (nav as Navigator | null)?.gpu;\n if (!gpu) return null;\n const req: GPURequestAdapterOptions = {};\n if (opts.powerPreference && opts.powerPreference !== \"default\") {\n req.powerPreference = opts.powerPreference;\n }\n if (opts.compat) {\n (req as { featureLevel?: \"compatibility\" }).featureLevel =\n \"compatibility\";\n }\n // Firefox rejects requestAdapter() (instead of returning null) on\n // platforms where WebGPU isn't shipped — the catch treats both\n // outcomes as \"unavailable\"\n const adapter = await gpu.requestAdapter(req);\n if (!adapter) return null;\n if (\n !opts.allowFallback &&\n (adapter as { isFallbackAdapter?: boolean }).isFallbackAdapter\n ) {\n return null;\n }\n const requiredFeatures: GPUFeatureName[] = [];\n if (opts.timing && adapter.features.has(\"timestamp-query\")) {\n requiredFeatures.push(\"timestamp-query\");\n }\n const device = await adapter.requestDevice({ requiredFeatures });\n // evict on loss so the next getGpuDevice() re-requests a fresh\n // adapter+device (all GpuSeries instances share this cache entry)\n device.lost.then(() => cache.delete(key));\n return device;\n } catch {\n return null;\n }\n })();\n p.catch(() => cache.delete(key));\n cache.set(key, p);\n }\n return p;\n}\n","import type { NormalizedSeries, NormalizedXY, Rect } from \"../core/types\";\nimport { parseColor } from \"./color\";\nimport { type GpuRequestOptions, getGpuDevice } from \"./device\";\n\n/**\n * WebGPU series renderer. Data is uploaded once per series as affine-encoded\n * f32 [x, y] pairs (+ an encoded prevY channel for animation) and lives on the\n * GPU: the domain→pixel transform runs in the vertex shader, so pan/zoom,\n * resize and view animation are uniform writes, not buffer re-uploads.\n * Streaming `append()` writes only the new tail into a per-series ring buffer.\n *\n * When a series has more than ~2 points per pixel column a compute pass does\n * M4 decimation (first/min/max/last per column) into a GPU-side output buffer\n * — the CPU never rescans the data. Pipelines use instanced vertex attributes\n * everywhere (no vertex-stage storage buffers), so they also run in WebGPU\n * compatibility mode.\n */\n\nconst HEADER = /* wgsl */ `\nstruct U {\n res: vec4f, // canvas w,h (device px), dpr, pad\n color: vec4f,\n p: vec4f, // line: width | area: baseCssY, plotY, plotH | points: radius\n map: vec4f, // cssX = ex*map.x + map.y ; cssY = map.w - ey*map.z\n anim: vec4f, // t, flow, invN, pad\n ring: vec4f, // start, cap (0 = linear), n, pad\n dec: vec4f, // cols, gapFillYEnc, pad, pad\n};\n@group(0) @binding(0) var<uniform> u: U;\n\nfn encToCss(e: vec2f) -> vec2f {\n return vec2f(e.x * u.map.x + u.map.y, u.map.w - e.y * u.map.z);\n}\nfn toClip(css: vec2f) -> vec4f {\n let d = css * u.res.z;\n return vec4f(d.x / u.res.x * 2.0 - 1.0, 1.0 - d.y / u.res.y * 2.0, 0.0, 1.0);\n}\nfn animT(i: f32) -> f32 {\n return clamp(\n u.anim.x * (1.0 + u.anim.y) - u.anim.y + i * u.anim.z, 0.0, 1.0,\n );\n}\n`;\n\nconst LINE_WGSL = /* wgsl */ `\n${HEADER}\nconst OFF = array<vec2f, 6>(\n vec2f(0.0, -1.0), vec2f(0.0, 1.0), vec2f(1.0, -1.0),\n vec2f(0.0, 1.0), vec2f(1.0, 1.0), vec2f(1.0, -1.0),\n);\nstruct VOut {\n @builtin(position) pos: vec4f,\n @location(0) edge: f32,\n};\nfn segQuad(v: vec2f, A: vec2f, B: vec2f) -> VOut {\n var dir = B - A;\n let len = length(dir);\n if (len < 1e-6) {\n dir = vec2f(1.0, 0.0);\n } else {\n dir = dir / len;\n }\n let nrm = vec2f(-dir.y, dir.x);\n let halfW = u.p.x * 0.5;\n let aa = 0.9;\n var o: VOut;\n o.pos = toClip(mix(A, B, v.x) + nrm * v.y * (halfW + aa));\n o.edge = v.y * (halfW + aa);\n return o;\n}\n@vertex fn vs(\n @builtin(vertex_index) vi: u32,\n @builtin(instance_index) inst: u32,\n @location(0) a: vec2f,\n @location(1) b: vec2f,\n @location(2) pa: f32,\n @location(3) pb: f32,\n) -> VOut {\n let ya = mix(pa, a.y, animT(f32(inst)));\n let yb = mix(pb, b.y, animT(f32(inst + 1u)));\n return segQuad(\n OFF[vi], encToCss(vec2f(a.x, ya)), encToCss(vec2f(b.x, yb)),\n );\n}\n@fragment fn fs(o: VOut) -> @location(0) vec4f {\n let halfW = u.p.x * 0.5;\n let a = 1.0 - smoothstep(halfW - 0.5, halfW + 0.9, abs(o.edge));\n return vec4f(u.color.rgb, u.color.a * a);\n}\n`;\n\n// decimated input: no prevY channel (compute already lerped); empty columns\n// carry an x=-1e30 sentinel so bridged segments can be killed\nconst LINE_FLAT_WGSL = /* wgsl */ `\n${HEADER}\nconst OFF = array<vec2f, 6>(\n vec2f(0.0, -1.0), vec2f(0.0, 1.0), vec2f(1.0, -1.0),\n vec2f(0.0, 1.0), vec2f(1.0, 1.0), vec2f(1.0, -1.0),\n);\nstruct VOut {\n @builtin(position) pos: vec4f,\n @location(0) edge: f32,\n};\n@vertex fn vs(\n @builtin(vertex_index) vi: u32,\n @location(0) a: vec2f,\n @location(1) b: vec2f,\n) -> VOut {\n var o: VOut;\n if (a.x < -1e20 || b.x < -1e20) {\n o.pos = vec4f(0.0, 0.0, 2.0, 1.0); // outside clip z-range → discarded\n o.edge = 0.0;\n return o;\n }\n let A = encToCss(a);\n let B = encToCss(b);\n var dir = B - A;\n let len = length(dir);\n if (len < 1e-6) {\n dir = vec2f(1.0, 0.0);\n } else {\n dir = dir / len;\n }\n let nrm = vec2f(-dir.y, dir.x);\n let halfW = u.p.x * 0.5;\n let aa = 0.9;\n let v = OFF[vi];\n o.pos = toClip(mix(A, B, v.x) + nrm * v.y * (halfW + aa));\n o.edge = v.y * (halfW + aa);\n return o;\n}\n@fragment fn fs(o: VOut) -> @location(0) vec4f {\n let halfW = u.p.x * 0.5;\n let a = 1.0 - smoothstep(halfW - 0.5, halfW + 0.9, abs(o.edge));\n return vec4f(u.color.rgb, u.color.a * a);\n}\n`;\n\nconst AREA_WGSL = /* wgsl */ `\n${HEADER}\nstruct VOut {\n @builtin(position) pos: vec4f,\n @location(0) grad: f32,\n};\n// input is doubled point data (each point twice): even verts land on the\n// path, odd verts drop to the baseline\n@vertex fn vs(\n @builtin(vertex_index) vi: u32,\n @location(0) top: vec2f,\n @location(1) prev: f32,\n) -> VOut {\n let isTop = (vi & 1u) == 0u;\n let y = mix(prev, top.y, animT(f32(vi >> 1u)));\n let css = encToCss(vec2f(top.x, y));\n var o: VOut;\n o.pos = toClip(vec2f(css.x, select(u.p.x, css.y, isTop)));\n o.grad = clamp((css.y - u.p.y) / max(u.p.z, 1.0), 0.0, 1.0);\n return o;\n}\n@fragment fn fs(o: VOut) -> @location(0) vec4f {\n let a = mix(0.16, 0.0, o.grad) * u.color.a;\n return vec4f(u.color.rgb, a);\n}\n`;\n\nconst AREA_FLAT_WGSL = /* wgsl */ `\n${HEADER}\nstruct VOut {\n @builtin(position) pos: vec4f,\n @location(0) grad: f32,\n};\n@vertex fn vs(\n @builtin(vertex_index) vi: u32,\n @location(0) top: vec2f,\n) -> VOut {\n let isTop = (vi & 1u) == 0u;\n let css = encToCss(top);\n var o: VOut;\n o.pos = toClip(vec2f(css.x, select(u.p.x, css.y, isTop)));\n o.grad = clamp((css.y - u.p.y) / max(u.p.z, 1.0), 0.0, 1.0);\n return o;\n}\n@fragment fn fs(o: VOut) -> @location(0) vec4f {\n let a = mix(0.16, 0.0, o.grad) * u.color.a;\n return vec4f(u.color.rgb, a);\n}\n`;\n\nconst POINTS_WGSL = /* wgsl */ `\n${HEADER}\nconst QUAD = array<vec2f, 6>(\n vec2f(-1.0, -1.0), vec2f(1.0, -1.0), vec2f(-1.0, 1.0),\n vec2f(-1.0, 1.0), vec2f(1.0, 1.0), vec2f(1.0, 1.0),\n);\nstruct VOut {\n @builtin(position) pos: vec4f,\n @location(0) local: vec2f,\n};\n@vertex fn vs(\n @builtin(vertex_index) vi: u32,\n @builtin(instance_index) inst: u32,\n @location(0) c: vec2f,\n @location(1) prev: f32,\n) -> VOut {\n let r = u.p.x;\n let q = QUAD[vi];\n let y = mix(prev, c.y, animT(f32(inst)));\n let css = encToCss(vec2f(c.x, y));\n var o: VOut;\n o.pos = toClip(css + q * r);\n o.local = q * r;\n return o;\n}\n@fragment fn fs(o: VOut) -> @location(0) vec4f {\n let r = u.p.x;\n let a = 1.0 - smoothstep(r - 1.2, r, length(o.local));\n return vec4f(u.color.rgb, u.color.a * a);\n}\n`;\n\n// M4 decimation: one thread per absolute pixel column emits first/min/max/last\n// (encoded, y already lerped) into a line region (4 pts/col) and a doubled\n// area-strip region (8 verts/col). Empty columns → sentinel / baseline fill.\nconst DECIMATE_WGSL = /* wgsl */ `\n${HEADER}\n@group(1) @binding(0) var<storage, read> xy: array<vec2f>;\n@group(1) @binding(1) var<storage, read> prev: array<f32>;\n@group(1) @binding(2) var<storage, read_write> dst: array<vec2f>;\n\nfn physIdx(i: u32) -> u32 {\n let cap = u32(u.ring.y);\n if (cap == 0u) {\n return i;\n }\n return (u32(u.ring.x) + i) % cap;\n}\nfn xEnc(i: u32) -> f32 {\n return xy[physIdx(i)].x;\n}\nfn yLerp(i: u32) -> f32 {\n let p = physIdx(i);\n return mix(prev[p], xy[p].y, animT(f32(i)));\n}\nfn lowerBound(e: f32) -> u32 {\n var lo = 0u;\n var hi = u32(u.ring.z);\n while (lo < hi) {\n let mid = (lo + hi) >> 1u;\n if (xEnc(mid) < e) {\n lo = mid + 1u;\n } else {\n hi = mid;\n }\n }\n return lo;\n}\n\n@compute @workgroup_size(64)\nfn dec(@builtin(global_invocation_id) gid: vec3u) {\n let c = gid.x;\n let cols = u32(u.dec.x);\n if (c >= cols) {\n return;\n }\n let lineBase = c * 4u;\n let areaBase = cols * 4u + c * 8u;\n // encoded-x range mapping to css column [c, c+1)\n let lo = lowerBound((f32(c) - u.map.y) / u.map.x);\n let hi = lowerBound((f32(c) + 1.0 - u.map.y) / u.map.x);\n if (lo >= hi) {\n let sent = vec2f(-1e30, -1e30);\n for (var k = 0u; k < 4u; k++) {\n dst[lineBase + k] = sent;\n }\n let gp = vec2f((f32(c) + 0.5 - u.map.y) / u.map.x, u.dec.y);\n for (var k = 0u; k < 8u; k++) {\n dst[areaBase + k] = gp;\n }\n return;\n }\n var iMin = lo;\n var iMax = lo;\n var mn = yLerp(lo);\n var mx = mn;\n for (var i = lo + 1u; i < hi; i++) {\n let y = yLerp(i);\n if (y < mn) {\n mn = y;\n iMin = i;\n }\n if (y > mx) {\n mx = y;\n iMax = i;\n }\n }\n let xs = array<u32, 4>(lo, iMin, iMax, hi - 1u);\n for (var k = 0u; k < 4u; k++) {\n let i = xs[k];\n let pt = vec2f(xEnc(i), yLerp(i));\n dst[lineBase + k] = pt;\n dst[areaBase + 2u * k] = pt;\n dst[areaBase + 2u * k + 1u] = pt;\n }\n}\n`;\n\n// GPUBufferUsage flags (lib.dom has the types but not the const objects)\nconst BUF_VERTEX_DST = 0x28; // VERTEX | COPY_DST\nconst BUF_UNIFORM_DST = 0x48; // UNIFORM | COPY_DST\nconst BUF_RESOLVE_SRC = 0x204; // QUERY_RESOLVE | COPY_SRC\nconst BUF_MAPREAD_DST = 0x09; // MAP_READ | COPY_DST\nconst BUF_SERIES = 0xac; // STORAGE | VERTEX | COPY_DST | COPY_SRC\nconst BUF_DEC = 0xa0; // STORAGE | VERTEX\nconst MAP_READ = 0x1;\nconst STAGE_ALL = 7; // VERTEX | FRAGMENT | COMPUTE\n\nconst UVEC = 7; // vec4s per uniform slot\nconst UBYTES = 256; // dynamic-offset aligned stride\nconst UBUF_SIZE = 256 * 1024;\nconst DEC_ELEMS_PER_COL = 12; // 4 line pts + 8 doubled area verts\n\ninterface Slot {\n n: number;\n cap: number;\n start: number;\n enc: { xr: number; xu: number; yr: number; yu: number };\n /** physical-order CPU copies (ring layout: logical i at (start+i)%cap) */\n encXY: Float32Array;\n encPrev: Float32Array;\n xy: GPUBuffer;\n prev: GPUBuffer;\n /** doubled strip data for direct area draws */\n scratch: GPUBuffer | null;\n scratchN: number;\n dec: GPUBuffer | null;\n decCols: number;\n bg: GPUBindGroup | null;\n decStamp: number;\n}\n\ninterface View {\n x: readonly [number, number];\n y: readonly [number, number];\n}\n\ninterface DrawOp {\n pipe: GPURenderPipeline;\n vbufs: { buf: GPUBuffer; off: number }[];\n u: number;\n verts: number;\n insts: number;\n}\n\nexport class GpuSeries {\n canvas: HTMLCanvasElement;\n device: GPUDevice;\n private ctx: GPUCanvasContext;\n private format: GPUTextureFormat;\n private opts: GpuRequestOptions;\n private layout!: GPUBindGroupLayout;\n private decLayout!: GPUBindGroupLayout;\n private ubiGroup!: GPUBindGroup;\n private ubuf!: GPUBuffer;\n private pipes!: {\n line: GPURenderPipeline;\n lineFlat: GPURenderPipeline;\n area: GPURenderPipeline;\n areaFlat: GPURenderPipeline;\n points: GPURenderPipeline;\n dec: GPUComputePipeline;\n };\n private dpr = 1;\n private slots: Slot[] = [];\n private slotCount = 0;\n private appliedRev = -1;\n private draws: DrawOp[] = [];\n private cmps: { slot: Slot; u: number }[] = [];\n private uOff = 0;\n private stamp = 0;\n private plotR: Rect = { x: 0, y: 0, w: 1, h: 1 };\n private cols = 1;\n private t = 1;\n private flow = 0;\n private tailScratch = new Float32Array(4);\n /** last measured GPU execution time in ms (when timing enabled) */\n gpuMs: number | null = null;\n private querySet: GPUQuerySet | null = null;\n private queryBuf: GPUBuffer | null = null;\n private readBuf: GPUBuffer | null = null;\n private reading = false;\n private timing = false;\n private destroyed = false;\n /** true once the device is unrecoverable — the chart falls back to Canvas2D */\n dead = false;\n /** true while a lost device is being re-acquired */\n recovering = false;\n\n get unavailable(): boolean {\n return this.dead || this.recovering;\n }\n\n private constructor(\n device: GPUDevice,\n canvas: HTMLCanvasElement,\n opts: GpuRequestOptions,\n ) {\n this.opts = opts;\n this.timing = !!opts.timing;\n this.canvas = canvas;\n canvas.style.cssText =\n \"position:absolute;inset:0;width:100%;height:100%;display:block;pointer-events:none\";\n const ctx = canvas.getContext(\"webgpu\") as GPUCanvasContext | null;\n if (!ctx) throw new Error(\"resolvcharts: webgpu context unavailable\");\n this.ctx = ctx;\n this.device = device;\n this.format = navigator.gpu.getPreferredCanvasFormat();\n this.setup(device);\n }\n\n static async create(opts: GpuRequestOptions = {}): Promise<GpuSeries | null> {\n const device = await getGpuDevice(opts);\n if (!device) return null;\n const canvas = document.createElement(\"canvas\");\n try {\n return new GpuSeries(device, canvas, opts);\n } catch {\n return null;\n }\n }\n\n /** (re)create all device-bound resources — called on init and after loss */\n private setup(device: GPUDevice): void {\n this.device = device;\n this.layout = device.createBindGroupLayout({\n entries: [\n {\n binding: 0,\n visibility: STAGE_ALL,\n buffer: { type: \"uniform\", hasDynamicOffset: true },\n },\n ],\n });\n this.decLayout = device.createBindGroupLayout({\n entries: [\n { binding: 0, visibility: 4, buffer: { type: \"read-only-storage\" } },\n { binding: 1, visibility: 4, buffer: { type: \"read-only-storage\" } },\n { binding: 2, visibility: 4, buffer: { type: \"storage\" } },\n ],\n });\n this.ubuf = device.createBuffer({\n size: UBUF_SIZE,\n usage: BUF_UNIFORM_DST,\n });\n this.ubiGroup = device.createBindGroup({\n layout: this.layout,\n entries: [\n { binding: 0, resource: { buffer: this.ubuf, size: UVEC * 16 } },\n ],\n });\n const pl = device.createPipelineLayout({\n bindGroupLayouts: [this.layout],\n });\n const decPl = device.createPipelineLayout({\n bindGroupLayouts: [this.layout, this.decLayout],\n });\n const mk = (\n code: string,\n topology: GPUPrimitiveTopology,\n buffers: GPUVertexBufferLayout[],\n ) =>\n device.createRenderPipeline({\n layout: pl,\n vertex: {\n module: device.createShaderModule({ code }),\n entryPoint: \"vs\",\n buffers,\n },\n fragment: {\n module: device.createShaderModule({ code }),\n entryPoint: \"fs\",\n targets: [{ format: this.format, blend: BLEND }],\n },\n primitive: { topology },\n });\n const iXY: GPUVertexBufferLayout = {\n arrayStride: 8,\n stepMode: \"instance\",\n attributes: [{ shaderLocation: 0, offset: 0, format: \"float32x2\" }],\n };\n const iXY1: GPUVertexBufferLayout = {\n arrayStride: 8,\n stepMode: \"instance\",\n attributes: [{ shaderLocation: 1, offset: 0, format: \"float32x2\" }],\n };\n const iPrev: GPUVertexBufferLayout = {\n arrayStride: 4,\n stepMode: \"instance\",\n attributes: [{ shaderLocation: 2, offset: 0, format: \"float32\" }],\n };\n const iPrev1: GPUVertexBufferLayout = {\n arrayStride: 4,\n stepMode: \"instance\",\n attributes: [{ shaderLocation: 3, offset: 0, format: \"float32\" }],\n };\n const iPrevPt: GPUVertexBufferLayout = {\n arrayStride: 4,\n stepMode: \"instance\",\n attributes: [{ shaderLocation: 1, offset: 0, format: \"float32\" }],\n };\n const vXY: GPUVertexBufferLayout = {\n arrayStride: 8,\n stepMode: \"vertex\",\n attributes: [{ shaderLocation: 0, offset: 0, format: \"float32x2\" }],\n };\n const vPrev: GPUVertexBufferLayout = {\n arrayStride: 4,\n stepMode: \"vertex\",\n attributes: [{ shaderLocation: 1, offset: 0, format: \"float32\" }],\n };\n this.pipes = {\n line: mk(LINE_WGSL, \"triangle-list\", [iXY, iXY1, iPrev, iPrev1]),\n lineFlat: mk(LINE_FLAT_WGSL, \"triangle-list\", [iXY, iXY1]),\n area: mk(AREA_WGSL, \"triangle-strip\", [vXY, vPrev]),\n areaFlat: mk(AREA_FLAT_WGSL, \"triangle-strip\", [vXY]),\n points: mk(POINTS_WGSL, \"triangle-list\", [iXY, iPrevPt]),\n dec: device.createComputePipeline({\n layout: decPl,\n compute: {\n module: device.createShaderModule({ code: DECIMATE_WGSL }),\n entryPoint: \"dec\",\n },\n }),\n };\n if (this.timing && device.features.has(\"timestamp-query\")) {\n this.querySet = device.createQuerySet({ type: \"timestamp\", count: 2 });\n this.queryBuf = device.createBuffer({\n size: 16,\n usage: BUF_RESOLVE_SRC,\n });\n this.readBuf = device.createBuffer({\n size: 16,\n usage: BUF_MAPREAD_DST,\n });\n }\n device.lost.then((info) => this.onLost(info));\n }\n\n private onLost(info: GPUDeviceLostInfo): void {\n if (this.destroyed) return;\n if (info.reason === \"destroyed\") {\n this.dead = true;\n return;\n }\n this.recovering = true;\n void getGpuDevice(this.opts).then((nd) => {\n if (!nd || this.destroyed) {\n this.fail();\n return;\n }\n try {\n this.teardownResources();\n this.setup(nd);\n try {\n this.configure();\n } catch {\n // some drivers reject reconfiguring a context with a new device —\n // swap in a fresh canvas instead\n const nc = document.createElement(\"canvas\");\n nc.width = this.canvas.width;\n nc.height = this.canvas.height;\n this.canvas.replaceWith(nc);\n this.canvas = nc;\n const ctx = nc.getContext(\"webgpu\") as GPUCanvasContext | null;\n if (!ctx) throw new Error(\"webgpu context lost\");\n this.ctx = ctx;\n this.configure();\n }\n this.appliedRev = -1; // force full re-upload on next frame\n this.recovering = false;\n } catch {\n this.fail();\n }\n });\n }\n\n private fail(): void {\n this.dead = true;\n this.recovering = false;\n this.destroy();\n }\n\n private teardownResources(): void {\n for (const s of this.slots) {\n s.xy.destroy();\n s.prev.destroy();\n s.scratch?.destroy();\n s.dec?.destroy();\n }\n this.slots = [];\n this.slotCount = 0;\n this.ubuf.destroy();\n this.queryBuf?.destroy();\n this.readBuf?.destroy();\n this.querySet?.destroy();\n this.querySet = null;\n this.queryBuf = null;\n this.readBuf = null;\n }\n\n private configure(): void {\n this.ctx.configure({\n device: this.device,\n format: this.format,\n alphaMode: \"premultiplied\",\n });\n }\n\n setSize(cssW: number, cssH: number, dpr: number): void {\n this.dpr = dpr;\n this.canvas.width = Math.max(1, Math.round(cssW * dpr));\n this.canvas.height = Math.max(1, Math.round(cssH * dpr));\n if (!this.unavailable) this.configure();\n }\n\n // ---------------------------------------------------------------- data --\n // Points are affine-encoded to f32: enc(v) = (v - ref) * unit. The shader\n // gets a second affine (encoded → css px) per frame, so any view window\n // lands on the same buffer without re-uploading. Ref/unit are fixed at\n // upload; out-of-range appends simply encode outside [0,1].\n\n private upload(i: number, xs: Float64Array, s: NormalizedSeries): void {\n const n = Math.min(xs.length, s.y.length);\n const xr = n > 0 ? (xs[0] as number) : 0;\n const xu =\n 1 /\n ((n > 0 ? (xs[n - 1] as number) - xr : 0) ||\n Math.max(1, Math.abs(xr), 1));\n let mn = Infinity;\n let mx = -Infinity;\n for (let j = 0; j < n; j++) {\n const v = s.y[j] as number;\n if (v < mn) mn = v;\n if (v > mx) mx = v;\n }\n const yr = mn === Infinity ? 0 : mn;\n const yu = 1 / (mx - mn || Math.max(1, Math.abs(yr)));\n let slot = this.slots[i];\n const cap = Math.max(1024, Math.ceil(n * 1.25));\n if (!slot || slot.cap < n) {\n slot?.xy.destroy();\n slot?.prev.destroy();\n slot?.dec?.destroy();\n slot = {\n n,\n cap,\n start: 0,\n enc: { xr, xu, yr, yu },\n encXY: new Float32Array(cap * 2),\n encPrev: new Float32Array(cap),\n xy: this.device.createBuffer({\n size: cap * 8,\n usage: BUF_SERIES,\n }),\n prev: this.device.createBuffer({\n size: cap * 4,\n usage: BUF_SERIES,\n }),\n scratch: null,\n scratchN: 0,\n dec: null,\n decCols: 0,\n bg: null,\n decStamp: -1,\n };\n this.slots[i] = slot;\n } else {\n slot.n = n;\n slot.start = 0;\n slot.enc = { xr, xu, yr, yu };\n slot.bg = null;\n slot.decStamp = -1;\n }\n const { encXY, encPrev } = slot;\n const prev = s.prevY;\n for (let j = 0; j < n; j++) {\n encXY[2 * j] = ((xs[j] as number) - xr) * xu;\n encXY[2 * j + 1] = ((s.y[j] as number) - yr) * yu;\n encPrev[j] = prev ? ((prev[j] as number) - yr) * yu : 0;\n }\n this.device.queue.writeBuffer(slot.xy, 0, encXY, 0, n * 2);\n this.device.queue.writeBuffer(slot.prev, 0, encPrev, 0, n);\n }\n\n /**\n * Full-upload hook: call once per frame with a revision that changes\n * whenever the data is replaced/rebuilt. Unchanged revisions are free.\n */\n syncData(d: NormalizedXY, rev: number): void {\n if (\n this.unavailable ||\n (rev === this.appliedRev && this.slotCount === d.series.length)\n ) {\n return;\n }\n for (let i = 0; i < d.series.length; i++) {\n const s = d.series[i];\n if (s) this.upload(i, d.sortedX, s);\n }\n this.slotCount = d.series.length;\n this.appliedRev = rev;\n }\n\n /**\n * Ring-buffer streaming append: writes only the appended tail per series.\n * `ys[i]` is the new y for series i, `prevYs[i]` the y it animates from\n * (the previous tail value), `dropped` how many leading points were evicted.\n */\n appended(\n x: number,\n ys: number[],\n prevYs: number[],\n dropped: number,\n ): boolean {\n if (this.unavailable) return false;\n const q = this.device.queue;\n for (let i = 0; i < this.slotCount; i++) {\n const s = this.slots[i];\n if (!s) return false;\n const n2 = s.n - dropped + 1;\n if (n2 > s.cap) this.grow(s, n2);\n s.start = (s.start + dropped) % s.cap;\n s.n = n2;\n const pNew = (s.start + s.n - 1) % s.cap;\n const { xr, xu, yr, yu } = s.enc;\n const ex = (x - xr) * xu;\n const ey = ((ys[i] ?? 0) - yr) * yu;\n const ep = ((prevYs[i] ?? 0) - yr) * yu;\n const t = this.tailScratch;\n t[0] = ex;\n t[1] = ey;\n q.writeBuffer(s.xy, pNew * 8, t, 0, 2);\n s.encXY[2 * pNew] = ex;\n s.encXY[2 * pNew + 1] = ey;\n t[0] = ep;\n q.writeBuffer(s.prev, pNew * 4, t, 0, 1);\n s.encPrev[pNew] = ep;\n // the displaced tail's prev channel becomes its own y (steady-state\n // invariant: prevY[i] = y[i] for every non-tail point)\n if (s.n > 1) {\n const pOld = (pNew + s.cap - 1) % s.cap;\n q.writeBuffer(s.prev, pOld * 4, t, 0, 1);\n s.encPrev[pOld] = ep;\n }\n }\n return true;\n }\n\n /** grow ring capacity, unwrapping logical order into the new buffer */\n private grow(s: Slot, need: number): void {\n const cap = Math.max(s.cap * 2, need + 1024);\n const a = s.cap - s.start;\n const enc = this.device.createCommandEncoder();\n const xy = this.device.createBuffer({ size: cap * 8, usage: BUF_SERIES });\n const prev = this.device.createBuffer({ size: cap * 4, usage: BUF_SERIES });\n enc.copyBufferToBuffer(s.xy, s.start * 8, xy, 0, a * 8);\n if (s.start > 0) enc.copyBufferToBuffer(s.xy, 0, xy, a * 8, s.start * 8);\n enc.copyBufferToBuffer(s.prev, s.start * 4, prev, 0, a * 4);\n if (s.start > 0)\n enc.copyBufferToBuffer(s.prev, 0, prev, a * 4, s.start * 4);\n this.device.queue.submit([enc.finish()]);\n s.xy.destroy();\n s.prev.destroy();\n s.xy = xy;\n s.prev = prev;\n const encXY = new Float32Array(cap * 2);\n const encPrev = new Float32Array(cap);\n encXY.set(s.encXY.subarray(s.start * 2, s.cap * 2), 0);\n encXY.set(s.encXY.subarray(0, s.start * 2), a * 2);\n encPrev.set(s.encPrev.subarray(s.start, s.cap), 0);\n encPrev.set(s.encPrev.subarray(0, s.start), a);\n s.encXY = encXY;\n s.encPrev = encPrev;\n s.cap = cap;\n s.start = 0;\n s.bg = null;\n }\n\n // --------------------------------------------------------------- frame --\n\n begin(plot: Rect, t = 1, flow = 0): void {\n this.plotR = plot;\n this.t = t;\n this.flow = flow;\n this.cols = Math.max(1, Math.ceil(plot.x + plot.w));\n this.stamp++;\n this.draws.length = 0;\n this.cmps.length = 0;\n this.uOff = 0;\n }\n\n /** encoded→css affine for this slot and view domain */\n private mapFor(s: Slot, view: View): [number, number, number, number] {\n const { xr, xu, yr, yu } = s.enc;\n const p = this.plotR;\n const ex0 = (view.x[0] - xr) * xu;\n const ex1 = (view.x[1] - xr) * xu;\n const ax = p.w / (ex1 - ex0 || 1e-30);\n const bx = p.x - ex0 * ax;\n const ey0 = (view.y[0] - yr) * yu;\n const ey1 = (view.y[1] - yr) * yu;\n const ay = p.h / (ey1 - ey0 || 1e-30);\n const by = p.y + ey1 * ay;\n return [ax, bx, ay, by];\n }\n\n private writeU(\n color: string,\n alpha: number,\n p: [number, number, number, number],\n map: [number, number, number, number],\n s: Slot,\n dec: [number, number],\n ): number {\n const off = this.uOff;\n this.uOff += UBYTES;\n const u = new Float32Array(UVEC * 4);\n u.set([this.canvas.width, this.canvas.height, this.dpr, 0]);\n const [r, g, b, a] = parseColor(color);\n u.set([r, g, b, a * alpha], 4);\n u.set(p, 8);\n u.set(map, 12);\n const inv = s.n > 1 ? this.flow / (s.n - 1) : 0;\n u.set([this.t, this.flow, inv, 0], 16);\n u.set([s.start, s.cap, s.n, 0], 20);\n u.set([dec[0], dec[1], 0, 0], 24);\n this.device.queue.writeBuffer(this.ubuf, off, u);\n return off;\n }\n\n private decimateWanted(s: Slot): boolean {\n return s.n > this.cols * 2;\n }\n\n private ensureDec(s: Slot): void {\n if (s.dec && s.decCols >= this.cols) return;\n s.dec?.destroy();\n const cols = Math.max(this.cols, Math.ceil(this.canvas.width / this.dpr));\n s.dec = this.device.createBuffer({\n size: cols * DEC_ELEMS_PER_COL * 8,\n usage: BUF_DEC,\n });\n s.decCols = cols;\n s.bg = null;\n }\n\n private dispatchDec(\n s: Slot,\n map: [number, number, number, number],\n gapFillY: number,\n ): void {\n if (s.decStamp === this.stamp) return;\n s.decStamp = this.stamp;\n this.ensureDec(s);\n if (!s.bg) {\n s.bg = this.device.createBindGroup({\n layout: this.decLayout,\n entries: [\n { binding: 0, resource: { buffer: s.xy } },\n { binding: 1, resource: { buffer: s.prev } },\n { binding: 2, resource: { buffer: s.dec as GPUBuffer } },\n ],\n });\n }\n const u = this.writeU(\"#ffffff\", 1, [0, 0, 0, 0], map, s, [\n this.cols,\n gapFillY,\n ]);\n this.cmps.push({ slot: s, u });\n }\n\n line(slot: number, color: string, width: number, view: View): void {\n const s = this.slots[slot];\n if (!s || s.n < 2) return;\n const map = this.mapFor(s, view);\n if (this.decimateWanted(s)) {\n this.dispatchDec(s, map, 0);\n const u = this.writeU(color, 1, [width, 0, 0, 0], map, s, [0, 0]);\n this.draws.push({\n pipe: this.pipes.lineFlat,\n vbufs: [\n { buf: s.dec as GPUBuffer, off: 0 },\n { buf: s.dec as GPUBuffer, off: 8 },\n ],\n u,\n verts: 6,\n insts: 4 * this.cols - 1,\n });\n return;\n }\n const u = this.writeU(color, 1, [width, 0, 0, 0], map, s, [0, 0]);\n const mk = (o0: number, o1: number, insts: number): DrawOp => ({\n pipe: this.pipes.line,\n vbufs: [\n { buf: s.xy, off: o0 * 8 },\n { buf: s.xy, off: o1 * 8 },\n { buf: s.prev, off: o0 * 4 },\n { buf: s.prev, off: o1 * 4 },\n ],\n u,\n verts: 6,\n insts,\n });\n if (s.start + s.n <= s.cap) {\n // contiguous run\n this.draws.push(mk(s.start, s.start + 1, s.n - 1));\n return;\n }\n // wrapped ring: run A (phys start..cap-1), bridging segment, run B (0..)\n const capA = s.cap - s.start;\n if (capA > 1) this.draws.push(mk(s.start, s.start + 1, capA - 1));\n // bridge: phys cap-1 → phys 0\n this.draws.push(mk(s.cap - 1, 0, 1));\n const rem = s.n - 1 - capA;\n if (rem > 0) this.draws.push(mk(0, 1, rem));\n }\n\n area(slot: number, color: string, baseVal: number, view: View): void {\n const s = this.slots[slot];\n if (!s || s.n < 2) return;\n const map = this.mapFor(s, view);\n const baseEnc = (baseVal - s.enc.yr) * s.enc.yu;\n const baseCss = map[3] - baseEnc * map[2];\n const p = this.plotR;\n if (this.decimateWanted(s)) {\n this.dispatchDec(s, map, baseEnc);\n const u = this.writeU(color, 1, [baseCss, p.y, p.h, 0], map, s, [0, 0]);\n this.draws.push({\n pipe: this.pipes.areaFlat,\n vbufs: [{ buf: s.dec as GPUBuffer, off: this.cols * 4 * 8 }],\n u,\n verts: 8 * this.cols,\n insts: 1,\n });\n return;\n }\n // direct strip: build doubled [x,y] + prev in logical order on CPU\n const m = s.n;\n const xyD = new Float32Array(m * 4);\n const pvD = new Float32Array(m * 2);\n for (let i = 0; i < m; i++) {\n const ph = (s.start + i) % s.cap;\n xyD[4 * i] = s.encXY[2 * ph] as number;\n xyD[4 * i + 1] = s.encXY[2 * ph + 1] as number;\n xyD[4 * i + 2] = xyD[4 * i] as number;\n xyD[4 * i + 3] = xyD[4 * i + 1] as number;\n pvD[2 * i] = s.encPrev[ph] as number;\n pvD[2 * i + 1] = pvD[2 * i] as number;\n }\n // scratch layout: doubled xy (m*16 B) then doubled prev (m*8 B)\n if (!s.scratch || s.scratchN < m) {\n s.scratch?.destroy();\n s.scratch = this.device.createBuffer({\n size: Math.max(4096, m * 24),\n usage: BUF_VERTEX_DST,\n });\n s.scratchN = m;\n }\n const prevOff = m * 16;\n this.device.queue.writeBuffer(s.scratch, 0, xyD);\n this.device.queue.writeBuffer(s.scratch, prevOff, pvD);\n const u = this.writeU(color, 1, [baseCss, p.y, p.h, 0], map, s, [0, 0]);\n this.draws.push({\n pipe: this.pipes.area,\n vbufs: [\n { buf: s.scratch, off: 0 },\n { buf: s.scratch, off: prevOff },\n ],\n u,\n verts: m * 2,\n insts: 1,\n });\n }\n\n points(\n slot: number,\n color: string,\n radius: number,\n alpha: number,\n view: View,\n ): void {\n const s = this.slots[slot];\n if (!s || s.n < 1) return;\n const map = this.mapFor(s, view);\n const u = this.writeU(color, alpha, [radius, 0, 0, 0], map, s, [0, 0]);\n const mk = (o0: number, insts: number): DrawOp => ({\n pipe: this.pipes.points,\n vbufs: [\n { buf: s.xy, off: o0 * 8 },\n { buf: s.prev, off: o0 * 4 },\n ],\n u,\n verts: 6,\n insts,\n });\n if (s.start + s.n <= s.cap) {\n this.draws.push(mk(s.start, s.n));\n return;\n }\n const capA = s.cap - s.start;\n this.draws.push(mk(s.start, capA));\n if (s.n - capA > 0) this.draws.push(mk(0, s.n - capA));\n }\n\n end(): void {\n if (this.unavailable || (!this.draws.length && !this.cmps.length)) return;\n try {\n const encoder = this.device.createCommandEncoder();\n if (this.cmps.length) {\n const cp = encoder.beginComputePass();\n cp.setPipeline(this.pipes.dec);\n for (const c of this.cmps) {\n cp.setBindGroup(0, this.ubiGroup, [c.u]);\n cp.setBindGroup(1, c.slot.bg as GPUBindGroup);\n cp.dispatchWorkgroups(Math.ceil(this.cols / 64));\n }\n cp.end();\n }\n if (this.draws.length) {\n const view = this.ctx.getCurrentTexture().createView();\n const d = this.dpr;\n const plot = this.plotR;\n const pass = encoder.beginRenderPass({\n colorAttachments: [\n {\n view,\n loadOp: \"clear\",\n storeOp: \"store\",\n clearValue: { r: 0, g: 0, b: 0, a: 0 },\n },\n ],\n ...(this.querySet\n ? {\n timestampWrites: {\n querySet: this.querySet,\n beginningOfPassWriteIndex: 0,\n endOfPassWriteIndex: 1,\n },\n }\n : {}),\n });\n pass.setScissorRect(\n Math.max(0, Math.floor(plot.x * d)),\n Math.max(0, Math.floor(plot.y * d)),\n Math.max(1, Math.floor(plot.w * d)),\n Math.max(1, Math.floor(plot.h * d)),\n );\n for (const op of this.draws) {\n pass.setPipeline(op.pipe);\n pass.setBindGroup(0, this.ubiGroup, [op.u]);\n for (let i = 0; i < op.vbufs.length; i++) {\n const v = op.vbufs[i];\n if (v) pass.setVertexBuffer(i, v.buf, v.off);\n }\n pass.draw(op.verts, op.insts);\n }\n pass.end();\n }\n const qs = this.querySet;\n const qb = this.queryBuf;\n const rb = this.readBuf;\n if (qs && qb && rb && !this.reading) {\n encoder.resolveQuerySet(qs, 0, 2, qb, 0);\n encoder.copyBufferToBuffer(qb, 0, rb, 0, 16);\n this.reading = true;\n this.device.queue.submit([encoder.finish()]);\n void rb.mapAsync(MAP_READ).then(\n () => {\n const v = new BigUint64Array(rb.getMappedRange());\n const t0 = v[0];\n const t1 = v[1];\n if (t0 !== undefined && t1 !== undefined) {\n this.gpuMs = Number(t1 - t0) / 1e6;\n }\n rb.unmap();\n this.reading = false;\n },\n () => {\n this.reading = false;\n },\n );\n } else {\n this.device.queue.submit([encoder.finish()]);\n }\n } catch {\n // transient device loss mid-frame — onLost() drives recovery\n }\n }\n\n destroy(): void {\n this.destroyed = true;\n for (const s of this.slots) {\n s.xy.destroy();\n s.prev.destroy();\n s.scratch?.destroy();\n s.dec?.destroy();\n }\n this.slots = [];\n this.ubuf?.destroy();\n this.queryBuf?.destroy();\n this.readBuf?.destroy();\n this.querySet?.destroy();\n try {\n this.ctx.unconfigure();\n } catch {\n // context may already be dead\n }\n this.canvas.remove();\n }\n}\n\nconst BLEND: GPUBlendState = {\n color: {\n srcFactor: \"src-alpha\",\n dstFactor: \"one-minus-src-alpha\",\n operation: \"add\",\n },\n alpha: {\n srcFactor: \"one\",\n dstFactor: \"one-minus-src-alpha\",\n operation: \"add\",\n },\n};\n"],"mappings":";;AACA,SAAgB,WAAW,GAA6C;CACtE,IAAI,EAAE,WAAW,GAAG,GAAG;EACrB,MAAM,IAAI,EAAE,MAAM,CAAC;EACnB,IAAI,EAAE,WAAW,GACf,OAAO;GACL,SAAS,EAAE,IAAc,EAAE,IAAI;GAC/B,SAAS,EAAE,IAAc,EAAE,IAAI;GAC/B,SAAS,EAAE,IAAc,EAAE,IAAI;GAC/B;EACF;EAEF,IAAI,EAAE,WAAW,GACf,OAAO;GACL,SAAS,EAAE,MAAM,GAAG,CAAC,GAAG,EAAE,IAAI;GAC9B,SAAS,EAAE,MAAM,GAAG,CAAC,GAAG,EAAE,IAAI;GAC9B,SAAS,EAAE,MAAM,GAAG,CAAC,GAAG,EAAE,IAAI;GAC9B;EACF;CAEJ;CACA,MAAM,IAAI,mBAAmB,KAAK,CAAC;CACnC,IAAI,GAAG;EACL,MAAM,QAAS,EAAE,EAAE,CAAY,MAAM,GAAG,CAAC,CAAC,KAAK,MAAM,OAAO,WAAW,CAAC,CAAC;EACzE,OAAO;IACJ,MAAM,MAAM,KAAK;IACjB,MAAM,MAAM,KAAK;IACjB,MAAM,MAAM,KAAK;GAClB,MAAM,MAAM;EACd;CACF;CACA,OAAO;EAAC;EAAG;EAAG;EAAG;CAAC;AACpB;;;;AClBA,MAAM,wBAAQ,IAAI,IAAuC;AAEzD,SAAgB,aACd,OAA0B,CAAC,GACA;CAC3B,MAAM,MAAM,KAAK,UAAU,IAAI;CAC/B,IAAI,IAAI,MAAM,IAAI,GAAG;CACrB,IAAI,CAAC,GAAG;EACN,KAAK,YAAuC;GAC1C,IAAI;IAEF,MAAM,OADM,OAAO,cAAc,cAAc,OAAO,UAAA,EACf;IACvC,IAAI,CAAC,KAAK,OAAO;IACjB,MAAM,MAAgC,CAAC;IACvC,IAAI,KAAK,mBAAmB,KAAK,oBAAoB,WACnD,IAAI,kBAAkB,KAAK;IAE7B,IAAI,KAAK,QACP,IAA4C,eAC1C;IAKJ,MAAM,UAAU,MAAM,IAAI,eAAe,GAAG;IAC5C,IAAI,CAAC,SAAS,OAAO;IACrB,IACE,CAAC,KAAK,iBACL,QAA4C,mBAE7C,OAAO;IAET,MAAM,mBAAqC,CAAC;IAC5C,IAAI,KAAK,UAAU,QAAQ,SAAS,IAAI,iBAAiB,GACvD,iBAAiB,KAAK,iBAAiB;IAEzC,MAAM,SAAS,MAAM,QAAQ,cAAc,EAAE,iBAAiB,CAAC;IAG/D,OAAO,KAAK,WAAW,MAAM,OAAO,GAAG,CAAC;IACxC,OAAO;GACT,QAAQ;IACN,OAAO;GACT;EACF,EAAA,CAAG;EACH,EAAE,YAAY,MAAM,OAAO,GAAG,CAAC;EAC/B,MAAM,IAAI,KAAK,CAAC;CAClB;CACA,OAAO;AACT;;;;;;;;;;;;;;;;AC7CA,MAAM,SAAoB;;;;;;;;;;;;;;;;;;;;;;;;;AA0B1B,MAAM,YAAuB;EAC3B,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAgDT,MAAM,iBAA4B;EAChC,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA4CT,MAAM,YAAuB;EAC3B,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;AA0BT,MAAM,iBAA4B;EAChC,OAAO;;;;;;;;;;;;;;;;;;;;;AAsBT,MAAM,cAAyB;EAC7B,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAkCT,MAAM,gBAA2B;EAC/B,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAmFT,MAAM,iBAAiB;AACvB,MAAM,kBAAkB;AACxB,MAAM,kBAAkB;AACxB,MAAM,kBAAkB;AACxB,MAAM,aAAa;AACnB,MAAM,UAAU;AAChB,MAAM,WAAW;AACjB,MAAM,YAAY;AAGlB,MAAM,SAAS;AACf,MAAM,YAAY;AAClB,MAAM,oBAAoB;AAkC1B,IAAa,YAAb,MAAa,UAAU;CA4CrB,IAAI,cAAuB;EACzB,OAAO,KAAK,QAAQ,KAAK;CAC3B;CAEA,YACE,QACA,QACA,MACA;EAlCY,KAAA,MAAA;EACU,KAAA,QAAA,CAAC;EACL,KAAA,YAAA;EACC,KAAA,aAAA;EACK,KAAA,QAAA,CAAC;EACiB,KAAA,OAAA,CAAC;EAC9B,KAAA,OAAA;EACC,KAAA,QAAA;EACM,KAAA,QAAA;GAAE,GAAG;GAAG,GAAG;GAAG,GAAG;GAAG,GAAG;EAAE;EAChC,KAAA,OAAA;EACH,KAAA,IAAA;EACG,KAAA,OAAA;EACO,KAAA,8BAAA,IAAI,aAAa,CAAC;EAEjB,KAAA,QAAA;EACgB,KAAA,WAAA;EACF,KAAA,WAAA;EACD,KAAA,UAAA;EAClB,KAAA,UAAA;EACD,KAAA,SAAA;EACG,KAAA,YAAA;EAEb,KAAA,OAAA;EAEM,KAAA,aAAA;EAWX,KAAK,OAAO;EACZ,KAAK,SAAS,CAAC,CAAC,KAAK;EACrB,KAAK,SAAS;EACd,OAAO,MAAM,UACX;EACF,MAAM,MAAM,OAAO,WAAW,QAAQ;EACtC,IAAI,CAAC,KAAK,MAAM,IAAI,MAAM,0CAA0C;EACpE,KAAK,MAAM;EACX,KAAK,SAAS;EACd,KAAK,SAAS,UAAU,IAAI,yBAAyB;EACrD,KAAK,MAAM,MAAM;CACnB;CAEA,aAAa,OAAO,OAA0B,CAAC,GAA8B;EAC3E,MAAM,SAAS,MAAM,aAAa,IAAI;EACtC,IAAI,CAAC,QAAQ,OAAO;EACpB,MAAM,SAAS,SAAS,cAAc,QAAQ;EAC9C,IAAI;GACF,OAAO,IAAI,UAAU,QAAQ,QAAQ,IAAI;EAC3C,QAAQ;GACN,OAAO;EACT;CACF;;CAGA,MAAc,QAAyB;EACrC,KAAK,SAAS;EACd,KAAK,SAAS,OAAO,sBAAsB,EACzC,SAAS,CACP;GACE,SAAS;GACT,YAAY;GACZ,QAAQ;IAAE,MAAM;IAAW,kBAAkB;GAAK;EACpD,CACF,EACF,CAAC;EACD,KAAK,YAAY,OAAO,sBAAsB,EAC5C,SAAS;GACP;IAAE,SAAS;IAAG,YAAY;IAAG,QAAQ,EAAE,MAAM,oBAAoB;GAAE;GACnE;IAAE,SAAS;IAAG,YAAY;IAAG,QAAQ,EAAE,MAAM,oBAAoB;GAAE;GACnE;IAAE,SAAS;IAAG,YAAY;IAAG,QAAQ,EAAE,MAAM,UAAU;GAAE;EAC3D,EACF,CAAC;EACD,KAAK,OAAO,OAAO,aAAa;GAC9B,MAAM;GACN,OAAO;EACT,CAAC;EACD,KAAK,WAAW,OAAO,gBAAgB;GACrC,QAAQ,KAAK;GACb,SAAS,CACP;IAAE,SAAS;IAAG,UAAU;KAAE,QAAQ,KAAK;KAAM,MAAM;IAAU;GAAE,CACjE;EACF,CAAC;EACD,MAAM,KAAK,OAAO,qBAAqB,EACrC,kBAAkB,CAAC,KAAK,MAAM,EAChC,CAAC;EACD,MAAM,QAAQ,OAAO,qBAAqB,EACxC,kBAAkB,CAAC,KAAK,QAAQ,KAAK,SAAS,EAChD,CAAC;EACD,MAAM,MACJ,MACA,UACA,YAEA,OAAO,qBAAqB;GAC1B,QAAQ;GACR,QAAQ;IACN,QAAQ,OAAO,mBAAmB,EAAE,KAAK,CAAC;IAC1C,YAAY;IACZ;GACF;GACA,UAAU;IACR,QAAQ,OAAO,mBAAmB,EAAE,KAAK,CAAC;IAC1C,YAAY;IACZ,SAAS,CAAC;KAAE,QAAQ,KAAK;KAAQ,OAAO;IAAM,CAAC;GACjD;GACA,WAAW,EAAE,SAAS;EACxB,CAAC;EACH,MAAM,MAA6B;GACjC,aAAa;GACb,UAAU;GACV,YAAY,CAAC;IAAE,gBAAgB;IAAG,QAAQ;IAAG,QAAQ;GAAY,CAAC;EACpE;EACA,MAAM,OAA8B;GAClC,aAAa;GACb,UAAU;GACV,YAAY,CAAC;IAAE,gBAAgB;IAAG,QAAQ;IAAG,QAAQ;GAAY,CAAC;EACpE;EACA,MAAM,QAA+B;GACnC,aAAa;GACb,UAAU;GACV,YAAY,CAAC;IAAE,gBAAgB;IAAG,QAAQ;IAAG,QAAQ;GAAU,CAAC;EAClE;EACA,MAAM,SAAgC;GACpC,aAAa;GACb,UAAU;GACV,YAAY,CAAC;IAAE,gBAAgB;IAAG,QAAQ;IAAG,QAAQ;GAAU,CAAC;EAClE;EACA,MAAM,UAAiC;GACrC,aAAa;GACb,UAAU;GACV,YAAY,CAAC;IAAE,gBAAgB;IAAG,QAAQ;IAAG,QAAQ;GAAU,CAAC;EAClE;EACA,MAAM,MAA6B;GACjC,aAAa;GACb,UAAU;GACV,YAAY,CAAC;IAAE,gBAAgB;IAAG,QAAQ;IAAG,QAAQ;GAAY,CAAC;EACpE;EACA,MAAM,QAA+B;GACnC,aAAa;GACb,UAAU;GACV,YAAY,CAAC;IAAE,gBAAgB;IAAG,QAAQ;IAAG,QAAQ;GAAU,CAAC;EAClE;EACA,KAAK,QAAQ;GACX,MAAM,GAAG,WAAW,iBAAiB;IAAC;IAAK;IAAM;IAAO;GAAM,CAAC;GAC/D,UAAU,GAAG,gBAAgB,iBAAiB,CAAC,KAAK,IAAI,CAAC;GACzD,MAAM,GAAG,WAAW,kBAAkB,CAAC,KAAK,KAAK,CAAC;GAClD,UAAU,GAAG,gBAAgB,kBAAkB,CAAC,GAAG,CAAC;GACpD,QAAQ,GAAG,aAAa,iBAAiB,CAAC,KAAK,OAAO,CAAC;GACvD,KAAK,OAAO,sBAAsB;IAChC,QAAQ;IACR,SAAS;KACP,QAAQ,OAAO,mBAAmB,EAAE,MAAM,cAAc,CAAC;KACzD,YAAY;IACd;GACF,CAAC;EACH;EACA,IAAI,KAAK,UAAU,OAAO,SAAS,IAAI,iBAAiB,GAAG;GACzD,KAAK,WAAW,OAAO,eAAe;IAAE,MAAM;IAAa,OAAO;GAAE,CAAC;GACrE,KAAK,WAAW,OAAO,aAAa;IAClC,MAAM;IACN,OAAO;GACT,CAAC;GACD,KAAK,UAAU,OAAO,aAAa;IACjC,MAAM;IACN,OAAO;GACT,CAAC;EACH;EACA,OAAO,KAAK,MAAM,SAAS,KAAK,OAAO,IAAI,CAAC;CAC9C;CAEA,OAAe,MAA+B;EAC5C,IAAI,KAAK,WAAW;EACpB,IAAI,KAAK,WAAW,aAAa;GAC/B,KAAK,OAAO;GACZ;EACF;EACA,KAAK,aAAa;EAClB,aAAkB,KAAK,IAAI,CAAC,CAAC,MAAM,OAAO;GACxC,IAAI,CAAC,MAAM,KAAK,WAAW;IACzB,KAAK,KAAK;IACV;GACF;GACA,IAAI;IACF,KAAK,kBAAkB;IACvB,KAAK,MAAM,EAAE;IACb,IAAI;KACF,KAAK,UAAU;IACjB,QAAQ;KAGN,MAAM,KAAK,SAAS,cAAc,QAAQ;KAC1C,GAAG,QAAQ,KAAK,OAAO;KACvB,GAAG,SAAS,KAAK,OAAO;KACxB,KAAK,OAAO,YAAY,EAAE;KAC1B,KAAK,SAAS;KACd,MAAM,MAAM,GAAG,WAAW,QAAQ;KAClC,IAAI,CAAC,KAAK,MAAM,IAAI,MAAM,qBAAqB;KAC/C,KAAK,MAAM;KACX,KAAK,UAAU;IACjB;IACA,KAAK,aAAa;IAClB,KAAK,aAAa;GACpB,QAAQ;IACN,KAAK,KAAK;GACZ;EACF,CAAC;CACH;CAEA,OAAqB;EACnB,KAAK,OAAO;EACZ,KAAK,aAAa;EAClB,KAAK,QAAQ;CACf;CAEA,oBAAkC;EAChC,KAAK,MAAM,KAAK,KAAK,OAAO;GAC1B,EAAE,GAAG,QAAQ;GACb,EAAE,KAAK,QAAQ;GACf,EAAE,SAAS,QAAQ;GACnB,EAAE,KAAK,QAAQ;EACjB;EACA,KAAK,QAAQ,CAAC;EACd,KAAK,YAAY;EACjB,KAAK,KAAK,QAAQ;EAClB,KAAK,UAAU,QAAQ;EACvB,KAAK,SAAS,QAAQ;EACtB,KAAK,UAAU,QAAQ;EACvB,KAAK,WAAW;EAChB,KAAK,WAAW;EAChB,KAAK,UAAU;CACjB;CAEA,YAA0B;EACxB,KAAK,IAAI,UAAU;GACjB,QAAQ,KAAK;GACb,QAAQ,KAAK;GACb,WAAW;EACb,CAAC;CACH;CAEA,QAAQ,MAAc,MAAc,KAAmB;EACrD,KAAK,MAAM;EACX,KAAK,OAAO,QAAQ,KAAK,IAAI,GAAG,KAAK,MAAM,OAAO,GAAG,CAAC;EACtD,KAAK,OAAO,SAAS,KAAK,IAAI,GAAG,KAAK,MAAM,OAAO,GAAG,CAAC;EACvD,IAAI,CAAC,KAAK,aAAa,KAAK,UAAU;CACxC;CAQA,OAAe,GAAW,IAAkB,GAA2B;EACrE,MAAM,IAAI,KAAK,IAAI,GAAG,QAAQ,EAAE,EAAE,MAAM;EACxC,MAAM,KAAK,IAAI,IAAK,GAAG,KAAgB;EACvC,MAAM,KACJ,MACE,IAAI,IAAK,GAAG,IAAI,KAAgB,KAAK,MACrC,KAAK,IAAI,GAAG,KAAK,IAAI,EAAE,GAAG,CAAC;EAC/B,IAAI,KAAK;EACT,IAAI,KAAK;EACT,KAAK,IAAI,IAAI,GAAG,IAAI,GAAG,KAAK;GAC1B,MAAM,IAAI,EAAE,EAAE;GACd,IAAI,IAAI,IAAI,KAAK;GACjB,IAAI,IAAI,IAAI,KAAK;EACnB;EACA,MAAM,KAAK,OAAO,WAAW,IAAI;EACjC,MAAM,KAAK,KAAK,KAAK,MAAM,KAAK,IAAI,GAAG,KAAK,IAAI,EAAE,CAAC;EACnD,IAAI,OAAO,KAAK,MAAM;EACtB,MAAM,MAAM,KAAK,IAAI,MAAM,KAAK,KAAK,IAAI,IAAI,CAAC;EAC9C,IAAI,CAAC,QAAQ,KAAK,MAAM,GAAG;GACzB,MAAM,GAAG,QAAQ;GACjB,MAAM,KAAK,QAAQ;GACnB,MAAM,KAAK,QAAQ;GACnB,OAAO;IACL;IACA;IACA,OAAO;IACP,KAAK;KAAE;KAAI;KAAI;KAAI;IAAG;IACtB,OAAO,IAAI,aAAa,MAAM,CAAC;IAC/B,SAAS,IAAI,aAAa,GAAG;IAC7B,IAAI,KAAK,OAAO,aAAa;KAC3B,MAAM,MAAM;KACZ,OAAO;IACT,CAAC;IACD,MAAM,KAAK,OAAO,aAAa;KAC7B,MAAM,MAAM;KACZ,OAAO;IACT,CAAC;IACD,SAAS;IACT,UAAU;IACV,KAAK;IACL,SAAS;IACT,IAAI;IACJ,UAAU;GACZ;GACA,KAAK,MAAM,KAAK;EAClB,OAAO;GACL,KAAK,IAAI;GACT,KAAK,QAAQ;GACb,KAAK,MAAM;IAAE;IAAI;IAAI;IAAI;GAAG;GAC5B,KAAK,KAAK;GACV,KAAK,WAAW;EAClB;EACA,MAAM,EAAE,OAAO,YAAY;EAC3B,MAAM,OAAO,EAAE;EACf,KAAK,IAAI,IAAI,GAAG,IAAI,GAAG,KAAK;GAC1B,MAAM,IAAI,MAAO,GAAG,KAAgB,MAAM;GAC1C,MAAM,IAAI,IAAI,MAAO,EAAE,EAAE,KAAgB,MAAM;GAC/C,QAAQ,KAAK,QAAS,KAAK,KAAgB,MAAM,KAAK;EACxD;EACA,KAAK,OAAO,MAAM,YAAY,KAAK,IAAI,GAAG,OAAO,GAAG,IAAI,CAAC;EACzD,KAAK,OAAO,MAAM,YAAY,KAAK,MAAM,GAAG,SAAS,GAAG,CAAC;CAC3D;;;;;CAMA,SAAS,GAAiB,KAAmB;EAC3C,IACE,KAAK,eACJ,QAAQ,KAAK,cAAc,KAAK,cAAc,EAAE,OAAO,QAExD;EAEF,KAAK,IAAI,IAAI,GAAG,IAAI,EAAE,OAAO,QAAQ,KAAK;GACxC,MAAM,IAAI,EAAE,OAAO;GACnB,IAAI,GAAG,KAAK,OAAO,GAAG,EAAE,SAAS,CAAC;EACpC;EACA,KAAK,YAAY,EAAE,OAAO;EAC1B,KAAK,aAAa;CACpB;;;;;;CAOA,SACE,GACA,IACA,QACA,SACS;EACT,IAAI,KAAK,aAAa,OAAO;EAC7B,MAAM,IAAI,KAAK,OAAO;EACtB,KAAK,IAAI,IAAI,GAAG,IAAI,KAAK,WAAW,KAAK;GACvC,MAAM,IAAI,KAAK,MAAM;GACrB,IAAI,CAAC,GAAG,OAAO;GACf,MAAM,KAAK,EAAE,IAAI,UAAU;GAC3B,IAAI,KAAK,EAAE,KAAK,KAAK,KAAK,GAAG,EAAE;GAC/B,EAAE,SAAS,EAAE,QAAQ,WAAW,EAAE;GAClC,EAAE,IAAI;GACN,MAAM,QAAQ,EAAE,QAAQ,EAAE,IAAI,KAAK,EAAE;GACrC,MAAM,EAAE,IAAI,IAAI,IAAI,OAAO,EAAE;GAC7B,MAAM,MAAM,IAAI,MAAM;GACtB,MAAM,OAAO,GAAG,MAAM,KAAK,MAAM;GACjC,MAAM,OAAO,OAAO,MAAM,KAAK,MAAM;GACrC,MAAM,IAAI,KAAK;GACf,EAAE,KAAK;GACP,EAAE,KAAK;GACP,EAAE,YAAY,EAAE,IAAI,OAAO,GAAG,GAAG,GAAG,CAAC;GACrC,EAAE,MAAM,IAAI,QAAQ;GACpB,EAAE,MAAM,IAAI,OAAO,KAAK;GACxB,EAAE,KAAK;GACP,EAAE,YAAY,EAAE,MAAM,OAAO,GAAG,GAAG,GAAG,CAAC;GACvC,EAAE,QAAQ,QAAQ;GAGlB,IAAI,EAAE,IAAI,GAAG;IACX,MAAM,QAAQ,OAAO,EAAE,MAAM,KAAK,EAAE;IACpC,EAAE,YAAY,EAAE,MAAM,OAAO,GAAG,GAAG,GAAG,CAAC;IACvC,EAAE,QAAQ,QAAQ;GACpB;EACF;EACA,OAAO;CACT;;CAGA,KAAa,GAAS,MAAoB;EACxC,MAAM,MAAM,KAAK,IAAI,EAAE,MAAM,GAAG,OAAO,IAAI;EAC3C,MAAM,IAAI,EAAE,MAAM,EAAE;EACpB,MAAM,MAAM,KAAK,OAAO,qBAAqB;EAC7C,MAAM,KAAK,KAAK,OAAO,aAAa;GAAE,MAAM,MAAM;GAAG,OAAO;EAAW,CAAC;EACxE,MAAM,OAAO,KAAK,OAAO,aAAa;GAAE,MAAM,MAAM;GAAG,OAAO;EAAW,CAAC;EAC1E,IAAI,mBAAmB,EAAE,IAAI,EAAE,QAAQ,GAAG,IAAI,GAAG,IAAI,CAAC;EACtD,IAAI,EAAE,QAAQ,GAAG,IAAI,mBAAmB,EAAE,IAAI,GAAG,IAAI,IAAI,GAAG,EAAE,QAAQ,CAAC;EACvE,IAAI,mBAAmB,EAAE,MAAM,EAAE,QAAQ,GAAG,MAAM,GAAG,IAAI,CAAC;EAC1D,IAAI,EAAE,QAAQ,GACZ,IAAI,mBAAmB,EAAE,MAAM,GAAG,MAAM,IAAI,GAAG,EAAE,QAAQ,CAAC;EAC5D,KAAK,OAAO,MAAM,OAAO,CAAC,IAAI,OAAO,CAAC,CAAC;EACvC,EAAE,GAAG,QAAQ;EACb,EAAE,KAAK,QAAQ;EACf,EAAE,KAAK;EACP,EAAE,OAAO;EACT,MAAM,QAAQ,IAAI,aAAa,MAAM,CAAC;EACtC,MAAM,UAAU,IAAI,aAAa,GAAG;EACpC,MAAM,IAAI,EAAE,MAAM,SAAS,EAAE,QAAQ,GAAG,EAAE,MAAM,CAAC,GAAG,CAAC;EACrD,MAAM,IAAI,EAAE,MAAM,SAAS,GAAG,EAAE,QAAQ,CAAC,GAAG,IAAI,CAAC;EACjD,QAAQ,IAAI,EAAE,QAAQ,SAAS,EAAE,OAAO,EAAE,GAAG,GAAG,CAAC;EACjD,QAAQ,IAAI,EAAE,QAAQ,SAAS,GAAG,EAAE,KAAK,GAAG,CAAC;EAC7C,EAAE,QAAQ;EACV,EAAE,UAAU;EACZ,EAAE,MAAM;EACR,EAAE,QAAQ;EACV,EAAE,KAAK;CACT;CAIA,MAAM,MAAY,IAAI,GAAG,OAAO,GAAS;EACvC,KAAK,QAAQ;EACb,KAAK,IAAI;EACT,KAAK,OAAO;EACZ,KAAK,OAAO,KAAK,IAAI,GAAG,KAAK,KAAK,KAAK,IAAI,KAAK,CAAC,CAAC;EAClD,KAAK;EACL,KAAK,MAAM,SAAS;EACpB,KAAK,KAAK,SAAS;EACnB,KAAK,OAAO;CACd;;CAGA,OAAe,GAAS,MAA8C;EACpE,MAAM,EAAE,IAAI,IAAI,IAAI,OAAO,EAAE;EAC7B,MAAM,IAAI,KAAK;EACf,MAAM,OAAO,KAAK,EAAE,KAAK,MAAM;EAC/B,MAAM,OAAO,KAAK,EAAE,KAAK,MAAM;EAC/B,MAAM,KAAK,EAAE,KAAK,MAAM,OAAO;EAC/B,MAAM,KAAK,EAAE,IAAI,MAAM;EACvB,MAAM,OAAO,KAAK,EAAE,KAAK,MAAM;EAC/B,MAAM,OAAO,KAAK,EAAE,KAAK,MAAM;EAC/B,MAAM,KAAK,EAAE,KAAK,MAAM,OAAO;EAE/B,OAAO;GAAC;GAAI;GAAI;GADL,EAAE,IAAI,MAAM;EACD;CACxB;CAEA,OACE,OACA,OACA,GACA,KACA,GACA,KACQ;EACR,MAAM,MAAM,KAAK;EACjB,KAAK,QAAQ;EACb,MAAM,oBAAI,IAAI,aAAa,EAAQ;EACnC,EAAE,IAAI;GAAC,KAAK,OAAO;GAAO,KAAK,OAAO;GAAQ,KAAK;GAAK;EAAC,CAAC;EAC1D,MAAM,CAAC,GAAG,GAAG,GAAG,KAAK,WAAW,KAAK;EACrC,EAAE,IAAI;GAAC;GAAG;GAAG;GAAG,IAAI;EAAK,GAAG,CAAC;EAC7B,EAAE,IAAI,GAAG,CAAC;EACV,EAAE,IAAI,KAAK,EAAE;EACb,MAAM,MAAM,EAAE,IAAI,IAAI,KAAK,QAAQ,EAAE,IAAI,KAAK;EAC9C,EAAE,IAAI;GAAC,KAAK;GAAG,KAAK;GAAM;GAAK;EAAC,GAAG,EAAE;EACrC,EAAE,IAAI;GAAC,EAAE;GAAO,EAAE;GAAK,EAAE;GAAG;EAAC,GAAG,EAAE;EAClC,EAAE,IAAI;GAAC,IAAI;GAAI,IAAI;GAAI;GAAG;EAAC,GAAG,EAAE;EAChC,KAAK,OAAO,MAAM,YAAY,KAAK,MAAM,KAAK,CAAC;EAC/C,OAAO;CACT;CAEA,eAAuB,GAAkB;EACvC,OAAO,EAAE,IAAI,KAAK,OAAO;CAC3B;CAEA,UAAkB,GAAe;EAC/B,IAAI,EAAE,OAAO,EAAE,WAAW,KAAK,MAAM;EACrC,EAAE,KAAK,QAAQ;EACf,MAAM,OAAO,KAAK,IAAI,KAAK,MAAM,KAAK,KAAK,KAAK,OAAO,QAAQ,KAAK,GAAG,CAAC;EACxE,EAAE,MAAM,KAAK,OAAO,aAAa;GAC/B,MAAM,OAAO,oBAAoB;GACjC,OAAO;EACT,CAAC;EACD,EAAE,UAAU;EACZ,EAAE,KAAK;CACT;CAEA,YACE,GACA,KACA,UACM;EACN,IAAI,EAAE,aAAa,KAAK,OAAO;EAC/B,EAAE,WAAW,KAAK;EAClB,KAAK,UAAU,CAAC;EAChB,IAAI,CAAC,EAAE,IACL,EAAE,KAAK,KAAK,OAAO,gBAAgB;GACjC,QAAQ,KAAK;GACb,SAAS;IACP;KAAE,SAAS;KAAG,UAAU,EAAE,QAAQ,EAAE,GAAG;IAAE;IACzC;KAAE,SAAS;KAAG,UAAU,EAAE,QAAQ,EAAE,KAAK;IAAE;IAC3C;KAAE,SAAS;KAAG,UAAU,EAAE,QAAQ,EAAE,IAAiB;IAAE;GACzD;EACF,CAAC;EAEH,MAAM,IAAI,KAAK,OAAO,WAAW,GAAG;GAAC;GAAG;GAAG;GAAG;EAAC,GAAG,KAAK,GAAG,CACxD,KAAK,MACL,QACF,CAAC;EACD,KAAK,KAAK,KAAK;GAAE,MAAM;GAAG;EAAE,CAAC;CAC/B;CAEA,KAAK,MAAc,OAAe,OAAe,MAAkB;EACjE,MAAM,IAAI,KAAK,MAAM;EACrB,IAAI,CAAC,KAAK,EAAE,IAAI,GAAG;EACnB,MAAM,MAAM,KAAK,OAAO,GAAG,IAAI;EAC/B,IAAI,KAAK,eAAe,CAAC,GAAG;GAC1B,KAAK,YAAY,GAAG,KAAK,CAAC;GAC1B,MAAM,IAAI,KAAK,OAAO,OAAO,GAAG;IAAC;IAAO;IAAG;IAAG;GAAC,GAAG,KAAK,GAAG,CAAC,GAAG,CAAC,CAAC;GAChE,KAAK,MAAM,KAAK;IACd,MAAM,KAAK,MAAM;IACjB,OAAO,CACL;KAAE,KAAK,EAAE;KAAkB,KAAK;IAAE,GAClC;KAAE,KAAK,EAAE;KAAkB,KAAK;IAAE,CACpC;IACA;IACA,OAAO;IACP,OAAO,IAAI,KAAK,OAAO;GACzB,CAAC;GACD;EACF;EACA,MAAM,IAAI,KAAK,OAAO,OAAO,GAAG;GAAC;GAAO;GAAG;GAAG;EAAC,GAAG,KAAK,GAAG,CAAC,GAAG,CAAC,CAAC;EAChE,MAAM,MAAM,IAAY,IAAY,WAA2B;GAC7D,MAAM,KAAK,MAAM;GACjB,OAAO;IACL;KAAE,KAAK,EAAE;KAAI,KAAK,KAAK;IAAE;IACzB;KAAE,KAAK,EAAE;KAAI,KAAK,KAAK;IAAE;IACzB;KAAE,KAAK,EAAE;KAAM,KAAK,KAAK;IAAE;IAC3B;KAAE,KAAK,EAAE;KAAM,KAAK,KAAK;IAAE;GAC7B;GACA;GACA,OAAO;GACP;EACF;EACA,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,KAAK;GAE1B,KAAK,MAAM,KAAK,GAAG,EAAE,OAAO,EAAE,QAAQ,GAAG,EAAE,IAAI,CAAC,CAAC;GACjD;EACF;EAEA,MAAM,OAAO,EAAE,MAAM,EAAE;EACvB,IAAI,OAAO,GAAG,KAAK,MAAM,KAAK,GAAG,EAAE,OAAO,EAAE,QAAQ,GAAG,OAAO,CAAC,CAAC;EAEhE,KAAK,MAAM,KAAK,GAAG,EAAE,MAAM,GAAG,GAAG,CAAC,CAAC;EACnC,MAAM,MAAM,EAAE,IAAI,IAAI;EACtB,IAAI,MAAM,GAAG,KAAK,MAAM,KAAK,GAAG,GAAG,GAAG,GAAG,CAAC;CAC5C;CAEA,KAAK,MAAc,OAAe,SAAiB,MAAkB;EACnE,MAAM,IAAI,KAAK,MAAM;EACrB,IAAI,CAAC,KAAK,EAAE,IAAI,GAAG;EACnB,MAAM,MAAM,KAAK,OAAO,GAAG,IAAI;EAC/B,MAAM,WAAW,UAAU,EAAE,IAAI,MAAM,EAAE,IAAI;EAC7C,MAAM,UAAU,IAAI,KAAK,UAAU,IAAI;EACvC,MAAM,IAAI,KAAK;EACf,IAAI,KAAK,eAAe,CAAC,GAAG;GAC1B,KAAK,YAAY,GAAG,KAAK,OAAO;GAChC,MAAM,IAAI,KAAK,OAAO,OAAO,GAAG;IAAC;IAAS,EAAE;IAAG,EAAE;IAAG;GAAC,GAAG,KAAK,GAAG,CAAC,GAAG,CAAC,CAAC;GACtE,KAAK,MAAM,KAAK;IACd,MAAM,KAAK,MAAM;IACjB,OAAO,CAAC;KAAE,KAAK,EAAE;KAAkB,KAAK,KAAK,OAAO,IAAI;IAAE,CAAC;IAC3D;IACA,OAAO,IAAI,KAAK;IAChB,OAAO;GACT,CAAC;GACD;EACF;EAEA,MAAM,IAAI,EAAE;EACZ,MAAM,MAAM,IAAI,aAAa,IAAI,CAAC;EAClC,MAAM,MAAM,IAAI,aAAa,IAAI,CAAC;EAClC,KAAK,IAAI,IAAI,GAAG,IAAI,GAAG,KAAK;GAC1B,MAAM,MAAM,EAAE,QAAQ,KAAK,EAAE;GAC7B,IAAI,IAAI,KAAK,EAAE,MAAM,IAAI;GACzB,IAAI,IAAI,IAAI,KAAK,EAAE,MAAM,IAAI,KAAK;GAClC,IAAI,IAAI,IAAI,KAAK,IAAI,IAAI;GACzB,IAAI,IAAI,IAAI,KAAK,IAAI,IAAI,IAAI;GAC7B,IAAI,IAAI,KAAK,EAAE,QAAQ;GACvB,IAAI,IAAI,IAAI,KAAK,IAAI,IAAI;EAC3B;EAEA,IAAI,CAAC,EAAE,WAAW,EAAE,WAAW,GAAG;GAChC,EAAE,SAAS,QAAQ;GACnB,EAAE,UAAU,KAAK,OAAO,aAAa;IACnC,MAAM,KAAK,IAAI,MAAM,IAAI,EAAE;IAC3B,OAAO;GACT,CAAC;GACD,EAAE,WAAW;EACf;EACA,MAAM,UAAU,IAAI;EACpB,KAAK,OAAO,MAAM,YAAY,EAAE,SAAS,GAAG,GAAG;EAC/C,KAAK,OAAO,MAAM,YAAY,EAAE,SAAS,SAAS,GAAG;EACrD,MAAM,IAAI,KAAK,OAAO,OAAO,GAAG;GAAC;GAAS,EAAE;GAAG,EAAE;GAAG;EAAC,GAAG,KAAK,GAAG,CAAC,GAAG,CAAC,CAAC;EACtE,KAAK,MAAM,KAAK;GACd,MAAM,KAAK,MAAM;GACjB,OAAO,CACL;IAAE,KAAK,EAAE;IAAS,KAAK;GAAE,GACzB;IAAE,KAAK,EAAE;IAAS,KAAK;GAAQ,CACjC;GACA;GACA,OAAO,IAAI;GACX,OAAO;EACT,CAAC;CACH;CAEA,OACE,MACA,OACA,QACA,OACA,MACM;EACN,MAAM,IAAI,KAAK,MAAM;EACrB,IAAI,CAAC,KAAK,EAAE,IAAI,GAAG;EACnB,MAAM,MAAM,KAAK,OAAO,GAAG,IAAI;EAC/B,MAAM,IAAI,KAAK,OAAO,OAAO,OAAO;GAAC;GAAQ;GAAG;GAAG;EAAC,GAAG,KAAK,GAAG,CAAC,GAAG,CAAC,CAAC;EACrE,MAAM,MAAM,IAAY,WAA2B;GACjD,MAAM,KAAK,MAAM;GACjB,OAAO,CACL;IAAE,KAAK,EAAE;IAAI,KAAK,KAAK;GAAE,GACzB;IAAE,KAAK,EAAE;IAAM,KAAK,KAAK;GAAE,CAC7B;GACA;GACA,OAAO;GACP;EACF;EACA,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,KAAK;GAC1B,KAAK,MAAM,KAAK,GAAG,EAAE,OAAO,EAAE,CAAC,CAAC;GAChC;EACF;EACA,MAAM,OAAO,EAAE,MAAM,EAAE;EACvB,KAAK,MAAM,KAAK,GAAG,EAAE,OAAO,IAAI,CAAC;EACjC,IAAI,EAAE,IAAI,OAAO,GAAG,KAAK,MAAM,KAAK,GAAG,GAAG,EAAE,IAAI,IAAI,CAAC;CACvD;CAEA,MAAY;EACV,IAAI,KAAK,eAAgB,CAAC,KAAK,MAAM,UAAU,CAAC,KAAK,KAAK,QAAS;EACnE,IAAI;GACF,MAAM,UAAU,KAAK,OAAO,qBAAqB;GACjD,IAAI,KAAK,KAAK,QAAQ;IACpB,MAAM,KAAK,QAAQ,iBAAiB;IACpC,GAAG,YAAY,KAAK,MAAM,GAAG;IAC7B,KAAK,MAAM,KAAK,KAAK,MAAM;KACzB,GAAG,aAAa,GAAG,KAAK,UAAU,CAAC,EAAE,CAAC,CAAC;KACvC,GAAG,aAAa,GAAG,EAAE,KAAK,EAAkB;KAC5C,GAAG,mBAAmB,KAAK,KAAK,KAAK,OAAO,EAAE,CAAC;IACjD;IACA,GAAG,IAAI;GACT;GACA,IAAI,KAAK,MAAM,QAAQ;IACrB,MAAM,OAAO,KAAK,IAAI,kBAAkB,CAAC,CAAC,WAAW;IACrD,MAAM,IAAI,KAAK;IACf,MAAM,OAAO,KAAK;IAClB,MAAM,OAAO,QAAQ,gBAAgB;KACnC,kBAAkB,CAChB;MACE;MACA,QAAQ;MACR,SAAS;MACT,YAAY;OAAE,GAAG;OAAG,GAAG;OAAG,GAAG;OAAG,GAAG;MAAE;KACvC,CACF;KACA,GAAI,KAAK,WACL,EACE,iBAAiB;MACf,UAAU,KAAK;MACf,2BAA2B;MAC3B,qBAAqB;KACvB,EACF,IACA,CAAC;IACP,CAAC;IACD,KAAK,eACH,KAAK,IAAI,GAAG,KAAK,MAAM,KAAK,IAAI,CAAC,CAAC,GAClC,KAAK,IAAI,GAAG,KAAK,MAAM,KAAK,IAAI,CAAC,CAAC,GAClC,KAAK,IAAI,GAAG,KAAK,MAAM,KAAK,IAAI,CAAC,CAAC,GAClC,KAAK,IAAI,GAAG,KAAK,MAAM,KAAK,IAAI,CAAC,CAAC,CACpC;IACA,KAAK,MAAM,MAAM,KAAK,OAAO;KAC3B,KAAK,YAAY,GAAG,IAAI;KACxB,KAAK,aAAa,GAAG,KAAK,UAAU,CAAC,GAAG,CAAC,CAAC;KAC1C,KAAK,IAAI,IAAI,GAAG,IAAI,GAAG,MAAM,QAAQ,KAAK;MACxC,MAAM,IAAI,GAAG,MAAM;MACnB,IAAI,GAAG,KAAK,gBAAgB,GAAG,EAAE,KAAK,EAAE,GAAG;KAC7C;KACA,KAAK,KAAK,GAAG,OAAO,GAAG,KAAK;IAC9B;IACA,KAAK,IAAI;GACX;GACA,MAAM,KAAK,KAAK;GAChB,MAAM,KAAK,KAAK;GAChB,MAAM,KAAK,KAAK;GAChB,IAAI,MAAM,MAAM,MAAM,CAAC,KAAK,SAAS;IACnC,QAAQ,gBAAgB,IAAI,GAAG,GAAG,IAAI,CAAC;IACvC,QAAQ,mBAAmB,IAAI,GAAG,IAAI,GAAG,EAAE;IAC3C,KAAK,UAAU;IACf,KAAK,OAAO,MAAM,OAAO,CAAC,QAAQ,OAAO,CAAC,CAAC;IAC3C,GAAQ,SAAS,QAAQ,CAAC,CAAC,WACnB;KACJ,MAAM,IAAI,IAAI,eAAe,GAAG,eAAe,CAAC;KAChD,MAAM,KAAK,EAAE;KACb,MAAM,KAAK,EAAE;KACb,IAAI,OAAO,KAAA,KAAa,OAAO,KAAA,GAC7B,KAAK,QAAQ,OAAO,KAAK,EAAE,IAAI;KAEjC,GAAG,MAAM;KACT,KAAK,UAAU;IACjB,SACM;KACJ,KAAK,UAAU;IACjB,CACF;GACF,OACE,KAAK,OAAO,MAAM,OAAO,CAAC,QAAQ,OAAO,CAAC,CAAC;EAE/C,QAAQ,CAER;CACF;CAEA,UAAgB;EACd,KAAK,YAAY;EACjB,KAAK,MAAM,KAAK,KAAK,OAAO;GAC1B,EAAE,GAAG,QAAQ;GACb,EAAE,KAAK,QAAQ;GACf,EAAE,SAAS,QAAQ;GACnB,EAAE,KAAK,QAAQ;EACjB;EACA,KAAK,QAAQ,CAAC;EACd,KAAK,MAAM,QAAQ;EACnB,KAAK,UAAU,QAAQ;EACvB,KAAK,SAAS,QAAQ;EACtB,KAAK,UAAU,QAAQ;EACvB,IAAI;GACF,KAAK,IAAI,YAAY;EACvB,QAAQ,CAER;EACA,KAAK,OAAO,OAAO;CACrB;AACF;AAEA,MAAM,QAAuB;CAC3B,OAAO;EACL,WAAW;EACX,WAAW;EACX,WAAW;CACb;CACA,OAAO;EACL,WAAW;EACX,WAAW;EACX,WAAW;CACb;AACF"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "resolvcharts",
3
- "version": "0.2.0",
3
+ "version": "0.3.0",
4
4
  "description": "A minimal, zero-dependency canvas charting library",
5
5
  "author": "Resolvo Cloud",
6
6
  "repository": {
@@ -53,6 +53,20 @@
53
53
  "access": "public",
54
54
  "provenance": true
55
55
  },
56
+ "scripts": {
57
+ "dev": "tsdown --watch",
58
+ "build": "tsdown && tsdown --format iife --minify --global-name ResolvCharts -d .cdn-tmp && mv .cdn-tmp/index.iife.js dist/resolvcharts.global.min.js && mv .cdn-tmp/index.iife.js.map dist/resolvcharts.global.min.js.map && rm -rf .cdn-tmp",
59
+ "typecheck": "tsc --noEmit",
60
+ "test": "vitest run",
61
+ "bench": "tsdown bench/perf.ts -d .bench-out --format esm --no-dts --external jsdom && node .bench-out/perf.mjs",
62
+ "lint": "biome check .",
63
+ "check:package": "publint && attw --pack . --profile node16",
64
+ "changeset": "changeset",
65
+ "prepack": "pnpm run build",
66
+ "prepublishOnly": "pnpm run typecheck && pnpm run test && pnpm run check:package",
67
+ "docs:api": "astro build --root site",
68
+ "docs:dev": "astro dev --root site"
69
+ },
56
70
  "devDependencies": {
57
71
  "@arethetypeswrong/cli": "^0.18.5",
58
72
  "@astrojs/starlight": "^0.42.6",
@@ -69,16 +83,5 @@
69
83
  "vitest": "^5.0.5",
70
84
  "vitest-canvas-mock": "^1.2.0"
71
85
  },
72
- "scripts": {
73
- "dev": "tsdown --watch",
74
- "build": "tsdown && tsdown --format iife --minify --global-name ResolvCharts -d .cdn-tmp && mv .cdn-tmp/index.iife.js dist/resolvcharts.global.min.js && mv .cdn-tmp/index.iife.js.map dist/resolvcharts.global.min.js.map && rm -rf .cdn-tmp",
75
- "typecheck": "tsc --noEmit",
76
- "test": "vitest run",
77
- "bench": "tsdown bench/perf.ts -d .bench-out --format esm --no-dts --external jsdom && node .bench-out/perf.mjs",
78
- "lint": "biome check .",
79
- "check:package": "publint && attw --pack . --profile node16",
80
- "changeset": "changeset",
81
- "docs:api": "astro build --root site",
82
- "docs:dev": "astro dev --root site"
83
- }
84
- }
86
+ "packageManager": "pnpm@12.14.0"
87
+ }
@@ -1,479 +0,0 @@
1
- //#region src/gpu/color.ts
2
- /** Parse a CSS color (#rgb, #rrggbb, rgb(), rgba()) into linear-ish 0-1 rgba. */
3
- function parseColor(c) {
4
- if (c.startsWith("#")) {
5
- const h = c.slice(1);
6
- if (h.length === 3) return [
7
- parseInt(h[0], 16) / 15,
8
- parseInt(h[1], 16) / 15,
9
- parseInt(h[2], 16) / 15,
10
- 1
11
- ];
12
- if (h.length === 6) return [
13
- parseInt(h.slice(0, 2), 16) / 255,
14
- parseInt(h.slice(2, 4), 16) / 255,
15
- parseInt(h.slice(4, 6), 16) / 255,
16
- 1
17
- ];
18
- }
19
- const m = /rgba?\(([^)]+)\)/.exec(c);
20
- if (m) {
21
- const parts = m[1].split(",").map((v) => Number.parseFloat(v));
22
- return [
23
- (parts[0] ?? 0) / 255,
24
- (parts[1] ?? 0) / 255,
25
- (parts[2] ?? 0) / 255,
26
- parts[3] ?? 1
27
- ];
28
- }
29
- return [
30
- 0,
31
- 0,
32
- 0,
33
- 1
34
- ];
35
- }
36
- //#endregion
37
- //#region src/gpu/device.ts
38
- /** Shared GPUDevice across charts — adapters/devices are expensive to acquire. */
39
- const cache = /* @__PURE__ */ new Map();
40
- function getGpuDevice(opts = {}) {
41
- const key = JSON.stringify(opts);
42
- let p = cache.get(key);
43
- if (!p) {
44
- p = (async () => {
45
- const gpu = (typeof navigator === "undefined" ? null : navigator)?.gpu;
46
- if (!gpu) return null;
47
- const req = {};
48
- if (opts.powerPreference && opts.powerPreference !== "default") req.powerPreference = opts.powerPreference;
49
- if (opts.compat) req.featureLevel = "compatibility";
50
- const adapter = await gpu.requestAdapter(req);
51
- if (!adapter) return null;
52
- const requiredFeatures = [];
53
- if (opts.timing && adapter.features.has("timestamp-query")) requiredFeatures.push("timestamp-query");
54
- return adapter.requestDevice({ requiredFeatures });
55
- })();
56
- p.catch(() => cache.delete(key));
57
- cache.set(key, p);
58
- }
59
- return p;
60
- }
61
- //#endregion
62
- //#region src/gpu/series.ts
63
- /**
64
- * WebGPU series renderer. Points arrive as interleaved [x, y] CSS-pixel pairs
65
- * (the same Float32Array the canvas path decimates into) uploaded as vertex
66
- * buffers; the GPU only rasterizes — instanced segment quads for lines, a
67
- * triangle strip to the baseline for areas, SDF circle sprites for scatter.
68
- *
69
- * Vertex-pulling via attributes is used everywhere (no vertex-stage storage
70
- * buffers), so the same pipelines work in WebGPU compatibility mode.
71
- */
72
- const HEADER = `
73
- struct U {
74
- res: vec4f, // canvas w, h (device px), dpr, unused
75
- color: vec4f,
76
- p: vec4f, // line: width | area: baseY, plotTop, plotH | points: radius
77
- };
78
- @group(0) @binding(0) var<uniform> u: U;
79
-
80
- fn toClip(p: vec2f) -> vec4f {
81
- let d = p * u.res.z;
82
- return vec4f(d.x / u.res.x * 2.0 - 1.0, 1.0 - d.y / u.res.y * 2.0, 0.0, 1.0);
83
- }
84
- `;
85
- const LINE_WGSL = `
86
- ${HEADER}
87
- const OFF = array<vec2f, 6>(
88
- vec2f(0.0, -1.0), vec2f(0.0, 1.0), vec2f(1.0, -1.0),
89
- vec2f(0.0, 1.0), vec2f(1.0, 1.0), vec2f(1.0, -1.0),
90
- );
91
- struct VOut {
92
- @builtin(position) pos: vec4f,
93
- @location(0) edge: f32,
94
- };
95
- @vertex fn vs(
96
- @builtin(vertex_index) vi: u32,
97
- @location(0) a: vec2f,
98
- @location(1) b: vec2f,
99
- ) -> VOut {
100
- let v = OFF[vi];
101
- var dir = b - a;
102
- let len = length(dir);
103
- if (len < 1e-6) {
104
- dir = vec2f(1.0, 0.0);
105
- } else {
106
- dir = dir / len;
107
- }
108
- let nrm = vec2f(-dir.y, dir.x);
109
- let halfW = u.p.x * 0.5;
110
- let aa = 0.9;
111
- let p = mix(a, b, v.x) + nrm * v.y * (halfW + aa);
112
- var o: VOut;
113
- o.pos = toClip(p);
114
- o.edge = v.y * (halfW + aa);
115
- return o;
116
- }
117
- @fragment fn fs(o: VOut) -> @location(0) vec4f {
118
- let halfW = u.p.x * 0.5;
119
- let a = 1.0 - smoothstep(halfW - 0.5, halfW + 0.9, abs(o.edge));
120
- return vec4f(u.color.rgb, u.color.a * a);
121
- }
122
- `;
123
- const AREA_WGSL = `
124
- ${HEADER}
125
- struct VOut {
126
- @builtin(position) pos: vec4f,
127
- @location(0) grad: f32,
128
- };
129
- // triangle strip over a doubled buffer: buf[2k] and buf[2k+1] both hold
130
- // point k; even verts land on the path, odd verts drop to the baseline
131
- @vertex fn vs(
132
- @builtin(vertex_index) vi: u32,
133
- @location(0) top: vec2f,
134
- ) -> VOut {
135
- let isTop = (vi & 1u) == 0u;
136
- let baseY = u.p.x;
137
- let y = select(baseY, top.y, isTop);
138
- var o: VOut;
139
- o.pos = toClip(vec2f(top.x, y));
140
- o.grad = clamp((top.y - u.p.y) / max(u.p.z, 1.0), 0.0, 1.0);
141
- return o;
142
- }
143
- @fragment fn fs(o: VOut) -> @location(0) vec4f {
144
- let a = mix(0.16, 0.0, o.grad) * u.color.a;
145
- return vec4f(u.color.rgb, a);
146
- }
147
- `;
148
- const POINTS_WGSL = `
149
- ${HEADER}
150
- const QUAD = array<vec2f, 6>(
151
- vec2f(-1.0, -1.0), vec2f(1.0, -1.0), vec2f(-1.0, 1.0),
152
- vec2f(-1.0, 1.0), vec2f(1.0, -1.0), vec2f(1.0, 1.0),
153
- );
154
- struct VOut {
155
- @builtin(position) pos: vec4f,
156
- @location(0) local: vec2f,
157
- };
158
- @vertex fn vs(
159
- @builtin(vertex_index) vi: u32,
160
- @location(0) c: vec2f,
161
- ) -> VOut {
162
- let r = u.p.x;
163
- let q = QUAD[vi];
164
- var o: VOut;
165
- o.pos = toClip(c + q * r);
166
- o.local = q * r;
167
- return o;
168
- }
169
- @fragment fn fs(o: VOut) -> @location(0) vec4f {
170
- let r = u.p.x;
171
- let a = 1.0 - smoothstep(r - 1.2, r, length(o.local));
172
- return vec4f(u.color.rgb, u.color.a * a);
173
- }
174
- `;
175
- const UNIFORM_SIZE = 64;
176
- const BLEND = {
177
- color: {
178
- srcFactor: "src-alpha",
179
- dstFactor: "one-minus-src-alpha",
180
- operation: "add"
181
- },
182
- alpha: {
183
- srcFactor: "one",
184
- dstFactor: "one-minus-src-alpha",
185
- operation: "add"
186
- }
187
- };
188
- const BUF_VERTEX_DST = 40;
189
- const BUF_UNIFORM_DST = 72;
190
- const BUF_RESOLVE_SRC = 516;
191
- const BUF_MAPREAD_DST = 9;
192
- const MAP_READ = 1;
193
- var GpuSeries = class GpuSeries {
194
- constructor(device, canvas, timing) {
195
- this.dpr = 1;
196
- this.drawIdx = 0;
197
- this.bufs = [];
198
- this.encoder = null;
199
- this.pass = null;
200
- this.gpuMs = null;
201
- this.querySet = null;
202
- this.queryBuf = null;
203
- this.readBuf = null;
204
- this.reading = false;
205
- this.areaScratch = /* @__PURE__ */ new Float32Array(0);
206
- this.device = device;
207
- if (timing && device.features.has("timestamp-query")) {
208
- this.querySet = device.createQuerySet({
209
- type: "timestamp",
210
- count: 2
211
- });
212
- this.queryBuf = device.createBuffer({
213
- size: 16,
214
- usage: BUF_RESOLVE_SRC
215
- });
216
- this.readBuf = device.createBuffer({
217
- size: 16,
218
- usage: BUF_MAPREAD_DST
219
- });
220
- }
221
- this.canvas = canvas;
222
- canvas.style.cssText = "position:absolute;inset:0;width:100%;height:100%;display:block;pointer-events:none";
223
- const ctx = canvas.getContext("webgpu");
224
- if (!ctx) throw new Error("resolvcharts: webgpu context unavailable");
225
- this.ctx = ctx;
226
- this.format = navigator.gpu.getPreferredCanvasFormat();
227
- this.layout = device.createBindGroupLayout({ entries: [{
228
- binding: 0,
229
- visibility: 3,
230
- buffer: { type: "uniform" }
231
- }] });
232
- const pl = device.createPipelineLayout({ bindGroupLayouts: [this.layout] });
233
- const mk = (code, topology, buffers) => device.createRenderPipeline({
234
- layout: pl,
235
- vertex: {
236
- module: device.createShaderModule({ code }),
237
- entryPoint: "vs",
238
- buffers
239
- },
240
- fragment: {
241
- module: device.createShaderModule({ code }),
242
- entryPoint: "fs",
243
- targets: [{
244
- format: this.format,
245
- blend: BLEND
246
- }]
247
- },
248
- primitive: { topology }
249
- });
250
- const pairLayout = [{
251
- arrayStride: 8,
252
- stepMode: "instance",
253
- attributes: [{
254
- shaderLocation: 0,
255
- offset: 0,
256
- format: "float32x2"
257
- }]
258
- }, {
259
- arrayStride: 8,
260
- stepMode: "instance",
261
- attributes: [{
262
- shaderLocation: 1,
263
- offset: 0,
264
- format: "float32x2"
265
- }]
266
- }];
267
- const ptLayout = {
268
- arrayStride: 8,
269
- stepMode: "instance",
270
- attributes: [{
271
- shaderLocation: 0,
272
- offset: 0,
273
- format: "float32x2"
274
- }]
275
- };
276
- const areaLayout = {
277
- arrayStride: 8,
278
- stepMode: "vertex",
279
- attributes: [{
280
- shaderLocation: 0,
281
- offset: 0,
282
- format: "float32x2"
283
- }]
284
- };
285
- this.pipes = {
286
- line: mk(LINE_WGSL, "triangle-list", pairLayout),
287
- area: mk(AREA_WGSL, "triangle-strip", [areaLayout]),
288
- points: mk(POINTS_WGSL, "triangle-list", [ptLayout])
289
- };
290
- }
291
- static async create(opts = {}) {
292
- const device = await getGpuDevice(opts);
293
- if (!device) return null;
294
- const canvas = document.createElement("canvas");
295
- try {
296
- return new GpuSeries(device, canvas, !!opts.timing);
297
- } catch {
298
- return null;
299
- }
300
- }
301
- setSize(cssW, cssH, dpr) {
302
- this.dpr = dpr;
303
- this.canvas.width = Math.max(1, Math.round(cssW * dpr));
304
- this.canvas.height = Math.max(1, Math.round(cssH * dpr));
305
- this.ctx.configure({
306
- device: this.device,
307
- format: this.format,
308
- alphaMode: "premultiplied"
309
- });
310
- }
311
- bufferFor(idx, bytes) {
312
- let b = this.bufs[idx];
313
- if (!b || b.size < bytes) {
314
- b?.destroy();
315
- b = this.device.createBuffer({
316
- size: Math.max(256, bytes),
317
- usage: BUF_VERTEX_DST
318
- });
319
- this.bufs[idx] = b;
320
- }
321
- return b;
322
- }
323
- begin(plot) {
324
- this.encoder = this.device.createCommandEncoder();
325
- const view = this.ctx.getCurrentTexture().createView();
326
- this.pass = this.encoder.beginRenderPass({
327
- colorAttachments: [{
328
- view,
329
- loadOp: "clear",
330
- storeOp: "store",
331
- clearValue: {
332
- r: 0,
333
- g: 0,
334
- b: 0,
335
- a: 0
336
- }
337
- }],
338
- ...this.querySet ? { timestampWrites: {
339
- querySet: this.querySet,
340
- beginningOfPassWriteIndex: 0,
341
- endOfPassWriteIndex: 1
342
- } } : {}
343
- });
344
- const d = this.dpr;
345
- this.pass.setScissorRect(Math.max(0, Math.floor(plot.x * d)), Math.max(0, Math.floor(plot.y * d)), Math.max(1, Math.floor(plot.w * d)), Math.max(1, Math.floor(plot.h * d)));
346
- this.drawIdx = 0;
347
- }
348
- draw(pipe, vbufs, color, alpha, params, vertCount, instances) {
349
- const pass = this.pass;
350
- if (!pass || instances <= 0) return;
351
- const [r, g, b, a] = parseColor(color);
352
- const udata = /* @__PURE__ */ new Float32Array(16);
353
- udata.set([
354
- this.canvas.width,
355
- this.canvas.height,
356
- this.dpr,
357
- 0
358
- ]);
359
- udata.set([
360
- r,
361
- g,
362
- b,
363
- a * alpha
364
- ], 4);
365
- udata.set(params, 8);
366
- const ubuf = this.device.createBuffer({
367
- size: UNIFORM_SIZE,
368
- usage: BUF_UNIFORM_DST
369
- });
370
- this.device.queue.writeBuffer(ubuf, 0, udata);
371
- const bind = this.device.createBindGroup({
372
- layout: this.layout,
373
- entries: [{
374
- binding: 0,
375
- resource: { buffer: ubuf }
376
- }]
377
- });
378
- pass.setPipeline(pipe);
379
- pass.setBindGroup(0, bind);
380
- for (let i = 0; i < vbufs.length; i++) {
381
- const v = vbufs[i];
382
- if (v) pass.setVertexBuffer(i, v.buf, v.offset);
383
- }
384
- pass.draw(vertCount, instances);
385
- }
386
- line(pts, color, width = 2) {
387
- const n = pts.length / 2;
388
- const idx = this.drawIdx++;
389
- const pbuf = this.bufferFor(idx, pts.byteLength);
390
- this.device.queue.writeBuffer(pbuf, 0, pts);
391
- this.draw(this.pipes.line, [{
392
- buf: pbuf,
393
- offset: 0
394
- }, {
395
- buf: pbuf,
396
- offset: 8
397
- }], color, 1, [
398
- width,
399
- 0,
400
- 0
401
- ], 6, n - 1);
402
- }
403
- area(pts, color, baseY, plot) {
404
- const n = pts.length / 2;
405
- if (this.areaScratch.length < n * 4) this.areaScratch = new Float32Array(n * 4);
406
- const d = this.areaScratch;
407
- for (let i = 0; i < n; i++) {
408
- const x = pts[2 * i];
409
- const y = pts[2 * i + 1];
410
- const o = 4 * i;
411
- d[o] = x;
412
- d[o + 1] = y;
413
- d[o + 2] = x;
414
- d[o + 3] = y;
415
- }
416
- const out = d.subarray(0, n * 4);
417
- const idx = this.drawIdx++;
418
- const pbuf = this.bufferFor(idx, out.byteLength);
419
- this.device.queue.writeBuffer(pbuf, 0, out);
420
- this.draw(this.pipes.area, [{
421
- buf: pbuf,
422
- offset: 0
423
- }], color, 1, [
424
- baseY,
425
- plot.y,
426
- plot.h
427
- ], n * 2, 1);
428
- }
429
- points(pts, color, radius = 2.5, alpha = .65) {
430
- const n = pts.length / 2;
431
- const idx = this.drawIdx++;
432
- const pbuf = this.bufferFor(idx, pts.byteLength);
433
- this.device.queue.writeBuffer(pbuf, 0, pts);
434
- this.draw(this.pipes.points, [{
435
- buf: pbuf,
436
- offset: 0
437
- }], color, alpha, [
438
- radius,
439
- 0,
440
- 0
441
- ], 6, n);
442
- }
443
- end() {
444
- if (!this.pass || !this.encoder) return;
445
- this.pass.end();
446
- const qs = this.querySet;
447
- const qb = this.queryBuf;
448
- const rb = this.readBuf;
449
- if (qs && qb && rb && !this.reading) {
450
- this.encoder.resolveQuerySet(qs, 0, 2, qb, 0);
451
- this.encoder.copyBufferToBuffer(qb, 0, rb, 0, 16);
452
- this.reading = true;
453
- this.device.queue.submit([this.encoder.finish()]);
454
- rb.mapAsync(MAP_READ).then(() => {
455
- const v = new BigUint64Array(rb.getMappedRange());
456
- const t0 = v[0];
457
- const t1 = v[1];
458
- if (t0 !== void 0 && t1 !== void 0) this.gpuMs = Number(t1 - t0) / 1e6;
459
- rb.unmap();
460
- this.reading = false;
461
- });
462
- } else this.device.queue.submit([this.encoder.finish()]);
463
- this.pass = null;
464
- this.encoder = null;
465
- }
466
- destroy() {
467
- for (const b of this.bufs) b.destroy();
468
- this.queryBuf?.destroy();
469
- this.readBuf?.destroy();
470
- this.querySet?.destroy();
471
- this.bufs = [];
472
- this.ctx.unconfigure();
473
- this.canvas.remove();
474
- }
475
- };
476
- //#endregion
477
- export { GpuSeries };
478
-
479
- //# sourceMappingURL=series-BdprL87H.mjs.map