Public registry of HomeRunner widget plugins built and maintained by Hudson Creative Studio. Each plugin lives in its own subdirectory and ships a manifest.json plus a dist/ build for consumption by the HomeRunner dashboard (lavender) plugin loader.
This is the deployment surface — the lavender plugin admin (/plugins) registers plugins by manifest URL, which it fetches from this repo (or its hosted mirror).
- An admin visits the dashboard plugin page (
devdash.homerunner.io/pluginsin BETA,dashboard.homerunner.io/pluginsonce GA) and pastes the publicmanifest.jsonURL — for example,https://hudsoncreativestudio.github.io/homerunner-widget-plugins/property-spotlight/manifest.json. - The dashboard validates the manifest (id, version, semver, schema, asset URLs), creates a registry record, and approves it for use.
- Asset URLs in the manifest are path-relative (
dist/<slug>.iife.js, etc.), so the dashboard's asset proxy resolves them against the manifest origin — no manifest edits needed when promoting between staging and production. - Customers enable approved plugins per-feed and configure them through the dashboard's symbolic UI form (driven by
uiSchemainside the manifest).
Each plugin is a self-contained create-hr-plugin project. Source and release artifacts co-locate in the same directory so anyone browsing the repo (or asking an LLM about it) sees how the manifest, build, and source relate without jumping repos.
homerunner-widget-plugins/
├── README.md ← this file
├── <plugin-slug>/
│ ├── manifest.json ← root manifest (id, version, configSchema, uiSchema, asset URLs)
│ ├── package.json ← plugin source — npm scripts, deps
│ ├── package-lock.json
│ ├── tsconfig.json
│ ├── vite.config.ts
│ ├── index.html ← dev preview shell
│ ├── serve.js ← local production-style preview server
│ ├── vercel.json ← optional Vercel rewrite config
│ ├── .env.example
│ ├── src/ ← TypeScript / TSX source
│ │ ├── index.tsx ← client IIFE entry
│ │ ├── widget.tsx ← React component + getInitialData
│ │ ├── ssr.ts ← dehydrateState + getStaticAssets
│ │ ├── ssr-entry.ts
│ │ ├── config.ts ← zod widgetSchema.extend + uiSchema
│ │ ├── data.ts ← public-api fetchers
│ │ ├── widget.css ← Tailwind + plugin styles
│ │ └── components/ui/ ← shadcn-style UI components
│ ├── scripts/
│ │ └── inject-schema.mjs ← pre-build: zod → JSON Schema → manifest.json
│ ├── api/ ← optional Vercel serverless functions
│ └── dist/ ← committed build output (served by GitHub Pages)
│ ├── <slug>.iife.js
│ ├── <slug>.css
│ ├── <slug>-ssr.umd.js
│ ├── <slug>-<sha8>.{js,css} ← content-hashed twins for cache-busting
│ └── manifest.json ← build-hash file map (separate from root manifest.json)
└── ...
One directory per plugin. The directory name should match the plugin's id field (kebab-case slug). Don't rename a directory after a plugin is registered with the dashboard — the manifest URL is the stable identifier.
Why commit dist/: GitHub Pages serves the repo as static files, so the build output has to be in the tree to be reachable by the lavender renderer. Treat dist/ as a release artifact rather than a working directory — only land it via npm run build from the same commit that updates source, never hand-edit.
| Plugin | Slug | Version | Description |
|---|---|---|---|
| Property Spotlight | property-spotlight |
1.0.1 | Single-property hero with image carousel, key stats, top amenities, rating badge, and CTA. |
- Scaffold the plugin directly in this repo:
cd homerunner-widget-plugins && npx create-hr-plugin <slug>. Authoring + release happen in the same directory tree. - Edit
<slug>/src/to build out the plugin behavior. - From inside
<slug>/, runnpm install, thennpm run build. That producesdist/(with content-hashed twins) and updatesmanifest.jsonwith the injectedconfigSchema+uiSchema. - Commit the source changes and the regenerated
manifest.json+dist/together so the published manifest always points at assets that exist in the same commit. - Push to
main. GitHub Pages picks up the new files in roughly 60–90 seconds. - Register the manifest URL with a HomeRunner admin via the dashboard plugin page.
- Bump
versionin both<slug>/package.jsonand<slug>/manifest.json(semver — patch for fixes, minor for new options, major for breaking schema changes). - From inside
<slug>/, wipe the build (find dist -type f -delete && find dist -type d -empty -delete) and runnpm run build. A cleandist/guarantees no stale hashed twins from prior builds end up in the tree. - Commit source + manifest +
dist/together; push. - The dashboard's manifest cache is short (5 min in the renderer; the GitHub Pages
Cache-Controlismax-age=600) — once both expire, the new version is live without an admin action. For an immediate cutover, ask an admin to re-register or refresh the plugin record.
This repo is served via GitHub Pages (or an equivalent CDN). The lavender renderer requires:
- Public, unauthenticated HTTPS access to
manifest.jsonand every asset URL it references. - Stable URLs across plugin versions — versioning is handled inside the manifest (
versionfield plus content-hashed asset filenames), not by changing URLs. - CORS-permissive responses (GitHub Pages and most static hosts handle this by default).
If a plugin author wants to host elsewhere (their own CDN, Vercel project, FlyWP path), they can — this repo is the HCS-managed registry, not the only valid origin.
Each plugin carries its own license inside its directory. If a plugin is missing a LICENSE file, treat it as proprietary to Hudson Creative Studio.