@happyvertical/smrt-playground
Shared playground discovery, runtime helpers, and host components for SMRT UI packages. Discovers per-package ./playground modules and renders them under a unified host.
Overview
smrt-playground is the canonical playground host for SMRT UI packages. Each
UI-shipping package exports a ./playground subpath; the host discovers them at
build time, merges them into a unified registry, and renders the entries through a shared PlaygroundHost Svelte component.
Installation
npm install @happyvertical/smrt-playgroundThe ./playground Subpath Contract
Each UI-shipping package opts in by exporting a ./playground subpath that
resolves to a module shaped like SmrtPlaygroundModule:
// packages/<name>/src/svelte/playground.ts
import type { SmrtPlaygroundModule } from '@happyvertical/smrt-playground';
const playground: SmrtPlaygroundModule = {
packageName: '@happyvertical/smrt-<name>',
// Optional: displayName, description, moduleMeta
entries: [
{
id: '<name>:component-id',
title: 'Human-readable title',
description: 'Optional short description.',
loadComponent: () => import('./components/MyComponent.svelte'),
// Optional:
order: 1,
props: { /* default props passed to the component */ },
// modes is a map keyed by 'mock' | 'live'
modes: { mock: { label: 'Mock' } },
},
],
};
export default playground;The package's package.json exports map must point ./playground at the
compiled module:
{
"exports": {
"./playground": {
"types": "./dist/playground.d.ts",
"import": "./dist/playground.js"
}
}
}Quick Start (Vite Plugin)
// vite.config.ts in your playground host app
import { smrtPlaygroundVitePlugin } from '@happyvertical/smrt-playground/vite';
import { sveltekit } from '@sveltejs/kit/vite';
export default {
plugins: [
sveltekit(),
smrtPlaygroundVitePlugin({
// All options are optional.
// mode: 'auto' (default) | 'workspace' | 'consumer'
mode: 'auto',
// workspaceRoot, packagesPattern, localPlaygroundPath
}),
],
};Render the Host
<!-- src/routes/+page.svelte -->
<script lang="ts">
import { PlaygroundHost } from '@happyvertical/smrt-playground/svelte';
import { playgroundModules } from 'virtual:smrt-playground/modules';
</script>
<PlaygroundHost modules={playgroundModules} />CLI Commands
The smrt playground commands are owned by @happyvertical/smrt-cli but
delegate to this runtime:
# Scaffold a playground host app
npx smrt playground init
# Run the playground in dev mode
npx smrt playground dev
# List discovered playground entries
npx smrt playground listModule Anatomy
discovery.ts— finds package-owned./playgroundmodules across workspace andnode_modulesruntime.ts— coerces and merges discovered modules into a unified registry consumed by the hosttemplates.ts— generates Svelte route templates for app-level and package-level playground hostssvelte/PlaygroundHost.svelte— the host component that renders discovered playground entriesvite.ts— Vite plugin used by the SvelteKit playground host to wire everything together
UI Surface Levels
smrt-playground is one of three UI surfaces a SMRT package may expose. From the
monorepo's docs/ui-surfaces.md:
./svelte— reusable components (ContentEditor,ArticleCard, etc.)./playground— preview metadata for the shared playground host (the standard for SMRT packages with Svelte components)./routes— package-owned page/workflow surfaces (not standardized for this release)
smrt-playground only discovers and renders. Component code and theming
live in individual packages (smrt-content/svelte, smrt-jobs/svelte,
etc.) or in smrt-svelte for shared primitives.
Gotchas
DOs
- Keep playground modules tiny — only metadata + dynamic
load() - Use the
idprefix convention<package-name>:<component>for uniqueness - Provide fixtures for components that require non-trivial input
- Expose
./playgroundinpackage.jsonexports — discovery relies on it
DON'Ts
- Don't ship component source from
smrt-playground— it's a host, not a component library - Don't import
smrt-playgroundinternals from individual packages — only the type surface is public - Don't rely on the private
host/directory — it's a Playwright e2e harness, not published - Don't conflate
./playgroundwith./routes— the former is preview metadata, the latter would be reusable app surfaces