Nychthemeron/docs/superpowers/plans/2026-05-11-library-with-playground.md
Matthew L McPeak 302a58c258
Some checks failed
ci / build (push) Failing after 21s
ci / publish (push) Has been skipped
ci / publish-docs (push) Has been skipped
Inital Commit
2026-07-15 20:01:01 -04:00

14 KiB

Library with Playground Implementation Plan

For agentic workers: REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (- [ ]) syntax for tracking.

Goal: Transform nychthemeron into a monorepo with a Vue component library (with PrimeVue + Tailwind) and interactive Storybook playground.

Architecture: Bun workspaces manage two independent packages — library (builds to ESM) and playground (Storybook dev server and static build). Shared configs at root level.

Tech Stack: Vue 3, PrimeVue, Tailwind CSS, Vite, Storybook, Vitest, TypeScript, Bun workspaces


Task 1: Create monorepo directory structure

Files:

  • Create: packages/library/ directory

  • Create: packages/playground/ directory

  • Step 1: Create packages directories

mkdir -p packages/library/src/{components,composables}
mkdir -p packages/library/__tests__
mkdir -p packages/playground/.storybook
mkdir -p packages/playground/stories
  • Step 2: Verify structure
ls -la packages/
# Expected output shows: library/ and playground/ directories

Task 2: Move existing source to library package

Files:

  • Move: src/packages/library/src/

  • Delete: vite.config.ts, vitest.config.ts, index.html (will recreate in packages)

  • Step 1: Move src directory

mv src packages/library/src
  • Step 2: Verify move
ls packages/library/src/
# Expected: App.vue, main.ts, __tests__/
  • Step 3: Delete old root-level config files
rm vite.config.ts vitest.config.ts index.html

Task 3: Update root package.json for monorepo

Files:

  • Modify: package.json

  • Step 1: Add workspaces and update root config

Replace the entire package.json with:

{
  "name": "nychthemeron",
  "version": "0.0.0",
  "private": true,
  "type": "module",
  "workspaces": [
    "packages/*"
  ],
  "scripts": {
    "dev": "bun -r --cwd packages/playground dev",
    "build": "bun -r --cwd packages/library build && bun -r --cwd packages/playground build",
    "preview": "bun -r --cwd packages/playground preview",
    "type-check": "vue-tsc --build",
    "lint": "eslint packages/*/src --fix",
    "format": "prettier --write --experimental-cli packages/*/src",
    "test": "bun -r --cwd packages/library test:unit"
  },
  "devDependencies": {
    "@tsconfig/node24": "^24.0.4",
    "@types/jsdom": "^28.0.1",
    "@types/node": "^24.12.2",
    "@vitejs/plugin-vue": "^6.0.6",
    "@vitest/eslint-plugin": "^1.6.16",
    "@vue/eslint-config-typescript": "^14.7.0",
    "@vue/test-utils": "^2.4.6",
    "@vue/tsconfig": "^0.9.1",
    "eslint": "^10.2.1",
    "eslint-config-prettier": "^10.1.8",
    "eslint-plugin-oxlint": "~1.60.0",
    "eslint-plugin-vue": "~10.8.0",
    "jiti": "^2.6.1",
    "jsdom": "^29.0.2",
    "npm-run-all2": "^8.0.4",
    "oxlint": "~1.60.0",
    "prettier": "3.8.3",
    "typescript": "~6.0.0",
    "vite": "^8.0.8",
    "vite-plugin-vue-devtools": "^8.1.1",
    "vitest": "^4.1.4",
    "vue": "^3.5.32",
    "vue-tsc": "^3.2.6"
  },
  "engines": {
    "node": "^20.19.0 || >=22.12.0"
  }
}
  • Step 2: Install dependencies for new workspace structure
bun install

Expected output: Bun detects workspaces and creates symlinks in each packages/*/node_modules


Task 4: Create library package.json

Files:

  • Create: packages/library/package.json

  • Step 1: Create library package config

{
  "name": "@nychthemeron/library",
  "version": "0.1.0",
  "type": "module",
  "exports": {
    ".": {
      "import": "./dist/index.js"
    }
  },
  "files": [
    "dist"
  ],
  "scripts": {
    "build": "vite build",
    "test:unit": "vitest"
  },
  "peerDependencies": {
    "vue": "^3.5.0",
    "primevue": "^18.0.0"
  },
  "devDependencies": {
    "@vitest/coverage-v8": "^2.0.0",
    "@vue/test-utils": "^2.4.6"
  }
}

Write this to packages/library/package.json

  • Step 2: Verify file exists
cat packages/library/package.json | grep '"name"'
# Expected: "@nychthemeron/library"

Task 5: Create library tsconfig.json

Files:

  • Create: packages/library/tsconfig.json

  • Step 1: Create library TypeScript config

{
  "extends": "../../tsconfig.json",
  "compilerOptions": {
    "outDir": "./dist",
    "declaration": true,
    "declarationMap": true,
    "emitDeclarationOnly": false
  },
  "include": [
    "src/**/*.ts",
    "src/**/*.vue"
  ],
  "exclude": [
    "dist",
    "**/*.spec.ts"
  ]
}

Write this to packages/library/tsconfig.json


Task 6: Create library vite.config.ts

Files:

  • Create: packages/library/vite.config.ts

  • Step 1: Create Vite library config

import { fileURLToPath } from 'node:url'
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'

export default defineConfig({
  plugins: [vue()],
  build: {
    lib: {
      entry: fileURLToPath(new URL('./src/index.ts', import.meta.url)),
      name: 'NychthemeronLibrary',
      formats: ['es'],
      fileName: () => 'index.js',
    },
    rollupOptions: {
      external: ['vue', 'primevue'],
      output: {
        globals: {
          vue: 'Vue',
          primevue: 'PrimeVue',
        },
      },
    },
  },
})

Write this to packages/library/vite.config.ts


Task 7: Create library vitest.config.ts

Files:

  • Create: packages/library/vitest.config.ts

  • Step 1: Create Vitest config

import { defineConfig } from 'vitest/config'
import vue from '@vitejs/plugin-vue'

export default defineConfig({
  plugins: [vue()],
  test: {
    globals: true,
    environment: 'jsdom',
    include: ['**/*.spec.ts'],
  },
})

Write this to packages/library/vitest.config.ts


Task 8: Create library export structure

Files:

  • Create: packages/library/src/components/index.ts

  • Create: packages/library/src/composables/index.ts

  • Modify: packages/library/src/index.ts

  • Step 1: Create components index (empty for now)

// Re-export all components here as they're added
// export { default as Button } from './Button/Button.vue'
// export { default as DatePicker } from './DatePicker/DatePicker.vue'

Write this to packages/library/src/components/index.ts

  • Step 2: Create composables index (empty for now)
// Re-export all composables here as they're added
// export { useDate } from './useDate'

Write this to packages/library/src/composables/index.ts

  • Step 3: Create root library entry point
export * from './components'
export * from './composables'

Write this to packages/library/src/index.ts

  • Step 4: Remove old App.vue and main.ts from library (they were for the app)
rm packages/library/src/App.vue packages/library/src/main.ts

Task 9: Create playground package.json

Files:

  • Create: packages/playground/package.json

  • Step 1: Create playground package config

{
  "name": "@nychthemeron/playground",
  "version": "0.1.0",
  "type": "module",
  "scripts": {
    "dev": "storybook dev -p 6006",
    "build": "storybook build",
    "preview": "npx vite preview"
  },
  "dependencies": {
    "@nychthemeron/library": "workspace:*",
    "primevue": "^18.0.0",
    "vue": "^3.5.32"
  },
  "devDependencies": {
    "@storybook/addon-essentials": "^8.0.0",
    "@storybook/addon-interactions": "^8.0.0",
    "@storybook/addon-links": "^8.0.0",
    "@storybook/blocks": "^8.0.0",
    "@storybook/vue3": "^8.0.0",
    "@storybook/vue3-vite": "^8.0.0",
    "storybook": "^8.0.0",
    "tailwindcss": "^3.4.0",
    "autoprefixer": "^10.4.0",
    "postcss": "^8.4.0",
    "typescript": "~6.0.0",
    "vue": "^3.5.32"
  }
}

Write this to packages/playground/package.json


Task 10: Create playground tsconfig.json

Files:

  • Create: packages/playground/tsconfig.json

  • Step 1: Create playground TypeScript config

{
  "extends": "../../tsconfig.json",
  "compilerOptions": {
    "composite": false,
    "jsx": "preserve",
    "lib": [
      "dom",
      "dom.iterable",
      "esnext"
    ]
  },
  "include": [
    ".storybook/**/*.ts",
    ".storybook/**/*.tsx",
    ".storybook/**/*.vue",
    "stories/**/*.ts",
    "stories/**/*.tsx",
    "stories/**/*.vue"
  ]
}

Write this to packages/playground/tsconfig.json


Task 11: Create playground Tailwind config

Files:

  • Create: packages/playground/tailwind.config.ts

  • Step 1: Create Tailwind config

import type { Config } from 'tailwindcss'

export default {
  content: [
    './.storybook/**/*.{ts,tsx,vue}',
    './stories/**/*.{ts,tsx,vue}',
    '../library/src/**/*.vue',
  ],
  theme: {
    extend: {
      colors: {
        primary: {
          50: '#f0f9ff',
          500: '#0ea5e9',
          900: '#0c2d6b',
        },
      },
    },
  },
  plugins: [],
} satisfies Config

Write this to packages/playground/tailwind.config.ts


Task 12: Create Storybook main config

Files:

  • Create: packages/playground/.storybook/main.ts

  • Step 1: Create Storybook main configuration

import type { StorybookConfig } from '@storybook/vue3-vite'

const config: StorybookConfig = {
  stories: [
    '../stories/**/*.stories.ts',
  ],
  addons: [
    '@storybook/addon-essentials',
    '@storybook/addon-interactions',
    '@storybook/addon-links',
  ],
  framework: {
    name: '@storybook/vue3-vite',
    options: {},
  },
  core: {
    disableTelemetry: true,
  },
}

export default config

Write this to packages/playground/.storybook/main.ts


Task 13: Create Storybook preview config

Files:

  • Create: packages/playground/.storybook/preview.ts

  • Step 1: Create Storybook preview configuration

import type { Preview } from '@storybook/vue3'
import 'primevue/resources/themes/lara-light-blue/theme.css'
import 'primevue/resources/primevue.min.css'
import '../tailwind.css'

const preview: Preview = {
  parameters: {
    layout: 'centered',
    docs: {
      description: {
        component: 'Component documentation',
      },
    },
  },
}

export default preview

Write this to packages/playground/.storybook/preview.ts


Task 14: Create Tailwind CSS entry point

Files:

  • Create: packages/playground/tailwind.css

  • Step 1: Create Tailwind directives file

@tailwind base;
@tailwind components;
@tailwind utilities;

Write this to packages/playground/tailwind.css


Task 15: Create example story

Files:

  • Create: packages/playground/stories/Example.stories.ts

  • Step 1: Create example story for testing

import type { Meta, StoryObj } from '@storybook/vue3'

const meta = {
  title: 'Example/Welcome',
  parameters: {
    layout: 'centered',
  },
  tags: ['autodocs'],
} satisfies Meta

export default meta
type Story = StoryObj<typeof meta>

export const Welcome: Story = {
  render: () => ({
    template: `
      <div class="p-8 text-center">
        <h1 class="text-3xl font-bold text-primary-500 mb-4">
          Nychthemeron Component Library
        </h1>
        <p class="text-gray-600">
          Interactive playground for Vue components with PrimeVue + Tailwind
        </p>
      </div>
    `,
  }),
}

Write this to packages/playground/stories/Example.stories.ts


Task 16: Install dependencies and verify structure

Files:

  • None (verification only)

  • Step 1: Install dependencies for all packages

bun install

Expected: All packages get dependencies installed, workspace links created

  • Step 2: Verify workspace structure
ls -la packages/library/node_modules/@nychthemeron/library
# Expected: symlink to ../..

ls -la packages/playground/node_modules/@nychthemeron/library
# Expected: symlink to ../../../library
  • Step 3: Type-check across monorepo
bun type-check

Expected: No TypeScript errors


Task 17: Test dev server startup

Files:

  • None (verification only)

  • Step 1: Start Storybook playground

bun dev

Expected output:

Storybook 8.x started
  Local: http://localhost:6006
  • Step 2: Verify Storybook loads in browser

Open http://localhost:6006 in a browser.

Expected: Storybook UI loads with "Example/Welcome" story visible showing the welcome message.

  • Step 3: Verify story renders correctly

In Storybook, click "Example/Welcome" → verify the welcome message displays with correct styling.

Expected:

  • Title: "Nychthemeron Component Library" (blue, large)

  • Subtitle: "Interactive playground..." (gray, smaller)

  • Step 4: Stop dev server

# Press Ctrl+C in terminal

Task 18: Test library build

Files:

  • None (verification only)

  • Step 1: Build library

bun -r --cwd packages/library build

Expected output:

✓ 123 modules transformed
dist/index.js  1.23 kb
dist/index.d.ts  0.5 kb
  • Step 2: Verify dist files exist
ls packages/library/dist/

Expected:

index.d.ts
index.js
  • Step 3: Verify exports are correct
head -20 packages/library/dist/index.js

Expected: JavaScript code with ES module exports (starts with import or defines exports)


Task 19: Initialize git for monorepo

Files:

  • None (git initialization only)

  • Step 1: Initialize git repo (if not already)

git init
  • Step 2: Add gitignore entries for workspace

Append to .gitignore:

packages/*/dist
packages/*/node_modules
packages/*/.storybook-static
  • Step 3: Create initial commit (SKIP - user requested no commits)

Note: Commit skipped per user request


Self-Review

Spec coverage:

  • Monorepo structure (Task 1)
  • Bun workspaces setup (Tasks 2-3)
  • Library package creation (Tasks 4-8)
  • Composables structure (Task 8)
  • Playground/Storybook setup (Tasks 9-15)
  • Tailwind integration (Tasks 11, 14)
  • PrimeVue initialization (Task 13)
  • Dev workflow verification (Task 17)
  • Build verification (Task 18)
  • Git initialization (Task 19)

Placeholder scan: No TBDs, "fill in later", incomplete steps. All code blocks are complete and exact.

Type consistency: Package names consistent (@nychthemeron/library, @nychthemeron/playground). All import paths and config keys match across tasks.

Scope: Plan produces working, testable monorepo. Library builds to dist/, Storybook starts and loads stories. Next phase (adding components) is separate.