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

@htmlbricks/hb-stylus-paper

v0.73.7

Published

Freehand drawing surface with modes (`draw`, `eraser`, `select`), brush `options`, `background_color` / `pen_color` / `pen_opacity`, and optional `load_draw`, `insert_image`, or `insert_text`. Supports `save_as`, `size`, `view`, `goto`, and events for str

Downloads

11,588

Readme

hb-stylus-paper — integrator guide

Category: inputs · Tags: inputs, drawing · Package: @htmlbricks/hb-stylus-paper · Custom element: hb-stylus-paper

Summary

hb-stylus-paper is a freehand drawing surface backed by SVG and perfect-freehand stroke smoothing. It supports draw, eraser, and select modes, configurable brush options, paper size, optional view (zoom and pan), and serialized payloads for loading drawings, inserting assets, and exporting JSON. Custom events report stroke lifecycle, selection rectangles, history index changes, saves, and load outcomes.

Layout metadata: this component is intended for fullscreen use in catalog tooling; give the host enough height and width for comfortable drawing.

Web component conventions

  • Attribute names use snake_case.
  • Booleans in HTML use the strings yes or no (for example debug).
  • Numbers (for example pen_opacity, goto) are passed as strings that the implementation parses.
  • Objects (options, size, view, load_draw, save_as, insert_image, insert_text) must be JSON strings when set from HTML or setAttribute, matching the shapes described below.

Attributes and props

| Attribute | Required | Description | |-----------|----------|-------------| | id | No | Logical instance id; echoed on events and in saved payloads. | | style | No | Optional host inline style (typed on the component interface). | | draw_id | No | Stable id for the current drawing session. If omitted, a random value with a timestamp suffix is generated. | | background_color | No | CSS color for the SVG background (default rgb(255,255,255)). | | pen_color | No | CSS color used for new strokes (default rgb(0,0,0)). | | pen_opacity | No | Stroke opacity; string or number coerced with Number() (default 1). | | mode | No | "draw" (default), "eraser", or "select". Leaving select clears the current selection highlight state. | | debug | No | "yes" shows a small debug readout (pointer type and button state); any other value is treated as no. | | options | No | JSON object: brush tuning for perfect-freehand. Defaults include size: 6, thinning: 0.7, smoothing: 0.5, streamline: 0.5. The implementation merges simulatePressure per pointer: false for pointerType === "pen", otherwise true, unless overridden in options. See Brush options. | | size | No | JSON TSize: requires paperSize (see Paper size); optional width / height for custom layouts. Default { "paperSize": "A4" }. | | view | No | JSON object: lockPan, lockZoom, zoom: { type: "fit" \| "custom", value: number }, pan: { x, y }. Defaults use fit zoom and zero pan with pan/zoom unlocked. | | goto | No | History index jump (coerced from string). Negative values reset internal formatting state; values are clamped to the loaded stroke count. After applying, the component emits changeIndex. | | load_draw | No | JSON TSave document: type, draw (array of IStroke), id, draw_id, name, version, size. When version or draw_id indicates a new document, strokes replace the canvas and drawLoaded / historyIndex fire. | | save_as | No | JSON { "name": string, "type": TSaveType }. Triggers export when strokes exist. Currently only type: "json" is implemented in the component; other TSaveType values log an error and do not emit save. | | insert_image | No | JSON { "name": string, "type": "png" \| "svg" \| "jpg" \| "jpeg", "uri"?: string, "base64"?: string }. Raster types enqueue an image stroke using base64 as href. svg is not fully wired (handler is a stub). On supported raster paths, imageLoaded fires with ok: true. Unsupported types do not dispatch imageLoaded. | | insert_text | No | JSON { "name": string, "content": string }. The handler is currently a stub (logging only); txtLoaded still fires with ok: true. |

Paper size

paperSize accepts the union defined in types/webcomponent.type.d.ts, including ISO sizes (A0A5, B0B6), North American names (letter, legal, tabloid, …), and custom. Internal layout logic explicitly maps A3 and A4 (default) to millimetre page dimensions for view calculations; other enum values should still be stored in save payloads for round-tripping.

Brush options

Logical fields follow TPerfectFreeHandOptions: size (required in typings when provided), optional thinning, smoothing, streamline, easing, simulatePressure, and optional start / end taper objects (taper, easing, cap). If options is parsed from JSON and omits numeric defaults, the component fills size, thinning, smoothing, and streamline from built-in defaults.

Interaction notes

  • Draw mode: primary button draws; each completed stroke increments the history index and emits endStroke then historyIndex.
  • Eraser: use mode="eraser", or in draw mode use stylus pressure 0 with primary button, or button 32 (middle / auxiliary), to erase by hitting stroke paths.
  • Select mode: drag a selection rectangle; strokes fully inside the box are marked selected and a selection event is emitted. Dragging inside an existing selection can group strokes into a multiplestroke entry for moving.

Events

Listen with addEventListener or framework bindings. Payloads match Events in types/webcomponent.type.d.ts.

| Event | detail (logical shape) | |-------|---------------------------| | startStroke | { id, draw_id, start: Date, stroke_id, index } — fired when a drawing gesture begins (twice on the first stroke of a session: once when the session start time is fixed, and again with the stroke start). | | endStroke | { id, draw_id, stroke_id, start, end, min, max, pathData, pen_color, index } — bounding box, SVG path data, and timestamps when the pointer releases after drawing. | | selection | { id, draw_id, minX, minY, maxX, maxY, strokes: IStroke[] } — rectangle in SVG coordinates and strokes whose bounds lie inside the box (only top-level stroke entries, not nested multipaths, in the strokes array). | | historyIndex | { id, draw_id, index, start_index? } — history cursor moved (new stroke, erase, load, etc.). | | changeIndex | { id, draw_id, index, start_index? } — emitted after a goto jump is applied. | | save | TSave — JSON export: type, draw, id, draw_id, name, version, size (only when save_as.type === "json" is handled). | | drawLoaded | { id, draw_id, index, start_index? } — after load_draw is applied. | | imageLoaded | { ok: boolean, error?: string, draw_id, id } — success after a supported raster insert_image; failures for unknown types do not currently emit this event. | | txtLoaded | { ok: boolean, error?: string, draw_id, id } — emitted after insert_text is processed (implementation stub). |

Authoring types: Events also declares beginStroke ({ date, id, draw_id }). The current component.wc.svelte implementation does not dispatch beginStroke; use startStroke for stroke lifecycle handling.

Styling (Bulma CSS variables)

The component uses Bulma 1.x inside the shadow root. Theme debug chrome by setting these variables on :host or an ancestor so they inherit onto the custom element (see extra/docs.ts).

| Variable | Role | |----------|------| | --bulma-size-small | Typography size for the debug banner when debug="yes". | | --bulma-scheme-main-bis | Background for the debug strip above the drawing surface. | | --bulma-radius | Corner radius on the debug panel. |

CSS ::part

None.

Slots

None.

Types reference

Stroke records (IStroke), save payloads (TSave, TSaveType), brush options (TPerfectFreeHandOptions), and the full Component / Events maps live in types/webcomponent.type.d.ts beside this package.

Minimal example

<hb-stylus-paper
  mode="draw"
  pen_color="rgb(0,0,0)"
  background_color="rgb(255,255,255)"
  pen_opacity="1"
  debug="no"
></hb-stylus-paper>

Example: brush options and JSON props

<hb-stylus-paper
  mode="draw"
  options='{"size":16,"thinning":0.7,"smoothing":0.5,"streamline":0.5}'
  size='{"paperSize":"A4"}'
></hb-stylus-paper>

Example: export JSON after drawing

Set save_as when you want a snapshot (for example from JavaScript after the user clicks Save):

const el = document.querySelector("hb-stylus-paper");
el.setAttribute(
  "save_as",
  JSON.stringify({ name: "sketch-1", type: "json" }),
);
el.addEventListener("save", (e) => {
  console.log(e.detail); // TSave
});

Only json export is implemented in the current build; choose other TSaveType values only if a future version adds encoders.