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

@screenjoy/pocket-golf

v0.1.0

Published

A mouse-only pocket golf Screenjoy.

Readme

@screenjoy/pocket-golf

Mouse-only golf for Screenjoy. Play continuous generated holes at /golf or choose Pocket Golf in the gallery. The generation lab at /golf/lab retains repeatable layouts and feedback collection using the same aiming, three-click swing, ball flight, and putting controls.

Install and embed

npm install @screenjoy/pocket-golf
import '@screenjoy/pocket-golf';
<pocket-golf
  seed="2026"
  hole-index="0"
  style="width: 100%; aspect-ratio: 1;"
></pocket-golf>

Import from your site's JavaScript entry point using a package-aware bundler. The import registers the element automatically. No React component, Screenjoy app route, external stylesheet, image assets, or manual setup call is required. The package owns generation, rendering, swing controls, putting, hole transitions, and browser scores. Its only dependency is @screenjoy/runtime, installed with it. Match the host element's size to the space on your site; all game styling lives in its shadow root.

Use seed for a repeatable course and hole-index for its starting hole. Both accept HTML attributes or the seed and holeIndex JavaScript properties. Changing either starts a new hole without clearing completed totals. Unlike the passive savers, Pocket Golf keeps its approved swing timing fixed and does not expose a speed attribute. Surrounding controls such as fullscreen, copying a link, or the feedback lab are optional host UI.

The app keeps seed entry, replay, new-course, pause, sharing and fullscreen controls around the play area. Hole links reproduce the exact generator version, seed, index and settings. The URL follows the current hole; refreshing starts that hole at the tee. New visits without a hole link start a fresh random seed.

Drag the amber marker, or click terrain, to set direction and target power. Click Swing to start the meter, choose power on either the rise or return, then click in the green accuracy zone on the return. The meter starts at the accuracy centerline. Power stays at zero through the green zone, then rises from 0–100% beyond it. The target and locked-power markers use this same scale. The meter keeps bouncing until a power is selected. Late power selection waits for the next accuracy pass, with no jump in the meter. The larger ring marks carry; the small ring marks predicted rest. On the green, aim for the stopping point. Mistiming accuracy adds a small directional error; the centered timing window is forgiving. Missing the accuracy pass cancels without a stroke.

Water or out of bounds costs one penalty and returns the ball to its pre-shot position. Sand stops the ball and reduces the next shot's range. Putts can leave the green. Sinking a shot displays a result such as “Birdie · -1” for 2.2 seconds, then fades into the next generated hole. Next hole can advance immediately. The sequence retains its generator version and settings. Hover or focus the score to see completed holes.

Completed holes update one versioned localStorage record, screenjoy:pocket-golf:score:v1, containing cumulative score relative to par and holes played. An unfinished hole contributes nothing. Replaying a completed hole counts again only when it is completed again. Restarting, resizing, reconnecting, and fades cannot double-count completion. Invalid data is ignored. Blocked storage keeps totals in memory for the session; the app shows a notice. Lab scores are separate and never update the playing total. Simultaneous cross-tab writes are not merged atomically, and scores do not sync across devices.

Supports seed and hole-index, the shared fps, paused, and motion attributes, plus play(), pause(), and restart(). Restart replays the hole without clearing completed totals. Reduced motion replaces the timed meter with Take shot and resolves travel and view changes immediately. It still shows the result briefly before advancing; pausing or hiding the page suspends that countdown. motion="allow" opts back into animation.

Generation lab

Open /golf/lab. Use Next hole to sample the weighted mix or choose Straight, Gentle bend, Dogleg, or Islands. Hazards can be mixed, absent, water only, or sand only. Generate applies the controls; Next continues the settings of the hole currently on screen. Previous returns to recently viewed holes. Replay returns the current hole to its tee.

A hole address includes generator version, seed, index, requested shape and hazard mix. Copy hole link produces a URL that regenerates that address. Invalid or unsupported addresses produce a visible error. New sessions use g3, which retains g2's green-side bunkers and larger lakes, gives fairway priority over water, and cuts a rounded rough bank into overlapping water. The bank expands fairway outlines by four world units and uses the same terrain query for rendering and ball contact. Sand placement is unchanged. Use Original, Larger water, and Rough buffer to compare versions for the same seed and index. All retain the same tee, fairway, green, cup and par. Released generator versions remain reproducible; subsequent changes should use a new version.

Every generated candidate is checked for safe approach landings using the actual shot simulation. The base generator retries at most 24 times, then uses a deterministic safe fallback. The g2 hazard pass makes bounded placement attempts and retains the original hazards if a safe replacement does not fit. The lab labels fallbacks. Par is the checked number of approach shots plus two putts, bounded to 3–5. Show a checked landing route draws the validator's resting positions; it is one safe route, not a mandatory path or optimal solution.

Feedback has an overall verdict, optional tags and notes. Save feedback retains the exact address, a geometry fingerprint, terrain counts, and current ball/last-shot details. Draft notes stay attached to their hole while browsing within the tab. Saved feedback survives reloads. Copy feedback formats a report for the conversation; Export JSON downloads all saved records. Nothing is sent automatically. Storage failure leaves records in the tab with a visible export reminder; clipboard failure exposes selectable text.

The lab holds completed holes for review rather than automatically advancing. It continues to support the shared fullscreen control. Set review before connecting the element to isolate lab scores from saved play.

import { registerPocketGolf } from '@screenjoy/pocket-golf/element';
registerPocketGolf();
const golf = document.querySelector('pocket-golf');
golf.startCourse({ seed: 'greenskeeper', index: 12, layout: 'dogleg', hazards: 'water' });
const state = golf.getSnapshot();

startCourse(settings) starts a generated sequence. loadHole(hole) copies supplied geometry and resets the current shot while retaining completed totals. getSnapshot() returns a copy of the ball and last shot. getTotals() returns { version, score, holes }; scoreSaved reports whether browser persistence is available. holeAddress exposes the exact current replay address. The element emits holechange with { address, settings } and scorechange with { version, score, holes, saved }. review holds the completion screen; show-route displays the checked approach route. Calling restart() replays whichever hole is loaded.

The package depends only on @screenjoy/runtime. course.ts owns terrain queries and the approved deterministic shot calculation. generator.ts routes versioned requests to the preserved generator-v1.ts, hazard tuning in generator-v2.ts, or rough shoreline rules in generator-v3.ts. scores.ts owns saved totals and result names. reviews.ts owns feedback serialization. The renderer and shot preview use the same hole model; resizing and fullscreen do not change world coordinates.

Installation notes

Use a bundler such as Vite to resolve the npm import. The package is ESM and ships TypeScript declarations. For server rendering, register on the client after mount. Give the element explicit dimensions. The root entry registers the custom element; /element exposes manual registration.

paused is a boolean HTML attribute: paused="false" still pauses. Remove it or set the property to false. The runtime respects reduced motion and pauses when offscreen or the document is hidden. motion="allow" explicitly overrides reduced motion; leave it unset by default.

Licensed under MIT. Copyright 2026 Steven Partridge.