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

sanity-canvas-skill

v0.3.2

Published

Read and write Sanity Canvas documents. Markdown ↔ Portable Text conversion with diff-based push.

Readme

Canvas Writer

Create and update Sanity Canvas documents programmatically.

Includes a reusable TypeScript library for markdown ↔ Canvas Portable Text conversion, and a CLI tool for reading/writing Canvas documents directly.

How It Works

Canvas documents live in a resource (not a regular Sanity project/dataset). The CLI uses @sanity/client with a special resource config to talk directly to the Canvas API.

The conversion library handles mapping between standard markdown and Canvas-specific Portable Text block types:

| Markdown | Canvas PTE Type | |---|---| | Paragraphs, headings, blockquotes | block (with style) | | Bold, italic, code, strikethrough | span marks (strong, em, code, strike-through) | | Bullet/numbered lists | block with listItem | | Links [text](url) | link annotation with href | | Code blocks ```lang ``` | canvasCode (lines as nested blocks) | | Images ![alt](url) | canvasImage (ephemeral src) | | Horizontal rules --- | canvasDivider |

What an Agent Needs From the User

To write to Canvas, an agent needs two things:

  1. A Sanity auth token — a global token (not project-scoped). Set as SANITY_TOKEN environment variable. The user can generate one at sanity.io/manage.

  2. A Canvas resource ID — identifies which Canvas workspace to write to. The user can find this by:

    • Going to canvas.sanity.io and looking at the URL path, OR
    • Using the Canvas API: GET https://api.sanity.io/vX/canvases?organizationId={orgId} returns resources with an id field.

That's it. With those two values, the agent can create, read, update, and delete Canvas documents.

Setup

# Clone and install
git clone [email protected]:snorrees/canvas-writer-studio.git
cd canvas-writer-studio
pnpm install

# Set your Sanity token
export SANITY_TOKEN="your-global-sanity-token"

CLI Usage

All commands require --resource <id> to specify the Canvas resource.

# List all documents
pnpm canvas --resource <resourceId> list
pnpm canvas --resource <resourceId> list --search "query"

# Read a document
pnpm canvas --resource <resourceId> read <docId>

# Create a new document from markdown
echo "# Hello World" | pnpm canvas --resource <resourceId> create "My Document"

# Set (replace) content from markdown
cat article.md | pnpm canvas --resource <resourceId> set <docId> content

# Set (replace) notes from markdown
cat notes.md | pnpm canvas --resource <resourceId> set <docId> notes

# Set title
pnpm canvas --resource <resourceId> set <docId> title "New Title"

# Append to content
cat extra.md | pnpm canvas --resource <resourceId> append <docId> content

# Append to notes
cat extra.md | pnpm canvas --resource <resourceId> append <docId> notes

# Delete a document
pnpm canvas --resource <resourceId> delete <docId>

Library API

The conversion functions can be imported directly for use in other tools:

import {markdownToCanvas} from './src/lib/markdownToCanvas'
import {canvasToMarkdown} from './src/lib/canvasToMarkdown'

// Markdown → Canvas Portable Text blocks
const blocks = markdownToCanvas('# Hello\n\nA paragraph with **bold**.')

// Canvas Portable Text blocks → Markdown
const markdown = canvasToMarkdown(blocks)

Development

# Run tests (37 tests covering all block types + roundtrip)
pnpm test

# Type check
pnpm typecheck

# Regenerate types after schema changes
pnpm typegen

# Lint
pnpm lint

# Build Studio
pnpm build

# Deploy Studio
pnpm deploy

Project Structure

src/
  lib/
    markdownToCanvas.ts    # Markdown → Canvas PTE conversion
    canvasToMarkdown.ts    # Canvas PTE → Markdown conversion
    __tests__/
      canvasMarkdown.test.ts  # 37 vitest tests
  scripts/
    canvas-write.ts        # CLI tool
  schemaTypes/             # Canvas document schema (mirrors sanity-io/canvas)
  components/
    SyncToCanvasInput.tsx   # Studio sync component (browser-side)
  structure.ts             # Custom Studio structure
  sanity.types.ts          # Generated types (via pnpm typegen)
sanity.config.ts           # Studio config
sanity.cli.ts              # CLI config + typegen config
schema.json                # Extracted schema (for typegen)

Studio

This repo also includes a Sanity Studio deployed at canvas-writer.sanity.studio. The Studio mirrors the Canvas schema and includes a sync component that can push documents to Canvas from the browser. The CLI approach is generally more useful for agents.