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

@stratchai/cathode

v0.1.6

Published

A retro CRT curved-screen datagrid for the web

Downloads

504

Readme

cathode

A retro CRT curved-screen datagrid for the web. Barrel-distorted columns, phosphor aesthetics, more data per viewport.

npm license bundle size types

cathode — workspace view in phosphor theme, curved trades grid + candle chart + log feed + terminal

Captured from demo/App.vue — workspace tab, theme="phosphor". Reproduce with npm run capture:hero (see tools/capture-hero.mjs).


Why

Flat datagrids waste peripheral vision. A curved screen — like a real CRT monitor — angles the left and right columns toward the viewer, creating a panoramic effect that lets you read more columns comfortably without horizontal eye strain. Edge columns are slightly foreshortened, fitting 10–15% more content at the same viewport width.

The effect is pure CSS 3D (perspective + rotateY per column). Text stays real DOM — selectable, copyable, accessible.


Quick start

npm install @stratchai/cathode

Minimal — drop a grid into a Vue 3 app:

<script setup lang="ts">
import { CathodeGrid, type ColDef } from '@stratchai/cathode'
import '@stratchai/cathode/style'

const cols: ColDef[] = [
  { field: 'ticker', headerName: 'Ticker' },
  { field: 'price',  headerName: 'Price'  },
]

const rows = [
  { ticker: 'BTC', price: 67_341.20 },
  { ticker: 'ETH', price: 2_481.05  },
]
</script>

<template>
  <CathodeGrid :column-defs="cols" :row-data="rows" theme="phosphor" />
</template>

That's it. The grid renders, the curve activates, the phosphor glow lights up.

<script setup lang="ts">
import { CathodeGrid } from '@stratchai/cathode'
import '@stratchai/cathode/style'
import type { ColDef, GridApi } from '@stratchai/cathode'

const cols: ColDef[] = [
  { field: 'ticker',   headerName: 'Ticker',  width: 90 },
  { field: 'price',    headerName: 'Price',   width: 100, cellStyle: { textAlign: 'right' } },
  { field: 'pnl',      headerName: 'PnL %',   width: 80  },
]

let api: GridApi

function onGridReady(e: { api: GridApi }) {
  api = e.api
  api.setGridOption('rowData', myRows)
}
</script>

<template>
  <CathodeGrid
    :column-defs="cols"
    :row-height="28"
    theme="phosphor"
    :curvature="12"
    :scanlines="true"
    :glow="true"
    :pagination="true"
    :pagination-page-size="50"
    @grid-ready="onGridReady"
    @row-clicked="e => console.log(e.data)"
  />
</template>

Status

v0.1.x — production-ready for small-to-mid datasets. Cathode is in active use rendering live trading data in a production dashboard.

| Works well for | Choose something else for | |----------------|---------------------------| | 100s–10ks of rows | 100k+ rows (use TanStack Table — virtual scrolling is on cathode's roadmap but not yet shipped) | | Vue 3 apps | React (no wrapper yet — see ROADMAP.md) | | Dashboards, status panels, sci-fi UIs | Spreadsheet-style apps with row grouping / aggregation (not yet shipped) | | Built-in CRT / phosphor aesthetic | Plain Material / Tailwind look — pass theme="none" and bring your own CSS vars |

See ROADMAP.md for what's coming next.


Props

| Prop | Type | Default | Description | |------|------|---------|-------------| | columnDefs | ColDef[] | required | Column definitions | | rowData | any[] | [] | Initial row data (use api.setGridOption('rowData', …) to update) | | rowHeight | number | 28 | Row height in px | | defaultColDef | Partial<ColDef> | {} | Merged into every column definition | | getRowStyle | (p) => CSSProperties | — | Per-row inline style callback | | pinnedBottomRowData | any[] | — | Rows pinned to the bottom of the scroll area | | pagination | boolean | false | Enable pagination bar | | paginationPageSize | number | 50 | Rows per page | | theme | 'none' \| 'phosphor' \| 'amber' \| 'paper' | 'none' | Built-in colour theme ('none' inherits parent CSS vars) | | curvature | number | 10 | Max rotateY angle (°) for edge columns — 0 = flat | | perspective | number | 1400 | CSS perspective distance (px) — higher = subtler vanishing point | | scanlines | boolean | true | Overlay repeating scanline gradient | | glow | boolean | true | Apply text-shadow phosphor glow to cell text |


Grid API

Emitted via @grid-ready. Mirrors the ag-Grid Community API surface used in typical dashboards.

api.setGridOption('rowData', rows)
api.setGridOption('pinnedBottomRowData', pinnedRows)
api.setGridOption('quickFilterText', 'BTC')

api.getColumnState()                   // → ColState[]
api.applyColumnState({ state, applyOrder })
api.setFilterModel({ status: { type: 'equals', filter: 'open' } })
api.getFilterModel()
await api.setColumnFilterModel('status', { type: 'equals', filter: 'open' })
api.onFilterChanged()                  // no-op — Vue reactivity handles it

api.refreshCells()                     // force re-evaluation (e.g. Age column)
api.exportDataAsCsv({ fileName: 'trades.csv' })
api.resetColumnState()

ColDef

interface ColDef {
  field?:          string           // row[field]
  headerName?:     string
  colId?:          string           // explicit ID; defaults to field → headerName slug
  width?:          number
  minWidth?:       number
  sortable?:       boolean
  filter?:         boolean          // shows ⌕ icon in header → popup text filter
  resizable?:      boolean
  hide?:           boolean
  sort?:           'asc' | 'desc'   // initial sort
  valueGetter?:    (p) => any
  valueFormatter?: (p) => string
  cellStyle?:      CSSProperties | ((p) => CSSProperties)
  cellRenderer?:   (p) => string    // HTML string rendered via v-html
  comparator?:     (a, b) => number
}

Themes

| Theme | Background | Text | Use for | |-------|-----------|------|---------| | none (default) | inherits --c-bg CSS var | inherits --c-tx1 | Drop into an existing dashboard | | phosphor | #060d06 | #33ff33 | Classic green CRT terminal | | amber | #0a0700 | #ffb000 | Amber phosphor | | paper | #f6f6f6 | #222 | Light / Lumen-style |

CSS custom properties (theme="none")

If no theme is set, the grid reads these variables from its parent — making it a natural fit alongside an existing :root / html.light token system:

--c-bg, --c-surface, --c-header, --c-tx1, --c-tx2, --c-tx4,
--c-border, --c-input

Contributing

See CONTRIBUTING.md for development setup, the Playwright regression-test suite, and the release process.


License

MIT — © stratchai