Trudy commited on
Commit
a6a0252
·
1 Parent(s): ac97894

fixed resize error

Browse files
public/index.html CHANGED
@@ -51,54 +51,7 @@
51
  // Store container reference in p5 instance
52
  p.containerWidth = container.clientWidth;
53
  p.containerHeight = container.clientHeight;
54
-
55
- let resizeTimeout = null;
56
- let resizeObserver = null;
57
-
58
- // Update container dimensions when needed
59
- const updateContainerSize = () => {
60
- const rect = container.getBoundingClientRect();
61
- const newWidth = rect.width;
62
- const newHeight = rect.height;
63
-
64
- // Only update if dimensions actually changed
65
- if (p.containerWidth !== newWidth || p.containerHeight !== newHeight) {
66
- p.containerWidth = newWidth;
67
- p.containerHeight = newHeight;
68
- if (p.windowResized) {
69
- p.windowResized();
70
- }
71
- }
72
- };
73
-
74
- // Debounced resize handler
75
- const debouncedResize = () => {
76
- if (resizeTimeout) {
77
- clearTimeout(resizeTimeout);
78
- }
79
- resizeTimeout = setTimeout(() => {
80
- updateContainerSize();
81
- resizeTimeout = null;
82
- }, 100); // Debounce for 100ms
83
- };
84
-
85
- // Setup resize observer
86
- const setupResizeObserver = () => {
87
- if (resizeObserver) {
88
- resizeObserver.disconnect();
89
- }
90
-
91
- resizeObserver = new ResizeObserver((entries) => {
92
- // Avoid processing if container is hidden or detached
93
- if (container.offsetParent !== null) {
94
- window.requestAnimationFrame(() => {
95
- debouncedResize();
96
- });
97
- }
98
- });
99
-
100
- resizeObserver.observe(container);
101
- };
102
 
103
  // Add the sketch code to p5 instance scope
104
  const sketchFunction = new Function('p', `
@@ -118,14 +71,23 @@
118
  }
119
  }
120
 
121
- // Always ensure we have window resize handling
122
- if (typeof windowResized !== 'function') {
123
- windowResized = function() {
124
- resizeCanvas(containerWidth, containerHeight, true);
125
- }
126
- }
127
-
128
- return { setup, draw, windowResized };
 
 
 
 
 
 
 
 
 
129
  }
130
  `);
131
 
@@ -149,25 +111,26 @@
149
  // Add a custom class to help with styling
150
  p._renderer.canvas.classList.add('p5-managed-canvas');
151
  }
152
-
153
- // Setup resize observer after canvas is added
154
- setupResizeObserver();
155
  }
156
  };
157
 
158
  p.draw = functions.draw.bind(p);
159
- p.windowResized = functions.windowResized.bind(p);
 
 
 
 
 
 
 
 
 
 
 
160
 
161
  // Cleanup when sketch is removed
162
  p._cleanup = () => {
163
- if (resizeObserver) {
164
- resizeObserver.disconnect();
165
- resizeObserver = null;
166
- }
167
- if (resizeTimeout) {
168
- clearTimeout(resizeTimeout);
169
- resizeTimeout = null;
170
- }
171
  };
172
  }, container);
173
 
 
51
  // Store container reference in p5 instance
52
  p.containerWidth = container.clientWidth;
53
  p.containerHeight = container.clientHeight;
54
+ p.container = container; // Store container reference
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
55
 
56
  // Add the sketch code to p5 instance scope
57
  const sketchFunction = new Function('p', `
 
71
  }
72
  }
73
 
74
+ // Return all defined p5 functions
75
+ return {
76
+ setup,
77
+ draw,
78
+ // Mouse events
79
+ mousePressed: typeof mousePressed === 'function' ? mousePressed : undefined,
80
+ mouseReleased: typeof mouseReleased === 'function' ? mouseReleased : undefined,
81
+ mouseMoved: typeof mouseMoved === 'function' ? mouseMoved : undefined,
82
+ mouseDragged: typeof mouseDragged === 'function' ? mouseDragged : undefined,
83
+ mouseClicked: typeof mouseClicked === 'function' ? mouseClicked : undefined,
84
+ doubleClicked: typeof doubleClicked === 'function' ? doubleClicked : undefined,
85
+ mouseWheel: typeof mouseWheel === 'function' ? mouseWheel : undefined,
86
+ // Keyboard events
87
+ keyPressed: typeof keyPressed === 'function' ? keyPressed : undefined,
88
+ keyReleased: typeof keyReleased === 'function' ? keyReleased : undefined,
89
+ keyTyped: typeof keyTyped === 'function' ? keyTyped : undefined
90
+ };
91
  }
92
  `);
93
 
 
111
  // Add a custom class to help with styling
112
  p._renderer.canvas.classList.add('p5-managed-canvas');
113
  }
 
 
 
114
  }
115
  };
116
 
117
  p.draw = functions.draw.bind(p);
118
+
119
+ // Bind all mouse and keyboard event handlers
120
+ if (functions.mousePressed) p.mousePressed = functions.mousePressed.bind(p);
121
+ if (functions.mouseReleased) p.mouseReleased = functions.mouseReleased.bind(p);
122
+ if (functions.mouseMoved) p.mouseMoved = functions.mouseMoved.bind(p);
123
+ if (functions.mouseDragged) p.mouseDragged = functions.mouseDragged.bind(p);
124
+ if (functions.mouseClicked) p.mouseClicked = functions.mouseClicked.bind(p);
125
+ if (functions.doubleClicked) p.doubleClicked = functions.doubleClicked.bind(p);
126
+ if (functions.mouseWheel) p.mouseWheel = functions.mouseWheel.bind(p);
127
+ if (functions.keyPressed) p.keyPressed = functions.keyPressed.bind(p);
128
+ if (functions.keyReleased) p.keyReleased = functions.keyReleased.bind(p);
129
+ if (functions.keyTyped) p.keyTyped = functions.keyTyped.bind(p);
130
 
131
  // Cleanup when sketch is removed
132
  p._cleanup = () => {
133
+ // No cleanup needed anymore
 
 
 
 
 
 
 
134
  };
135
  }, container);
136
 
src/App.scss CHANGED
@@ -198,12 +198,11 @@ body {
198
 
199
  .p5-editor-container {
200
  width: 100%;
201
- height: calc(100% - 100px);
202
- border-radius: 12px;
203
- border: 2px solid var(--gray-600);
204
  overflow: hidden;
205
- box-shadow: 0 4px 12px rgba(0, 0, 0, 0.2);
206
- background-color: var(--Neutral-10);
207
 
208
  @media (max-width: 1024px) {
209
  width: 100%;
 
198
 
199
  .p5-editor-container {
200
  width: 100%;
201
+ height: 600px;
202
+ position: relative;
 
203
  overflow: hidden;
204
+ border-radius: 10px;
205
+ background: #1e1e1e;
206
 
207
  @media (max-width: 1024px) {
208
  width: 100%;
src/components/p5/P5WithEditor.tsx CHANGED
@@ -27,6 +27,7 @@ declare global {
27
  initSketch: (container: HTMLElement) => void;
28
  updateSketch: (code: string, container: HTMLElement) => boolean;
29
  removeSketch: () => void;
 
30
  }
31
  }
32
 
@@ -47,8 +48,13 @@ function P5WithEditorComponent() {
47
  const [isSending, setIsSending] = useState(false);
48
  const [isAnimatingCode, setIsAnimatingCode] = useState(false);
49
  const [cursorPosition, setCursorPosition] = useState<{ lineNumber: number, column: number } | null>(null);
 
50
  const editorRef = useRef<any>(null);
51
  const animationTimeoutRef = useRef<NodeJS.Timeout | null>(null);
 
 
 
 
52
 
53
  // Function to handle editor mounting
54
  const handleEditorDidMount = (editor: any) => {
@@ -190,20 +196,33 @@ function P5WithEditorComponent() {
190
  // Convert to array if it's not already
191
  const partsArray = Array.isArray(parts) ? parts : [parts];
192
 
193
- // Check if there's text content and we have editor content
194
  const hasTextContent = partsArray.some(part => part.text);
195
 
196
- if (hasTextContent && editorContent) {
197
  // Show sending indicator
198
  setIsSending(true);
199
 
200
- // Format the code before sending
201
- const formattedCode = formatCodeForModel(editorContent);
202
-
203
- // Add the current editor content as context
204
- partsArray.push({
205
- text: `\n\n--- CURRENT P5.JS CODE IN EDITOR ---\n\`\`\`javascript\n${formattedCode}\n\`\`\`\n\nPlease consider this code when responding to my request. If I'm asking for changes or improvements, use this as the starting point.`
206
- });
 
 
 
 
 
 
 
 
 
 
 
 
 
207
 
208
  // Hide sending indicator after a short delay
209
  setTimeout(() => setIsSending(false), 1000);
@@ -217,7 +236,7 @@ function P5WithEditorComponent() {
217
  return () => {
218
  client.send = originalSend;
219
  };
220
- }, [client, editorContent]);
221
 
222
  useEffect(() => {
223
  if (containerRef.current) {
@@ -314,38 +333,42 @@ function windowResized() {
314
  }
315
  `;
316
 
 
 
 
317
  // Set the editor content and displayed content
318
  setEditorContent(testSketch);
319
  setDisplayedContent(testSketch);
320
 
321
  // Update the sketch with the test code
322
  window.updateSketch(testSketch, containerRef.current);
323
- }
324
-
325
- // Cleanup on unmount
326
- return () => {
327
- window.removeSketch();
328
- };
329
- }, []);
330
 
331
- useEffect(() => {
332
- setConfig({
333
- model: "models/gemini-2.0-flash-exp",
334
- generationConfig: {
335
- temperature: 0.1,
336
- responseModalities: "audio",
337
- speechConfig: {
338
- voiceConfig: {
339
- prebuiltVoiceConfig: {
340
- voiceName: "Puck"
 
341
  }
342
  }
343
- }
344
- },
345
- systemInstruction: {
346
- parts: [
347
- {
348
- text: `You are a P5.js creative coding expert that helps users create interactive sketches.
 
 
 
 
 
 
 
349
 
350
  When a user requests a sketch:
351
  1. Always use the updateSketch function to create or modify sketches
@@ -360,31 +383,39 @@ You can create sketches using:
360
  - Sprite-based games (p5.play library)
361
  - Full window canvas with automatic resizing
362
 
 
 
363
  Focus on creating visually engaging and interactive experiences. As soon as the user requests a sketch, confirm you heard them, THEN you should create the sketch and then explain what it does and how to interact with it. Be EXTREMELY brief and pithy.`
364
- },
365
- ],
366
- },
367
- tools: [
368
- {
369
- functionDeclarations: [
370
- {
371
- name: "updateSketch",
372
- description: "Create or update the P5.js sketch with new code. The sketch will run in a full-window canvas.",
373
- parameters: {
374
- type: SchemaType.OBJECT,
375
- properties: {
376
- sketch: {
377
- type: SchemaType.STRING,
378
- description: "Complete P5.js sketch code including all variable declarations, setup(), draw(), and any additional functions needed. The code should be a complete, self-contained sketch."
379
- }
380
- },
381
- required: ["sketch"]
382
- }
383
- }
384
  ],
385
  },
386
- ],
387
- });
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
388
  }, [setConfig]);
389
 
390
  useEffect(() => {
@@ -487,22 +518,30 @@ Focus on creating visually engaging and interactive experiences. As soon as the
487
  return;
488
  }
489
 
490
- // Always update both editor content and displayed content when user types
491
  setEditorContent(value);
492
  setDisplayedContent(value);
493
 
494
- if (!containerRef.current) {
495
- console.warn("Container ref is not available");
496
- return;
497
  }
498
 
499
- try {
500
- console.log("Updating sketch from editor");
501
- const result = window.updateSketch(value, containerRef.current);
502
- console.log("Editor update result:", result);
503
- } catch (error) {
504
- console.error("Error updating sketch from editor:", error);
505
- }
 
 
 
 
 
 
 
 
506
  };
507
 
508
  const startResizing = useCallback((e: React.MouseEvent) => {
@@ -527,13 +566,11 @@ Focus on creating visually engaging and interactive experiences. As soon as the
527
  const newWidth = (e.clientX / containerWidth) * 100;
528
  setEditorWidth(Math.min(Math.max(20, newWidth), 80)); // Limit between 20% and 80%
529
 
530
- // Force p5.js to update its dimensions
531
- if (containerRef.current) {
532
- // Small delay to let the DOM update
533
- setTimeout(() => {
534
- const event = new Event('resize');
535
- window.dispatchEvent(event);
536
- }, 50);
537
  }
538
  }
539
  }
 
27
  initSketch: (container: HTMLElement) => void;
28
  updateSketch: (code: string, container: HTMLElement) => boolean;
29
  removeSketch: () => void;
30
+ mySketch: any;
31
  }
32
  }
33
 
 
48
  const [isSending, setIsSending] = useState(false);
49
  const [isAnimatingCode, setIsAnimatingCode] = useState(false);
50
  const [cursorPosition, setCursorPosition] = useState<{ lineNumber: number, column: number } | null>(null);
51
+ const [isFirstQuestion, setIsFirstQuestion] = useState(true); // Track if this is the first question
52
  const editorRef = useRef<any>(null);
53
  const animationTimeoutRef = useRef<NodeJS.Timeout | null>(null);
54
+ const updateTimeoutRef = useRef<NodeJS.Timeout | null>(null);
55
+
56
+ // Store test sketch reference
57
+ const testSketchRef = useRef<string>("");
58
 
59
  // Function to handle editor mounting
60
  const handleEditorDidMount = (editor: any) => {
 
196
  // Convert to array if it's not already
197
  const partsArray = Array.isArray(parts) ? parts : [parts];
198
 
199
+ // Check if there's text content
200
  const hasTextContent = partsArray.some(part => part.text);
201
 
202
+ if (hasTextContent) {
203
  // Show sending indicator
204
  setIsSending(true);
205
 
206
+ if (isFirstQuestion) {
207
+ // For the first question, include the initial test sketch code
208
+ const sketchToUse = testSketchRef.current || editorContent;
209
+ const formattedCode = formatCodeForModel(sketchToUse);
210
+
211
+ // Add the test sketch as context for the first question
212
+ partsArray.push({
213
+ text: `\n\n--- CURRENT P5.JS CODE IN EDITOR ---\n\`\`\`javascript\n${formattedCode}\n\`\`\`\n\nPlease use this code as a starting point. You can modify or improve it based on my request.`
214
+ });
215
+
216
+ // Mark first question as used
217
+ setIsFirstQuestion(false);
218
+ } else if (editorContent) {
219
+ // For subsequent questions, use the current editor content
220
+ const formattedCode = formatCodeForModel(editorContent);
221
+
222
+ partsArray.push({
223
+ text: `\n\n--- CURRENT P5.JS CODE IN EDITOR ---\n\`\`\`javascript\n${formattedCode}\n\`\`\`\n\nPlease consider this code when responding to my request. If I'm asking for changes or improvements, use this as the starting point.`
224
+ });
225
+ }
226
 
227
  // Hide sending indicator after a short delay
228
  setTimeout(() => setIsSending(false), 1000);
 
236
  return () => {
237
  client.send = originalSend;
238
  };
239
+ }, [client, editorContent, isFirstQuestion]);
240
 
241
  useEffect(() => {
242
  if (containerRef.current) {
 
333
  }
334
  `;
335
 
336
+ // Store test sketch in the ref for later use
337
+ testSketchRef.current = testSketch;
338
+
339
  // Set the editor content and displayed content
340
  setEditorContent(testSketch);
341
  setDisplayedContent(testSketch);
342
 
343
  // Update the sketch with the test code
344
  window.updateSketch(testSketch, containerRef.current);
 
 
 
 
 
 
 
345
 
346
+ // Configure the model with the test sketch included in the system instruction
347
+ setConfig({
348
+ model: "models/gemini-2.0-flash-exp",
349
+ generationConfig: {
350
+ temperature: 0.1,
351
+ responseModalities: "audio",
352
+ speechConfig: {
353
+ voiceConfig: {
354
+ prebuiltVoiceConfig: {
355
+ voiceName: "Puck"
356
+ }
357
  }
358
  }
359
+ },
360
+ systemInstruction: {
361
+ parts: [
362
+ {
363
+ text: `You are a P5.js creative coding expert that helps users create interactive sketches.
364
+
365
+ INITIAL CODE IN EDITOR:
366
+ \`\`\`javascript
367
+ ${testSketch}
368
+ \`\`\`
369
+
370
+ When the user asks their first question, use the above code as a starting point. Modify it based on their request.
371
+ Your responses should be direct, helpful, and technically accurate. Users are looking for creative coding help with p5.js sketches.
372
 
373
  When a user requests a sketch:
374
  1. Always use the updateSketch function to create or modify sketches
 
383
  - Sprite-based games (p5.play library)
384
  - Full window canvas with automatic resizing
385
 
386
+ In the setup() function, ALWAYS use the createCanvas(containerWidth, containerHeight) function to create the canvas. DO NOT EVER use windowWidth or windowHeight.
387
+
388
  Focus on creating visually engaging and interactive experiences. As soon as the user requests a sketch, confirm you heard them, THEN you should create the sketch and then explain what it does and how to interact with it. Be EXTREMELY brief and pithy.`
389
+ },
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
390
  ],
391
  },
392
+ tools: [
393
+ {
394
+ functionDeclarations: [
395
+ {
396
+ name: "updateSketch",
397
+ description: "Create or update the P5.js sketch with new code. The sketch will run in a full-window canvas.",
398
+ parameters: {
399
+ type: SchemaType.OBJECT,
400
+ properties: {
401
+ sketch: {
402
+ type: SchemaType.STRING,
403
+ description: "Complete P5.js sketch code including all variable declarations, setup(), draw(), and any additional functions needed. The code should be a complete, self-contained sketch. In the setup() function, ALWAYS use the createCanvas(containerWidth, containerHeight) function to create the canvas. DO NOT EVER use windowWidth or windowHeight."
404
+ }
405
+ },
406
+ required: ["sketch"]
407
+ }
408
+ }
409
+ ],
410
+ },
411
+ ],
412
+ });
413
+ }
414
+
415
+ // Cleanup on unmount
416
+ return () => {
417
+ window.removeSketch();
418
+ };
419
  }, [setConfig]);
420
 
421
  useEffect(() => {
 
518
  return;
519
  }
520
 
521
+ // Always update editor content immediately for responsiveness
522
  setEditorContent(value);
523
  setDisplayedContent(value);
524
 
525
+ // Clear any existing timeout
526
+ if (updateTimeoutRef.current) {
527
+ clearTimeout(updateTimeoutRef.current);
528
  }
529
 
530
+ // Debounce the sketch update
531
+ updateTimeoutRef.current = setTimeout(() => {
532
+ if (!containerRef.current) {
533
+ console.warn("Container ref is not available");
534
+ return;
535
+ }
536
+
537
+ try {
538
+ console.log("Updating sketch from editor");
539
+ const result = window.updateSketch(value, containerRef.current);
540
+ console.log("Editor update result:", result);
541
+ } catch (error) {
542
+ console.error("Error updating sketch from editor:", error);
543
+ }
544
+ }, 1000); // Wait for 1 second of no changes before updating
545
  };
546
 
547
  const startResizing = useCallback((e: React.MouseEvent) => {
 
566
  const newWidth = (e.clientX / containerWidth) * 100;
567
  setEditorWidth(Math.min(Math.max(20, newWidth), 80)); // Limit between 20% and 80%
568
 
569
+ // Update sketch dimensions directly if needed
570
+ if (containerRef.current && window.mySketch) {
571
+ window.mySketch.containerWidth = containerRef.current.clientWidth;
572
+ window.mySketch.containerHeight = containerRef.current.clientHeight;
573
+ window.mySketch.resizeCanvas(window.mySketch.containerWidth, window.mySketch.containerHeight);
 
 
574
  }
575
  }
576
  }
src/components/p5/p5-with-editor.scss CHANGED
@@ -5,6 +5,7 @@
5
  overflow: hidden;
6
  position: relative;
7
  border-radius: 10px;
 
8
 
9
  @media (max-width: 768px) {
10
  flex-direction: column;
@@ -107,6 +108,7 @@
107
  position: relative;
108
  background: #000;
109
  overflow: hidden;
 
110
 
111
  canvas {
112
  display: block !important;
@@ -115,6 +117,7 @@
115
  position: relative !important;
116
  margin: auto;
117
  object-fit: contain;
 
118
  }
119
 
120
  // Fix for p5.js accessibility tooltips
 
5
  overflow: hidden;
6
  position: relative;
7
  border-radius: 10px;
8
+ border: 2px solid #2d2d2d;
9
 
10
  @media (max-width: 768px) {
11
  flex-direction: column;
 
108
  position: relative;
109
  background: #000;
110
  overflow: hidden;
111
+ pointer-events: auto;
112
 
113
  canvas {
114
  display: block !important;
 
117
  position: relative !important;
118
  margin: auto;
119
  object-fit: contain;
120
+ pointer-events: auto;
121
  }
122
 
123
  // Fix for p5.js accessibility tooltips