{"adoption": {"forks": 212, "observed_at": "2026-08-28T04:09:27.991869+00:00", "stars": 5693}, "canonical_url": "https://ross.abutalabs.com/products/perfect-freehand", "card": {"archived": false, "artifact_type": "library", "description": "Draw perfect pressure-sensitive freehand lines.", "domain": ["graphics", "web-development", "frontend"], "enriched": true, "function": ["graphics", "image-processing"], "health_score": 83, "homepage": "https://perfectfreehand.com", "language": "HTML", "license": "MIT", "license_family": "permissive", "maturity": "active", "member_repos": ["steveruizok/perfect-freehand"], "name": "steveruizok/perfect-freehand", "platform": ["browser", "cross-platform"], "pushed_at": "2026-04-13T04:44:47+00:00", "repo": "steveruizok/perfect-freehand", "stars": 5693, "tags": ["drawing", "freehand-strokes", "pressure-sensitivity", "svg", "html-canvas", "typescript", "stroke-generation", "nodejs"], "topics": ["pressure", "svg", "html-canvas", "drawing", "lines", "stroke", "graphics", "variable-width"], "urls": [], "use_cases": ["draw pressure-sensitive freehand lines in a web app", "build a digital whiteboard or note-taking sketch tool", "convert mouse or stylus input points into smooth variable-width strokes", "render hand-drawn strokes as SVG paths or canvas polygons", "add natural-looking pen strokes to a drawing application", "simulate pen pressure from mouse movement"], "what_it_is": "A TypeScript library that generates pressure-sensitive freehand stroke outlines from input points, exportable as polygons for rendering with SVG, HTML Canvas, or any other technology. It simulates or accepts real stylus pressure and offers customizable stroke appearance options.", "when_to_avoid": ["you need a full drawing application with layers, undo, or color tools", "you're working outside JavaScript/TypeScript without using one of the community ports", "you need vector editing or bezier manipulation rather than stroke generation"], "when_to_choose": ["you need realistic, pressure-sensitive freehand strokes in SVG or Canvas", "you want a small, framework-agnostic library that just returns outline points", "you're building a whiteboard, sketching, or annotation tool in the browser", "you want to support both stylus pressure and simulated mouse pressure"]}, "data_as_of": "2026-08-30T08:39:29.467469+00:00", "members": [{"path": "/products/perfect-freehand", "repo": "steveruizok/perfect-freehand", "role": "main", "score": 67}], "provenance": {"archived": {"kind": "observed", "observed_at": "2026-08-28T04:09:27.991869+00:00", "source": "github"}, "artifact_type": {"confidence": null, "enriched_at": "2026-08-29T17:53:43.660638+00:00", "kind": "inferred", "prompt_version": 1, "sources": [{"content_hash": "c6216eb85825cbd36d398f6b0b37dfe58048a576579796085a36476c7473d5d5", "fetched_at": "2026-08-28T04:09:27.991869+00:00", "kind": "readme", "missing": false, "url": "https://github.com/steveruizok/perfect-freehand"}, {"content_hash": "04244aac6e4d450f137c5f8610b97fcbc564be3d623e38e1845b3a9b11087ffe", "fetched_at": "2026-08-29T08:49:09.625093+00:00", "kind": "homepage", "missing": false, "url": "https://perfectfreehand.com"}], "taxonomy_version": 1}, "description": {"kind": "observed", "observed_at": "2026-08-28T04:09:27.991869+00:00", "source": "github"}, "domain": {"confidence": null, "enriched_at": "2026-08-29T17:53:43.660638+00:00", "kind": "inferred", "prompt_version": 1, "sources": [{"content_hash": "c6216eb85825cbd36d398f6b0b37dfe58048a576579796085a36476c7473d5d5", "fetched_at": "2026-08-28T04:09:27.991869+00:00", "kind": "readme", "missing": false, "url": "https://github.com/steveruizok/perfect-freehand"}, {"content_hash": "04244aac6e4d450f137c5f8610b97fcbc564be3d623e38e1845b3a9b11087ffe", "fetched_at": "2026-08-29T08:49:09.625093+00:00", "kind": "homepage", "missing": false, "url": "https://perfectfreehand.com"}], "taxonomy_version": 1}, "enriched": {"inputs": [], "kind": "computed", "method": "enrichment_status"}, "function": {"confidence": null, "enriched_at": "2026-08-29T17:53:43.660638+00:00", "kind": "inferred", "prompt_version": 1, "sources": [{"content_hash": "c6216eb85825cbd36d398f6b0b37dfe58048a576579796085a36476c7473d5d5", "fetched_at": "2026-08-28T04:09:27.991869+00:00", "kind": "readme", "missing": false, "url": "https://github.com/steveruizok/perfect-freehand"}, {"content_hash": "04244aac6e4d450f137c5f8610b97fcbc564be3d623e38e1845b3a9b11087ffe", "fetched_at": "2026-08-29T08:49:09.625093+00:00", "kind": "homepage", "missing": false, "url": "https://perfectfreehand.com"}], "taxonomy_version": 1}, "health_score": {"inputs": ["days_since_push", "days_since_release", "archived"], "kind": "computed", "method": "health_v1"}, "homepage": {"kind": "observed", "observed_at": "2026-08-28T04:09:27.991869+00:00", "source": "github"}, "language": {"kind": "observed", "observed_at": "2026-08-28T04:09:27.991869+00:00", "source": "github"}, "license": {"kind": "observed", "observed_at": "2026-08-28T04:09:27.991869+00:00", "source": "github"}, "license_family": {"inputs": ["license"], "kind": "computed", "method": "license_family"}, "maturity": {"confidence": null, "enriched_at": "2026-08-29T17:53:43.660638+00:00", "kind": "inferred", "prompt_version": 1, "sources": [{"content_hash": "c6216eb85825cbd36d398f6b0b37dfe58048a576579796085a36476c7473d5d5", "fetched_at": "2026-08-28T04:09:27.991869+00:00", "kind": "readme", "missing": false, "url": "https://github.com/steveruizok/perfect-freehand"}, {"content_hash": "04244aac6e4d450f137c5f8610b97fcbc564be3d623e38e1845b3a9b11087ffe", "fetched_at": "2026-08-29T08:49:09.625093+00:00", "kind": "homepage", "missing": false, "url": "https://perfectfreehand.com"}], "taxonomy_version": 1}, "member_repos": {"kind": "observed", "observed_at": "2026-08-28T04:09:27.991869+00:00", "source": "github"}, "name": {"kind": "observed", "observed_at": "2026-08-28T04:09:27.991869+00:00", "source": "github"}, "platform": {"confidence": null, "enriched_at": "2026-08-29T17:53:43.660638+00:00", "kind": "inferred", "prompt_version": 1, "sources": [{"content_hash": "c6216eb85825cbd36d398f6b0b37dfe58048a576579796085a36476c7473d5d5", "fetched_at": "2026-08-28T04:09:27.991869+00:00", "kind": "readme", "missing": false, "url": "https://github.com/steveruizok/perfect-freehand"}, {"content_hash": "04244aac6e4d450f137c5f8610b97fcbc564be3d623e38e1845b3a9b11087ffe", "fetched_at": "2026-08-29T08:49:09.625093+00:00", "kind": "homepage", "missing": false, "url": "https://perfectfreehand.com"}], "taxonomy_version": 1}, "pushed_at": {"kind": "observed", "observed_at": "2026-08-28T04:09:27.991869+00:00", "source": "github"}, "repo": {"kind": "observed", "observed_at": "2026-08-28T04:09:27.991869+00:00", "source": "github"}, "stars": {"kind": "observed", "observed_at": "2026-08-28T04:09:27.991869+00:00", "source": "github"}, "tags": {"confidence": null, "enriched_at": "2026-08-29T17:53:43.660638+00:00", "kind": "inferred", "prompt_version": 1, "sources": [{"content_hash": "c6216eb85825cbd36d398f6b0b37dfe58048a576579796085a36476c7473d5d5", "fetched_at": "2026-08-28T04:09:27.991869+00:00", "kind": "readme", "missing": false, "url": "https://github.com/steveruizok/perfect-freehand"}, {"content_hash": "04244aac6e4d450f137c5f8610b97fcbc564be3d623e38e1845b3a9b11087ffe", "fetched_at": "2026-08-29T08:49:09.625093+00:00", "kind": "homepage", "missing": false, "url": "https://perfectfreehand.com"}], "taxonomy_version": 1}, "topics": {"kind": "observed", "observed_at": "2026-08-28T04:09:27.991869+00:00", "source": "github"}, "urls": {"kind": "observed", "observed_at": "2026-08-28T04:09:27.991869+00:00", "source": "github"}, "use_cases": {"confidence": null, "enriched_at": "2026-08-29T17:53:43.660638+00:00", "kind": "inferred", "prompt_version": 1, "sources": [{"content_hash": "c6216eb85825cbd36d398f6b0b37dfe58048a576579796085a36476c7473d5d5", "fetched_at": "2026-08-28T04:09:27.991869+00:00", "kind": "readme", "missing": false, "url": "https://github.com/steveruizok/perfect-freehand"}, {"content_hash": "04244aac6e4d450f137c5f8610b97fcbc564be3d623e38e1845b3a9b11087ffe", "fetched_at": "2026-08-29T08:49:09.625093+00:00", "kind": "homepage", "missing": false, "url": "https://perfectfreehand.com"}], "taxonomy_version": 1}, "what_it_is": {"confidence": null, "enriched_at": "2026-08-29T17:53:43.660638+00:00", "kind": "inferred", "prompt_version": 1, "sources": [{"content_hash": "c6216eb85825cbd36d398f6b0b37dfe58048a576579796085a36476c7473d5d5", "fetched_at": "2026-08-28T04:09:27.991869+00:00", "kind": "readme", "missing": false, "url": "https://github.com/steveruizok/perfect-freehand"}, {"content_hash": "04244aac6e4d450f137c5f8610b97fcbc564be3d623e38e1845b3a9b11087ffe", "fetched_at": "2026-08-29T08:49:09.625093+00:00", "kind": "homepage", "missing": false, "url": "https://perfectfreehand.com"}], "taxonomy_version": 1}, "when_to_avoid": {"confidence": null, "enriched_at": "2026-08-29T17:53:43.660638+00:00", "kind": "inferred", "prompt_version": 1, "sources": [{"content_hash": "c6216eb85825cbd36d398f6b0b37dfe58048a576579796085a36476c7473d5d5", "fetched_at": "2026-08-28T04:09:27.991869+00:00", "kind": "readme", "missing": false, "url": "https://github.com/steveruizok/perfect-freehand"}, {"content_hash": "04244aac6e4d450f137c5f8610b97fcbc564be3d623e38e1845b3a9b11087ffe", "fetched_at": "2026-08-29T08:49:09.625093+00:00", "kind": "homepage", "missing": false, "url": "https://perfectfreehand.com"}], "taxonomy_version": 1}, "when_to_choose": {"confidence": null, "enriched_at": "2026-08-29T17:53:43.660638+00:00", "kind": "inferred", "prompt_version": 1, "sources": [{"content_hash": "c6216eb85825cbd36d398f6b0b37dfe58048a576579796085a36476c7473d5d5", "fetched_at": "2026-08-28T04:09:27.991869+00:00", "kind": "readme", "missing": false, "url": "https://github.com/steveruizok/perfect-freehand"}, {"content_hash": "04244aac6e4d450f137c5f8610b97fcbc564be3d623e38e1845b3a9b11087ffe", "fetched_at": "2026-08-29T08:49:09.625093+00:00", "kind": "homepage", "missing": false, "url": "https://perfectfreehand.com"}], "taxonomy_version": 1}}, "score": {"components": {"activity": 77, "longevity": 100, "rhythm": 36}, "computed_at": "2026-09-03T02:20:16.233290+00:00", "flags": [], "formula": "round(0.45*activity + 0.35*rhythm + 0.20*longevity); archived -> min(score, 10)", "inputs": {"age_days": 2021, "days_push": 142, "days_rel": 214, "gap_med": null, "n_releases_24m": 1}, "score": 67, "version": 2}, "staleness": {"enrichment_outdated": false, "low_confidence": false, "scrape_days": 9, "stale_scrape": false}}