bluedither 1.0.16 → 1.0.18

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -121,6 +121,9 @@ export default async function install(args) {
121
121
 
122
122
  console.log(`Copied ${copied} files to ${bdDir}`);
123
123
 
124
+ // Auto-wire Vite plugin if vite.config exists
125
+ autoWireVitePlugin(targetDir);
126
+
124
127
  // Generate Claude Code command file
125
128
  const claudeDir = resolve(targetDir, '.claude', 'commands');
126
129
  mkdirSync(claudeDir, { recursive: true });
@@ -145,14 +148,46 @@ $ARGUMENTS
145
148
  To apply the theme, use Claude Code:
146
149
  /apply-theme [description of your site]
147
150
 
148
- To customize visually, add this to your HTML:
149
- <script src="./bluedither/bluedither-tuner-inject.js"></script>
150
-
151
- For auto-saving, run in a separate terminal:
152
- npx bluedither tune --save-only
151
+ The tuner panel loads automatically in dev mode.
152
+ Click "Commit Changes" to save tweaks to tokens.json.
153
153
  `);
154
154
  }
155
155
 
156
+ function autoWireVitePlugin(targetDir) {
157
+ // Find vite.config file
158
+ const variants = ['vite.config.js', 'vite.config.ts', 'vite.config.mjs', 'vite.config.mts'];
159
+ let configPath = null;
160
+ for (const v of variants) {
161
+ const p = resolve(targetDir, v);
162
+ if (existsSync(p)) { configPath = p; break; }
163
+ }
164
+ if (!configPath) return;
165
+
166
+ const config = readFileSync(configPath, 'utf-8');
167
+
168
+ // Skip if already wired
169
+ if (config.includes('bluedither')) return;
170
+
171
+ // Add import and plugin
172
+ const importLine = `import { bluedither } from './bluedither/dev-middleware.js'\n`;
173
+ let updated = importLine + config;
174
+
175
+ // Add bluedither() to plugins array
176
+ updated = updated.replace(
177
+ /plugins:\s*\[([^\]]*)\]/,
178
+ (match, inner) => {
179
+ const trimmed = inner.trim();
180
+ if (trimmed.endsWith(',')) {
181
+ return `plugins: [${trimmed} bluedither()]`;
182
+ }
183
+ return `plugins: [${trimmed}, bluedither()]`;
184
+ }
185
+ );
186
+
187
+ writeFileSync(configPath, updated);
188
+ console.log(`Wired BlueDither plugin into ${basename(configPath)}`);
189
+ }
190
+
156
191
  async function installFromRegistry(slug, targetDir) {
157
192
  console.log(`\n Installing theme "${slug}" from marketplace...\n`);
158
193
 
@@ -221,6 +256,9 @@ async function installFromRegistry(slug, targetDir) {
221
256
  const { framework, typescript } = detectFramework(targetDir);
222
257
  console.log(` Detected framework: ${framework}${typescript ? ' + TypeScript' : ''}`);
223
258
 
259
+ // Auto-wire Vite plugin
260
+ autoWireVitePlugin(targetDir);
261
+
224
262
  const claudeDir = resolve(targetDir, '.claude', 'commands');
225
263
  mkdirSync(claudeDir, { recursive: true });
226
264
 
@@ -243,10 +281,7 @@ $ARGUMENTS
243
281
  To apply the theme, use Claude Code:
244
282
  /apply-theme [description of your site]
245
283
 
246
- To customize visually, add this to your HTML:
247
- <script src="./bluedither/bluedither-tuner-inject.js"><\/script>
248
-
249
- For auto-saving, run in a separate terminal:
250
- npx bluedither tune --save-only
284
+ The tuner panel loads automatically in dev mode.
285
+ Click "Commit Changes" to save tweaks to tokens.json.
251
286
  `);
252
287
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "bluedither",
3
- "version": "1.0.16",
3
+ "version": "1.0.18",
4
4
  "description": "A bold, dithered-shader hero theme for Claude Code — skill + fine-tuner",
5
5
  "type": "module",
6
6
  "bin": {
@@ -2,6 +2,40 @@
2
2
 
3
3
  When the target project uses **React** (detected via `react` in package.json dependencies), follow these patterns.
4
4
 
5
+ ## CRITICAL: File Placement Rules
6
+
7
+ **In `src/` (importable source files):**
8
+ - All `.jsx`/`.tsx` component files
9
+ - `bluedither.css` — CSS custom properties + rules
10
+ - `paper-shaders-bundle.js` — copied from `bluedither/shaders/`
11
+ - Any other JS modules that are `import`-ed
12
+
13
+ **In `public/bluedither/` (static assets loaded at runtime):**
14
+ - `bluedither-tuner.js` — tuner panel
15
+ - `bluedither-tuner.css` — tuner styles
16
+ - `bluedither-tuner-inject.js` — tuner loader
17
+ - `tokens.json` — design tokens (read at runtime by tuner)
18
+ - `tokens.defaults.json` — default tokens
19
+ - `dev-middleware.js` — Vite commit endpoint
20
+
21
+ **NEVER import JS files from `public/` — Vite will error.** Shader files MUST be in `src/`.
22
+
23
+ Copy shader files during generation:
24
+ ```bash
25
+ cp bluedither/shaders/paper-shaders-bundle.js src/paper-shaders-bundle.js
26
+ ```
27
+
28
+ Copy tuner assets to public:
29
+ ```bash
30
+ mkdir -p public/bluedither
31
+ cp bluedither/bluedither-tuner.js public/bluedither/
32
+ cp bluedither/bluedither-tuner.css public/bluedither/
33
+ cp bluedither/bluedither-tuner-inject.js public/bluedither/
34
+ cp bluedither/tokens.json public/bluedither/
35
+ cp bluedither/tokens.defaults.json public/bluedither/
36
+ cp bluedither/dev-middleware.js public/bluedither/
37
+ ```
38
+
5
39
  ## Detection
6
40
 
7
41
  React is detected when `package.json` contains `react` in `dependencies` or `devDependencies`. Also check for:
@@ -11,76 +45,96 @@ React is detected when `package.json` contains `react` in `dependencies` or `dev
11
45
 
12
46
  ## Component Structure
13
47
 
14
- Generate separate component files matching `structure.json` nodes:
48
+ Generate all component files in `src/`:
15
49
 
16
- ### `BlueDitherTheme.jsx` (or `.tsx`)
17
- Root component wrapping the full layout. Imports and composes child components.
50
+ ### `src/App.jsx` (or modify existing)
51
+ Root component wrapping the full layout. Imports shader, CSS, and loads tuner in dev mode.
18
52
 
19
53
  ```jsx
20
- import { BlueDitherHeader } from './BlueDitherHeader';
21
- import { BlueDitherHero } from './BlueDitherHero';
54
+ import { useEffect, useRef } from 'react';
55
+ import { ShaderMount, ditheringFragmentShader, DitheringShapes, DitheringTypes, getShaderColorFromString } from './paper-shaders-bundle.js';
22
56
  import './bluedither.css';
23
57
 
24
- export function BlueDitherTheme() {
58
+ // Content from tokens.json content section
59
+ const CONTENT = { /* ... */ };
60
+
61
+ // Shader params from tokens.json shader + colors sections
62
+ const SHADER_PARAMS = { /* ... */ };
63
+
64
+ function App() {
65
+ const shaderRef = useRef(null);
66
+
67
+ // Initialize shader
68
+ useEffect(() => {
69
+ if (!shaderRef.current) return;
70
+ const mount = new ShaderMount(shaderRef.current, ditheringFragmentShader, {
71
+ u_colorFront: getShaderColorFromString(SHADER_PARAMS.colorFront),
72
+ u_colorBack: getShaderColorFromString(SHADER_PARAMS.colorBack),
73
+ u_shape: DitheringShapes[SHADER_PARAMS.shape] ?? DitheringShapes.warp,
74
+ u_type: DitheringTypes[SHADER_PARAMS.type] ?? DitheringTypes['2x2'],
75
+ u_pxSize: SHADER_PARAMS.size,
76
+ u_scale: SHADER_PARAMS.scale,
77
+ u_rotation: SHADER_PARAMS.rotation,
78
+ u_originX: 0.5, u_originY: 0.5,
79
+ u_worldWidth: 0, u_worldHeight: 0,
80
+ u_fit: 0, u_offsetX: 0, u_offsetY: 0,
81
+ }, { alpha: true, premultipliedAlpha: false }, SHADER_PARAMS.speed, 0, 2);
82
+
83
+ // CRITICAL: expose for tuner
84
+ window.__BD_SHADER__ = mount;
85
+ return () => { mount.dispose(); window.__BD_SHADER__ = null; };
86
+ }, []);
87
+
88
+ // Load tuner in dev mode only
89
+ useEffect(() => {
90
+ if (import.meta.env.DEV) {
91
+ const s = document.createElement('script');
92
+ s.src = '/bluedither/bluedither-tuner-inject.js';
93
+ document.body.appendChild(s);
94
+ return () => s.remove();
95
+ }
96
+ }, []);
97
+
25
98
  return (
26
99
  <div className="bd-root">
27
- <BlueDitherHero />
28
- <BlueDitherHeader />
100
+ <div className="bd-hero">
101
+ <div className="bd-hero-inner">
102
+ <div className="bd-shader-layer" ref={shaderRef} />
103
+ {/* hero content */}
104
+ </div>
105
+ </div>
106
+ <header className="bd-header">
107
+ {/* header content */}
108
+ </header>
29
109
  </div>
30
110
  );
31
111
  }
32
112
  ```
33
113
 
34
- ### `BlueDitherHeader.jsx`
35
- Navbar component with logo, nav items, and CTA.
114
+ Note: The shader uses `ShaderMount` directly from `paper-shaders-bundle.js` — do NOT create a separate shader wrapper module. Import `ShaderMount`, `ditheringFragmentShader`, `DitheringShapes`, `DitheringTypes`, and `getShaderColorFromString` directly.
36
115
 
37
- - Nav items come from `content.navItems` token array
38
- - Use `<nav>` with `<a>` elements for nav items
39
- - CTA is an `<a>` or `<button>` element
116
+ The `window.__BD_SHADER__` assignment is **required** — the tuner calls `updateParams()` on it for live shader editing. The ShaderMount instance has `setUniforms()` and `setSpeed()` methods. The tuner's `updateParams` maps token names to uniform names (e.g., `colorFront` → `u_colorFront`).
40
117
 
41
- ### `BlueDitherHero.jsx`
42
- Hero section with shader and text content.
118
+ ### `src/bluedither.css`
119
+ All CSS custom properties and `.bd-*` class rules.
43
120
 
44
- - **Shader initialization**: Use `useEffect` + `useRef` for the shader parent div. **CRITICAL**: Assign the mount to `window.__BD_SHADER__` so the tuner can update shader params live:
45
- ```jsx
46
- import { useEffect, useRef } from 'react';
121
+ ## Vite Config
47
122
 
48
- const shaderRef = useRef(null);
49
-
50
- useEffect(() => {
51
- // Dynamic import to avoid SSR issues
52
- import('./paper-shaders-bundle.js').then(({ ShaderMount, ditheringFragmentShader, getShaderColorFromString }) => {
53
- const mount = new ShaderMount(shaderRef.current, ditheringFragmentShader, uniforms, opts, speed, 0, 2);
54
- window.__BD_SHADER__ = mount;
55
- return () => { mount.dispose(); window.__BD_SHADER__ = null; };
56
- });
57
- }, []);
123
+ The `npx bluedither install` command auto-wires the Vite plugin. If it wasn't auto-wired, add manually:
124
+ ```js
125
+ import { bluedither } from './bluedither/dev-middleware.js'
126
+ export default defineConfig({ plugins: [react(), bluedither()] })
58
127
  ```
59
128
 
60
- ### `bluedither.css`
61
- All CSS custom properties and `.bd-*` class rules, identical to the vanilla `<style>` block but as an external file.
62
-
63
129
  ## TypeScript
64
130
 
65
131
  If TypeScript is detected, use `.tsx` extensions and add minimal type annotations:
66
- - Props interfaces where components accept props
67
132
  - `useRef<HTMLDivElement>(null)` for refs
68
133
 
69
134
  ## Next.js
70
135
 
71
136
  If Next.js is detected:
72
137
  - Add `"use client"` at the top of components that use `useEffect` or `useRef`
73
- - The CSS file can be imported directly in the component
74
-
75
- ## File Output
76
-
77
- | File | Contents |
78
- |------|----------|
79
- | `BlueDitherTheme.jsx/tsx` | Root layout component |
80
- | `BlueDitherHeader.jsx/tsx` | Navbar component |
81
- | `BlueDitherHero.jsx/tsx` | Hero + shader component |
82
- | `bluedither.css` | CSS custom properties + rules |
83
- | `paper-shaders-bundle.js` | Shader library (copied) |
84
138
 
85
139
  ## Content Handling
86
140