SugarStitch is a local-first Node/TypeScript scraper for fiber arts pattern websites. It is meant to support a few related workflows without forcing users into one style of use:
- scrape one known pattern page
- scrape many known pattern pages from a list
- start from a listing or archive page, discover child links, and scrape the discovered pattern pages
- preview extraction before saving files
The project supports both a command-line interface and a simple browser UI so the same scraping engine can be used by both technical and non-technical users.
At a high level, SugarStitch now supports:
- CLI scraping
- CLI startup banner
- local browser UI
- light/dark mode toggle in the UI
- selector presets
- one-off selector overrides
- saved site profiles
- preview mode
- output directory selection
- discovery crawl mode
- crawl language filtering
- crawl pagination support for listing pages with regular paginated URLs
- duplicate detection by
sourceUrl - plain-text pattern artifact generation
- PDF and image downloading
The project is split into three main layers:
-
Shared scraping engine File:
src/scraper.ts -
CLI wrapper File:
src/index.ts -
Local browser UI File:
src/server.ts
The shared scraper owns the real behavior. The CLI and UI should stay as thin adapters around that logic.
-
src/scraper.tsShared types, selector presets, saved profile loading, preview logic, discovery crawl logic, pagination expansion, language filtering, page scraping, file downloads, and JSON append behavior. -
src/index.tsCLI argument parsing, URL source handling, output path resolution, crawl option collection, and handoff into the shared scraper. -
src/server.tsSmall Node HTTP server that renders the HTML UI, serves local branding assets, handles preview/scrape form posts, manages loading-state UX, and returns result pages. -
sugarstitch.profiles.jsonStarter saved profile config file. The UI and CLI know how to load profiles from it by default. -
README.mdUser-facing usage guide. -
CHANGELOG.mdRelease-oriented change history. -
scripts/add-shebang.jsAdds a Node shebang to the built CLI entrypoint after TypeScript compilation. -
package.jsonPackage metadata, scripts, executablebinentry, and dependency definitions.
The shared scraper currently handles:
- selector preset definitions
- selector override sanitization and merging
- saved site profile loading
- run strategy resolution
- URL normalization and deduplication
- preview extraction
- bounded discovery crawl
- crawl language filtering
- pagination seed expansion for listing pages
- image and PDF download handling
- plain-text pattern artifact generation
- output JSON loading and append behavior
- duplicate
sourceUrlprevention
If a feature changes what SugarStitch actually scrapes or how it discovers pages, it should usually begin in src/scraper.ts.
The selector system has three layers:
-
Built-in preset Examples:
generic,wordpress,woocommerce -
Optional saved profile Loaded from a JSON config file and typically used for site-specific tuning
-
Optional one-off overrides Per-run selector overrides that replace only the fields provided
Resolution order:
- choose preset
- optionally load saved profile
- merge profile overrides
- merge one-off overrides last
That means:
- one-off overrides win over profile values
- profile values win over the base preset
Preview mode exists to answer:
“Before I download anything, what does SugarStitch think this page contains?”
The preview flow:
- resolve preset/profile/override strategy
- fetch the page HTML
- run selector extraction
- return title, description, materials, instructions, image URLs, and PDF URLs
- also derive a fuller page-text block for plain-text artifact output
- do not write JSON
- do not download assets
This is the safest way to validate selectors on a new site.
Discovery crawl mode is for archive or listing pages where the real patterns live deeper in the site.
The crawl flow:
- start from one or more seed URLs
- optionally expand paginated listing pages
- fetch page HTML
- collect link targets from
a[href] - resolve them to absolute URLs
- optionally restrict to the same domain
- optionally restrict by language
- optionally filter by URL or link text pattern
- stop at the configured depth and max-URL limits
- pass the discovered URLs into the normal scrape flow
Important:
- crawl mode is intentionally bounded
- it is not meant to be a full general-purpose spider
- it is designed to help discover likely pattern pages from listing pages
Some sites expose multiple language sections from the same listing page. For example:
- English archive page
- French archive page
- Portuguese archive page
The crawler can now prefer one language when discovered URLs clearly indicate a language, either by query string or pathname conventions. This helps avoid mixing multiple language archives into a single run.
This is especially useful for sites like Tilda where a top-level page links to multiple language-specific pattern sections.
Some sites use a Load More interaction in the UI, but also expose those later batches as normal paginated URLs.
SugarStitch now supports pagination-aware crawl seeding:
- inspect the seed page for listing pagination hints
- detect max page counts where possible
- add
/page/2/,/page/3/, and similar listing pages up to a configured cap - continue crawl discovery from those expanded listing pages
This works well when the site exposes traditional archive pages even if the visual UI presents them as a load-more interaction.
Each successful page becomes a PatternData object with:
titledescriptionmaterialsinstructionssourceUrllocalImageslocalPdfslocalTextFile
Output behavior:
- JSON is appended to an output file
- duplicate
sourceUrlentries are skipped before re-scraping - downloaded images go into
images/<sanitized-title>/ - downloaded PDFs go into
pdfs/<sanitized-title>/ - extracted page text is written to
texts/<sanitized-title>/pattern.txt - all of that lives under the selected output directory
The UI is intentionally simple and server-rendered.
Key design choices:
- no frontend framework
- HTML assembled on the server
- form-submit workflow instead of a client-side app
- loading overlay and spinner so long requests feel active
- persisted light/dark theme toggle with light mode as the default
- result pages returned after preview or scrape completion
Why it is structured this way:
- easy to maintain
- easy to inspect
- minimal dependencies
- keeps most logic in the shared scraper instead of duplicated client code
The CLI acts as a thin adapter over the shared scraper. It currently handles:
- mutual exclusion of
--urland--file - URL list loading from files
- output path and output directory resolution
- crawl option parsing
- startup banner rendering
- preview vs full scrape routing
If behavior is purely about command syntax or argument ergonomics, it belongs in src/index.ts.
A “successful” scrape does not mean every field matched.
Examples of valid successful runs:
- title plus PDF download only
- title plus images only
- title, description, and article content with no PDF
This matters because some fiber arts sites store the actual pattern inside a PDF, while others use a blog-post layout with visible HTML content.
- selector quality is site-dependent
- some sites render important content with JavaScript after load
- browser security means the UI uses an output-directory path field rather than a native folder picker
- the crawler is bounded and heuristic-based, not exhaustive
- HTTPS certificate issues on some environments can affect preview or scrape runs against certain sites
- pagination support currently assumes the site exposes discoverable regular listing pages rather than a fully hidden API-only load-more flow
If development continues, strong candidates include:
- richer site-specific profile library
- selector test diagnostics showing which selector matched which field
- live streaming logs in the UI instead of request/response-only updates
- optional desktop wrapper if native folder selection becomes important
- export options beyond JSON
- more explicit crawl diagnostics for why a URL was followed or skipped
- support for sites whose load-more behavior only exists through AJAX or browser interaction
npm run buildnpm run scrape -- --url "https://example.com/pattern"npm run uiIf scraping quality is the issue:
- edit
src/scraper.ts
If CLI behavior is the issue:
- edit
src/index.ts
If UI workflow or local-browser UX is the issue:
- edit
src/server.ts
If site-specific defaults are the issue: