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

hexo-sam-reader

v1.0.2

Published

SAM (Software Automatic Mouth) text-to-speech (TTS) reader widget for Hexo blog posts

Readme

hexo-sam-reader

A Hexo plugin that adds a SAM (Software Automatic Mouth) text-to-speech (TTS) reader widget to your blog posts. SAM reads your post content aloud.

See demo by going to blog.trintler.me, go to any post, and check the sidebar.

Made with love by trintlermint.

Installation

npm

npm install hexo-sam-reader

pnpm

use this if you have pnpm-lock.yaml instead:

pnpm install hexo-sam-reader

GitHub

npm install github:trintlermint/hexo-sam-reader

Clone

git clone https://github.com/trintlermint/hexo-sam-reader.git
npm install ./hexo-sam-reader

Usage

Enable SAM

Add sam: true to any given post's front matter:

---
title: my-post
date: 2026-01-01
sam: true
---

Add helper

In your theme's sidebar or meta partial (e.g. layout/_partial/post/meta.ejs), call the helper:

<%- sam_reader() %>

[!NOTE] I know this feels impractical to need to setup, however this is to allow more freedom for you, the end user.

The widget only renders on posts where sam: true is set.

Configuration

Add a sam_reader section to your site's _config.yml. All fields are optional and fall back to sensible defaults.

sam_reader:
  # Front matter key that enables SAM on a post for `sam:true` (default: 'sam')
  # if you change this, ensure you change the front matter on your posts to the key you changed to.
  front_matter_key: sam

  # CSS selector for the post content container
  content_selector: ".mypage" # for example, for default landscape theme use `".e-content"`

  # where bunddled generator.js is served (default: /js/hexo-sam-reader)
  asset_path: "/js/hexo-sam-reader"

  # Default voice settings (adjustable per-session via sliders) (resets to default after ctrl+r)
  # If you change the settings mid SAM talking, pause him and start him again to see change.
  # See https://discordier.github.io/sam/demos.html for demo
  speed: 72 # 20-200
  pitch: 64 # 0-255
  mouth: 128 # 0-255
  throat: 128 # 0-255

  # silence duration (ms) inserted between sections e.g. H1 -> H2
  pause_ms: 400

  # max characters per SAM chunk, longer text is split at sentence/comma boundaries
  chunk_max_length: 200

  # extra CSS selectors to skip when extracting text (comma-separated)
  # these are added to the built-in skip list (pre, script, style, .highlight, etc.)
  # this is so that SAM doesnt recite things which are irrelevant.
  skip_selectors: ".my-widget, .ad-banner"

  # abbreviation map: keys are matched as whole words and replaced before speaking.
  # all-cap keys are case-sensitive and mixed-case keys are case-insensitive.
  # this is important when sam-reader.js translates your stuff for sam.js to read
  abbreviations:
    SSH: "S S H"
    CLI: "C L I"
    API: "A P I"
    HTML: "H T M L"
    CSS: "C S S"
    LaTeX: "lay-tech"
    CMake: "see-make"

  # widget styling
  style:
    background: "#000"
    border_color: "#924a41"
    text_color: "#c08179"
    button_bg: "#352b42"
    button_hover_bg: "#924a41"
    button_active_bg: "#493aa5"
    button_active_border: "#867ade"
    progress_bg: "#252525"
    progress_bar: "#867ade"
    progress_border: "#3a3a3a"
    status_color: "#bbb"
    config_accent: "#867ade"
    font_family: "DOS, SimHei, Monaco, Menlo, Consolas, 'Courier New', monospace"

Abbreviations

The abbreviations map replaces whole-word matches before text is sent to SAM. This is useful for acronyms, technical terms, or any word SAM mispronounce.

[!TIP] You can just chek by testing SAM a ton of times, I will make a reliable list in the future.

abbreviations:
  # spell out acronyms
  ICPC: "I C P C" # for example, if this isnt done it will be pronounced as "ikpk", not what we want haha
  GPU: "G P U"
  WASM: "web assembly"
  LaTeX: "lay-tech"
  nginx: "engine-x"
  # shorthands
  "e.g.": "for example"
  "i.e.": "that is"

Styling

You only need to specify the colors you want to change. Unspecified values use the defaults.

# example: green-themed widget (like freemind.bithack!)
sam_reader:
  style:
    border_color: "#2d5a27"
    text_color: "#7ec876"
    button_bg: "#1a3a15"
    progress_bar: "#4caf50"
    config_accent: "#4caf50"

Text cleaning

The following transformations are always applied (not configurable): | Input | Spoken as | | ------------ | -------------------------- | | >= | "greater than or equal to" | | <= | "less than or equal to" | | != | "not equal to" | | === | "strictly equals" | | == | "equals" | | > | "greater than" | | < | "less than" | | / (spaced) | "OR" | | / | "slash" |

[!NOTE] I will be changing this from being not configurable but for me this is of most ease, wait for new releases please.

[!NOTE] URLs, email addresses, footnote markers such as ([^1]), and non-ASCII characters are stripped.

Inside out

  1. Generator; (lib/generator.js) serves the bundled sam.js library as a virtual Hexo asset at the configured asset_path.
  2. Helper; (lib/helper.js) renders the widget HTML/CSS/JS when <%- sam_reader() %> is called in a template.
  3. On the client side, the widget extracts text from the post content container, cleans it for sam.js, splits it into chunks, and plays them sequentially using the Web Audio API (see credits on how discordier did it.)

Credits

  • sam.js by discordier, JS port of SAM
  • Original SAM by Don't Ask Software (Mark Barton), 1982

License

MIT; 2026 Niladri Adhikary