@shopify/klint 0.0.98 → 0.2.0

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.
@@ -0,0 +1,423 @@
1
+ #!/bin/bash
2
+
3
+ # Auto-generated create-editor script
4
+ # Generated from klint-editor working folder
5
+
6
+ PROJECT_DIR="${1:-.}"
7
+ PROJECT_NAME=$(basename "$PROJECT_DIR")
8
+
9
+ echo "Creating Klint editor in $PROJECT_DIR..."
10
+
11
+ # Create directory if it doesn't exist
12
+ mkdir -p "$PROJECT_DIR"
13
+ cd "$PROJECT_DIR"
14
+
15
+ # Create src directory
16
+ mkdir -p src
17
+
18
+ # Create package.json
19
+ cat > package.json << EOF
20
+ {
21
+ "name": "$PROJECT_NAME",
22
+ "version": "0.1.0",
23
+ "private": true,
24
+ "type": "module",
25
+ "scripts": {
26
+ "dev": "vite",
27
+ "build": "vite build",
28
+ "preview": "vite preview"
29
+ },
30
+ "dependencies": {
31
+ "@monaco-editor/react": "^4.7.0",
32
+ "@shopify/klint": "^0.0.98",
33
+ "react": "^18.3.1",
34
+ "react-dom": "^18.3.1"
35
+ },
36
+ "devDependencies": {
37
+ "@types/react": "^18.3.3",
38
+ "@types/react-dom": "^18.3.0",
39
+ "@vitejs/plugin-react": "^4.3.1",
40
+ "typescript": "^5.5.4",
41
+ "vite": "^5.4.0"
42
+ }
43
+ }
44
+ EOF
45
+
46
+ # Create vite.config.ts
47
+ cat > vite.config.ts << 'EOF'
48
+ import { defineConfig } from 'vite';
49
+ import react from '@vitejs/plugin-react';
50
+
51
+ export default defineConfig({
52
+ plugins: [react()],
53
+ });
54
+ EOF
55
+
56
+ # Create tsconfig.json
57
+ cat > tsconfig.json << 'EOF'
58
+ {
59
+ "compilerOptions": {
60
+ "target": "ES2020",
61
+ "useDefineForClassFields": true,
62
+ "lib": ["ES2020", "DOM", "DOM.Iterable"],
63
+ "module": "ESNext",
64
+ "skipLibCheck": true,
65
+
66
+ /* Bundler mode */
67
+ "moduleResolution": "bundler",
68
+ "allowImportingTsExtensions": true,
69
+ "resolveJsonModule": true,
70
+ "isolatedModules": true,
71
+ "noEmit": true,
72
+ "jsx": "react-jsx",
73
+
74
+ /* Linting */
75
+ "strict": true,
76
+ "noUnusedLocals": true,
77
+ "noUnusedParameters": true,
78
+ "noFallthroughCasesInSwitch": true
79
+ },
80
+ "include": ["src"],
81
+ "references": [{ "path": "./tsconfig.node.json" }]
82
+ }
83
+ EOF
84
+
85
+ # Create tsconfig.node.json
86
+ cat > tsconfig.node.json << 'EOF'
87
+ {
88
+ "compilerOptions": {
89
+ "composite": true,
90
+ "skipLibCheck": true,
91
+ "module": "ESNext",
92
+ "moduleResolution": "bundler",
93
+ "allowSyntheticDefaultImports": true
94
+ },
95
+ "include": ["vite.config.ts"]
96
+ }
97
+ EOF
98
+
99
+ # Create index.html
100
+ cat > index.html << 'EOF'
101
+ <!doctype html>
102
+ <html lang="en">
103
+ <head>
104
+ <meta charset="UTF-8" />
105
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
106
+ <title>Klint Editor</title>
107
+ </head>
108
+ <body>
109
+ <div id="root"></div>
110
+ <script type="module" src="/src/main.tsx"></script>
111
+ </body>
112
+ </html>
113
+ EOF
114
+
115
+ # Create src/main.tsx
116
+ cat > src/main.tsx << 'EOF'
117
+ import React from "react";
118
+ import ReactDOM from "react-dom/client";
119
+ import App from "./App.tsx";
120
+
121
+ ReactDOM.createRoot(document.getElementById("root")!).render(
122
+ <React.StrictMode>
123
+ <App />
124
+ </React.StrictMode>
125
+ );
126
+
127
+ EOF
128
+
129
+ # Create src/App.tsx
130
+ cat > src/App.tsx << 'EOF'
131
+ import { useState, useEffect, useRef, useCallback } from "react";
132
+ import { Editor } from "@monaco-editor/react";
133
+ import { useKlint, Klint, type KlintContext } from "@shopify/klint";
134
+
135
+ const defaultCode = `
136
+ function preload(K) {
137
+ console.log(K, "Welcome to Klint Editor! 🎨✨");
138
+ }
139
+
140
+ function setup(K) {
141
+ K.textFont("Inter");
142
+ K.textSize(64);
143
+ K.noStroke();
144
+ K.alignText("center", "middle");
145
+ }
146
+
147
+ function draw(K) {
148
+ K.background('rgba(125, 0, 255, 255)');
149
+ K.fillColor("#FFF");
150
+ // Mouse is available directly on K after being extended in preload
151
+ const mouseX = K.mouse ? K.mouse.x : K.width * 0.5;
152
+ const mouseY = K.mouse ? K.mouse.y : K.height * 0.5;
153
+ K.circle(mouseX, mouseY + Math.sin(K.frame * 0.03) * 100, 50);
154
+ }
155
+
156
+ `;
157
+
158
+ // Define the return type for evaluated user code
159
+ interface UserCode {
160
+ preload?: (K: KlintContext) => Promise<void> | void;
161
+ setup?: (K: KlintContext) => void;
162
+ draw?: (K: KlintContext) => void;
163
+ }
164
+
165
+ // Separate Klint Canvas component
166
+ function KlintCanvas({ code }: { code: string }) {
167
+ const klintHook = useKlint();
168
+ const { KlintMouse } = klintHook;
169
+ const mouseHook = KlintMouse();
170
+ const [error, setError] = useState<string | null>(null);
171
+ const [isClient, setIsClient] = useState(false);
172
+
173
+ // Set isClient to true after component mounts
174
+ useEffect(() => {
175
+ setIsClient(true);
176
+ }, []);
177
+
178
+ // Create a sandbox environment with hooks available
179
+ const createSandbox = useCallback((): UserCode => {
180
+ try {
181
+ // Create a mock context for code evaluation (not runtime execution)
182
+ // The real context will be passed to preload/setup/draw when they're called
183
+ const sandbox = {
184
+ K: {
185
+ // Provide mock mouse hook access for code evaluation
186
+ useMouse: () => mouseHook,
187
+ // Add other hooks here as needed
188
+ },
189
+ console: console,
190
+ };
191
+
192
+ // Evaluate the code in the sandbox
193
+ const userCode = new Function(
194
+ "K",
195
+ `
196
+ "use strict";
197
+ let userPreload, userSetup, userDraw;
198
+
199
+ // Make hooks available in global scope
200
+ const useMouse = K.useMouse;
201
+
202
+ // Execute user code
203
+ ${code}
204
+
205
+ // Return the lifecycle functions
206
+ return {
207
+ preload: preload || userPreload,
208
+ setup: setup || userSetup,
209
+ draw: draw || userDraw
210
+ };
211
+ `
212
+ );
213
+
214
+ // Execute the code with the sandbox
215
+ const result = userCode(sandbox.K) as UserCode;
216
+ setError(null);
217
+ return result;
218
+ } catch (err) {
219
+ console.error("Error evaluating code:", err);
220
+ setError(err instanceof Error ? err.message : String(err));
221
+ return { preload: undefined, setup: undefined, draw: undefined };
222
+ }
223
+ }, [code, mouseHook]);
224
+
225
+ // Create a ref to hold the evaluated code
226
+ const userCodeRef = useRef<UserCode | null>(null);
227
+
228
+ // Update the code when it changes
229
+ useEffect(() => {
230
+ if (isClient) {
231
+ userCodeRef.current = createSandbox();
232
+ }
233
+ }, [isClient, createSandbox]);
234
+
235
+ const preload = useCallback(
236
+ async (K: KlintContext) => {
237
+ // Extend K with mouse data directly
238
+ K.extend("mouse", mouseHook.mouse);
239
+ // Add mouse event handlers
240
+ K.extend("onMouseClick", mouseHook.onClick);
241
+ K.extend("onMouseIn", mouseHook.onMouseIn);
242
+ K.extend("onMouseOut", mouseHook.onMouseOut);
243
+ K.extend("onMouseDown", mouseHook.onMouseDown);
244
+ K.extend("onMouseUp", mouseHook.onMouseUp);
245
+
246
+ if (userCodeRef.current?.preload) {
247
+ try {
248
+ await userCodeRef.current.preload(K);
249
+ } catch (err) {
250
+ console.error("Error in preload:", err);
251
+ setError(err instanceof Error ? err.message : String(err));
252
+ }
253
+ }
254
+ },
255
+ [mouseHook]
256
+ );
257
+
258
+ const setup = useCallback((K: KlintContext) => {
259
+ if (userCodeRef.current?.setup) {
260
+ try {
261
+ userCodeRef.current.setup(K);
262
+ } catch (err) {
263
+ console.error("Error in setup:", err);
264
+ setError(err instanceof Error ? err.message : String(err));
265
+ }
266
+ }
267
+ }, []);
268
+
269
+ const draw = useCallback((K: KlintContext) => {
270
+ if (userCodeRef.current?.draw) {
271
+ try {
272
+ userCodeRef.current.draw(K);
273
+ } catch (err) {
274
+ console.error("Error in draw:", err);
275
+ setError(err instanceof Error ? err.message : String(err));
276
+ }
277
+ }
278
+ }, []);
279
+
280
+ if (!isClient) {
281
+ return (
282
+ <div style={{ width: "100%", height: "100%", background: "#000" }}></div>
283
+ );
284
+ }
285
+
286
+ if (error) {
287
+ return (
288
+ <div
289
+ style={{
290
+ width: "100%",
291
+ height: "100%",
292
+ background: "#300",
293
+ color: "#f88",
294
+ padding: "20px",
295
+ fontFamily: "monospace",
296
+ whiteSpace: "pre-wrap",
297
+ }}
298
+ >
299
+ {error}
300
+ </div>
301
+ );
302
+ }
303
+
304
+ return (
305
+ <Klint
306
+ context={klintHook.context}
307
+ preload={preload}
308
+ setup={setup}
309
+ draw={draw}
310
+ options={{
311
+ origin: "corner",
312
+ unsafemode: "true",
313
+ }}
314
+ />
315
+ );
316
+ }
317
+
318
+ function App() {
319
+ const [code, setCode] = useState(defaultCode);
320
+ const [runningCode, setRunningCode] = useState(defaultCode);
321
+ const [isClient, setIsClient] = useState(false);
322
+ const [canvasKey, setCanvasKey] = useState(0); // Add a key to force remount
323
+
324
+ // Set isClient to true after component mounts
325
+ useEffect(() => {
326
+ setIsClient(true);
327
+ }, []);
328
+
329
+ // Function to run code and clear console
330
+ const runCode = useCallback(() => {
331
+ // Clear the console before running new code
332
+ console.clear();
333
+ setRunningCode(code);
334
+ // Increment the key to force a complete remount of the KlintCanvas
335
+ setCanvasKey((prev) => prev + 1);
336
+ }, [code]);
337
+
338
+ // Function to clear the editor
339
+ const clearCode = useCallback(() => {
340
+ setCode("");
341
+ setRunningCode("");
342
+ setCanvasKey((prev) => prev + 1);
343
+ }, []);
344
+
345
+ if (!isClient) {
346
+ return <div style={{ height: "100vh", background: "#1e1e1e" }}></div>;
347
+ }
348
+
349
+ return (
350
+ <div style={{ display: "flex", flexDirection: "column", height: "100vh" }}>
351
+ <div style={{ display: "flex", gap: "8px", margin: "8px" }}>
352
+ <button
353
+ onClick={runCode}
354
+ style={{
355
+ padding: "8px 16px",
356
+ backgroundColor: "#4CAF50",
357
+ color: "white",
358
+ border: "none",
359
+ borderRadius: "4px",
360
+ cursor: "pointer",
361
+ }}
362
+ >
363
+ Run
364
+ </button>
365
+ <button
366
+ onClick={clearCode}
367
+ style={{
368
+ padding: "8px 16px",
369
+ backgroundColor: "#f44336",
370
+ color: "white",
371
+ border: "none",
372
+ borderRadius: "4px",
373
+ cursor: "pointer",
374
+ }}
375
+ >
376
+ Clear
377
+ </button>
378
+ </div>
379
+ <div style={{ display: "flex", flex: 1 }}>
380
+ <div style={{ flex: 1 }}>
381
+ <Editor
382
+ height="100%"
383
+ defaultLanguage="javascript"
384
+ value={code}
385
+ onChange={(value) => setCode(value || "")}
386
+ options={{
387
+ minimap: { enabled: false },
388
+ fontSize: 14,
389
+ theme: "vs-dark",
390
+ }}
391
+ onMount={(editor) => {
392
+ editor.updateOptions({ theme: "vs-dark" });
393
+ }}
394
+ />
395
+ </div>
396
+ <div style={{ flex: 1, background: "#000" }}>
397
+ <KlintCanvas key={`${canvasKey}-${runningCode}`} code={runningCode} />
398
+ </div>
399
+ </div>
400
+ </div>
401
+ );
402
+ }
403
+
404
+ export default App;
405
+
406
+ EOF
407
+
408
+ # Create .gitignore
409
+ cat > .gitignore << 'EOF'
410
+ node_modules
411
+ dist
412
+ .env
413
+ EOF
414
+
415
+
416
+ echo "✅ Klint editor created successfully!"
417
+ echo ""
418
+ echo "Next steps:"
419
+ echo " cd $PROJECT_DIR"
420
+ echo " npm install"
421
+ echo " npm run dev"
422
+ echo ""
423
+ echo "The editor will be available at http://localhost:5173"
@@ -0,0 +1,232 @@
1
+ #!/bin/bash
2
+
3
+ # Klint Dev Sandbox Generator
4
+ # Creates a lightweight Vite setup for quick Klint prototyping
5
+
6
+ PROJECT_DIR="${1:-.}"
7
+ PROJECT_NAME=$(basename "$PROJECT_DIR")
8
+
9
+ echo "🏖️ Creating Klint dev sandbox in $PROJECT_DIR..."
10
+
11
+ # Create directory if it doesn't exist
12
+ mkdir -p "$PROJECT_DIR"
13
+ cd "$PROJECT_DIR"
14
+
15
+ # Create src directory
16
+ mkdir -p src
17
+
18
+ # Create package.json
19
+ cat > package.json << EOF
20
+ {
21
+ "name": "$PROJECT_NAME",
22
+ "version": "0.1.0",
23
+ "private": true,
24
+ "type": "module",
25
+ "scripts": {
26
+ "dev": "vite",
27
+ "build": "vite build",
28
+ "preview": "vite preview"
29
+ },
30
+ "dependencies": {
31
+ "@shopify/klint": "^0.0.98",
32
+ "react": "^18.3.1",
33
+ "react-dom": "^18.3.1"
34
+ },
35
+ "devDependencies": {
36
+ "@types/react": "^18.3.3",
37
+ "@types/react-dom": "^18.3.0",
38
+ "@vitejs/plugin-react": "^4.3.1",
39
+ "typescript": "^5.5.4",
40
+ "vite": "^5.4.0"
41
+ }
42
+ }
43
+ EOF
44
+
45
+ # Create vite.config.ts
46
+ cat > vite.config.ts << 'EOF'
47
+ import { defineConfig } from 'vite';
48
+ import react from '@vitejs/plugin-react';
49
+
50
+ export default defineConfig({
51
+ plugins: [react()],
52
+ server: {
53
+ port: 3000,
54
+ open: true
55
+ }
56
+ });
57
+ EOF
58
+
59
+ # Create tsconfig.json
60
+ cat > tsconfig.json << 'EOF'
61
+ {
62
+ "compilerOptions": {
63
+ "target": "ES2020",
64
+ "useDefineForClassFields": true,
65
+ "lib": ["ES2020", "DOM", "DOM.Iterable"],
66
+ "module": "ESNext",
67
+ "skipLibCheck": true,
68
+ "moduleResolution": "bundler",
69
+ "allowImportingTsExtensions": true,
70
+ "resolveJsonModule": true,
71
+ "isolatedModules": true,
72
+ "noEmit": true,
73
+ "jsx": "react-jsx",
74
+ "strict": true,
75
+ "noUnusedLocals": false,
76
+ "noUnusedParameters": false,
77
+ "noFallthroughCasesInSwitch": true
78
+ },
79
+ "include": ["src"],
80
+ "references": [{ "path": "./tsconfig.node.json" }]
81
+ }
82
+ EOF
83
+
84
+ # Create tsconfig.node.json
85
+ cat > tsconfig.node.json << 'EOF'
86
+ {
87
+ "compilerOptions": {
88
+ "composite": true,
89
+ "skipLibCheck": true,
90
+ "module": "ESNext",
91
+ "moduleResolution": "bundler",
92
+ "allowSyntheticDefaultImports": true
93
+ },
94
+ "include": ["vite.config.ts"]
95
+ }
96
+ EOF
97
+
98
+ # Create index.html
99
+ cat > index.html << 'EOF'
100
+ <!doctype html>
101
+ <html lang="en">
102
+ <head>
103
+ <meta charset="UTF-8" />
104
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
105
+ <title>Klint Sandbox</title>
106
+ <style>
107
+ body { margin: 0; padding: 0; background: #111; }
108
+ #root { width: 100vw; height: 100vh; }
109
+ </style>
110
+ </head>
111
+ <body>
112
+ <div id="root"></div>
113
+ <script type="module" src="/src/main.tsx"></script>
114
+ </body>
115
+ </html>
116
+ EOF
117
+
118
+ # Create src/main.tsx
119
+ cat > src/main.tsx << 'EOF'
120
+ import React from "react";
121
+ import ReactDOM from "react-dom/client";
122
+ import App from "./App.tsx";
123
+
124
+ ReactDOM.createRoot(document.getElementById("root")!).render(
125
+ <React.StrictMode>
126
+ <App />
127
+ </React.StrictMode>
128
+ );
129
+ EOF
130
+
131
+ # Create src/App.tsx with a simple example
132
+ cat > src/App.tsx << 'EOF'
133
+ import { useKlint, Klint } from "@shopify/klint";
134
+
135
+ export default function App() {
136
+ const { context, KlintMouse } = useKlint();
137
+ const mouse = KlintMouse();
138
+
139
+ const setup = (K: any) => {
140
+ K.textFont("Inter, sans-serif");
141
+ K.textSize(48);
142
+ K.alignText("center", "middle");
143
+ K.noStroke();
144
+ };
145
+
146
+ const draw = (K: any) => {
147
+ // Background with trailing effect
148
+ K.background("rgba(20, 20, 40, 0.1)");
149
+
150
+ // Mouse-following circle
151
+ const mouseX = mouse.x || K.width / 2;
152
+ const mouseY = mouse.y || K.height / 2;
153
+
154
+ // Animated circle
155
+ K.fillColor("#00ff88");
156
+ const size = 50 + Math.sin(K.frame * 0.02) * 20;
157
+ K.circle(mouseX, mouseY, size);
158
+
159
+ // Some text
160
+ K.fillColor("#ffffff");
161
+ K.text("Klint Dev Sandbox", K.width / 2, K.height / 2 + 150);
162
+ K.textSize(24);
163
+ K.text("Move your mouse around!", K.width / 2, K.height / 2 + 200);
164
+
165
+ // Corner info
166
+ K.textSize(16);
167
+ K.alignText("left", "top");
168
+ K.text(\`Frame: \${K.frame}\`, 20, 20);
169
+ K.text(\`Mouse: \${Math.round(mouseX)}, \${Math.round(mouseY)}\`, 20, 40);
170
+ };
171
+
172
+ return (
173
+ <Klint
174
+ context={context}
175
+ setup={setup}
176
+ draw={draw}
177
+ options={{
178
+ origin: "corner"
179
+ }}
180
+ />
181
+ );
182
+ }
183
+ EOF
184
+
185
+ # Create .gitignore
186
+ cat > .gitignore << 'EOF'
187
+ node_modules
188
+ dist
189
+ .env
190
+ .DS_Store
191
+ EOF
192
+
193
+ # Create README.md
194
+ cat > README.md << 'EOF'
195
+ # Klint Dev Sandbox
196
+
197
+ A lightweight development environment for prototyping with Klint.
198
+
199
+ ## Quick Start
200
+
201
+ \`\`\`bash
202
+ npm install
203
+ npm run dev
204
+ \`\`\`
205
+
206
+ ## What's included
207
+
208
+ - ⚡ Vite for fast hot reload
209
+ - 🎨 Klint pre-configured
210
+ - 🖱️ Mouse interactions ready
211
+ - 📱 Responsive canvas
212
+
213
+ ## Tips
214
+
215
+ - Edit \`src/App.tsx\` to create your sketch
216
+ - Use \`setup(K)\` for initialization
217
+ - Use \`draw(K)\` for your main loop
218
+ - The canvas fills the entire viewport
219
+ - Hot reload updates instantly
220
+
221
+ Happy creative coding! 🎨
222
+ EOF
223
+
224
+ echo "✅ Klint dev sandbox created successfully!"
225
+ echo ""
226
+ echo "🚀 Quick start:"
227
+ echo " cd $PROJECT_DIR"
228
+ echo " npm install"
229
+ echo " npm run dev"
230
+ echo ""
231
+ echo "The sandbox will open at http://localhost:3000"
232
+ echo "Perfect for quick prototyping and creative experiments! 🎨"