npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

gpu-view

v0.2.0

Published

Natural language to table view specs: filter, sort, group, aggregate, limit, chart

Readme

gpu-view

Natural language to table view specs: filter, sort, group, aggregate, limit, chart.

Tiny model (37,775 parameters, int6), trained from scratch, runs on WebGPU or the CPU in the browser. Zero dependencies, 35.5 KiB Brotli including the weights. Part of gpu-utils.

It is schema-blind: the model never sees your field names. You pass the schema at call time and it is injected as anonymous per-token features ("this token matched a field of kind number"), so the same weights work on issues, wine cellars and greenhouses without retraining.

npm install gpu-view
import { parse } from "gpu-view";

const schema = {
  fields: [
    { name: "revenue", kind: "number", aliases: ["sales"] },
    { name: "region", kind: "enum", values: ["EMEA", "APAC", "Americas"] },
    { name: "closed_at", kind: "date", aliases: ["closed", "close date"] },
    { name: "owner", kind: "text", aliases: ["rep"] },
  ],
};

const spec = await parse("total revenue by region this quarter, top 10, as a bar chart", { schema });
// {
//   filters:   [{ field: "closed_at", op: "between", value: ["2026-07-01", "2026-09-30"], span: { start: 26, end: 38 } }],
//   sort:      [],
//   groupBy:   [{ field: "region", span: { start: 17, end: 23 } }],
//   aggregate: [{ fn: "sum", field: "revenue", span: { start: 0, end: 13 } }],
//   limit:     10,
//   chart:     "bar",
//   diagnostics: [],
//   tokens: [{ text: "total", start: 0, end: 5, role: "AGG_FN", boundary: true }, ...],
// }

Other phrases it handles: open issues assigned to me sorted by priority, customers in Germany or France with more than 5 orders, average order value per month last year, line chart, unarchived repos with no maintainer, repos not updated in the last 30 days, vintage 2019 or older, plants without a species, newest first, limit 25.

Options

| Option | Purpose | |---|---| | schema | { fields: [{ name, kind: "text" \| "number" \| "date" \| "enum" \| "boolean", aliases?, values? }] }. Required. | | now | Reference date for relative phrases (Date or ISO string). Defaults to the current time. | | dateField | Date field to use when a time phrase names none and the schema has several date fields. | | backend | "auto" (default), "cpu" or "webgpu". A single phrase always runs on the CPU under auto; parseMany batches onto the GPU. |

Output

filters[].op is one of eq neq contains gt gte lt lte between in is_true is_false is_empty not_empty. Values are canonical enum strings, numbers (5k → 5000, $1,200 → 1200), ISO dates or [from, to] pairs. sort[].dir is asc/desc; aggregate[].fn is count sum avg min max; chart is table bar line pie number; granularity is set for "per month"-style groups. Every clause carries a span (UTF-16 offsets, half-open) into the input, and every token is returned with its predicted role.

Anything the compiler cannot resolve becomes a diagnostics entry with a stable code (unknown_field, unknown_value, ambiguous_value, unresolved_time, ambiguous_date_field, unsupported_negation, ...) and a span, instead of a guess.

How it works

tokenize() splits the phrase into character-class runs and whitespace is dropped. Each token gets sparse feature ids: word and consonant-skeleton hashes, shape, length, a closed lexicon of operator/sort/group/aggregate/chart/time words, and the schema-membership features that make the model schema-blind: matched a field (its kind, begin/inside, exact / stem / prefix / typo, via an alias), matched an enum value (unique owner? owned by the nearest preceding or following field?), and the kind of and distance to the nearest field match on either side. The field words themselves never reach the model.

A 37,775-parameter tagger from the shared scan family (@gpu-utils/runtime scanTaggerForward; summed embeddings → bidirectional gated affine scan h[t] = a[t]·h[t−1] + (1−a[t])·tanh(u[t]) as a parallel prefix scan → residual 5-tap depthwise convolution → mean-pooled context → two-layer head) emits one of 14 roles per token (FIELD OP VALUE TIME_VALUE CONJ NEG SORT_FIELD SORT_DIR GROUP_FIELD AGG_FN AGG_FIELD LIMIT CHART O) plus a clause-boundary logit, so several filters in one phrase stay apart.

Deterministic TypeScript then compiles the roles: it resolves field spans back to your schema (aliases, plurals, prefixes, one-character typos), canonicalises enum values, parses numbers with k/m suffixes and currency symbols, resolves relative dates (today, last 30 days, this quarter, q2 2025, march, a bare year, ISO dates) against now, maps operator phrases and negation onto the op set, pairs aggregate functions with their fields, and reports diagnostics for anything left over. Comparatives and superlatives resolve through aliases: list cheap or tall as an alias of a numeric field and cheapest first sorts ascending, taller than 50 cm becomes gt 50. A boolean field word may carry its negation as a prefix (unarchived, nonbillable, inactive). Mark one date field primary: true so bare time phrases ("this quarter") attach to it when the schema has several.

Clauses compile independently, so a last pass normalises the spec as a whole: two eq filters on the same enum field become one value list, a not_empty implied by another filter on the same field is dropped, a field sorted twice keeps the direction the user spelled out, and duplicate aggregates collapse.

Size and speed

| Measure | Value | |---|---| | Bundle (min + Brotli, weights included) | 35.5 KiB (budget 39.1 KiB) | | Parameters | 37,775 (int6) | | Import + weight decode | ~5.2 ms (Node 24, Xeon 2.9 GHz) | | First parse (JIT warm-up) | ~13.5 ms | | Warm CPU parse, 14-token phrase | ~0.63 ms | | CPU batch of 1000 phrases | ~590 ms |

The canonical scan-family WGSL kernel from @gpu-utils/runtime (one workgroup per phrase, one thread per hidden channel) matches the CPU path to 1.5e-5 in a batched dispatch on Mesa's software Vulkan; it is used by parseMany for batches, where readback cost is amortised. Real-GPU timings are not measured yet.

Limitations

  • Trained entirely on synthetic phrases. Held-out generated schemas reach 88% exact spec match; three hand-written sets of ~65 phrases over unseen schemas reach 74% / 67% / 72%. See MODEL_CARD.md for the failure analysis.
  • A comparative or superlative only resolves when the adjective is a field word: with no long alias on pages, longest books first sorts nothing. Say so in the schema (aliases: ["long"]) or the phrase is reported as unresolved.
  • A number whose only field cue is a unit noun that is not a field word (under 30 minutes when no field is called minutes) is reported, not guessed onto a field.
  • Free-text values the model has never seen are often not recognised as values (titles containing catan); quoting them (titles containing "catan") is reliable.
  • Verb-phrase negation (games i do not own, workouts that were not completed) is missed.
  • before/after on a year-like numeric field (published before 2010) compiles to eq.
  • Filters are always ANDed; or only forms value lists. Negated contains and date ranges that end in the future are unsupported and reported; a negated window that ends now (not updated in the last 30 days) becomes lt <window start>.
  • top N without a by field only sets limit; it does not infer a sort from an aggregate.
  • "Per month" needs one date field, a primary: true date field, or options.dateField.
  • English only.

Training

cd packages/gpu-view/training
uv sync
uv run python -m gpu_view.data      # fixtures, eval sets, 160K-phrase corpus (~4 min)
uv run python -m gpu_view.train     # 14 epochs of int6 QAT on 2 CPU threads (~12 min)
uv run python -m gpu_view.export    # ../model/{manifest.json,weights.txt,fixtures.json}
uv run pytest                       # featurizer/time/matcher parity, generator invariants, WGSL via wgpu-py