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

@scratch-code/block-spec

v0.1.0

Published

Semantic Scratch block specifications and an extensible registry

Readme

@scratch-code/block-spec

Semantic Scratch block specifications and an extensible registry. A spec describes the connections a block exposes and the initial content used to draw empty slots. It does not describe a block instance's current contents.

Installation

npm install @scratch-code/block-spec

This package is ESM-only and requires Node.js 22 or newer.

import { createBlockSpecRegistry, type BlockSpec } from '@scratch-code/block-spec';

const moveSteps: BlockSpec = {
  opcode: 'motion_movesteps',
  shape: 'command',
  inputs: {
    STEPS: {
      connection: 'value',
      accepts: 'number',
      default: {
        kind: 'input',
        type: 'number',
        value: 10,
        metadata: { scratch: { numericKind: 'number' } },
      },
    },
  },
  fields: {},
  arguments: [{ kind: 'input', name: 'STEPS' }],
  bindings: { scratchblocks: { blockId: 'MOTION_MOVESTEPS' } },
};

const registry = createBlockSpecRegistry();
registry.register(moveSteps);
registry.get('motion_movesteps'); // moveSteps

Connections and defaults

connection preserves the distinction between a value slot and a statement slot. accepts is a semantic constraint on a value slot; it is deliberately different from Input.type in @scratch-code/ast, which describes the content currently occupying a slot.

Defaults use AST Input nodes. Scalar shadows therefore retain details such as metadata.scratch.numericKind, while menu shadows can be represented by a complete BlockInput containing their opcode and fields. A statement slot may also have a BlockInput default, as used by a procedure definition's prototype.

arguments is the language-independent identity and canonical order of fields and inputs. It does not describe translated display order. Syntax codecs use explicit bindings such as bindings.scratchblocks.blockId; they do not infer identity from English message text. source.scratchBlocks and source.scratchVm record source-file provenance separately from scratchblocks-plus syntax bindings.

Field scratchblocks bindings contain only surface information the codec cannot infer, such as input shape and canonical dropdown label/value pairs. Raw Scratch Blocks args* definitions no longer carry ordering or identity responsibilities.

Hat blocks distinguish the curved, event-style hat from the flat procedure definition hat:

const definition: BlockSpec = {
  opcode: 'procedures_definition',
  shape: 'hat',
  hatStyle: 'define',
  inputs: { custom_block: { connection: 'statement' } },
  fields: {},
  arguments: [{ kind: 'input', name: 'custom_block' }],
};

Dynamic specs

Every registry entry has a stable base spec and may have a resolver. get always returns the base; resolve returns the context-dependent final spec. The context contains only semantic information chosen by the consumer. Turning an AST block into that context belongs in a converter or adapter package.

type StopContext = { hasNext: boolean };

const registry = createBlockSpecRegistry<StopContext>();
registry.register(baseStopSpec, (base, context) => ({
  ...base,
  shape: context.hasNext ? 'command' : 'terminal',
}));

registry.get('control_stop'); // stable baseStopSpec
registry.resolve('control_stop', { hasNext: false }); // terminal final spec

Resolvers run for every resolve call and must return the registered opcode. Use replace when intentionally replacing both a base spec and its resolver.

SB3 boundary

A future SB3 adapter can combine a resolved spec with an AST block. The spec provides connection requirements and default shadows; the AST provides current values, IDs, mutations, and source metadata. The adapter remains responsible for SB3 primitive codes, generated IDs, and parent/next/input relationships.

This package intentionally contains no built-in block definitions, global registry, SB3 adapter, or AST-to-context extractor.