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

@wenhaoqi/wasm_design_utils

v0.1.1

Published

OKLCH ↔ sRGB in WebAssembly, image palette extraction, and squircle/capsule SVG paths — browser ESM.

Downloads

234

Readme

@wenhaoqi/wasm_design_utils

浏览器优先的 ESM 包:在 WebAssembly 中提供 sRGB ↔ OKLCH 转换、图片主色/调色板提取,以及 squircle / capsule 的 SVG d 路径。附带可在 macOS 上编译的 C 命令行工具extract-colors 使用 ImageIO / CoreGraphics 读图)。

English

仓库布局

| 路径 | 说明 | |------|------| | native/*.c | 算法与 CLI 源码 | | src/*.js | 浏览器端封装(通过 import.meta.url 加载 src/wasm/ 下的 WASM) | | src/wasm/*.wasm | Emscripten 构建产物(执行 make wasm;若未提交可从源码生成) | | bin/* | make native 生成的本地可执行文件(默认被 git 忽略) | | examples/minimal.html | 本地静态页演示(需 HTTP 访问;先构建 WASM) |

安装

npm install @wenhaoqi/wasm_design_utils

仅包含 ESM"type": "module")。TypeScript 可使用自带的 .d.ts

子路径导出

| 入口 | 用途 | |------|------| | @wenhaoqi/wasm_design_utils | 聚合导出(见下方 API) | | @wenhaoqi/wasm_design_utils/color | 仅 OKLCH ↔ sRGB | | @wenhaoqi/wasm_design_utils/extract-colors | 仅图片取色 | | @wenhaoqi/wasm_design_utils/squircle | 仅 squircle/capsule 路径 |

构建工具(Vite、Webpack 5+ 等)会把 src/wasm/*.wasm 作为资源打包。若 WASM 尚未生成,请在本仓库执行 make wasm,或将构建好的四个 .wasm 放到包的 src/wasm/ 中。


浏览器 API 概览

颜色:initrgb2oklchoklch2rgb_absoklch2rgb_rel

| 函数 | 作用 | |------|------| | init(options?) | 并行预加载 oklch2rgb.wasmrgb2oklch.wasm(幂等)。可选 oklch2rgbUrlrgb2oklchUrl(相对本模块或完整 URL)。 | | rgb2oklch(r, g, b) | sRGB 8 位通道 0–255 → { L, C, h }(L∈[0,1],h 为度)。 | | oklch2rgb_abs(L, C, h) | 绝对色度 OKLCH → { R, G, B }。 | | oklch2rgb_rel(L, h, rel) | 相对色度 rel∈[0,1]:在该 L、h 下使用色域内可达最大色度的比例(忽略单独传入的 C)→ { R, G, B }。 |

默认 WASM 路径为相对模块的 ./wasm/oklch2rgb.wasm./wasm/rgb2oklch.wasm

取色:extractColorsinitExtractColorsWasm

| 函数 | 作用 | |------|------| | initExtractColorsWasm(options?) | 预加载 extract-colors.wasm;可选 wasmUrl。 | | extractColors(input, opts?) | 从 URL 字符串HTMLImageElementImageData(或 { data, width, height })提取调色板。返回若干 { hex, red, green, blue, hue, intensity, lightness, saturation, area, … },排序与实现一致。 |

常用选项:pixelsdistancesaturationDistancelightnessDistancehueDistancecrossOrigincolorValidator(r,g,b,a)

平滑圆角路径:initSquircleWasmgetSquirclegetCapsulegetPath

| 函数 | 作用 | |------|------| | initSquircleWasm(options?) | 预加载 squircle-svg.wasm;可选 wasmUrl。 | | getSquircle(w, h, r) | 返回 squircle 形状的 SVG path d 字符串。 | | getCapsule(w, h, r) | 返回 capsule 形状的 SVG path d 字符串。 | | getPath(shape, w, h, r) | shape'squircle''capsule' 时委托上述二者。 |


JavaScript 用法(逐 API)

可使用包根或子路径导入,例如 "@wenhaoqi/wasm_design_utils""@wenhaoqi/wasm_design_utils/color"

颜色

init(options?)

预热两块颜色 WASM;也可不设:首次调用转换函数时会自动加载。

import { init } from "@wenhaoqi/wasm_design_utils";

await init();

自定义 WASM 地址(完整 URL 或由打包工具解析的路径):

await init({
  oklch2rgbUrl: new URL("./assets/oklch2rgb.wasm", import.meta.url).href,
  rgb2oklchUrl: "https://cdn.example.com/rgb2oklch.wasm",
});

rgb2oklch(r, g, b)

import { rgb2oklch } from "@wenhaoqi/wasm_design_utils";

const { L, C, h } = await rgb2oklch(255, 128, 64);
// L ∈ [0,1],C ≥ 0,h 为度(C≈0 时 h 视为 0)

oklch2rgb_abs(L, C, h)

import { oklch2rgb_abs } from "@wenhaoqi/wasm_design_utils";

const { R, G, B } = await oklch2rgb_abs(0.63, 0.25, 29.2);

oklch2rgb_rel(L, h, rel)

import { oklch2rgb_rel } from "@wenhaoqi/wasm_design_utils";

// rel ∈ [0,1]:当前 L、h 下可达最大色度所占比例
const { R, G, B } = await oklch2rgb_rel(0.7, 40, 0.5);

取色

initExtractColorsWasm(options?)

import { initExtractColorsWasm } from "@wenhaoqi/wasm_design_utils";

await initExtractColorsWasm();

await initExtractColorsWasm({
  wasmUrl: new URL("./wasm/extract-colors.wasm", import.meta.url).href,
});

extractColors(input, opts?)

import extractColors from "@wenhaoqi/wasm_design_utils/extract-colors";

// 已解码的 <img> / Image / 画布位图
const swatches = await extractColors(document.querySelector("#photo"));
// 图片 URL(跨域时需配置 crossOrigin)
const fromHttp = await extractColors("https://example.com/photo.jpg", {
  crossOrigin: "anonymous",
});
// 聚类与抽样参数(默认值与实现一致)
const tuned = await extractColors(img, {
  pixels: 64000,
  distance: 0.22,
  saturationDistance: 0.2,
  lightnessDistance: 0.2,
  hueDistance: 1 / 12,
});
// 聚类前过滤像素
const maskBg = await extractColors(img, {
  colorValidator: (r, g, b, a) => a > 128,
});

每个色块包含 hexredgreenbluehueintensitylightnesssaturationarea 等字段。

Squircle / capsule

initSquircleWasm(options?)

import { initSquircleWasm } from "@wenhaoqi/wasm_design_utils";

await initSquircleWasm();

await initSquircleWasm({
  wasmUrl: new URL("./wasm/squircle-svg.wasm", import.meta.url).href,
});

getSquircle(width, height, radius)

import { getSquircle } from "@wenhaoqi/wasm_design_utils";

const d = await getSquircle(200, 120, 16);

getCapsule(width, height, radius)

import { getCapsule } from "@wenhaoqi/wasm_design_utils";

const d = await getCapsule(300, 80, 24);

getPath(shape, width, height, radius)

import { getPath } from "@wenhaoqi/wasm_design_utils";

const squircleD = await getPath("squircle", 200, 120, 16);
const capsuleD = await getPath("capsule", 200, 120, 16);

组合示例(纯 ESM)

import {
  init,
  rgb2oklch,
  oklch2rgb_abs,
  extractColors,
  getPath,
} from "@wenhaoqi/wasm_design_utils";

await init();
const { L, C, h } = await rgb2oklch(128, 100, 231);
const rgb = await oklch2rgb_abs(L, C, h);

const img = document.querySelector("#photo");
const palette = await extractColors(img, { pixels: 64000 });

const d = await getPath("squircle", 200, 120, 16);
document.querySelector("path").setAttribute("d", d);

仅子路径导入:

import { oklch2rgb_rel } from "@wenhaoqi/wasm_design_utils/color";
import extractColors from "@wenhaoqi/wasm_design_utils/extract-colors";
import { getCapsule } from "@wenhaoqi/wasm_design_utils/squircle";

React(仅客户端)

import { useEffect, useState } from "react";
import { init, rgb2oklch } from "@wenhaoqi/wasm_design_utils";

export function OklchChip({ r, g, b }) {
  const [label, setLabel] = useState("…");

  useEffect(() => {
    let cancelled = false;
    (async () => {
      await init();
      const { L, C, h } = await rgb2oklch(r, g, b);
      if (!cancelled) setLabel(`oklch(${L.toFixed(3)} ${C.toFixed(3)} ${h.toFixed(1)})`);
    })();
    return () => { cancelled = true; };
  }, [r, g, b]);

  return <span style={{ fontFamily: "monospace" }}>{label}</span>;
}

在 Next.js 等环境中请仅在 客户端 使用动态 import() 加载本包(依赖 fetch / Image / WASM)。


发布到 npm

包名为 @wenhaoqi/wasm_design_utils(作用域包)。package.json 中已配置 "publishConfig": { "access": "public" },便于在 npm 上发布为公开包。

发布到 npm 的压缩包必须包含 src/wasm/ 下的四个 .wasm 文件(oklch2rgb.wasmrgb2oklch.wasmextract-colors.wasmsquircle-svg.wasm)。在执行 npm publish 前任选其一:

  1. **做法 A — 提交 WASM:**在本机执行 make wasm(需安装 Emscripten,且 emccPATH 中),再把生成的 src/wasm/*.wasm 提交进仓库;或
  2. 做法 B — 发布时再编:在已安装 emcc 的机器上执行 npm publishprepublishOnly 会运行 scripts/ensure-wasm-built.js:若缺少上述文件则自动执行 make wasm

若两种条件都不满足,npm publish 会失败并提示原因,避免发出不含 WASM 的损坏包。

npm login
npm publish

本地可先运行 node scripts/ensure-wasm-built.js 检查 WASM(与 prepublishOnly 逻辑一致)。


本地开发与构建

Makefile(推荐)

首次在本机构建 WASM、且系统里没有全局 emcc 时:

npm run setup:wasm

会在 ./emsdk/ 克隆官方 SDK(已被 git 忽略)、安装最新 Emscripten 并执行 make wasm。之后可直接:

source emsdk/emsdk_env.sh
make wasm
# 生成 bin/* 与 src/wasm/*.wasm,并运行烟测
make all

make native   # 仅 macOS 本地 CLI → bin/
make wasm     # 需 PATH 中有 emcc,或先用上面的 emsdk_env.sh
make test
make clean
  • 原生 extract-colors 依赖 macOSImageIOCoreGraphicsCoreFoundation
  • WASM 使用 -s STANDALONE_WASM=1、无胶水脚本,导出符号见 Makefile

一键脚本

./scripts/build_all.sh

演示页

make wasm
python3 -m http.server 8000
# 打开 http://localhost:8000/examples/minimal.html

命令行工具(make native

| 命令 | 说明 | |------|------| | bin/rgb2oklch R G B | 输出 L C h(文本) | | bin/oklch2rgb L C h [rel] | 输出 R G B;可选第四参数相对色度 0–1 | | bin/extract-colors <图片> | JSON 调色板(与 Web 端同源算法) | | bin/squircle_svg squircle|capsule W H R | 打印 SVG path |


许可

MIT,见 LICENSE