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.
- package/cli/commands/install.js +45 -10
- package/package.json +1 -1
- package/theme/generators/react.md +97 -43
package/cli/commands/install.js
CHANGED
|
@@ -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
|
-
|
|
149
|
-
|
|
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
|
-
|
|
247
|
-
|
|
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
|
@@ -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
|
|
48
|
+
Generate all component files in `src/`:
|
|
15
49
|
|
|
16
|
-
### `
|
|
17
|
-
Root component wrapping the full layout. Imports and
|
|
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 {
|
|
21
|
-
import {
|
|
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
|
-
|
|
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
|
-
<
|
|
28
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
### `
|
|
42
|
-
|
|
118
|
+
### `src/bluedither.css`
|
|
119
|
+
All CSS custom properties and `.bd-*` class rules.
|
|
43
120
|
|
|
44
|
-
|
|
45
|
-
```jsx
|
|
46
|
-
import { useEffect, useRef } from 'react';
|
|
121
|
+
## Vite Config
|
|
47
122
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
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
|
|