@usman404/crowjs 1.0.2

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,551 @@
1
+ import { Input } from "./Input.js";
2
+
3
+ export class TextField extends Input{
4
+ /**
5
+ * Creates a text input field with advanced editing features
6
+ * @param {number} x - The x-coordinate
7
+ * @param {number} y - The y-coordinate
8
+ * @param {number} width - The width
9
+ * @param {number} height - The height
10
+ * @param {Object} options - Configuration options
11
+ * @param {string|null} options.id - Component ID
12
+ * @param {Component|null} options.parent - Parent component
13
+ * @param {string} options.backgroundColor - Background color
14
+ * @param {string} options.textColor - Text color
15
+ * @param {boolean} options.borderFlag - Show border
16
+ * @param {p5.Color} options.borderColor - Border color
17
+ * @param {number} options.borderWidth - Border width
18
+ * @param {number} options.cornerRadius - Corner radius
19
+ * @param {boolean} options.enableShadow - Enable shadow
20
+ * @param {string} options.shadowColor - Shadow color
21
+ * @param {number} options.shadowIntensity - Shadow opacity
22
+ * @param {number} options.shadowSpread - Shadow spread
23
+ * @param {number} options.shadowDetail - Shadow layers
24
+ * @param {string} options.placeholder - Placeholder text
25
+ * @param {string} options.text - Initial text
26
+ * @param {string} options.textAlign - Text alignment
27
+ * @param {number} options.padding - Internal padding
28
+ */
29
+ constructor(x, y, width, height,
30
+ {
31
+ id=null,
32
+ parent=null,
33
+ backgroundColor='rgb(255, 255, 255)',
34
+ textColor='rgb(0, 0, 0)',
35
+ borderFlag = true,
36
+ borderColor = color(0),
37
+ borderWidth = 1,
38
+ cornerRadius = 0,
39
+ enableShadow=false,
40
+ shadowColor= 'rgb(0,0,0)',
41
+ shadowIntensity= 0.4,
42
+ shadowSpread= 3,
43
+ shadowDetail=5,
44
+ placeholder="",
45
+ text="",
46
+ textAlign = "left",
47
+ padding = 10,
48
+ }={}) {
49
+ super(x, y, width, height, backgroundColor, borderFlag, borderColor,
50
+ borderWidth, cornerRadius, enableShadow, shadowColor, shadowIntensity,
51
+ shadowSpread, shadowDetail, {parent: parent, type: "Input", id: id});
52
+
53
+ this.cursorPos = 0;
54
+ this.text = text;
55
+ this.textSize = 30;
56
+ this.displayXOffset = 0;
57
+
58
+ this.textAlign = textAlign;
59
+ this.padding = padding;
60
+ this.textColor = textColor;
61
+ this.placeholder = placeholder;
62
+
63
+ this.cursorVisible = true;
64
+ this.lastCursorToggle = millis();
65
+ this.cursorBlinkInterval = 500;
66
+
67
+ this.selectionStart = null;
68
+ this.selectionEnd = null;
69
+ this.isSelecting = false;
70
+
71
+ this.addEventListener("keyPress", (event)=>this.onKeyPress(event));
72
+ // this.addEventListener("click", (event)=>this.onMouseClick(event));
73
+ this.addEventListener("press", (event)=>this.onMousePress(event)); // NEW
74
+ this.addEventListener("drag", (event)=>this.onMouseDrag(event));
75
+ this.addEventListener("release", (event)=>this.onMouseRelease(event));
76
+ this.addEventListener("hover", (event)=>this.onMouseHover(event));
77
+ this.addEventListener("blur", (event)=>this.onBlur(event));
78
+ // this.addEventListener("focus", (event)=>this.onFocus(event));
79
+ }
80
+
81
+ /**
82
+ * Handles mouse hover events
83
+ * @param {MouseEvent} event - The hover event
84
+ */
85
+ onMouseHover(event){
86
+ // event.stopPropagation();
87
+ }
88
+
89
+ /**
90
+ * Handles mouse release events
91
+ * @param {MouseEvent} event - The release event
92
+ */
93
+ onMouseRelease(event) {
94
+ this.isSelecting = false;
95
+ }
96
+
97
+ // onFocus(event){
98
+ // console.log("focus called!");
99
+ // }
100
+
101
+ onBlur(event){
102
+ this.isSelecting = false;
103
+
104
+ // Clear selection
105
+ this.selectionStart = null;
106
+ this.selectionEnd = null;
107
+
108
+ // Cursor usually hides after blur in textfields
109
+ this.cursorVisible = false;
110
+
111
+ console.log("blur called!");
112
+
113
+ event.stopPropagation();
114
+ }
115
+
116
+ onMousePress(event) {
117
+ if (!this.isFocused) {
118
+ this.focus();
119
+ }
120
+
121
+ this.isSelecting = true;
122
+
123
+ // Clamp X for initial cursor position
124
+ let x = event.x;
125
+ if (x <= this.x - 1000) x = this.x - 1000;
126
+ if (x >= this.x + this.width + 1000) x = this.x + this.width + 1000;
127
+
128
+ // Convert X → character index
129
+ let idx = this.getCursorIndexFromX(x);
130
+
131
+ // Set selection start and cursor immediately (start selecting instantly)
132
+ this.selectionStart = idx;
133
+ this.selectionEnd = idx;
134
+ this.cursorPos = idx;
135
+
136
+ // Ensure cursor visible & auto scroll
137
+ this.scrollCursorIntoView();
138
+ this.cursorVisible = true;
139
+ this.lastCursorToggle = millis();
140
+
141
+ event.stopPropagation();
142
+ }
143
+
144
+ onMouseDrag(event) {
145
+ if (this.isSelecting && this.isFocused) {
146
+
147
+ let x = event.x;
148
+ if (x <= this.x - 1000) x = this.x - 1000;
149
+ if (x >= this.x + this.width + 1000) x = this.x + this.width + 1000;
150
+
151
+ let pos = this.getCursorIndexFromX(x);
152
+
153
+ this.selectionEnd = pos;
154
+ this.cursorPos = pos;
155
+
156
+ this.scrollCursorIntoView();
157
+ this.cursorVisible = true;
158
+ this.lastCursorToggle = millis();
159
+
160
+ event.stopPropagation();
161
+ }
162
+ }
163
+
164
+ onKeyPress(event) {
165
+ // ADDED: if there's an active selection and user types or presses backspace/delete,
166
+ // we should remove the selection first (so typed char replaces selection)
167
+ const hasSelection = this.selectionStart !== null && this.selectionStart !== this.selectionEnd;
168
+
169
+ if (keyCode === LEFT_ARROW) {
170
+ if (keyIsDown(CONTROL)) {
171
+ this.jumpLeftByOneWord();
172
+ } else {
173
+ this.moveCursorLeft(1);
174
+ }
175
+ // collapse selection when using arrows (typical behavior)
176
+ this.selectionStart = this.selectionEnd = this.cursorPos;
177
+ } else if (keyCode === RIGHT_ARROW) {
178
+ if (keyIsDown(CONTROL)) {
179
+ this.jumpRightByOneWord();
180
+ } else {
181
+ this.moveCursorRight(1);
182
+ }
183
+ this.selectionStart = this.selectionEnd = this.cursorPos;
184
+ } else if (keyCode === BACKSPACE) {
185
+ if (hasSelection) {
186
+ // ADDED: delete selection (Backspace with selection deletes selection)
187
+ this.deleteSelectedText();
188
+ } else if (keyIsDown(CONTROL)) {
189
+ this.deleteOneWord();
190
+ } else {
191
+ this.deleteOneChar();
192
+ }
193
+ // collapse selection after deletion
194
+ this.selectionStart = this.selectionEnd = this.cursorPos;
195
+ } else if (key.length === 1) {
196
+ // ADDED: if a selection exists, remove it before insertion so typed char replaces selection
197
+ if (hasSelection) {
198
+ this.deleteSelectedText();
199
+ }
200
+ // Insert the character at cursor
201
+ this.text = this.text.slice(0, this.cursorPos) + key + this.text.slice(this.cursorPos);
202
+ this.moveCursorRight(1);
203
+ // collapse selection after insertion
204
+ this.selectionStart = this.selectionEnd = this.cursorPos;
205
+ }
206
+
207
+ this.cursorVisible = true;
208
+ this.lastCursorToggle = millis();
209
+ }
210
+
211
+
212
+ /**
213
+ * Compute the X coordinate where the rendered text starts (accounts for alignment & displayXOffset)
214
+ * ADDED helper -- use this from click/drag/any cursor-from-x routines.
215
+ */
216
+ computeTextStartX() {
217
+ // ADDED: measure full text width once
218
+ push();
219
+ textSize(this.textSize);
220
+ let fullWidth = textWidth(this.text || ""); // safe for empty string
221
+ pop();
222
+
223
+ if (this.textAlign === "left") {
224
+ // left aligned starts at left padding, minus the scroll offset
225
+ return this.x + this.padding - this.displayXOffset;
226
+ } else if (this.textAlign === "right") {
227
+ // right aligned: text ends at width - padding, so start is that minus fullWidth
228
+ return this.x + this.width - this.padding - fullWidth - this.displayXOffset;
229
+ } else { // center or anything else
230
+ return this.x + this.width / 2 - fullWidth / 2 - this.displayXOffset;
231
+ }
232
+ }
233
+
234
+ /**
235
+ * Convert absolute click X into cursor index (0..text.length).
236
+ * ADDED helper - replaces duplicated click/drag loop logic.
237
+ */
238
+ getCursorIndexFromX(clickX) {
239
+ // Compute text start and relative click
240
+ let textStartX = this.computeTextStartX(); // ADDED use centralized function
241
+ let relativeX = clickX - textStartX;
242
+
243
+ // Early out: before start
244
+ if (relativeX <= 0) return 0;
245
+
246
+ // Measure and walk characters
247
+ push();
248
+ textSize(this.textSize);
249
+ let cumulativeWidth = 0;
250
+ let pos = 0;
251
+ const len = this.text.length;
252
+ for (let i = 0; i < len; i++) { // ADDED: loop < len (avoid charAt(len))
253
+ let ch = this.text.charAt(i);
254
+ let nextWidth = textWidth(ch);
255
+ // Midpoint rule: place cursor before the character if closer to left half
256
+ if (relativeX < cumulativeWidth + nextWidth / 2) {
257
+ pos = i;
258
+ pop();
259
+ return pos;
260
+ }
261
+ cumulativeWidth += nextWidth;
262
+ pos = i + 1; // cursor after this char
263
+ }
264
+ pop();
265
+
266
+ // If we got here, click is after all characters -> cursor at end
267
+ return len;
268
+ }
269
+
270
+
271
+ deleteSelectedText(){
272
+ if (this.selectionStart !== null && this.selectionStart !== this.selectionEnd) {
273
+ let start = min(this.selectionStart, this.selectionEnd);
274
+ let end = max(this.selectionStart, this.selectionEnd);
275
+
276
+ this.text = this.text.slice(0, start) + this.text.slice(end);
277
+ this.cursorPos = start;
278
+
279
+ // ADDED: clear selection anchors and ensure they reflect cursor
280
+ this.selectionStart = this.selectionEnd = null;
281
+ }
282
+ }
283
+
284
+ /**
285
+ * Moves cursor left by one word (Ctrl+Left arrow)
286
+ */
287
+ jumpLeftByOneWord(){
288
+ if (this.cursorPos > 0) {
289
+ let i = this.cursorPos - 1;
290
+ while (i > 0 && this.text[i] === ' ') i--;
291
+ while (i > 0 && this.text[i - 1] !== ' ') i--;
292
+ this.cursorPos = i;
293
+
294
+ this.scrollCursorIntoViewLeft();
295
+ }
296
+ }
297
+
298
+ /**
299
+ * Moves cursor right by one word (Ctrl+Right arrow)
300
+ */
301
+ jumpRightByOneWord(){
302
+ if (this.cursorPos < this.text.length) {
303
+ let i = this.cursorPos;
304
+ while (i < this.text.length && this.text[i] !== ' ') i++;
305
+ while (i < this.text.length && this.text[i] === ' ') i++;
306
+ this.cursorPos = i;
307
+
308
+ this.scrollCursorIntoViewRight();
309
+ }
310
+ }
311
+
312
+ /**
313
+ * Deletes one word to the left (Ctrl+Backspace)
314
+ */
315
+ deleteOneWord(){
316
+ if (this.cursorPos > 0) {
317
+ let i = this.cursorPos - 1;
318
+
319
+ while (i > 0 && this.text[i] === ' ') {
320
+ i--;
321
+ }
322
+
323
+ while (i > 0 && this.text[i - 1] !== ' ') {
324
+ i--;
325
+ }
326
+
327
+ this.text = this.text.slice(0, i) + this.text.slice(this.cursorPos);
328
+ this.cursorPos = i;
329
+
330
+ this.scrollCursorIntoViewLeft();
331
+ }
332
+ }
333
+
334
+ /**
335
+ * Deletes one character to the left (Backspace)
336
+ */
337
+ deleteOneChar(){
338
+ if (this.cursorPos > 0) {
339
+ this.text = this.text.slice(0, this.cursorPos - 1) + this.text.slice(this.cursorPos);
340
+ this.moveCursorLeft(1);
341
+ }
342
+ }
343
+
344
+ /**
345
+ * Calculates the width of text between two positions
346
+ * @param {number} startPos - Starting character position
347
+ * @param {number} endPos - Ending character position
348
+ * @returns {number} The width in pixels
349
+ */
350
+ findTextWidth(startPos, endPos){
351
+ startPos = constrain(startPos, 0, this.text.length);
352
+ endPos = constrain(endPos, 0, this.text.length);
353
+
354
+ push();
355
+ textSize(this.textSize);
356
+ let txt = this.text.slice(startPos, endPos);
357
+ let txtWidth = textWidth(txt);
358
+ pop();
359
+ return txtWidth;
360
+ }
361
+
362
+ /**
363
+ * Calculates the width of given text
364
+ * @param {string} text - The text to measure
365
+ * @returns {number} The width in pixels
366
+ */
367
+ findTextWidthOfGivenText(text){
368
+ push();
369
+ textSize(this.textSize);
370
+ let txtWidth = textWidth(text);
371
+ pop();
372
+ return txtWidth;
373
+ }
374
+
375
+ /**
376
+ * Moves cursor right by specified number of characters
377
+ * @param {number} increment - Number of characters to move
378
+ */
379
+ moveCursorRight(increment){
380
+ if (this.cursorPos < this.text.length) {
381
+ this.cursorPos += increment;
382
+ }
383
+
384
+ this.scrollCursorIntoViewRight();
385
+ }
386
+
387
+ /**
388
+ * Moves cursor left by specified number of characters
389
+ * @param {number} decrement - Number of characters to move
390
+ */
391
+ moveCursorLeft(decrement){
392
+ if(this.cursorPos > 0){
393
+ this.cursorPos -= decrement;
394
+ }
395
+
396
+ this.scrollCursorIntoViewLeft();
397
+ }
398
+
399
+ /**
400
+ * Ensures cursor remains visible when moving right
401
+ * @param {Object} options - Scroll options
402
+ * @param {number|null} options.cursorX - Optional cursor X position
403
+ */
404
+ scrollCursorIntoViewRight({cursorX=null} = {}){
405
+ if(!cursorX){
406
+ cursorX = this.findTextWidth(0, this.cursorPos);
407
+ }
408
+
409
+ if (cursorX - this.displayXOffset > this.width - this.padding) {
410
+ this.displayXOffset = cursorX - this.width + 2*this.padding;
411
+ }
412
+
413
+ if(!cursorX){
414
+ this.displayXOffset = max(0, this.displayXOffset);
415
+ }
416
+ }
417
+
418
+ /**
419
+ * Ensures cursor remains visible when moving left
420
+ * @param {Object} options - Scroll options
421
+ * @param {number|null} options.cursorX - Optional cursor X position
422
+ */
423
+ scrollCursorIntoViewLeft({cursorX=null} = {}){
424
+ if(!cursorX){
425
+ cursorX = this.findTextWidth(0, this.cursorPos);
426
+ }
427
+
428
+ if(cursorX - this.displayXOffset < this.padding){
429
+ this.displayXOffset = cursorX - this.padding;
430
+ }
431
+
432
+ if(!cursorX){
433
+ this.displayXOffset = max(0, this.displayXOffset);
434
+ }
435
+ }
436
+
437
+ /**
438
+ * Ensures cursor remains within visible area
439
+ */
440
+ scrollCursorIntoView(){
441
+ let cursorX = this.findTextWidth(0, this.cursorPos);
442
+ this.scrollCursorIntoViewRight(cursorX);
443
+ this.scrollCursorIntoViewLeft(cursorX);
444
+ this.displayXOffset = max(0, this.displayXOffset);
445
+ }
446
+
447
+ /**
448
+ * Converts text alignment string to P5 constant
449
+ * @returns {number} P5 alignment constant
450
+ */
451
+ getTextAlignment(){
452
+ if(this.textAlign==="right"){
453
+ return RIGHT;
454
+ } else {
455
+ return LEFT;
456
+ }
457
+ }
458
+
459
+ /**
460
+ * Renders the text field with text, cursor, and selection
461
+ */
462
+ show(){
463
+ if(this.enableShadow){
464
+ this.drawShadow();
465
+ }
466
+
467
+ push();
468
+ beginClip();
469
+ rect(this.x, this.y, this.width, this.height, this.cornerRadius);
470
+ endClip();
471
+
472
+ push();
473
+ fill(this.backgroundColor);
474
+ rect(this.x, this.y, this.width, this.height, this.cornerRadius);
475
+ pop();
476
+
477
+ fill(this.textColor);
478
+ textAlign(this.getTextAlignment(), CENTER);
479
+ textSize(this.textSize);
480
+
481
+ let x, y;
482
+ if(this.textAlign==="left"){
483
+ x = this.x - this.displayXOffset + this.padding;
484
+ } else if(this.textAlign==="right") {
485
+ x = this.x - this.displayXOffset + this.width - this.textSize;
486
+ }
487
+ y = this.y + this.height/2 + this.height*0.01;
488
+
489
+ if (this.selectionStart !== null && this.selectionEnd !== null && this.selectionStart !== this.selectionEnd) {
490
+ let start = min(this.selectionStart, this.selectionEnd);
491
+ let end = max(this.selectionStart, this.selectionEnd);
492
+
493
+ let highlightX = x + this.findTextWidth(0, start);
494
+ let highlightWidth = this.findTextWidth(start, end);
495
+ let highlightY = y - this.textSize * 0.7;
496
+
497
+ push();
498
+ fill('rgba(15, 111, 206, 0.7)');
499
+ noStroke();
500
+ rect(highlightX, highlightY, highlightWidth, this.textSize);
501
+ pop();
502
+ }
503
+
504
+ text(this.text, x, y);
505
+
506
+ if (millis() - this.lastCursorToggle > this.cursorBlinkInterval) {
507
+ this.cursorVisible = !this.cursorVisible;
508
+ this.lastCursorToggle = millis();
509
+ }
510
+
511
+ if(this.isFocused){
512
+ let cursorX = x + this.findTextWidth(0, this.cursorPos);
513
+ if (this.cursorVisible) {
514
+ stroke(this.textColor);
515
+ strokeWeight(2);
516
+ line(cursorX, y - this.textSize * 0.5, cursorX, y + this.textSize * 0.45);
517
+ }
518
+ }
519
+
520
+ if(this.borderFlag) {
521
+ noFill();
522
+ stroke(this.borderColor);
523
+ strokeWeight(this.borderWidth);
524
+ rect(this.x, this.y, this.width, this.height, this.cornerRadius);
525
+ }
526
+
527
+ pop();
528
+ }
529
+
530
+ /**
531
+ * Updates text size based on current height
532
+ */
533
+ updateTextSize(){
534
+ this.textSize = this.height * 0.9;
535
+ this.scrollCursorIntoView();
536
+ }
537
+
538
+ /**
539
+ * Handles width changes
540
+ */
541
+ updateWidth(){
542
+ //don't do anything here!
543
+ }
544
+
545
+ /**
546
+ * Handles height changes and updates text size
547
+ */
548
+ updateHeight(){
549
+ this.updateTextSize();
550
+ }
551
+ }
@@ -0,0 +1,97 @@
1
+ import { Component } from "../Core/Component.js";
2
+
3
+ export class UIComponent extends Component{
4
+ /**
5
+ * Creates a new UIComponent with visual styling
6
+ * @param {number} x - The x-coordinate
7
+ * @param {number} y - The y-coordinate
8
+ * @param {number} width - The width
9
+ * @param {number} height - The height
10
+ * @param {p5.Color} backgroundColor - Background color
11
+ * @param {boolean} borderFlag - Whether to show border
12
+ * @param {p5.Color} borderColor - Border color
13
+ * @param {number} borderWidth - Border width
14
+ * @param {number} cornerRadius - Corner radius for rounded corners
15
+ * @param {boolean} enableShadow - Whether to render shadow
16
+ * @param {string} shadowColor - Shadow color in RGB format
17
+ * @param {number} shadowIntensity - Shadow opacity (0-1)
18
+ * @param {number} shadowSpread - Shadow spread amount
19
+ * @param {number} shadowDetail - Number of shadow layers
20
+ * @param {Object} options - Additional options
21
+ * @param {Component|null} options.parent - Parent component
22
+ * @param {string} options.type - Component type
23
+ * @param {string|null} options.id - Component ID
24
+ */
25
+ constructor(x, y, width, height, backgroundColor, borderFlag, borderColor,
26
+ borderWidth, cornerRadius, enableShadow, shadowColor, shadowIntensity,
27
+ shadowSpread, shadowDetail, {parent=null, type="", id=null} = {}){
28
+ super(x, y, width, height, {parent: parent, type: type, id: id});
29
+
30
+ this.backgroundColor = backgroundColor;
31
+
32
+ this.borderFlag = borderFlag;
33
+ if(this.borderFlag){
34
+ this.borderColor = borderColor;
35
+ this.borderWidth = borderWidth;
36
+ }
37
+
38
+ this.enableShadow = enableShadow;
39
+
40
+ if(this.enableShadow){
41
+ this.shadowColor = shadowColor;//rgb value
42
+ this.shadowIntensity = shadowIntensity;//opacity value between 0 and 1
43
+ this.shadowSpread = shadowSpread;//stroke width of each of those rectangles
44
+ this.shadowDetail = shadowDetail;//number of rectangles that will be drawn around the component
45
+ }
46
+
47
+ this.cornerRadius = cornerRadius;
48
+ }
49
+ /**
50
+ * Updates the component's width (abstract method)
51
+ * @abstract
52
+ */
53
+ updateWidth(){};
54
+ /**
55
+ * Updates the component's height (abstract method)
56
+ * @abstract
57
+ */
58
+ updateHeight(){};
59
+ /**
60
+ * Converts RGB color string to array of numbers
61
+ * @param {string} shadowColor - RGB color string like "rgb(255,255,255)"
62
+ * @returns {number[]|null} Array of [r, g, b] values or null if invalid
63
+ */
64
+ rgbToArray(shadowColor) {
65
+ let match = shadowColor.match(/\d+/g);
66
+ return match ? match.map(Number) : null;
67
+ }
68
+ /**
69
+ * Renders a shadow effect around the component
70
+ * @param {Object} options - Shadow rendering options
71
+ */
72
+ drawShadow({}={}){
73
+ let color = this.rgbToArray(this.shadowColor);
74
+ if(color==null){
75
+ console.log("shadow color value is not in the correct format: rgb(0,0,0)");
76
+ return;
77
+ }
78
+
79
+ if(this.shadowIntensity>1){
80
+ this.shadowIntensity=1;
81
+ console.log("shadow intensity should be between 0 and 1 inclusive.\nAny value given outside of the range will be clipped to the ends.");
82
+ } else if(this.shadowIntensity<0){
83
+ console.log("shadow intensity should be between 0 and 1 inclusive.\nAny value given outside of the range will be clipped to the ends.");
84
+ this.shadowIntensity=0;
85
+ }
86
+
87
+ for(let i=1; i<=this.shadowDetail; i++){
88
+ push();
89
+ noFill();
90
+ let alpha = this.shadowIntensity * pow(1 - i / this.shadowDetail, 2);
91
+ stroke(`rgba(${color[0]}, ${color[1]}, ${color[2]}, ${alpha})`);
92
+ strokeWeight(this.shadowSpread);
93
+ rect(this.x-((i*this.shadowSpread)/2), this.y-((i*this.shadowSpread)/2), this.width+(i*this.shadowSpread), this.height+(i*this.shadowSpread), this.cornerRadius);
94
+ pop();
95
+ }
96
+ }
97
+ }
Binary file
package/index.html ADDED
@@ -0,0 +1,15 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.9.4/p5.js"></script>
5
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.9.4/addons/p5.sound.min.js"></script>
6
+ <link rel="stylesheet" type="text/css" href="style.css">
7
+ <meta charset="utf-8" />
8
+
9
+ </head>
10
+ <body>
11
+ <main>
12
+ </main>
13
+ <script type="module" src="sketch.js"></script>
14
+ </body>
15
+ </html>
package/package.json ADDED
@@ -0,0 +1,23 @@
1
+ {
2
+ "name": "@usman404/crowjs",
3
+ "version": "1.0.2",
4
+ "description": "lightweight and extensible GUI library built on top of p5.js",
5
+ "keywords": [
6
+ "CROWJS"
7
+ ],
8
+ "homepage": "https://github.com/UsmanAli404/P5GUI#readme",
9
+ "bugs": {
10
+ "url": "https://github.com/UsmanAli404/P5GUI/issues"
11
+ },
12
+ "repository": {
13
+ "type": "git",
14
+ "url": "git+https://github.com/UsmanAli404/P5GUI.git"
15
+ },
16
+ "license": "MIT",
17
+ "author": "Usman Ali",
18
+ "type": "commonjs",
19
+ "main": "sketch.js",
20
+ "scripts": {
21
+ "test": "echo \"Error: no test specified\" && exit 1"
22
+ }
23
+ }