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

@oval-vote/brand

v0.1.1

Published

The Oval design system: tokens, components, logo, and wordmark

Readme

Oval Brand

The design system for Oval, the plain-text format for voting guides, and for the organization that publishes it. Everything here is the source: the mark, the wordmark, the colors, the typefaces, the tokens, and the components that the website, the renderer, the editor, and the extension draw on. index.html shows all of it on one page and is published at brand.oval.vote.

The mark

The mark is a ballot oval, filled in: a printed ring, a gap of paper, and the voter's ink inside. The ellipse is 1.75 times as wide as it is tall. The ring is the marking purple and 0.075 of the height thick; the fill is ink, 0.65 of the height wide and 0.325 tall, centered. The gap between them is what makes it read as a marked ballot rather than a dot.

| File | Use | | --------------------------- | ---------------------------------------------------------------------------------- | | logo/mark.svg | The mark in color on light paper: ink fill, purple ring. | | logo/mark-reverse.svg | The mark in the dark palette, for dark paper. | | logo/mark-mono.svg | One color, taken from currentColor, for places that allow a single color. | | logo/mark-outline.svg | Both ellipses as strokes in currentColor, for an unfilled state. | | logo/wordmark.svg | "Oval" set in Instrument Serif as outlines, in ink. | | logo/wordmark-reverse.svg | The wordmark in the dark palette. | | logo/lockup.svg | The mark beside the wordmark, centered on the capitals. | | logo/lockup-reverse.svg | The lockup in the dark palette. | | logo/favicon.svg | A 32-pixel version with a thicker ring. | | logo/icon.svg | A square app icon: the mark on paper with rounded corners, 1024 pixels. | | logo/avatar.svg, .png | The square avatar for GitHub and other services that round the corners themselves. |

Every file in logo/ is generated by npm run logo from one geometry in scripts/logo.mjs, which downloads Instrument Serif from Google's fonts repository and outlines the word with fontkit, so the files contain no text and need no font installed. npm run avatar rasterizes the avatar. CI fails when either is stale.

On dark paper use the -reverse files. A page that follows the viewer's theme shows one or the other with a <picture> element and a prefers-color-scheme media query, or two images toggled by the same theme rules as the tokens, as index.html does.

Keep clear space of half the mark's height on every side. Do not show the mark smaller than 16 pixels tall (use the favicon below that), stretch it off its ratio, rotate it, add a shadow or gradient, place it on a pattern or photograph, or recolor it, least of all in party colors. Do not place it beside a candidate or party as if it were their bubble. The wordmark is always Instrument Serif; do not set the name in another face or add a tagline inside the lockup.

Color

The palette is a ballot: paper, ink, and the purple that marks it.

| Token | Light | Dark | Role | | -------------- | --------- | --------- | -------------------------------------------------------------------- | | paper | #f2f1ec | #131313 | Page background: warm stock in light, neutral graphite in dark. | | paper-raised | #fbfaf7 | #1c1c1c | A surface lifted from the page: a card, a callout, a control. | | paper-sunken | #e9e8e2 | #0d0d0d | A surface set into the page: code blocks, wells. | | ink | #17150f | #e8e6e1 | Text, the mark's fill, anything drawn in ink. | | ink-soft | #5f5b50 | #9a9892 | Secondary text: eligibility lines, metadata, captions, placeholders. | | rule | #cfccc2 | #2c2c2c | Hairlines, borders, table rules. | | mark | #8347ae | #b48ad9 | The marking purple: the ring, link underlines, focus rings, badges. | | mark-soft | #ebe1f4 | #2a2234 | A tint of purple for badge and hover backgrounds. | | support | #2e6b3a | #6cc07a | A supported campaign or a yes recommendation. | | support-soft | #e3efe4 | #1a2a1d | A tint of support for badge backgrounds. | | oppose | #c4343a | #ef6f72 | An opposed campaign or a no recommendation. | | oppose-soft | #f8e3e3 | #331c1d | A tint of oppose for badge backgrounds. |

Red and blue carry party meaning in American politics, so the accent is purple, which belongs to no party, and the only red is the one that means "against" on a specific question. Support is a green that is not a party color either. Never use mark to color a party, a candidate, or a position on a question; parties are labeled with their own abbreviations in ink.

Both themes are designed, not inverted. The purple is a different value per theme so that it passes as text on both papers: 5.3:1 on light and 6.7:1 on dark. Every text color reaches 4.5:1 on its paper; index.html tabulates the ratios.

Type

| Role | Family | Weights | Use | | ------- | ---------------------------------------------------------------------- | -------- | -------------------------------------------------------- | | Display | Instrument Serif | 400 | The wordmark and display-size headings only. | | Text | Newsreader | 400, 500 | Running text and headings. Variable, optical sizes 6–72. | | UI | Public Sans | 400, 600 | Labels, controls, badges, navigation, tables of data. | | Mono | IBM Plex Mono | 400, 500 | Oval source, identifiers, and code. |

Newsreader is a newspaper text face, which is where voting guides have lived for a century. Public Sans is the typeface of the United States Web Design System, so civic interfaces already read in it. Instrument Serif gives the name a voice of its own at large sizes and is not used for text. All four are open source and served from Google Fonts; tokens/oval.css names the fallback stacks.

The scale is display 4.5rem, h1 2.75, h2 2, h3 1.5, lead 1.375, body 1.125, mono 0.9375, small 0.875, label 0.75. Running text is at a line height of 1.5 on a measure of 44rem; headings are at 1.15; uppercase labels in Public Sans take 0.06em of letter spacing.

Space and shape

Spacing is a 4-pixel base: steps 1, 2, 3, 4, 6, 8, 12, 16, and 24, named by their multiple. Radii are small (0.125rem) for badges, control (0.25rem) for buttons and fields, card (0.5rem) for surfaces, pill, and oval (50%) for the bubble. Rules are 1px hairlines. There are no shadows; surfaces are raised by tone and a rule.

Components

css/components.css defines classes prefixed oval-, built only from the tokens: type roles (oval-display through oval-label and oval-mono), oval-link, buttons (oval-button with -secondary, -quiet, -small), fields (oval-field, oval-input, oval-select, oval-textarea, oval-field-note), badges (oval-badge with -support, -oppose, -mark), oval-card, callouts (oval-callout with -support, -oppose), oval-table, oval-code, and the ballot row (oval-ballot, oval-ballot-row, oval-bubble, oval-bubble-filled, oval-stance). The primary button is ink on paper and turns purple on hover; purple is never the resting color of a control. Focus is a 2px ring in the marking purple on every interactive element. Transitions are 150ms and drop to 0ms under prefers-reduced-motion.

Tokens

tokens/oval.css declares every value above as a custom property prefixed --oval-, with the dark values under prefers-color-scheme: dark and under [data-theme="dark"], so a page can follow the system or set a theme itself. tokens/oval.json is the same set as data, with a description on each token, for tools that generate from it.

Load the tokens, then the components if you want them, then the fonts:

<link rel="stylesheet" href="https://brand.oval.vote/tokens/oval.css" />
<link rel="stylesheet" href="https://brand.oval.vote/css/components.css" />
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link
  rel="stylesheet"
  href="https://fonts.googleapis.com/css2?family=Instrument+Serif&family=Newsreader:ital,opsz,wght@0,6..72,400;0,6..72,500;1,6..72,400&family=Public+Sans:wght@400;600&family=IBM+Plex+Mono:wght@400;500&display=swap"
/>

Voice

Oval's writing is plain and declarative, the register of a specification: short sentences, active voice, nouns people recognize. It does not pitch. The name is "Oval" in prose, .oval as a file extension, and oval as the command and the keyword; never "OVAL" or "oval" at the start of a sentence about the project.

Using the identity

The logo and wordmark identify the Oval project. Use them to refer to Oval, to show that a tool reads or writes the format, or to link to oval.vote. Do not use them to suggest that the project endorses a guide, a candidate, a party, or a position, and do not modify them.

License

The files in logo/ are licensed under CC BY-ND 4.0: copy and redistribute them unchanged, with attribution, and do not make derivatives. Everything else, including the tokens, the stylesheets, and the scripts, is licensed under the MIT License. Both texts are in LICENSE.

Developing

npm ci
npm run logo       # regenerates every file in logo/ from scripts/logo.mjs
npm run avatar     # regenerates logo/avatar.png from logo/avatar.svg
npm run check      # formatting and that the generated files are current; CI runs this

Open index.html in a browser to see the system on one page.

Publishing

Every push to main that passes npm run check deploys the page to GitHub Pages. npm run build assembles dist/ from index.html, logo/, tokens/, and css/, and the workflow uploads that directory, so nothing else in the repository is served.

The same files are published to npm as @oval-vote/brand, so a project can depend on the tokens and components instead of linking to the site:

npm install @oval-vote/brand
import "@oval-vote/brand/tokens/oval.css";
import "@oval-vote/brand/css/components.css";
import tokens from "@oval-vote/brand/tokens/oval.json" with { type: "json" };

A release is a tag. Set the version with npm version <version> --no-git-tag-version, commit, tag the commit v<version>, and push the tag. The release workflow runs the checks, confirms that the tag matches package.json, and publishes with provenance through trusted publishing, so no token is stored anywhere.